# Design — `blueprints` Decisions for building `blueprints` out from a single List illustration into a gallery of many. Terminology: see [CONTEXT.md](CONTEXT.md). ## D1 · Content sourcing: hand-authored typed data + bespoke specimen Each blueprint is a **typed TS data module** (`src/data/Blueprint.ts`), transcribed by hand from its ontology README, paired with a **bespoke Specimen** component. The generic **Viewer** renders everything else (Readout, composition map, state machine) from that data. - **Why not parse the ontology at build time?** The Specimen must be hand-built for every blueprint regardless (the ontology only provides an ASCII sketch), so parsing would automate only the cheap, structured text — at the cost of fragile markdown/mermaid parsing and a build-time coupling to the ontology repo's exact format. Not worth it. - **Source of truth** stays the `blueprint-ontology` repo; the data modules are a faithful transcription, cited in each module's header. Structural split this implies: | Part | Generic (data-driven) | Bespoke (per blueprint) | | ---------------------------------- | ------------------------------------ | ----------------------------------- | | Chrome (title block, tabs, legend) | ✓ | | | Readout (dossier per function) | ✓ | | | Composition map | ✓ (from `extends` + `composes` data) | | | State machine | ✓ (from nodes/edges data) | | | Specimen | | ✓ component slotted into the Viewer | ## D2 · Routing: vue-router, URL per blueprint Add `vue-router`. Routes: `/` → Gallery, `/b/:slug` → the blueprint's illustration (e.g. `/b/list`). Deep-linkable and shareable; browser back/forward works. The nginx SPA fallback (`try_files … /index.html`) already serves client routes, so no server change is needed. A blueprint registry (`src/data/blueprints.ts`) maps `slug → { data module, specimen component, meta }` and is the single source both the router and the Gallery read from. ## D3 · Gallery: illustrated-only, grows over time The Gallery lists **only** blueprints that have an illustration; it grows as we add them. No greyed "planned" cards. Rationale: keeps the landing clean and truthful, and avoids maintaining metadata for 45 not-yet-built entries. A blueprint appears in the Gallery precisely when it is registered in `src/data/blueprints.ts`. ## D4 · Build-out slice #1: foundation + Grid **Foundation (refactor, no UX change to List):** - `pnpm add vue-router`; `App.vue` → thin shell with a header (link home) + ``. - `src/views/GalleryView.vue` (`/`) — cards from the registry. - `src/views/BlueprintView.vue` (`/b/:slug`) — resolves the registry entry, renders the Viewer. - `src/components/BlueprintViewer.vue` — the **generic Viewer**, generalized from the current List-specific `App.vue`: title block, legend, function tabs + full view, two panes, optional composition map + state machine, footer. Props: a `Blueprint` object + the blueprint's Specimen component (injected via ``). - Generic `Blueprint` type in `src/data/blueprint.ts` (signature, functions, coreInvariants, optional composition, optional stateMachine, meta). `listBlueprint.ts` conforms to it. Specimens move to `src/specimens/`. - `src/data/blueprints.ts` — registry: `slug → { meta, blueprint, specimen }`. **Content:** `gridBlueprint.ts` + `src/specimens/GridSpecimen.vue` (2D tile grid). **Ships:** Gallery listing List + Grid; `/b/list` (same UX, refactored) and `/b/grid`. **Gates before push:** `pnpm build` clean · `pnpm lint` · `pnpm fmt`; then commit → push (auto-deploys) → verify `https://blueprints.apoena.dev`. Subsequent slices add one blueprint each (Table, Feed, …).