11 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.mdD1 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 contractblueprints/<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). SetextendsName(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 setstateMachine: LOADSTATE_MACHINE. - A blueprint with its own lifecycle authors a bespoke
StateMachine(nodeswith hand-placedx/y/w/h,edges,initId,caption,field). Copy the layout approach fromrememberMeBlueprint.ts. - If the bespoke machine has transition kinds not already in
SmKind, add them to bothSmKindandSM_COLORSinsrc/data/blueprint.ts(a color per kind). Reuse an existing kind whenever the semantics match. - A blueprint with no lifecycle simply omits
stateMachine.
- Set features that compose Async + Paginated + Pullable (List, Grid, Feed,
Table…) reuse the shared machine:
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 asFIG.NNin 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">, propsdefineProps<{ activeId: string }>().- A
computedframewith onecaseper functionidplus adefault(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
hlclass and adata-tagattribute (e.g.◈ DISPLAY), and the.hl/.hl[data-tag]::afterCSS 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_COLORSonly if a new transition kind is genuinely needed). Don't refactor the Viewer or existing blueprints as a side effect.