system
400.wtf

400.wtf / system / docs · docs/ADR/0001-astro-islands-with-vue-artifacts.md

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:only sidesteps SSR of WebGL/canvas code entirely.
  • (−) Two component models (Astro templates + Vue SFCs) in one head.
  • (−) Astro’s ClientRouter view transitions are less controllable than an SPA router — the persistent background needs the ADR-0002 workaround.
  • (−) client:only islands 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).