Smoother animations
This commit is contained in:
fraxle
2026-06-07 10:05:20 +01:00
parent 1459740d96
commit b3c9ed2068
+17 -12
View File
@@ -79,7 +79,7 @@ const GROUND_SPEC = {
// desert-green, parasol warm, boat sail-coloured, etc. Run through the cycle
// (objTone) at render time so they darken at night, warm at sunset, etc.
const MATERIAL = {
oak: '#4f7d39', pine: '#356040', bush: '#5a8a44', hedge: '#4c7a3e',
oak: '#4f7d39', pine: '#356040', bush: '#2e5218', hedge: '#4c7a3e',
cactus: '#5f8a4a', palm: '#4a7d3e', parasol: '#bb5a46', reed: '#74803c',
boat: '#ccc4ad',
};
@@ -540,19 +540,23 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date(), g
// running instead of restarting (which looked like the clouds shaking).
const cloudDim = isDay ? 1 : 0.55; // moonlit clouds read dimmer at night
function buildCloudLayer(cov, yBand, scale, durSec, seed, key) {
if (cov == null || cov < 8) return null;
const f = Math.min(1, cov / 100);
const count = Math.round(1 + f * 3); // 1..4 sprites
// Always render the maximum 4 sprites so existing <image> elements persist
// in the DOM and their opacity can CSS-transition instead of blinking in/out.
const maxCount = 4;
const f = cov != null ? Math.min(1, cov / 100) : 0;
const activeCount = (cov != null && cov >= 8) ? Math.round(1 + f * 3) : 0;
const baseOp = Math.min(0.9, (0.22 + f * 0.6) * cloudDim);
const w = 92 * scale, hh = 48 * scale;
const op = Math.min(0.9, (0.22 + f * 0.6) * cloudDim);
const imgs = [];
for (let k = 0; k < count; k++) {
const px = (seed * 47 + k * (200 / count)) % 200;
for (let k = 0; k < maxCount; k++) {
const px = (seed * 47 + k * (200 / maxCount)) % 200;
const py = yBand + (((seed + k * 7) % 12) - 6);
const spriteOp = k < activeCount ? baseOp : 0;
[px, px + 200].forEach((X, j) => {
imgs.push(html`<image key=${k + '-' + j} href=${CLOUD_IMG}
x=${(X - w / 2).toFixed(1)} y=${(py - hh / 2).toFixed(1)}
width=${w.toFixed(1)} height=${hh.toFixed(1)} opacity=${op.toFixed(2)}
width=${w.toFixed(1)} height=${hh.toFixed(1)} opacity=${spriteOp.toFixed(2)}
style="transition:opacity 2s ease"
preserveAspectRatio="xMidYMid meet" />`);
});
}
@@ -1006,11 +1010,11 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date(), g
<circle cx=${cx} cy=${cy} r=${lensR} />
</clipPath>
<linearGradient id="scope-lens-sky" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color=${skyTopTint} />
<stop offset="100%" stop-color=${skyBotTint} />
<stop offset="0%" stop-color=${skyTopTint} style="transition:stop-color 2s ease" />
<stop offset="100%" stop-color=${skyBotTint} style="transition:stop-color 2s ease" />
</linearGradient>
<linearGradient id="scope-lens-grass" x1="0" y1="0" x2="0" y2="1">
${groundStops.map((s, i) => html`<stop key=${i} offset=${s.off + '%'} stop-color=${s.col} />`)}
${groundStops.map((s, i) => html`<stop key=${i} offset=${s.off + '%'} stop-color=${s.col} style="transition:stop-color 2s ease" />`)}
</linearGradient>
<!-- Soft scrim behind the readout so the numbers stay legible over busy ground -->
<radialGradient id="scope-readout-scrim" gradientUnits="userSpaceOnUse" cx=${cx} cy="142" r="50">
@@ -1065,7 +1069,8 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date(), g
<circle cx=${cx} cy="142" r="50" fill="url(#scope-readout-scrim)" />
<g key="scope-wx">
${cloudLayers}
${fogAlpha > 0 && html`<rect x="0" y="0" width="200" height="200" fill=${`rgba(${fogColor},${fogAlpha.toFixed(2)})`} />`}
<rect x="0" y="0" width="200" height="200" fill=${`rgb(${fogColor})`}
opacity=${fogAlpha.toFixed(2)} style="transition:opacity 2s ease" />
</g>
</g>
${(() => {