ADR-0001 — Astro static shell with Vue islands for artifacts
Status: Accepted (documents the existing decision, 2026-02)
Context
The site is a static content collection (artifact pages) wrapped in a heavily interactive shell (WebGL background) with fully interactive islands (the artifacts themselves). Traffic pattern: cold visits from shared links; success metric is memorability, not app-like session depth.
Problem
Choose a rendering framework that keeps the static parts static (fast cold loads for shared links), lets interactive islands be authored in a productive component model, and stays maintainable for one person.
Decision
Astro 5 as the site framework, prerendering all routes. Vue 3 (@astrojs/vue) as the
island framework; artifacts mount with client:only="vue" from MDX bodies. Tailwind 4
for styling. State that must survive navigation lives outside Vue (module scope,
localStorage), because islands unmount on route swaps.
Alternatives considered
- Nuxt (full Vue SSR/SPA): one framework everywhere, richer transitions — but the whole page becomes a hydrated app; static content pays app overhead; view-transition continuity would be custom anyway.
- Plain Vite + vanilla TS: minimal, maximal control (lusion-style) — but every page, route, and meta tag is hand-rolled; content collections, MDX, and prerendering would be reinvented badly.
- React/Next islands: equivalent capability; Vue chosen on author fluency and smaller runtime. No technical blocker either way.
- Astro + no framework (web components / vanilla islands): lighter, but artifact authoring speed matters more than the ~30 kB Vue runtime.
Tradeoffs
- (+) Static HTML for every route; islands hydrate only where needed; MDX gives artifacts a prose future for free.
- (+)
client:onlysidesteps SSR of WebGL/canvas code entirely. - (−) Two component models (Astro templates + Vue SFCs) in one head.
- (−) Astro’s
ClientRouterview transitions are less controllable than an SPA router — the persistent background needs the ADR-0002 workaround. - (−)
client:onlyislands render nothing until JS loads (hydration blank — see ux.md R3).
Consequences
- Artifact = folder + MDX + Vue island is the standing contract (ADR-0003).
- Anything that must survive navigation cannot live in Vue component state.
- Framework lock-in is shallow: artifacts are mostly framework-agnostic TS (Spider/Vector classes, reducer) with thin Vue wrappers — deliberate, keep it so.
Future evolution
- If Astro’s islands or ClientRouter ever fight the continuity requirement, the escape hatch is fewer pages (single-page shell with internal states), not a framework swap.
- Revisit only on Astro major-version pain or if artifact authoring shifts heavily to another model (e.g., TSL/WebGPU pieces with no DOM needs).