Skip to content

ADR-061 — Surface hotspots are regions, not points (axis-aligned region_bounds on SurfaceSite)

Status · Accepted Date · 2026-05-30 Closes into · static/data/schemas/surface-site.schema.json (schema additions) + src/types/surface-site.ts (TS type additions) Related · RFC-017 (Surface Hotspots, v0.7 — this ADR supersedes the disc/point geometry choice made there), Issue #283 (Surface hotspots v2 epic), Issue #284 (follow-on base sphere texture LOD) Triggered by · Visual review of v0.7 surface hotspots (2026-05-30): the current disc primitive is dishonest about both image footprint and semantic extent; selection halos decouple from content; layer transitions read as stickers, not terrain

Context

The original surface-hotspots design (PRD-014 / RFC-017) modelled each site as a point(lat, lon) plus an optional location_uncertainty_m radius. The Tier-2 patches (hotspot-surface-patch.ts) render this point as a circular CircleGeometry disc on the sphere, with a larger regional ring beneath. The disc diameter is fixed (1 km detail, 3 km regional context) and explicitly stylized — the source modal admits "3:1 ratio is a stylized 'you are HERE' callout — at true scale HiRISE would be a sub-pixel speck inside the CTX disc."

Reviewing the actual experience in May 2026 surfaced four failures (full analysis in #283):

  1. The disc shape encodes nothing about the data — it is neither true footprint nor named region.
  2. At mid-zoom, the hard-edged circle reads as a sticker pasted on the sphere, not as terrain data.
  3. On the moon, the selection halo decouples from the disc into a giant blue ring floating in empty space around the much smaller dark disc.
  4. At deepest zoom, nothing communicates that the user has crossed the imagery's resolving power — they read "Mars is blurry" instead of "I'm zooming past pixels."

NASA's two reference families solve these honestly by encoding shape:

  • Image-extent rectangles (Perseverance location map): each HiRISE swath is drawn at its actual rectangular ground footprint.
  • Region-of-interest rectangles (Lunar South Pole moonbase plan): named areas — "Connecting Ridge", "Haworth", "Malapert Massif" — are translucent quads bounded by the semantic region.

Decision

Each surface site gains an optional region_bounds — an axis-aligned { lat_min, lat_max, lon_min, lon_max } quad — plus region_kind (enum: landing_ellipse | traverse_bbox | roi_quad | image_swath) and region_bearing_deg (for rotated ellipses).

  • Schema (surface-site.schema.json): all three fields added as optional. An if/then rule enforces region_bounds requires kind: 'surface'. Antimeridian-crossing regions are split into two entries in v1 (lat_min ≤ lat_max and lon_min ≤ lon_max enforced).
  • TypeScript (src/types/surface-site.ts): mirrored as RegionBounds + RegionKind types + three optional fields on SurfaceSite.
  • Field ordering: region_bounds + region_kind sit immediately after lat / lon in both schema and serialized JSON to keep geometry grouped (enforced by the Slice 1 backfill script's reorder()).
  • Backward compat: all three fields are optional. Sites without region_bounds continue to render via the legacy disc primitive until Slice 3 of #283 replaces it. The backfill script (scripts/mockups/backfill-region-bounds.mjs) populates 19 moon and 16 mars surface sites with documented landing ellipses and rover traverse bboxes — sources cited inline in the script.

Alternatives considered

  • Polygon vertices (Array<{lat, lon}>) — strictly more expressive (arbitrary shape), but 95% of sites are landing ellipses or rover wander envelopes that an AABB captures adequately. Polygons add complexity (winding order, self-intersection checks) without payoff for v1. Can be added later (region_polygon alongside region_bounds) if a real need surfaces.
  • Rotated ellipse ({cx, cy, a, b, bearing}) — closer to the actual physical shape of a Mars descent ellipse, but harder to backfill (no public source publishes ellipses in this canonical form) and harder to render as a click target on a curved sphere. Decided to store the AABB and add an optional region_bearing_deg for rendering hint — the actual ellipse can be drawn inside the box when bearing is set.
  • Reuse location_uncertainty_m — would have meant keeping the circle and just changing visual treatment. Rejected because the shape is the dishonesty; keeping a circle means accepting it.

Consequences

  • Slices 2–6 of #283 can now consume the new schema without further data changes.
  • TA.md ADR table needs updating to mark ADR-059, ADR-060, ADR-062 still reserved (this ADR claims ADR-061 from the v0.7 RFC-017 reservation pool).
  • One inaccurate forward-reference in src/types/surface-site.ts (a comment that misattributed ADR-061 to the Tier 3 panorama field) is fixed in this same change.
  • The legacy disc primitive in hotspot-surface-patch.ts stays for now — Slice 3 of #283 replaces it. During the transition, both rendering paths exist; the dispatcher picks based on region_bounds presence.

Orrery — architecture documentation · MIT · No tracking