ADR-012 — SvelteKit as application framework
Status · Accepted Date · 2026-04-28 Supersedes · ADR-002 (vanilla JS), ADR-003 (Vite standalone) TA anchor · §stack
Context
The production application needs a component model for stateful UI (HUD panels, detail panels, card grids, tab strips), server-side rendering for SEO-readiness, and a clean integration path with Three.js and Canvas 2D rendering. ADR-002 chose vanilla JS; at production scale with millions of users and multiple contributors that decision does not hold.
Decision
SvelteKit as the application framework. Vite remains the underlying bundler — SvelteKit uses it internally.
Rationale
SvelteKit compiles components to vanilla JS at build time — no virtual DOM, no runtime framework overhead. This matters alongside Three.js, which is already a large bundle. Svelte's reactivity model is a compile-time transformation rather than a runtime subscription system, which integrates cleanly with Three.js animation loops (no reconciliation conflicts). SvelteKit's file-based routing aligns with the six-screen structure. TypeScript support is first-class. SSR is available when SEO becomes a priority.
The component model is exactly right for Orrery's UI: HUD panels are Svelte components with reactive props, the mission card grid is a {#each} loop over the data client's output, the detail panel tabs are a small state machine.
Alternatives considered
- React + Next.js — larger contributor pool; heavier runtime (React + ReactDOM adds ~40KB); reconciliation can conflict with Three.js canvas management; rejected in favour of lighter runtime.
- Vue + Nuxt — valid alternative; smaller ecosystem than React; no clear advantage over SvelteKit for this use case; rejected.
- Vanilla JS — see ADR-002 supersession reasoning above.
Consequences
Positive: reactive UI without framework overhead; clean Three.js integration; TypeScript-native; SSR available; contributor-friendly component model. Negative: Svelte-specific syntax has a learning curve for contributors unfamiliar with it; smaller contributor pool than React.
Implementation notes
npm create svelte@latest. File-based routing in src/routes/. Three.js screens initialised in onMount() to avoid SSR conflicts. Canvas elements managed outside Svelte's reactivity — Svelte owns the shell, Three.js owns the canvas.