Skip to content

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.

Orrery — architecture documentation · MIT · No tracking