From 10452115d7f1de20568ba8f5962440317fbf5120 Mon Sep 17 00:00:00 2001 From: fraxle Date: Sun, 7 Jun 2026 16:28:10 +0100 Subject: [PATCH] 2.9.5 Fix day cycle --- assets/js/app.js | 17 ++++++++++++----- assets/js/components.js | 4 ++-- data/tracking.json | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/assets/js/app.js b/assets/js/app.js index d583ecf..578736f 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -35,6 +35,7 @@ import { POLLEN_TYPES, COL_DESCRIPTIONS, UTCI_ENVIRONMENTS } from './config.js'; import { useAppState } from './hooks/useAppState.js'; import { DayTabs } from './components/DayTabs.js'; import { computeWhyFeelsLike, computeGlanceSummary } from './compute.js'; +import { solarElevationDeg } from './physics.js'; import { exportDayXls } from './export.js'; const html = htm.bind(h); @@ -262,13 +263,19 @@ export function UTCIForecast() { // Derived from currentRow and the active day - no side effects. const whyFeelsLike = computeWhyFeelsLike(currentRow ?? null, UTCI_ENVIRONMENTS[utciEnv]); - // During time-lapse, the scope reads an interpolated row at the simulated - // instant instead of the live "now" row. Everything else stays on real now. + // Interpolated row at the precise current instant — used for the scope + // display even outside playback so there's no jump when play is pressed. + const nowRow = interpolateRowAt(hourlyRows, now.getTime()); + // During time-lapse, advance from simMs; otherwise fall back to nowRow/currentRow. const simRow = (playing && simMs != null) ? interpolateRowAt(hourlyRows, simMs) : null; - const scopeRow = simRow || currentRow; - const scopeElev = simRow ? simRow.elev : (liveElev ?? currentRow?.elev ?? 0); + const scopeRow = simRow || nowRow || currentRow; + // Elevation computed continuously from the simulated instant so the sun + // starts exactly where liveElev left off (same solarElevationDeg call). + const scopeElev = (playing && simMs != null && location?.lat != null) + ? solarElevationDeg(location.lat, location.lon, new Date(simMs)) + : (liveElev ?? currentRow?.elev ?? 0); const scopeDt = simRow ? simRow.dt : now; - const scopeCat = simRow ? utciCategory(simRow.utciAdj) : currentCat; + const scopeCat = scopeRow ? utciCategory(scopeRow.utciAdj) : currentCat; // Synthesize a storm overlay (lightning) when the simulated hour is wet; // outside playback keep the real active event. const scopeEvent = simRow ? ((simRow.precip ?? 0) >= 4 ? { id: 'storm' } : null) : lensEvent; diff --git a/assets/js/components.js b/assets/js/components.js index 1961121..d4f510f 100644 --- a/assets/js/components.js +++ b/assets/js/components.js @@ -616,7 +616,7 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date(), g c = blendHex(c, greyTarget, tintAmt * 0.3); // weather grey return c; } - const snowTone = blendHex(skyBotTint, '#ffffff', 0.6); // snow caps (dim at night) + const snowTone = blendHex(skyBotTint, '#ffffff', isDay ? 0.6 : isTwil ? 0.38 : 0.20); // Readout scrim colour: light by day (dark text), dark by night (light text). const scrimColor = isDay ? '#f1e8d0' : '#0b0916'; @@ -693,7 +693,7 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date(), g // Alpine: a distant range of irregular, jagged peaks (not pyramids) — // off-centre summits with sub-shoulders, hazier the further back. if (spec.obj.mountains) { - const capTone = blendHex(skyBotTint, '#ffffff', 0.72); // snow, cycle-lit + const capTone = blendHex(skyBotTint, '#ffffff', isDay ? 0.72 : isTwil ? 0.46 : 0.24); const mtn = (x, w, h, seed, d) => { const r = seededRng(seed); const tone = objTone('#6a6258', d); // rocky; far = hazier diff --git a/data/tracking.json b/data/tracking.json index 1fad780..b26d1fe 100644 --- a/data/tracking.json +++ b/data/tracking.json @@ -1,6 +1,6 @@ { "2026-06-07": { - "visits": 1, + "visits": 2, "profiles": { "showall": 1 }