Skip to content

RFC-012 — Mars Surface Map · technical strategy

Orrery · Closed RFC · v0.1 · May 2026

Status: Closed (v0.4.0 / v0.5.0) Author: product Closed by: ADR-037 (shared surface-site type, deferred component), ADR-038 (per-body 2D projection: Mars equirectangular, Moon orthographic dual-disc), ADR-039 (bidirectional cross-link contract). Shared <SurfaceMap> component refactor deferred to v0.6.0 (issue #42). Slice gate: v0.4.0 (Mars Surface Map shipped) Why this is an RFC (historical context): PRD-009 specified a Mars peer of /moon — same panel pattern, same site catalogue shape. The technical questions were about abstraction (do /mars and /moon share a generic SurfaceMap, or stay independent?), projection (the Moon's near/far-disc 2D view doesn't translate to Mars cleanly — Mars has no permanent far side), and cross-linking (every site is also a mission card; how do we keep the two views from drifting?).


Context

/moon shipped in v0.1 with:

  • 3D sphere with rotation
  • 2D toggle: dual-disc near-side / far-side
  • Site markers, agency-coloured
  • Detail panel: OVERVIEW · GALLERY · LEARN
  • Site-to-mission cross-link via shared id

Mars adds these constraints:

  • ~16 confirmed surface artefacts (vs Moon's 16 — comparable count)
  • No "near side / far side" — Mars rotates fully every 24h 39 min and is observed from all sides
  • Failed landings are part of the Mars story (Schiaparelli, Beagle 2, Mars 2/3/6) — Moon's catalogue is mostly successful
  • Latitude clustering is a story (most successes near the equator due to EDL physics) — invisible on a 3D globe but obvious on a 2D map
  • Mission cross-link is much stronger than for Moon (every Mars site has a mission card; many Moon sites do too but the linkage was retrofitted)

Open Questions

OQ-1 — Generic SurfaceMap component, or independent /mars + /moon?

OptionCode reuseCustomisation costRisk
A. Independent/mars/+page.svelte is a fork of /moon/+page.svelte, edited for Mars0% reuseLowest startup costDrift over time; bug fixes have to be made twice
B. Generic component<SurfaceMap body={...} sites={...} /> consumes both Mars + Moon~70% reuseInitial refactor of /moon (~1 day)Coupling: a change to one body's UI risks the other
C. Shared schema only — same surface-site.ts type, separate page components0% UI reuse, 100% data reuseNo refactorDrift in UI; aligned in data

Recommendation: B. The two pages are doing the same thing. A generic component avoids the fork-and-drift problem. The Moon-specific bits (near-side / far-side dual disc) become props (projection: 'orthographic-pair' | 'equirectangular') on the generic component. /mars passes 'equirectangular'; /moon keeps the dual-disc.

The refactor is a one-time cost. Subsequent feature work (e.g. adding rover traverses in V1.5) ships once for both.


OQ-2 — 2D projection for Mars

The Moon's 2D view (orthographic pair: near-side disc + far-side disc) works because Earth-locked tidal rotation makes "near" and "far" semantically meaningful. For Mars, every longitude is equally observable.

OptionProsCons
A. Equirectangular (rectangular projection: lat 0…180°, lon 0…360°)Simplest; reads like a world map; latitude clustering instantly visiblePolar distortion (Mars's poles aren't rover targets — low cost)
B. Mollweide (equal-area elliptical)Beautiful; fair representationMost users don't know how to read it; pole detail lost
C. Orthographic pair (eastern hemisphere + western hemisphere)Mirrors /moon's dual-disc visual rhythmNothing about Mars's geography respects a hemisphere split
D. Polar-projection toggle (south-pole disc; north-pole disc)Highlights polar landers (Phoenix near 68°N)Equatorial sites get crowded near the disc edge

Recommendation: A — Equirectangular. The latitude-clustering story is the educational payload. Mollweide is prettier but the audience reads world-maps as rectangles. Polar-projection (D) can ship as V1.5 if Phoenix / planned ExoMars-Vikram-class polar work warrants it.

ADR-038 to lock equirectangular for Mars and reaffirm orthographic-pair for Moon (the projection decision is per-body, not global).


OQ-3 — Failed-attempt visual encoding

Mars catalogue has confirmed-success, partial-success, and confirmed-failure landers, all with known surface positions. Today /moon doesn't carry this distinction (most Moon entries are successes; the few failures are buried in the description).

OptionEncoding
A. Same dot, dashed outline for failureDashed white border instead of solid
B. Same dot, opacity reduction for failure60% opacity on the agency colour
C. Different shapeCross or X for failures, disc for success
D. Two separate legend categories per agency"USA · success" + "USA · failure" rows in the legend

Recommendation: A — Dashed outline. Carries information without inventing a second visual vocabulary. Legend explains "dashed = mission ended before / during landing." Applies to /moon too — Beresheet, Vikram-on-Chandrayaan-2, etc., become better-encoded.


Every Mars surface site corresponds to a mission card. From the site panel, the user should be able to "open the full mission card." From the mission card, the user should be able to "see this on the surface."

OptionUX
A. Site panel → "FULL MISSION CARD" button → /missions?id=curiosityExisting pattern (FLY-button family)
B. Site panel → embedded mission summary inlineNo navigation; less discoverability of the card itself
C. Both directions — site → card AND card → siteSymmetric but adds a button to /missions cards

Recommendation: C. Add a "ON THE SURFACE" chip to mission cards whose mission has a corresponding /mars site. Click navigates to /mars?site=[id]. The reverse direction is the existing FLY/mission-link pattern. Both are URL-addressable and survive deep-link sharing.


OQ-5 — When does /mars get added to the nav?

The current nav (post v0.4 reorder) is: EXPLORE → MISSIONS → PLAN → FLY → EARTH → MOON

Adding MARS:

  • After MOON (preserves "by destination" cluster after the simulator screens) — new tail position
  • Before EARTH (preserves rough "size order: Earth → Moon → Mars" but breaks the existing v0.4 order)
  • Between MOON and FLY (breaks the simulator cluster)

Recommendation: After MOON. Final order: EXPLORE → MISSIONS → PLAN → FLY → EARTH → MOON → MARS. Story arc: simulators first, then the destination catalogue (Moon prologue → Mars main act).


OQ-6 — Rover traverses in V1 (resolved)

Decision (2026-05-05): C — V1 ships traverses for all four successful rovers as a static snapshot vendored at build. Sojourner (~100 m) and Zhurong (~2 km) tracks too tiny to plot meaningfully — defer to V1.5.

PRD-009 originally deferred this; PM revisited the trade after seeing how strong the visual payoff is for the educational story ("you can see Curiosity wandered, Perseverance went straight, Opportunity beat them both") and confirmed traverses ship in V1.

Vendoring policy: snapshot at each release, no live refresh. NASA publishes daily traverse data freely (CC-0 / NASA-OSA); we capture a mars-traverses/[rover].json polyline per rover, refreshed by hand at release time. Active rovers move ~50 m/sol on average, so a per-release snapshot is "fresh enough" — formal real-time plumbing deferred to a later RFC.

RoverTrack length (snapshot)Source
Curiosity~33 kmNASA MSL Analyst's Notebook
Perseverance~30 kmNASA Mars 2020 traverse data
Opportunity45.16 km (final)NASA archive
Spirit7.73 km (final)NASA archive

Implementation: traverses load on-demand only when zoom passes a threshold (no global-view perf hit); each traverse simplified at build time to ≤ 500 waypoints via Douglas-Peucker.


OQ-7 — Orbital layer for /mars (and /moon parity)

/moon has rendering code for type: 'orbiter' site shapes (a hovering torus above the surface — src/routes/moon/+page.svelte:239) but moon-sites.json carries zero orbiter entries today. The path is dead code. Mars without active orbiters renders as visually inert — no MAVEN, no MRO, no Mars Express, no TGO, no Tianwen-1 orbiter, no Hope. That's understating ~30 years of orbital imagery and atmospheric science.

Resolution path:

OptionWhat we ship in V1
A. Surface only (PRD's original V1)Same shape as today's /moon; orbiters stay as cards in /missions
B. Surface + dimmed-icon orbiter pin on the surface beneath each orbiterHacky; doesn't represent "actually in orbit"
C. Surface + orbital ring layerEach orbiter is a small dot moving on its own faint inclined ring around the body. Click → panel.

Recommendation (decided 2026-05-05): C. A <SurfaceMap> renders three layers: surface markers · orbital rings + dots · traverses. Each layer is independently toggleable from the new chip rail (matches /explore's PLANETS / DWARFS / COMETS / ISM pattern).

Animation policy (V1). Orbiter dots move at a perception-scaled rate, not the orbit's true period. A real ~2 h orbit at 1× sim time would be a blur. Each dot completes one ring per ~30 s of real time so the user can see motion without it being distracting. Inactive / ended orbiters render dimmed, non-moving. No real-time positions or live ephemeris in V1 — the orbital phase is decorative, not predictive. Live ephemeris deferred to a later RFC if there's appetite.

Moon parity (decided 2026-05-05). Same <SurfaceMap> runs both Mars and Moon. moon-sites.json is backfilled with at least 5 lunar orbiter entries to validate the orbital layer doesn't drift between bodies:

  • LRO (NASA · 2009 · ACTIVE)
  • Clementine (NASA-DoD · 1994 · ENDED)
  • Chandrayaan-1 (ISRO · 2008 · ENDED 2009)
  • Chang'e 1 (CNSA · 2007 · ENDED 2009)
  • Chang'e 2 (CNSA · 2010 · ENDED 2014)
  • Lunar Prospector (NASA · 1998 · ENDED 1999)
  • SMART-1 (ESA · 2003 · ENDED 2006)

The Moon backfill is part of the same generic-component refactor (OQ-1).


Decision criteria

We accept a recommendation when:

  1. The generic SurfaceMap refactor doesn't regress /moon (e2e suite passes).
  2. The Mars 3D + 2D toggle works at 375 px width with no horizontal scroll.
  3. Cross-link round-trip works: /mars?site=curiosity → click "FULL MISSION CARD" → /missions?id=curiosity → click "ON THE SURFACE" → back to /mars?site=curiosity.
  4. Failed-attempt encoding reads correctly without colour-only cues (accessibility).
  5. Schema validation (ADR-019) covers mars-sites.json from day one.

Closure path

  • ADR-037 — Generic SurfaceMap component + shared surface-site.ts type with kind: 'surface' | 'orbiter' discriminator. Refactor /moon onto it.
  • ADR-038 — Per-body 2D projection: Mars equirectangular, Moon orthographic-pair (status quo). Polar-projection toggle deferred.
  • ADR-039 — Bidirectional cross-link contract between site panels and mission cards.
  • ADR-? — Orbital layer animation policy (perception-scaled, not ephemeris-correct in V1).

Traverses (OQ-6) and orbital layer (OQ-7) both ship in V1 per the 2026-05-05 PM revision. Live ephemeris + live rover positions explicitly deferred to a later RFC.


Orrery · RFC-012 · v0.1 · Open.

Orrery — architecture documentation · MIT · No tracking