Skip to content

Releases: chipi/orrery

v0.6.3

16 May 21:22

Choose a tag to compare

Mobile UX + reliability pass. Five user-filed mobile polish issues (#125-#129) plus three v0.6.2 follow-ups land together: missions density matches fleet, science-lens overlap on /fly cleared, space-stations black-canvas race fixed, deterministic e2e replacing retry-passes, release tooling made truly one-command, bundle warning silenced, and the encyclopedia gains two curated companion lists.

Added

  • Reading list at /science/reading-list (issue #128) — 8 curated beginner-to-intermediate space books (Cosmos, Pale Blue Dot, A Brief History of Time, The Right Stuff, Packing for Mars, Rocket Propulsion Elements, Fundamentals of Astrodynamics, How to Read the Solar System) + 5 long-form blog/journalism recommendations (Planetary Society, Casey Handmer, Eric Berger / Ars Technica, NASA Spaceflight Forum, Damn Interesting). Audience badges (beginner/intermediate/advanced), explanatory blurbs.
  • Watch list at /science/watch-list (issue #129) — 7 sci-fi films (Contact, Interstellar, 2001, The Martian, Apollo 13, Moon, For All Mankind), 4 documentaries (For All Mankind '89, In the Shadow of the Moon, Cosmos: A Personal Voyage, When We Left Earth), 3 podcasts (Off-Nominal, MECO, Are We There Yet?), 4 YouTube channels (Scott Manley, Everyday Astronaut, Veritasium, PBS Space Time).
  • Both new pages are anchored as tab cards at the bottom of the /science rail nav. New paraglide keys science_tab_reading_list + science_tab_watch_list in en-US; other 13 locales fall back to JS title-casing via the existing tabLabel helper (full localisation deferred to the next wave23 batch).
  • scripts/release-rehearsal.ts — interactive version bump + CHANGELOG scaffold (issue #223). When the script detects package.json.version doesn't match the argument version, it offers to bump it via a [Y/n] prompt. When the CHANGELOG section is missing, it offers to scaffold a stub with today's date + empty Added/Fixed/Changed shells. Non-TTY contexts (CI, scripted) take the "no" default — the fail-closed contract from v0.6.2 #134 holds.
  • .github/workflows/release.yml auto-publishing GH Release on tag push (was v0.6.2 work but properly exercised for the first time on v0.6.3 — confirmed idempotent on the v0.6.2 retag, marked Latest only for stable semver).

Changed

  • Mobile mission tiles → 2-per-row (issue #125) — /missions card grid uses repeat(auto-fill, minmax(150px, 1fr)) on ≤600 px so the layout matches /fleet density (which the user prefers). Both surfaces carry agency logos so the same minimum-width floor works; very narrow viewports (<340 px) degrade gracefully to 1 column.
  • Equal-height cards in /missions + /fleet grids (issue #225) — within a row, card heights now stretch to match the tallest. Was sizing to content, so a card with a long name + caveat sat taller than its neighbours and broke the visual rhythm. Two-line fix per file: .card-li { height: 100% } + .card { height: 100% }.
  • Science layers panel — collapsed-by-default on mobile, raised z-index (issue #126) — the expanded panel was overlapping /fly's CAPCOM ticker. Now ships as a strip on ≤600 px (tap to expand), max-height 50vh → 40vh, z-index 32 → 37 so the active interaction renders above the CAPCOM panel rather than under it.
  • /science wider page + flexible right rail (issue #226) — .page max-width 1200 → 1440 px, right rail track 220px → minmax(220px, 320px). On viewports >1200 px the layout was sitting centered with empty margin on the right, and the right-rail section list couldn't grow into that space. Now wider viewports get more usable area and the section list claims some of it (capped so the prose column stays dominant). Mid-range (768-1024 px) behaviour unchanged.
  • vite.config.ts chunk-size warning ceiling 500 → 700 kB (issue #224). Identified the two offenders: three.module.js ~513 kB (already auto-chunked by Vite, can't tree-shake further at the SvelteKit layer) and Paraglide's messages.js ~665 kB (per-locale split needs an outputStructure: 'locale-modules' change in inlang/project — deferred follow-up). Both intentional; raising the ceiling stops the build log from carrying a known-known every release. >700 kB is now the real regression flag.

Fixed

  • Space stations 3D black-canvas on cold mount (issue #127). /iss + /tiangong kicked off startThree() via queueMicrotask after onMount set viewMode='3d', but queueMicrotask fires BEFORE the browser's first layout pass on a cold load — so container.clientWidth read 0 and the renderer was sized 0×0, giving a permanent black screen until something else triggered a resize (the workaround the user reported: navigating away and back). Fix: new startThreeWhenSized() wrapper subscribes a ResizeObserver to the container and starts THREE on the first non-zero size emit. Synchronous when container is already sized (no regression in the happy path).
  • /moon + /mars: rotate planet to face the deep-linked site (issue #227). When a mission card's "to the surface" cross-link lands on /moon?site=X or /mars?site=X, the panel + halo open but previously the planet stayed in its default orientation — the site itself could be on the far side, invisible until the user manually dragged. New faceMoonAtSite() / faceMarsAtSite() callbacks (gated on a face: true option to selectSite) compute the longitude angle of the site and set moonMesh.rotation.y / marsMesh.rotation.y so the site lands on the camera-facing +Z hemisphere. autoSpin pauses so it stays put. Latitude isn't adjusted (camera moves would be a heavier change), but the longitude flip alone fixes the "site on far side" case the user reported.
  • /fly red-dot vs blue-tube split — root-cause rewrite (issue #228). Five prior attempts (v0.6.1 sprite-tube alignment, v0.6.2 future-tube tip snap, plus three intermediate translations) treated symptoms. A debug log on the v0.6.2 build showed the gap between the TubeGeometry cross-section centroid and the spacecraft sprite peaking at 20.33 scene-units mid-arc (Earth orbit is 80 units, so the gap was visually huge). Root cause: THREE.TubeGeometry samples its curve via getPointAt(arc-length uniform u) even when the source PolylineCurve3 overrides getPoint(t) to be a uniform-t lerp. For Kepler ellipses sampled at uniform true anomaly (transferEllipse in mission-arc.ts), adjacent-chord lengths differ by ~10× between perihelion and aphelion — so arc-length-uniform u disagreed with uniform-t parameter by exactly the gap we were chasing. Heliocentric tubes rewritten as one mesh per leg with a manual builder that places cross-sections at exactly pts[i] and a ShaderMaterial whose fragment shader paints bright if vT<uProgress, dim otherwise — boundary lands at the sprite by mathematical identity (proven numerically against a Kepler-shape unit test, zero gap across 100 sampled t values). Same shader-gradient treatment applied to cislunar phase lines (#228b): each phase line carries per-vertex aT, per-frame uProgress derived from met_days vs phase's [start_met_days, end_met_days] window. Net delete: outLineFuture/retLineFuture meshes, snapTubeTip vertex-mutation function + tipMutation cache, PolylineCurve3 class (now unused), v0.6.2 debug console.log. ~140 LOC added, ~210 LOC removed.
  • 5 flaky mobile e2e tests — deterministic waits replacing retry-passes (issue #222). v0.6.2's release rehearsal had 5 mobile-chromium tests passing on retry: earth.spec (satellite click) added a 150 ms panel.waitFor({state:'visible'}) per click instead of bare isVisible(); earth.spec (ISS GALLERY thumbnails) bumped timeout 5 s → 10 s for image-load on slow CI; fly.spec (3D/2D toggle) swapped fragile role+name regex for [data-testid="fly-view-toggle"] + not.toHaveText(initialLabel); _helpers/nav.ts.clickNavLink waits for the drawer link to be visible before clicking (covers i18n-pt-BR.spec); mars.spec (FULL MISSION CARD cross-link) dropped waitForLoadState('networkidle') (mars streams canvas textures continuously, never hits the 500 ms quiet window) + bumped cross-link timeout to 10 s.

v0.6.2

16 May 14:51

Choose a tag to compare

Reliability + release-tooling pass on top of v0.6.1. Tightens the e2e suite (deterministic readiness signals, body-text translation coverage, Linux visual baselines), removes a parallel-agent footgun in validate-data, and codifies the AGENTS.md release-readiness checklist as actual tooling — a one-command pre-tag dry run and an auto-publish GH Release workflow on tag push.

Added

  • npm run release:rehearsal vX.Y.Z (issue #134) — single command that runs preflight + e2e on both desktop-chromium and mobile-chromium projects, extracts the matching ## [X.Y.Z] block from CHANGELOG.md, and creates a DRAFT GH Release. Fail-closed on any step. Codifies the AGENTS.md §"Before tagging or releasing" checklist so the rule is verifiable, not just documented.
  • .github/workflows/release.yml — auto-publish GH Release on tag push (issue #135). Fires on any v* tag push. Extracts the CHANGELOG section, creates the Release with that body, marks Latest only for stable semver (pre-releases like v0.6.2-rc1 don't bump the homepage marker). Idempotent — re-runs on a re-tagged commit update the existing Release. Eliminates the "tagged but no Release" failure mode that hit v0.6.0 + v0.6.1.
  • Mobile Cmd-K affordance in /science (issue #137) — the encyclopedia search trigger is now reachable on ≤640 px viewports via a Search row in the hamburger drawer. Same aria-label as the desktop rail Search button, so getByRole('button', {name: /Search the encyclopedia/i}) matches in both viewports. New nav_search paraglide key in all 14 locales.
  • scripts/regenerate-visual-baselines-linux.sh + npm run regen-visual-baselines-linux (issue #132). Runs the pinned Playwright Docker image with a host-side .linux-node-modules/ overlay so Linux visual baselines are generated bit-identical to CI's ubuntu-latest runner, without touching the host's darwin install. Six new *-linux.png baselines committed; the test.skip(process.platform !== 'darwin') guard from v0.6.1 is dropped.
  • docs/guides/visual-regression-baselines.md — full regeneration workflow + commit conventions + three documented failure modes (esbuild arch collision, /.npm EACCES, non-deterministic renders). Cross-linked from visual.spec.ts.
  • tests/e2e/i18n-body-text-desktop.spec.ts (issue #131) — desktop-only smoke covering 6 EU-Latin locales (de/es/fr/it/nl/pt-BR) asserting that a translated body-text token (plan_empty_title) actually renders. Closes the coverage gap the v0.6.1 html[lang]-only migration left: a silent Paraglide en-US fallback on a translated screen now fails the smoke instead of passing.

Fixed

  • /fly 3D ↔ 2D hash-invariant flake — deterministic readiness signal (issue #133). Replaces the v0.6.1 data-out-vertex-hash stability poll with ADR-056 hooks: window.__flyArcHash() + window.__fly2DArcHash() return the stable 11-vertex hash or null while hydrating; window.__flyMissionId() returns the id of the mission most recently committed to page $state. Reading from Svelte's reactive $state at call time eliminates the microtask gap between framework flush and DOM attribute write. Targeted run (12 cases): 5 consecutive runs, zero flake. Full suite: 62/62 in 1.3 min.
  • validate-data no longer scans untracked PRD/RFC drafts (issue #136). Scoped the doc-gating-sentence check to git ls-files docs/prd docs/rfc docs/adr so a parallel agent's untracked draft can't refuse your unrelated git push. Staged-but-uncommitted files still get gated. Falls back to the filesystem walk if git isn't accessible (CI shallow-clone edge case). The stash-and-restore workaround from AGENTS.md §"Pre-push hook quirks" + CLAUDE.md §"Untracked PRD/RFC drafts" is dropped.

Changed

  • AGENTS.md + CLAUDE.md updated with v0.6.2 references: the new pre-push behaviour (#136), the release rehearsal script (#134), the auto-publish workflow (#135), and the linux visual baseline workflow (#132).

v0.6.1 — e2e stability + footer + /fly 3D fix + PWA auto-update + space-themed docs

16 May 09:54

Choose a tag to compare

A patch landing the day after v0.6.0 to stabilise CI / e2e, add a build-date stamp + README + CHANGELOG links in the footer, fix a long-standing /fly 3D sprite-tube alignment bug, switch the service worker to silent auto-update, and ship a space-themed VitePress docs site.

Added

  • Footer build date + README + CHANGELOG links — the footer now reads Gallery | Credits | Library | License | README | v0.6.1 · 2026-05-16. README is a separate link (back from being merged into the version pill); the version + deploy-date pill links to CHANGELOG.md on GitHub instead of the README. Build date is injected at build time via Vite define (same pattern as __APP_VERSION__), so it doubles as a quick-scan "this is the build live on GH Pages today" signal.
  • VitePress docs site — space theme + guides folder — full docs/ rewrite with a custom theme (docs/.vitepress/theme/custom.css) matching the production app palette (--orrery-bg #04040c, gold #ffc850, teal #4ecdc4, mars #c1440e); Bebas Neue + Space Mono + Crimson Pro from Google Fonts; static starfield + radial-gradient glow on the home hero (pure CSS, no images). Navigation revised: Home / Guides (user + translator) / Decisions (TA / ADR / RFC / PRD indices) / ↗ Live App. Footer + sidebar + tables + code blocks + custom blocks re-tinted; local-search input + outline-on-right + 640 px mobile breakpoint tuned. npm run docs:build green after fixing 15 dead links surfaced by the guide move.

Changed

  • PWA service worker → silent auto-updatevite.config.ts switches registerType: 'prompt' to 'autoUpdate'. New SW bundles install silently on the user's next navigation instead of surfacing a "new version · refresh" toast that asked the user a question they couldn't answer with context. Modern PWA default (Twitter / Slack / Discord behaviour). Trade-off: a user with the app open for hours stays on the old version until they navigate — acceptable for an explorer / docs app. Drops layout_pwa_new_version + layout_pwa_refresh message keys across all 14 locales.

Fixed

  • /fly 3D sprite-tube tip alignment — the red dot lagged on outbound and led on return because spacecraftPos() and the in-frame snapTubeTip() lerp re-derived the spacecraft's position from the same waypoints through two independent code paths; algebraically identical, visually drifty under sustained playback. Refactored snapTubeTip to translate the tip cross-section directly to sc.pos × SCALE_3D (single source of truth), so the tube cone tip and the sprite are guaranteed to coincide every frame, on both arcs.
  • Mobile e2e regressions (hamburger drawer) — 14 i18n locale-chip smoke specs + fleet.spec (nav exposes the FLEET link) + smoke.spec (nav bar is visible …) targeted the desktop .center nav strip, which is display: none on ≤640 px viewports since the v0.6.0 mobile-nav overhaul. New tests/e2e/_helpers/nav.ts exposes clickNavLink() + localeChip() — viewport-aware nav navigation, and the locale-chip locator is scoped to [data-locale-picker] so it doesn't collide with button.chip filter chips on screens like /fly. The remaining 2 affected suites (fleet.spec + smoke.spec) open the menu inline.
  • /science Cmd-K spec skipped on mobile — the Search button is display: none on ≤640 px (desktop affordance, see src/routes/science/+layout.svelte); the two Cmd-K specs now test.skip() on mobile viewports.
  • Visual-regression baselines skipped on non-darwinvisual.spec.ts baselines are committed as *-darwin.png (maintainer's machine); CI Linux looks for *-linux.png and reports "missing baseline" on every run. Suite now test.skip()s on non-darwin until linux baselines are committed too. Local darwin runs still execute the assertions.
  • /library axe scan timeout in CI — 678 outbound-link rows × every axe rule exceeded the per-test 30 s playwright budget on cold Ubuntu runners (35–43 s in failing runs). Bumped to 90 s for /library specifically; other a11y-pilot routes stay on the default.
  • missions.spec count drift — Apollo 13 shipped as the 37th mission (17th Moon entry) in v0.6.0, but the spec was still asserting 36 / 16. Bumped to 37 / 17 to match.
  • fly-render-validation 3D ↔ 2D hash-invariant flake — Mariner 4, Apollo 11, and Apollo 17 occasionally failed on the first run and passed on retry. Bumped the data-view='2d' wait from 5 s to 10 s; swapped the locator to [data-testid="fly-view-toggle"] (more stable than a label regex now that the toggle row has five sibling panel-visibility buttons).
  • e2e workflow timeout 40 → 60 min — the suite is 23–30 min steady-state, but flaky retries plus the /library axe scan push the worst case past 40. 60 min gives 2× margin without masking a runaway hang.

Internal

  • @playwright/test 1.59.1 → 1.60.0 — dedup playwright-core to a single version so svelte-check no longer sees two distinct Page types (was blocking CI typecheck after @axe-core/playwright landed and pulled playwright-core@1.60.0).
  • package-lock.json regenerated with --cpu=x64 --os=linux --include=optional — keeps the Linux-only native deps (@emnapi/core, @emnapi/runtime, esbuild@0.28.0, yaml@2.9.0) in the lockfile so GH Actions runners' npm ci doesn't reject the sync.

v0.6.0 — cislunar /fly + /fleet + landing page + Observation/Life-in-space science tabs

16 May 09:54

Choose a tag to compare

The cislunar release. /fly learns Moon-mission geometry — every Apollo-class free-return, Artemis hybrid free-return, Chandrayaan-3 spiral, and Chang'e LOR rendered as its own per-profile trajectory in an Earth-centred view. The /science encyclopedia grows two new tabs (Observation + Life in Space). A new top-level /fleet explorer ships. And the visit starts on a real landing page at / instead of an explore-redirect.

Added — cislunar /fly view (ADR-058)

  • Per-mission cislunar trajectory machinerybuildCislunarTrajectory() parses each Moon mission's new flight.cislunar_profile (parking orbit, TLI ∆v + C3, translunar type, lunar arrival altitude / periselene, return ∆v) and produces a typed phase sequence (parking → tli_coast → lunar_arrival → tei_coast → reentry). 17 Moon missions populated (Apollo 11/13/17 + Artemis 2/3 + Luna 9/17/24 + LRO + Clementine + Chandrayaan 1/3 + Chang'e 4/5/6 + SLIM + Blue Moon Mk1).
  • Earth-Centred Inertial scene at true Earth-Moon scale (SCALE_CISLUNAR = 1/10 000) — auto-engages for any mission whose dest === 'MOON'. Phase-coloured trajectory lines, ∆v annotation sprites, real Earth + Moon textures, moon-frame group that tracks lunar drift so lunar-orbit / descent / ascent phases anchor to the Moon as it moves.
  • Auto-zoom across phases — camera close to Earth during parking / spiral_earth / reentry, pulled back across translunar coast, lerped in toward the Moon during lunar_orbit / lunar_flyby / descent / ascent. Mouse-wheel during a phase wins; next phase transition re-arms the lerp.
  • Moon-proximity override — flyby-only profiles (Artemis II, Apollo 13) have no explicit lunar_flyby phase, so the camera now zooms whenever the spacecraft computes to within 80 000 km of the Moon centre, regardless of phase type.
  • 8 science layers wired into the cislunar scene at parity with heliocentric — hover, soi, gravity, velocity, centripetal, apsides, coast, conics. SoI rings sized to Earth (924 000 km) + Moon (66 100 km). Coast preview integrates a two-body Earth-gravity prediction forward 33 h.
  • Heliocentric auto-zoom (interplanetary missions) — DEPARTURE close-up on Earth → wide cruise framing on the Earth↔destination midpoint → APPROACH close-up on the live destination. Mirror sub-phases for round-trips. Tube drawRange round-snaps to whole segments so the sprite stays aligned with the trajectory tip under close-up zoom.
  • 2D cislunar fallback for the /fly 2D toggle — same per-mission geometry rendered to canvas with Earth at centre and an auto-zoom on lunar phases.
  • Apollo 13 added as the 37th mission — free-return flyby with aborted LOI.

Added — /science Observation + Life in Space tabs

  • Observation tab (S1–S3 / issues #80 #81) — 7 sections covering Adaptive Optics · Black Holes · Coronagraphs · Interferometry · Space Photography · Spectroscopy · Wormholes. New ObservatoryShowcase strip on the space-photography section gallery imagery expanded to 96 observatory images across the fleet gallery pipeline.
  • Life in Space tab (S2 / issue #80) — sections covering microgravity, radiation, IVA, EVA, lunar suits, long-duration life support, and crew-health topics. Three new suit-family sections (IVA / EVA / lunar suits) cross-link to /fleet.
  • /science now spans 85 sections across 10 tabs (was 54 / 8). 71 hand-coded SVG diagrams (was 62) — one per section + 10 tab covers, with the fail-closed integrity gate enforcing the count on every build.
  • Diagram polish pass — S6 wave repaints 50+ existing diagrams across orbits / transfers / propulsion / mission-phases / porkchop / scales-time to match the latest design-system tokens (flag flips, blueprint accents).
  • photo field wired into section pages — high-value imagery embedded on 18 sections (NASA / ESA observatory + agency photography), all with full image-provenance coverage.

Added — /fleet explorer + space-suit category

  • New top-level /fleet route — bill-of-materials view across the fleet (rockets, capsules, landers, rovers, orbiters, observatories) and now space-suits. Selection halos, per-planet pill colors on filters, Mars labels.
  • Space-suit category — 13 suit-family entries (en-US) with full provenance + i18n wave 2/3 across 12 locales + sr-Cyrl manual overlays for the 3 new suit sections. Wired into validate-data + schemas. Krechet placeholder + sokol-m fallbacks. linked_missions use real mission IDs.

Added — root / landing page (PRD-013 / UXS-013 / Issue #74)

  • Real landing replacing the / → /explore 307 redirect — hero (ORRERY 96 px wordmark + tagline + two CTAs), what-is-this section, why-this-exists section, multi-paragraph guided tour, 11-card grid covering every primary nav destination + /fleet, footer block linking to GitHub / README / License / Credits / Library / Technical Authority. Long-form scrollable single column, mobile-first (375 px → 1-col cards). 49 new landing_* keys translated to all 14 supported locales. Browser-locale auto-detection on first paint. 10 e2e tests on desktop + mobile.

Added — Dutch locale + i18n coverage

  • Dutch (nl) locale — 14th supported language (issue #72). Full UI bundle (711 keys) at 100% parity with the other 13 locales. Native name Nederlands, short tag NL, flag 🇳🇱. LocalePicker entry added between Italiano and Српски. Translations follow the ESA-NL physics/astronomy glossary; mission and agency proper nouns kept in original.
  • Dutch entity overlay tree — full coverage across missions / planets / sun / rockets / earth-objects / moon-sites / mars-sites / iss-modules / iss-visitors / tiangong-modules / tiangong-visitors / scenarios (161 files).
  • /science overlay gap closed for es/de/fr/it — 14 files (history/_intro + 6 history sections + space-stations/_intro + 4 space-stations sections + mission-phases/eva + scales-time/long-duration) translated for the four EU locales that already had partial coverage. Brings es/de/fr/it from 49 → 63 /science files each.
  • iss-visitors/ overlays for all 13 non-en-US locales — closes the en-US-only gap for cargo_dragon, crew_dragon, cygnus, htv_x, progress_ms, soyuz_ms, starliner. 7 files × 13 locales = 91 new files.
  • i18n wave 2/3 for 28 new sections + 13 suit entries across the 12 non-en-US locales.

Added — Mobile + Browser-locale ergonomics (ADR-057)

  • Browser-locale URL canonicalisation (Issue #73 Gap 1) — auto-detected locales rewrite the URL to the canonical ?lang=de form via replaceState, so bookmarks and share-links carry the locale. 10 unit + 5 e2e tests.
  • orrery_locale cookie for explicit locale overrides (Issue #73 Gap 2 / ADR-057 Accepted) — single functional cookie (SameSite=Lax, 1-year, no PII), written only on explicit LocalePicker click. Sits between URL and navigator.language in the resolution chain. Auto-detect paths never write the cookie.
  • Mobile UX overhaul — hamburger nav, collapsible /fly HUD on narrow viewports, compact /science section rail, footer-overlay improvements, per-planet pill colors.
  • Build version in footerCredits | Library | v0.6.0 strip; version injected via Vite define from package.json.
  • Nav wordmark polish — bumped to 36 px, vertically centred within the 52 px nav bar.

Added — Documentation + tooling

  • Tech BOM generator (closes #92) — scripts/build-tech-bom.ts writes docs/TECH-BOM.md listing every npm package shipped or used at build time, with version + license. License-audited fail-closed in CI.
  • PRD-014 + RFC-017 — Surface Hotspots (progressive landing-site exploration).
  • ADR-055, ADR-056, ADR-057, ADR-058i18n cookie scope, surface-map design, locale persistence cookie scope, cislunar /fly architecture.

Changed

  • /fly left rail consolidated — identity / navigation / flight-params / systems / spacecraft-state stack flush in one column. Top-controls bar puts FlightDirectorBanner + ScienceLayersPanel side-by-side instead of stacked vertically.
  • Solar / Cislunar /fly toggle de-scoped (ADR-058 amendment) — Moon missions render exclusively in cislunar view; heliocentric Moon-mode no longer toggleable. The PiP context inset was also dropped during smoke-testing.
  • Mars + maps polish — selection halos on /mars / /moon, label rendering for Mars sites, drop redundant README footer link.

Fixed

  • CI e2e timeout bumped 25 → 40 min for the v0.6 suite size.
  • apollo13.jpg sourced + suit-diagram spec-panel fixes; sokol-m placeholder.
  • Tech BOM GitHub-shorthand + LICENSE URL — unblocks the deploy.
  • Heliocentric tube/sprite alignment under close-up auto-zoom — round-snap fixes the visible offset.
  • Artemis II cislunar zoom — Moon-proximity check now fires for hybrid-free-return profiles that skip the explicit lunar_flyby phase.

Dependencies

  • Bulk Dependabot bump — vitest 2 → 4 · svelte 5.16 → 5.55 + 4 minor.

v0.5.0 — encyclopedia + explorers + LEARN-link stewardship

09 May 15:42

Choose a tag to compare

The encyclopedia + explorers release. Three new primary nav routes (/iss, /tiangong, /science), a layered "Science Lens" of live physics annotations across every 3D scene, and end-to-end outbound-link provenance discipline.

Closes the v0.5.0 milestone (#6) — Tiangong Explorer + the LEARN-link stewardship rollout — plus the Science encyclopedia (#39) and ISS Explorer (#41) bodies of work that were originally on v0.4.0 but read more cleanly here together.

/science — in-app encyclopedia (PRD-008 / RFC-011)

The headline of v0.5.0. 54 sections across 7 tabs: Orbits · Mission Phases · Planets & Bodies · Spaceflight · Space Stations · History · Space-101 landing.

  • 48 hand-coded SVG diagrams (engineering blueprint style — white-on-black with teal accents)
  • KaTeX server-rendered formulas — client receives static HTML, no JS math library (ADR-034)
  • Right-rail navigation, Cmd-K search overlay, narrative_101 lead-ins on every section
  • Cross-screen ?-chips deep-linking from /missions, /fly, /explore, /plan, /earth, /moon, /mars, /iss, /tiangong straight to the relevant chapter

/science integration with the rest of the app:

  • SCIENCE tab on every detail panel (MissionPanel, PlanetPanel, SunPanel, SmallBodyPanel)
  • Science Lens toggle gates a layer of in-scene physics annotations across every 3D scene
  • Flight Director banner on /fly — 5-phase narration (Departure · Trans-X Injection · Cruise · Approach · Arrival), each phase deep-linking to the matching /science section
  • Why? popovers explain individual numeric labels in context across every panel
  • Mission Sandbox layered onto /plan porkchop — pin one cell, click another → ΔDEP / ΔTOF / Δ∆v compare panel

Live physics overlays — Science Layers: Eleven sub-toggleable layers behind the lens — spheres of influence, hover info cards, gravity vectors, velocity vectors, centripetal arrows, apsides + true anomaly, engine-off coast preview, conic-section family panel, microgravity axes, atmosphere shells, tidal-lock indicator, ozone holes.

Closes #39.

ISS Explorer (/iss) — PRD-010 / RFC-013

A full station-explorer route built on a shared station-geometry library:

  • 32 modules (every USOS + ROS module + visiting craft) with per-module 3D pickability (raycast-driven panel open) plus hover outlines and emissive selection pulse
  • Full module panel: OVERVIEW · GALLERY · TECHNICAL · ANATOMY · SCIENCE · LEARN tabs
  • Per-module agency badges in the drawer
  • Sun-tracking solar-array animation
  • Microgravity axes lens-gated overlay (ZENITH/NADIR · PROGRADE/RETROGRADE · PORT/STARBOARD)
  • Orbit-regime banner with WhyPopovers on altitude/inclination/period
  • Hand-drawn ANATOMY diagrams for 9 visiting spacecraft (Crew Dragon, Soyuz MS, Cygnus, Dragon, Progress, HTV, Starliner, ATV, Shenzhou)
  • 2D blueprint views (top + side projections)

Closes #41.

Tiangong Explorer (/tiangong) — PRD-011 / RFC-014

Mirror of /iss for China's Tiangong station, built on the shared station-geometry library:

  • Tianhe core + Wentian + Mengtian lab modules with sun-tracking gallium-arsenide arrays
  • Three docked-vehicle slots (Shenzhou, Tianzhou, plus visiting spot)
  • Polished low-end fallback (auto-switch to list view on under-20 fps hardware)
  • ADR-048/049/050 lock the asset pipeline, module pickability rules, and low-end fallback contract

Closes #50.

LEARN-link stewardship — ADR-051

End-to-end discipline for every outbound link in the app:

  • L-A — ADR-051 + RFC-015 + audit doc (the policy)
  • L-B — Per-link provenance manifest + LinkCredit.svelte + LearnLink.svelte + AJV validation
  • L-C — Agency-portal LEARN-link enrichment (non-US first; native-language priority)
  • L-D — Public /library page (bill-of-links across the entire app); Mission Library renamed to Mission Catalog
  • L-E — Outbound link-checker chained into npm run fetch with freshness gating

Closes #51 epic + #52 / #53 / #54 / #55 / #56.

Test infrastructure — flake-free e2e under headless WebGL

The first run of the full e2e suite after the v0.5.0 UX wave landed exposed 46 stacked failures — the previous 25-min CI window kept being cancelled by superseding pushes before ever reaching them. Categorised + fixed in 3 commits:

  • 12 i18n locale tests broke when the LocalePicker added flag emojis (🇩🇪 DE instead of DE) — swapped to toContainText.
  • /missions filter pills + timeline collapsed by default; tests now click the strip open and the page auto-expands when filter URL params are present.
  • /plan porkchop selector collided with a ScienceChip aria-label; pinned tests to canvas.porkchop.
  • PlanetPanel LEARN tab folded into SCIENCE — tests follow.
  • FlightDirectorBanner inner anchor href; tests follow.
  • /iss + /tiangong canvas-click tests replaced their flaky spiral-search with a deterministic window.__pickAt() test hook + canvas.click({position}) (bypasses overlays).
  • All 8× waitForTimeout(<magic>) replaced with deterministic readiness signals: data-objects-count / data-sites-count / data-view / data-sim-day / data-sc-phase attributes.
  • /iss + /tiangong perf-fallback (FPS<20 → list mode) skipped under navigator.webdriver — software-rasterizer WebGL on GH Actions was tripping the gate.

Result: e2e job dropped from 25-min timeout to 16-min clean pass.

Stack notes

No new dependencies. Three.js still r128. SvelteKit + Paraglide-js + ajv + KaTeX (build-time only). Static export via adapter-static — still deploys to GitHub Pages with no backend.

🤖 Notes generated with Claude Code

v0.4.0 — Languages + Mars Surface Map + image credit stewardship

09 May 15:49

Choose a tag to compare

The internationalisation + maps + provenance release. All 12 supported locales now at 100% UI parity, full Mars Surface Map, and end-to-end image provenance discipline.

(/iss, /tiangong, and the /science encyclopedia all landed during this development window but are scoped to v0.5.0 — see the v0.5.0 release for those.)

Closes the v0.4.0 milestone (#5): #30 v0.1.10 audit cleanup, #36/#37/#38 i18n Waves 1/2/3, #40 Mars Surface Map, #44/#45 agency-first imagery, #47/#48 image credit rollout. (#39 Science and #41 ISS Explorer were originally also tagged to this milestone but are reframed under v0.5.0 in the release narrative since they form a coherent encyclopedia + explorer story together with Tiangong.)

Languages — 12 locales now fully covered

UI message bundle (684 keys) translated key-for-key across every supported locale: Spanish · French · German · Italian · Portuguese-BR · Mandarin · Japanese · Korean · Hindi · Arabic (RTL) · Russian · Serbian-Cyrillic. Locale picker shows national flags.

Closes #36 (Wave 1: fr/de/pt-BR/it) · #37 (Wave 2 CJK: zh-CN/ja/ko) · #38 (Wave 3: hi/ar-RTL/ru).

Mars Surface Map (/mars) — PRD-009 / RFC-012

A new primary nav route. Equirectangular 2D Mars map + 3D globe with surface-feature panels for landing sites, orbital probes, and major regions. Atmosphere shell layer (~120 km) lens-gated. Per-site GALLERY · TECHNICAL · LEARN tabs. Rover traverses rendered as cross-linked path overlays. 16 surface sites + 11 orbiters at ship.

Closes #40.

Image credit rollout — ADR-046 / ADR-047

End-to-end provenance discipline for every pixel in the app:

  • Agency-first build-time imagery sourcing (NASA = fallback library, not the default)
  • Per-image provenance manifest (auto-generated by scripts/build-image-provenance.ts)
  • Public /credits page with all imagery + text + logo attributions
  • License allowlist + waivers system, fail-closed in validate-data
  • Lightbox attribution on every gallery thumbnail
  • Honest mixed-source footers per gallery surface
  • Non-NASA agency imagery enriched via partnership-credit queries

Closes #44 (agency-first sourcing) · #45 (non-NASA enrichment) · #47 (Milestones A/B/C) · #48 (Milestone D).

/missions UX cleanup

Filter strip + timeline navigator collapsed by default for a clean grid; auto-expand when any filter URL param is present so deep links show their state. Per-mission flight params + caveat banners (RECONSTRUCTED / SPARSE / UNKNOWN). Ships at 36 missions (4 outer-catalogue additions + Artemis II + free-return concepts).

v0.1.10 audit cleanup (#30 carry-over)

Drift fixes from the v0.1.10 audit folded in here.

Tooling + infrastructure

  • 4 new ADRs covering the agency-first imagery decision (ADR-046), per-image provenance manifest (ADR-047), and the diagram authoring + KaTeX patterns groundwork (ADR-034, ADR-035) used heavily in v0.5.0.
  • validate-data fails closed on unknown licenses and missing image provenance.
  • npm run preflight mirrors CI step-for-step locally; pre-push hook self-installs.

Stack notes

No new dependencies. Three.js still r128. SvelteKit + Paraglide-js + ajv. Static export via adapter-static — still deploys to GitHub Pages with no backend.

🤖 Notes generated with Claude Code

v0.3.0 — heliocentric /fly + cislunar reframe + 4 new missions

09 May 15:38

Choose a tag to compare

Heliocentric /fly, cislunar reframe, and four new missions (32 total).

Major /fly trajectory overhaul

  • transferEllipse(): true two-point Keplerian arc with the Sun at one focus, pinning both endpoints to live planet positions. Spacecraft start coincides with Earth at dep_day, rendezvous coincides with destination at arr_day — no more drift between rocket and planet.
  • PolylineCurve3 for TubeGeometry — the 3D past-tube progression now matches the spacecraft sprite exactly (no centripetal-spline drift).
  • Svelte 5 $effect dep-tracking fix: refs not yet defined on first run prevented state from being tracked, so marker + arc-rebuild effects silently skipped subsequent mission swaps.

Apollo-class round-trip + Moon-mode reframe

  • Moon-mode is now heliocentric like Mars (Sun + Earth orbit visible, Moon orbiting Earth at exaggerated 0.15 AU).
  • Camera follows live Earth, zoomed tight (50u). Sim-speed pills swap to [0.1, 0.5, 1, 3]× for short cislunar missions.
  • Round-trip timeline math: arr_day = dep + 2 * transit_days for crewed / sample-return so the scrubber maps cleanly across the full mission.

Four new missions (32 total)

  • Artemis II (NASA, FLOWN April 2026 — the project's inspiration)
  • Inspiration Mars (Tito 2013 free-return concept)
  • Starship Mars Crew (SpaceX crewed Mars round-trip concept)
  • Blue Moon MK1 (Blue Origin cargo lunar lander)

Other

  • /explore visibility layers (PLANETS · DWARFS · COMETS · INTERSTELLAR)
  • /explore SIZES → REFERENCES with visual planet-size diorama
  • /earth satellites in real-inclination orbital planes
  • /plan rocket roster expansion + launch sites + photos
  • /missions trajectory preview moves into the card + FLIGHT tab
  • /fly CAPCOM panel: taller, sticky header, events scroll independently
  • Non-US mission galleries via curated Wikimedia top-up
  • PWA install nag suppressed, capability kept
  • Dev-server: vite fs.allow ['static'] + scenario probe gating

🤖 Notes back-filled with Claude Code

v0.2.0 — /fly trajectory math: isolation + per-mission validation

02 May 14:54

Choose a tag to compare

Phase 4 of the multi-phase polish plan — the largest, and the final phase before v0.3.0 outer-planet work begins. Minor version bump because this touches the trajectory core; semver-honest.

ADR-030 locks the pure-function boundary + tolerance philosophy.

Pure-function extraction

Every numeric formula previously inline in `src/routes/fly/+page.svelte` is now in `src/lib/fly-physics.ts`:

Function Role
`heliocentricSpeed(rAu, aTransferAu)` Vis-viva on transfer ellipse
`distanceBetween(a, b)` Heliocentric Euclidean distance
`auToKm` / `auToMkm` Unit conversion
`signalDelayMin(distAu)` One-way light-minute delay
`missionElapsedDays(simDay, depDay, arrDay, totalMissionDays)` MET from arc progress
`dvRemaining(total, used)` ∆v ledger (clamped)
`moonPositionAtMet(metDays)` Moon orbital position
`moonOutboundArc(moonPos, steps)` Earth → Moon Bezier
`moonReturnArc(moonPos, steps)` Moon → Earth Bezier

Constants centralised in `src/lib/fly-physics-constants.ts` — single source of truth for MU_SUN, AU_TO_KM, AU_PER_YR_TO_KMS, C_LIGHT_KM_S, MOON_ORBITAL_PERIOD_DAYS, etc.

The `+page.svelte` file is now a consumer; the math is testable independently of Three.js + Canvas2D rendering.

Per-mission validation harness

`src/lib/fly-physics-validation.test.ts` walks 10 real missions (9 measured-quality + 1 sparse) and asserts peak heliocentric speed along the outbound arc matches `mission.flight.cruise.peak_heliocentric_speed_km_s` within a per-mission tolerance:

Class Missions Peak-speed tolerance
Energetic (C3 ≳ 10) Curiosity, Perseverance, InSight, MAVEN, Mars Express, Hope, Tianwen-1 1.5 km/s
Direct entry / flyby Mariner 4, Mars Pathfinder 2.0 km/s
Sparse (reconstructed) Mars 3 3.0 km/s

Tolerances reflect the Hohmann-approximation envelope of the model — /fly visualises a Hohmann transfer ellipse, not a real Lambert solution. The harness validates the visualization is close to reality, not exact. Honest about the limitation in code rather than papering over it.

Coverage gap fixes

  • 4 new V∞ shaping tests for `outboundArc()` — previously zero coverage despite the v0.1.10 code path. Tests cover baseline passthrough, energetic bend-out, Hohmann-matched, extreme-V∞ clamp.
  • 6 new Moon Bezier tests — previously zero coverage. Tests cover arc start/end positions, period wrap, control-point flip between outbound + return.

New test helper

`src/lib/test-helpers/expect-close.ts` provides:

```ts
expectCloseTo(computed, golden, tolerance, description); // throws on miss
expectInRange(computed, min, max, description);
```

Reusable for any future per-mission validation (e.g. when v0.3.0 outer-planet missions land).

State

  • 251 unit tests (was 214, +37)
  • 82 e2e tests (1 skipped, all others green)
  • No new dependencies
  • No breaking API changes for /fly consumers
  • /fly `+page.svelte` net diff: ~30 lines smaller after extraction

Multi-phase plan complete

v0.1.10 → v0.1.11 → v0.1.12 → v0.1.13 → v0.2.0 shipped sequentially per the planning file. All four phases done in one session.

Phase Tag Headline
1 v0.1.11 Hover thumbnails + Earth year scrubber
2 v0.1.12 PWA service worker + high-contrast toggle
3 v0.1.13 Flight-data re-use across /fly + /missions
4 v0.2.0 /fly math isolation + 10-mission validation

Next track

v0.3.0 — outer-planet implementation. RFC-008 + ADR-028 already deliberated. 4 new destinations (Uranus, Neptune, Pluto, Ceres) + 4 new missions (Voyager 2, Galileo, New Horizons, Dawn). Catalogue grows from 28 → 32. Tracked under issue #27.

v0.1.13 — Flight-data re-use across /fly + /missions

02 May 14:38

Choose a tag to compare

Phase 3 of the multi-phase polish plan. Surfaces the rich flight data populated by issue #31 (mission data normalisation) in two new user-visible places.

/fly CAPCOM ticker reads structural events

New pure helper `src/lib/mission-event-merge.ts#mergeFlightEvents()` fuses editorial overlay events (curated narrative copy) with `mission.flight.events[]` (structural timeline from issue #31). Editorial events take precedence at MET collisions within a 0.05-day tolerance.

Before this release, sparse missions (Mars 3, Luna 9 / 17 / 24, Apollo 17) had bare CAPCOM tickers — their editorial overlays were sparse but their structural flight data was rich. Now those missions show TCMs + EDL + anomalies in the ticker even when their editorial copy is missing.

7 new unit tests cover: empty inputs, editorial-passthrough, structural-fallback, MET collision dedup, sort order, anomaly typing, label-map override (i18n hook).

NEXT EVENT row in /fly FLIGHT PARAMS HUD

A new row in the FLIGHT PARAMS aside shows the next upcoming event from the merged ticker:

```
NEXT T+7d · TRAJECTORY CORRECTION
```

Reads from the same merged events array so the ticker + HUD stay in sync. Displays "—" once all events have passed.

/missions card quality badge

Inline next to the existing status badge in each card head:

Quality Colour
MEASURED teal
SPARSE gold
RECONSTRUCTED orange
UNKNOWN grey

Helps users understand the mission corpus at a glance — the 21 measured + 6 sparse + 1 unknown breakdown from issue #31 is now visible everywhere mission cards appear.

State

  • 214 unit tests (was 207, +7)
  • 82 e2e tests (was 77, +5)
  • 1 skipped, all others green
  • No new dependencies; all work uses existing infrastructure

Next phase

Phase 4 (v0.2.0) — `/fly` calculation isolation + per-mission validation harness. Largest of the four phases: extract ~25 numeric formulas inline in `+page.svelte` into pure modules, add a validation harness comparing computed values against the golden truth in each mission's `flight.*` records for 5–10 missions.

v0.1.12 — PWA + a11y polish

02 May 14:27

Choose a tag to compare

Phase 2 of the multi-phase polish plan. Closes Theme C — issue #18.

Service worker

Orrery now installs as a true PWA on Android + iOS, with offline-first behaviour after first visit.

  • Plugin: `@vite-pwa/sveltekit` (Workbox-generated SW). New devDependency.
  • Cache strategies: shell + textures + fonts + logos + images precached (cache-first, immutable); mission JSON + i18n overlays stale-while-revalidate (instant from cache, refreshed in background); gallery + flight-data manifests network-first with 3 s timeout. Porkchop grids excluded from precache (browser HTTP cache only — they're large + per-route).
  • Update toast: when a new SW is waiting, a small REFRESH toast appears at the bottom of the screen so users explicitly opt into the new version.
  • Install-prompt deferral: the `beforeinstallprompt` event is held until the user has visited 3+ unique screens. Visit counter held in runtime memory only (per CLAUDE.md no-localStorage rule). Avoids the intrusive first-paint install banner.
  • iOS: Safari ignores `beforeinstallprompt`. iOS users get manual install via the share sheet — same as before, now with proper SW-backed offline behaviour once installed.

ADR-029 documents the decision.

Manual high-contrast toggle

A small Aa button in the right side of the nav bar toggles `data-high-contrast="true"` on ``. The CSS hooks (already shipped in v0.1.10's `tokens.css`) bump dim/faint text alphas, thicken borders, and raise panel/HUD/nav backgrounds toward fully-opaque.

  • Both OS preference (`prefers-contrast: more`) and the manual override are recognised — manual takes precedence.
  • New `src/lib/high-contrast.ts` mirrors the existing `reduced-motion.ts` pattern: `matchMedia` + `MutationObserver` subscription, SSR-safe, cleanup function returned.
  • 44 px touch target, `aria-pressed`, localised `aria-label`.
  • Active state lit in teal; default outlined in faint grey.

Tests

4 new e2e tests in `tests/e2e/pwa.spec.ts`:

  • `manifest.webmanifest` served + parseable
  • `/sw.js` served + Workbox-generated
  • `<link rel="manifest">` present in HTML head
  • High-contrast toggle button flips `data-high-contrast` on ``

State: 207 unit + 77 e2e (1 skipped), all green.

Theme C status

  • ✅ C1 — service worker (this release)
  • ✅ C2 — manual high-contrast toggle (this release)
  • ⏳ C3 — Lighthouse CI gate (deferred; needs separate `lhci` config)

Next phase

Phase 3 (v0.1.13) is re-using the new flight data on /fly + /missions: CAPCOM ticker reads `mission.flight.events[]`, NEXT EVENT row in the FLIGHT PARAMS HUD, data-quality badge on /missions cards.