ADR-050 — Tiangong Explorer low-end fallback (?view=list + heuristics)
Status · Accepted Date · 2026-05-07 Closes · RFC-014 (with ADR-048, ADR-049) TA anchor · §components Related · ADR-042 (the ISS analogue, copied verbatim), ADR-025 (accessibility), PRD-011
Context
RFC-014 OQ-3 requires a non-WebGL path and automatic degradation on weak devices for /tiangong. The decision mirrors ADR-042 verbatim — same detection rules, same URL override, same single-reactive-viewMode UX.
Decision
URL override
?view=list forces list mode: alphabetical module + visitor list, same src/lib/components/StationModulePanel.svelte content (the renamed/generalised panel — see Phase E of the rollout plan). No WebGL initialisation — no THREE.WebGLRenderer, no proxy build.
Auto-fallback
After 3D mode starts, measure FPS for ~2 s via requestAnimationFrame deltas. If sustained < 20 fps, switch to list mode and dispose renderer, scene, and module group geometry.
If navigator.deviceMemory is defined and < 4, skip 3D and open in list mode immediately (Chrome/Android hint).
If WebGL context creation fails, list mode.
UX
Single reactive viewMode: '3d' | 'list' — same flicker-avoidance discipline as /iss: decide mode before first paint when URL/device hints demand list, otherwise fall through to 3D.
Toggle
HUD control syncs URL (view search param) so shareable links reproduce mode.
Consequences
Positive: Accessibility + low-end coverage without maintaining two full feature sets. Identical fallback contract across /iss and /tiangong reduces test surface.
Negative: navigator.deviceMemory is non-standard — treated as optional signal only.
Implementation notes
FPS sampler runs only when viewMode === '3d' after buildTiangongProxyStation() returns. Disposal path mirrors the ISS stopThree() helper.