Files
blueprints/.claude/skills/illustrate-blueprint/SKILL.md
Julien Calixte 5dff87a90d chore(skills): add illustrate-blueprint skill
Guided workflow for turning a blueprint-ontology blueprint into an
interactive illustration: read the source contract, author the typed data
module and bespoke specimen, register the pair, and verify the build.
2026-07-02 23:29:14 +02:00

9.8 KiB

name, description
name description
illustrate-blueprint Illustrate a UI-pattern blueprint from the blueprint-ontology repo as an interactive schematic in this app. Use when asked to illustrate, add, render, or build the illustration for a blueprint — e.g. "illustrate the table blueprint", "add the feed blueprint", "/illustrate-blueprint stack". Reads the source contract from ../blueprint-ontology, authors the typed data module and a bespoke specimen, registers the pair, and verifies the build.

Illustrate a blueprint

Turn one blueprint from the blueprint-ontology repo into an interactive illustration in this app (blueprints, deployed at https://blueprints.apoena.dev).

Read CONTEXT.md (ubiquitous language) and DESIGN.md (architecture) at the repo root first if you haven't this session — they define the vocabulary (Illustration, Viewer, Specimen, Readout, Companion, Function) used throughout.

What an illustration is

The generic Viewer (src/components/BlueprintViewer.vue) renders every generic part — title block, legend, function tabs, the full-view Readout, the composition map, and the state machine — from a blueprint's typed data. You author two things per blueprint and register them:

File What it is
src/data/<camel>Blueprint.ts the Blueprint object — the contract as typed data (see the Blueprint type in src/data/blueprint.ts)
src/specimens/<Pascal>Specimen.vue the bespoke static visual mock (left pane), with per-function highlighting
src/data/blueprints.ts one line registering the { blueprint, specimen } pair under its slug

Registering in blueprints.ts is all that's needed — the Gallery (/) and the route /b/<slug> both derive from the registry automatically. Do not hand-edit the router or the Gallery.

This is interpretive authoring, not parsing. DESIGN.md D1 deliberately rejects auto-generating from the ontology: the specimen must be hand-built, and the contract material (behaviors, invariants, failures, performance) has to be redistributed per function. Do the transcription by hand, faithfully.

Reference examples

Study the closest existing pair before you start — copy its shape, don't reinvent:

Kind Data module Specimen Notes
Feature (set) src/data/listBlueprint.ts src/specimens/ListSpecimen.vue reuses the shared LOADSTATE_MACHINE (src/data/loadStateMachine.ts)
Feature (set) src/data/gridBlueprint.ts src/specimens/GridSpecimen.vue 2D tile layout
Feature (temporal) src/data/calendarBlueprint.ts src/specimens/CalendarSpecimen.vue annotates one surface per function
Capability src/data/rememberMeBlueprint.ts src/specimens/RememberMeSpecimen.vue defines a bespoke state machine + new SmKinds

Workflow

0 · Read the source blueprint

The source of truth is the sibling repo, default ../blueprint-ontology (confirm the path if it's not there). For a blueprint with slug <slug>, read all three:

  • blueprints/<slug>/README.md — the prose contract
  • blueprints/<slug>/<slug>.als — the formal model (the real invariants/behaviors)
  • blueprints/<slug>/<slug>.test.als — checks that pin the contract

The README anatomy is fixed: Signature → UI snapshot → State machine → Behaviors → Invariants → Functional analysis → Critical performance → Failure modes → Formal model. Map it to the Blueprint type like this:

README section Blueprint field
# Name<Item> + intro one-liner name, tagline
Signature / Standard composition sig (header, fields, types), role, extendsName, composesCount
Relations related[] ({ name, relation })
UI snapshot (ASCII sketch) informs the Specimen — not a data field
State machine stateMachine — reuse LOADSTATE_MACHINE or author a bespoke one (see step 2)
Behaviors distributed into functions[].behaviors[] ({ sig, pre, eff })
Invariants → Core top-level coreInvariants[]
Invariants → per-behavior the owning functions[].invariants[]
Functional analysis (the table) functions[] — one row = one BlueprintFunction
Critical performance distributed into functions[].perf[]
Failure modes distributed into functions[].failures[]
Formal model rendered automatically from slug in the footer

1 · Decide role and state-machine strategy

  • Role"feature" (a pattern the user interacts with: List, Grid, Calendar) or "capability" (composes onto a host: Async, RememberMe, MFA). Set extendsName (the base/host) and, for features that compose capabilities, composesCount.
  • State machine
    • Set features that compose Async + Paginated + Pullable (List, Grid, Feed, Table…) reuse the shared machine: import { LOADSTATE_MACHINE } and set stateMachine: LOADSTATE_MACHINE.
    • A blueprint with its own lifecycle authors a bespoke StateMachine (nodes with hand-placed x/y/w/h, edges, initId, caption, field). Copy the layout approach from rememberMeBlueprint.ts.
    • If the bespoke machine has transition kinds not already in SmKind, add them to both SmKind and SM_COLORS in src/data/blueprint.ts (a color per kind). Reuse an existing kind whenever the semantics match.
    • A blueprint with no lifecycle simply omits stateMachine.

2 · Author src/data/<camel>Blueprint.ts

Export a const <camel>: Blueprint. Conform exactly to the Blueprint interface — open src/data/blueprint.ts and follow it field by field. Start the file with a header comment citing the ontology source (README + .als), like the existing modules do.

Per function (one per Functional-analysis row):

  • id — short, kebab/lowercase, stable; the specimen switches on it.
  • name — the table's Function name.
  • fig"01", "02", … in table order (shown as FIG.NN in the specimen cap).
  • caps — the blueprint(s)/capability that provide this function (drives the composition-map links and the Readout's "source capability").
  • verb — the table's Responsibility, tightened to one imperative sentence.
  • state[name, type] pairs for the state this function touches.
  • behaviors / invariants / failures / perf / notes — pull the matching lines from the README's Behaviors / Invariants / Failure modes / Critical performance sections. Leave arrays empty ([]) when a function has none.

Fill composition when the pattern is a host-plus-capabilities or a capability over a host: caps[] (nodes, mark the core one core: true), funcs[] (function names in order), links[] ([capId, functionName] pairs). The composition map only renders when composition is present.

3 · Author src/specimens/<Pascal>Specimen.vue

The Specimen is a static (never live) visual mock of the pattern's real UI, bespoke to this blueprint. Contract:

  • <script setup lang="ts">, props defineProps<{ activeId: string }>().
  • A computed frame with one case per function id plus a default (the "full"/overview view). Function ids must match the data module — a mismatch means selecting that tab highlights nothing.
  • Each frame highlights the region that function owns using the shared callout convention: the highlighted element gets the hl class and a data-tag attribute (e.g. ◈ DISPLAY), and the .hl / .hl[data-tag]::after CSS from an existing specimen renders the dashed-amber outline + label. Copy that CSS block verbatim.
  • Use theme variables, not hard-coded colors: var(--color-base-content), --color-accent (amber highlight), --color-secondary (cyan ink), --color-error, --color-success. Reuse the local aliases the existing specimens define (--ink, --amber, --cyan, --green, --red, --paper, --line, --line-strong).
  • Pick the specimen shape that fits: features with a real screen mock its surface and move the highlight per function (List/Grid/Calendar); a capability with little UI of its own shows its few screens plus the machinery it owns (RememberMe's device + secure-storage vault + state badges).

Keep it self-contained and scoped (<style scoped>); no new dependencies.

4 · Register the pair

In src/data/blueprints.ts: import the data export and the specimen component, then add one entry to REGISTRY keyed by the slug (kebab-case, matching the ontology folder and blueprint.slug). That's the only wiring required.

5 · Verify (all must pass)

pnpm build      # vue-tsc type-check + vite build — catches Blueprint-type drift
pnpm lint       # oxlint
pnpm fmt        # oxfmt (pnpm fmt:check to verify only)

Then sanity-check it renders: pnpm dev and open /b/<slug> — every function tab should highlight a region, the Readout should populate, and the composition map / state machine (if present) should draw. The /run or /verify skills can drive this if you want runtime confirmation.

Conventions checklist

  • Code style: no semicolons, double quotes (oxfmt enforces; see .oxfmtrc.json).
  • Names: slug = kebab-case (remember-me); data export = camelCase (rememberMe); data file = <camel>Blueprint.ts; specimen = <Pascal>Specimen.vue.
  • Function ids are shared contract between the data module and the specimen — keep them identical.
  • Transcribe faithfully from the ontology; cite the source in the file header. The ontology stays the source of truth — the data module is a transcription.
  • Don't edit the router or Gallery; don't add "planned" cards (D3 — the Gallery lists only illustrated blueprints).
  • Scope discipline: add the new files + the registry line (+ SmKind/SM_COLORS only if a new transition kind is genuinely needed). Don't refactor the Viewer or existing blueprints as a side effect.