RFC-013 — ISS Explorer · 3D model pipeline & module pickability
Orrery · Closed RFC · v0.1 · May 2026
Status: Closed (accepted 2026-05-05 — ADR-040, ADR-041, ADR-042) Author: product Closes into: ADR-040 (model source + asset pipeline), ADR-041 (module-pick strategy + LOD), ADR-042 (low-end-device fallback) Slice gate: v0.4 Why this is an RFC: PRD-010 promises a rotatable 3D ISS where every module is clickable, panelled, and historically attributed. The technical questions cluster around the model (where do we get a 3D ISS that's accurate, cleanly licensed, and small enough to ship?), picking (mesh-per-module is conceptually clean but explodes the tris budget — what's the right granularity?), and fallback (we promised a low-end-device path; is that a list view, a 2D diagram, or a simplified 3D model?).
Context
The ISS is the largest, most complex, longest-occupied human spacecraft ever flown. Existing 3D model resources:
- NASA-3D Resources — multiple official ISS GLTF / OBJ models, NASA Open Source Agreement (close to public-domain).
- NASA Eyes on the Solar System — high-fidelity model used in NASA's WebGL apps; not directly redistributable.
- Wikimedia Commons / Sketchfab community — many community models, mixed quality and licences (CC-BY most common).
- Custom Blender authoring — ~3 weeks to author a low-poly station from reference photos.
PRD-010 wants:
- 16 pressurised modules individually clickable
- < 4 MB compressed initial load
- Renders at ≥ 30 fps on 2020-baseline mobile
- Visually faithful to the reference photo (the audience knows what the ISS looks like)
- Dark-theme native (matte white module skins, gold MLI, blue solar panels)
These are achievable but not trivially. The tris budget alone is the first hard constraint.
Open Questions
OQ-1 — Where does the model come from?
| Option | Source | Licence | Tris budget | Authoring cost |
|---|---|---|---|---|
| A. NASA-3D Resources GLB, simplified | NASA repo, Blender decimation pass | NASA Open Source Agreement (very permissive) | Original ~500k tris → simplified to ~50k | ~3 days simplification + cleanup |
| B. Custom Blender model from scratch | Hand-authored | Project-owned (cleanest) | Target ~30k tris | ~3 weeks |
| C. Sketchfab / community CC-BY | Community model with commercial redistribution licence | CC-BY (with attribution) | Variable | ~1 day import + cleanup |
| D. Procedural — generate cylinders + boxes for modules from spec | Code-driven from iss-modules.json | Project-owned | ~5k tris | ~2 days authoring + spec |
Recommendation: A. NASA-3D Resources is the cleanest pedigree for an accurate model; the licence is permissive; the simplification pass is well-trodden Blender work. Option D is tempting (procedural would be an instant fallback for OQ-3) but produces a "block diagram" rather than the recognisable station — fails the "audience knows what the ISS looks like" test.
The simplified GLB ships at static/models/iss/iss-low.glb; original-source attribution recorded in static/models/iss/CREDITS.md per PA §principles.
OQ-2 — Module pickability: mesh-per-module or pick atlas?
PRD-010 wants 16 modules individually clickable. There are two architectural options.
| Option | How it works | Tris cost | Per-module operations | Memory |
|---|---|---|---|---|
| A. Mesh-per-module | Each module is a separate THREE.Mesh in a Group; Raycaster intersects against the module list | +0 (same total geometry, just split) | Trivial (mesh.userData.moduleId) | One draw call per module = 16 draw calls vs ~1 |
| B. Single mesh + UV pick atlas | One unified mesh; a colour-coded atlas texture marks each module's UV island; pick by reading the picked pixel's colour | -0 (single mesh, single draw call) | Read pixel from offscreen render; map colour → moduleId | One draw call but offscreen-render-on-pick adds latency |
| C. Mesh-per-module + truss as one merged mesh | Hybrid: pressurised modules individual; trusses + arrays merged | +0 | Same as A | ~17 draw calls (16 modules + 1 truss complex) |
Recommendation: C. Mesh-per-pressurised-module gives the click target. Trusses + solar arrays are visual scenery in V1 (PRD-010 explicitly defers per-truss pickability) and can be a single merged mesh. Total ~17 draw calls is well within budget.
OQ-3 — Low-end-device fallback (PRD-010 §scope §technical)
PRD-010 promises ?view=list falls back to an alphabetical list with the same panel structure. Implementation question: how do we detect a low-end device, and what does "list mode" look like exactly?
| Option | Detection | List UX |
|---|---|---|
A. URL-only (?view=list) | User opt-in or default for known-bad UA | Alphabetical list of cards; tap → panel |
| B. URL + heuristic auto-fallback | If WebGL not supported OR navigator.deviceMemory < 4 OR initial render < 20 fps → switch to list automatically | Same list UX |
| C. URL + a small "switch to list view" toast | Render an "if 3D is slow, switch to list" banner the first time the user lands; dismissed via toast | Same list UX |
Recommendation: A + B combined. URL parameter is the explicit override. Heuristic auto-fallback (no WebGL, low memory, or sustained sub-20 fps after 2 seconds) flips to list view automatically. C is a polish-pass that we can layer on later.
ADR-042 records the detection rules so they're testable.
OQ-4 — Earth backdrop in V1?
PRD-010 V1 commits to a black-space backdrop with Earth deferred to V1.5. Worth re-checking: a faint Earth limb behind the station is visually striking and reinforces "low-Earth orbit." Cost is small (sphere + texture, no animation).
| Option | Cost | Risk |
|---|---|---|
| A. Black space backdrop only (per PRD) | 0 | Visual feels disembodied |
| B. Static Earth limb at the bottom of the viewport | +1 day | Adds 1 sphere + a 2K texture (~1.5 MB compressed); some performance hit on low-end |
| C. Animated Earth (slow rotation matching real ISS orbital period scaled down) | +2 days | Distracts from the model |
Recommendation: B for V1. A static Earth limb is a 90% visual win for a 10% cost. Ship it with the existing 2k_earth_daymap.jpg asset (same as /earth / /explore). Place it permanently below the station's centre of mass; the user always sees the station "above" Earth as in canonical photos.
OQ-5 — Truss segments pickable in V1?
PRD-010 V1 commits to pressurised modules pickable, trusses non-pickable. The truss has its own engineering history (P0–P6, S0–S6, Canadarm2). User research note: most casual users don't ask about specific truss segments by name; they ask about Canadarm.
| Option | V1 scope |
|---|---|
| A. Trusses non-pickable (PRD V1) | Pressurised modules only |
| B. Canadarm2 separately pickable, trusses still grouped | +1 module to clickable list |
| C. Per-segment trusses | +12 click targets — overkill for V1 |
Recommendation: B. Canadarm2 is iconic enough to deserve its own panel (history: built by MDA / CSA in 2001, the only Canadian-engineered piece on the station, used for every visiting-vehicle capture). Per-segment trusses defer to V2.
OQ-6 — LOD (level of detail) strategy
A 50k-tri model at 60 fps on a 2020 phone is achievable but tight. LOD = swap to a lower-poly version when zoomed out.
| Option | Cost | Benefit |
|---|---|---|
| A. Single LOD (one model at all distances) | 0 | Simplest |
| B. Two-level LOD — full at near, ~10k-tri version at far | +1 day authoring + Three.js LOD plumbing | Smoother low-end performance |
| C. Three-level LOD | +2 days | Marginal gain over B |
Recommendation: A for V1, B for V1.1 if perf metrics fall short. Three.js's built-in LOD is straightforward to add later. Don't optimise prematurely.
OQ-7 — Where does ISS sit in the nav?
Current nav (post v0.4 + new pages from PRD-009): EXPLORE → MISSIONS → PLAN → FLY → EARTH → MOON → MARS.
Adding ISS:
- After EARTH (preserves "LEO context" — Earth then ISS in LEO)
- Before EARTH (treat ISS as a thing in space, distinct from "the Earth screen")
- After MARS (keeps the planetary cluster intact, ISS as the tail)
Recommendation: After EARTH. Final order: EXPLORE → MISSIONS → PLAN → FLY → EARTH → ISS → MOON → MARS. ISS is in LEO; placing it next to /earth groups them as the "near-Earth" cluster. The simulator screens (PLAN/FLY) live before, the destination catalogue (MOON/MARS) lives after.
ADR-040 to lock the nav order alongside the asset-pipeline decision.
Decision criteria
We accept the resolution when:
- The 3D model loads in < 4 MB compressed (gzipped GLB).
- Initial render reaches ≥ 30 fps on a baseline 2020 mobile device (Pixel 4 / iPhone 11 / Galaxy A50 class).
- All 16 pressurised modules + Canadarm2 are individually pickable with no false-positives on the truss complex.
?view=listfallback path renders all panel content without WebGL.- Heuristic auto-fallback flips to list view without flicker on detected low-end devices.
- Earth backdrop (if shipped) doesn't crash low-end devices.
- Model + texture credits are recorded in
CREDITS.mdper PA §principles.
Closure path
- ADR-040 — Asset pipeline: diagrammatic proxy + optional future NASA GLB swap-in. Earth backdrop using existing
2k_earth_daymap.jpg. Nav slot after EARTH. - ADR-041 — Module pickability: mesh-per-pressurised-module + Canadarm2 + merged-truss. ~17 draw calls.
- ADR-042 — Low-end-device fallback:
?view=listURL override + heuristic auto-fallback (no WebGL, low memory, sustained sub-20 fps).
Multi-LOD (OQ-6 option B), per-truss pickability (OQ-5 option C), animated Earth (OQ-4 option C) all deferred to V1.5 / V2.
Orrery · RFC-013 · v0.1 · Closed.