2.9.1
Smoother animations
This commit is contained in:
+17
-12
@@ -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>
|
||||
${(() => {
|
||||
|
||||
Reference in New Issue
Block a user