3D replay: auto theme default, speed + glide-ratio trail colours, camera continuity across backdrop switches#233
Merged
Conversation
- Theme defaults to auto ('system') when nothing is stored — follows
prefers-color-scheme live. Explicit dark/light choices are untouched.
- New 'Speed' trail colouring: per-vertex smoothed ground speed
(prefix-sum path length over the same +/-3-fix window as vario,
computed at load), rendered on the sequential ramp from SPEED_MIN to
SPEED_MAX (18-108 km/h; the floor isn't 0 because nobody flies below
stall speed, which would waste the ramp's bottom third). Useful for
reading strategy: thermalling drift vs cruise vs full-bar glides.
- New 'Glide ratio' trail colouring: red (poor) -> yellow -> green
(good), scaled logarithmically over 2..32 so a 4->8 improvement
reads as strongly as 16->32. Climbing/level segments render flat in
the themed vario-zero colour - glide is effectively infinite there.
- Colour-scale legend covers both modes (speed in the user's units;
glide as ratios with the geometric-mean midpoint and a
'climb = grey' note).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZpFYsCEyR7ck3bWmQNhCr
Switching abstract <-> map snapped to each backend's default framing — a jarring loss of continuity. Both camera models reduce to the same five numbers, so rebuild() now captures a backend-agnostic ViewState from the outgoing backend and seeds the incoming one (setInitialView before mount, applied instead of the default whole-task framing): - look-at point in local ENU (y = 0 from the map side — it has no elevated look-at), - bearingDeg (shared compass convention), - pitchDeg (0 = straight down; abstract's polar angle maps 1:1, clamped to Mapbox's 85 max), - mpp — metres per pixel at the view centre, which carries the zoom without either side knowing the other's projection model: abstract distance = mpp*viewportH / (2*tan(fov/2)); map zoom = log2(40075016.686*cos(lat)/mpp) - 9 (the exact inverse of its getMetresPerPixel). Theme switches ride the same path, so they no longer reset the camera either. Round-trip pinned by terrain-view.test.ts (mocked mapbox); Playwright verifies bearing and scale-bar width survive a rebuild. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DZpFYsCEyR7ck3bWmQNhCr
|
Preview Deployment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #230.
Auto is the default theme
With nothing stored, the replay now follows the OS colour scheme (
'system') instead of defaulting to dark — and keeps following it live. Users who explicitly picked Dark or Light are unaffected (their stored choice wins).New trail colouring: Speed
Colours the trail by ground speed — useful for reading strategy: thermalling drift vs cruise vs full-bar glides jump out at a glance.
assembleTracks(horizontal path length over the same ±3-fix window as the vario smoothing, via a per-pilot prefix sum — no inner loop), fed to the trail shader as a newaSpeedattribute shared by the line and points passes.SPEED_MIN= 18 km/h toSPEED_MAX= 108 km/h. The floor isn't 0 — nobody flies below stall speed, and anchoring the ramp at 0 wasted its bottom third and compressed the useful range (first cut did exactly that; re-ranged after eyeballing).New trail colouring: Glide ratio
t = log2(g/2)/log2(16)in the shader, fromaSpeed / −aVario).Both modes get colour-scale legends: speed in the user's preferred units (
≤18 km/h … ≥108 km/h), glide as ratios with the geometric-mean midpoint (≤2 · 8 · ≥32 · climb = grey).Camera continuity across backdrop (and theme) switches
Switching Abstract ↔ Map used to snap to each backend's default framing — a jarring loss of continuity. Both camera models reduce to the same five numbers, so
rebuild()now captures a backend-agnosticViewStatefrom the outgoing backend and seeds the incoming one (setInitialViewbeforemount(), applied instead of the default whole-task framing):y= 0 from the map side — it has no elevated look-at),bearingDeg(shared compass convention),pitchDeg(0 = straight down; abstract's polar angle maps 1:1, clamped to Mapbox's 85° max),mpp— metres per pixel at the view centre, which carries the zoom without either side knowing the other's projection model: abstract camera distance= mpp·viewportH / (2·tan(fov/2)); mapzoom = log2(40075016.686·cos(lat)/mpp) − 9, the exact inverse of itsgetMetresPerPixel.Theme switches ride the same path, so they no longer reset the camera either.
Verification
bun run typecheck:allpasses; replay unit tests 17/17 (terrain-follow, newterrain-viewround-trip: applyView → getViewState recovers x/z/bearing/pitch/mpp exactly, pitch clamps at 85°, zoom accounts for latitude).docs/3d-flight-replay-notes.md§5.14b).🤖 Generated with Claude Code
https://claude.ai/code/session_01DZpFYsCEyR7ck3bWmQNhCr