@pilotspace/add 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,33 @@ All notable changes to the ADD method (`@pilotspace/add` on npm,
4
4
  `pilotspace-add` on PyPI) are documented here. The format follows
5
5
  [Keep a Changelog](https://keepachangelog.com/); versions follow semver.
6
6
 
7
+ ## [1.5.0] — 2026-06-16
8
+
9
+ The UDD design-loop release: defining the design *before* the code is now a
10
+ guided, evidence-backed loop inside the method. A new `design.md` drives the UDD
11
+ beats to a confirmed screen, a wireframe + HTML-mock recipe renders a real screen
12
+ the human approves before build, and the engine measures that the confirmation
13
+ was actually captured. All additive; no breaking changes (SemVer MINOR).
14
+
15
+ ### Added
16
+ - **UDD design-definition loop (`design.md`)** — turns the foundation's UDD
17
+ concern into a runnable loop: a low-fi structural wireframe → a self-contained
18
+ HTML mock (resolve semantic tokens → one kit class per component → compose the
19
+ prototype tree → populate with mock data) → a captured screen the human
20
+ confirms *before* any build. Wired into `0-setup` and `1-specify`.
21
+ - **Wireframe + HTML-mock recipe (`udd-wireframe.md`) + sample templates** — a
22
+ zero-dependency, any-stack floor for rendering a prototype tree into a real
23
+ screen, with a worked sample set (`tokens.sample.css`, `kit.sample.css`,
24
+ `welcome.sample.html`, `settings.sample.html` reusing the kit,
25
+ `wireframe.sample.txt`). One semantic-token flip re-themes every screen by
26
+ construction. An optional `@json-render/image` (Satori → PNG/SVG, no browser)
27
+ fast path is noted for JS-ecosystem projects.
28
+ - **Capture-evidence convention + `missing_capture` WARN** — design captures live
29
+ at `.add/design/captures/<name>.<ext>`; `add.py check` emits a never-red
30
+ `missing_capture` warning for any prototype lacking a capture (silent when
31
+ absent, so non-UI projects stay clean). The engine *measures* capture presence;
32
+ it never renders.
33
+
7
34
  ## [1.4.0] — 2026-06-15
8
35
 
9
36
  The guided-onboarding release: starting and running an ADD project is now guided
@@ -47,6 +47,17 @@ the method already names, made explicit as three concerns.
47
47
  test that behaviour; the foundation keeps the design intent that makes a screen
48
48
  worth building.
49
49
 
50
+ When a milestone has screens, UDD is not only a static `DESIGN.md` — it runs a
51
+ **design-definition loop** that turns the domain into a screen the human has *seen
52
+ and confirmed before build*. Its four beats are `review-domain → research-components
53
+ → wireframe → render-capture-confirm`: read the domain into screens and regions,
54
+ research and reuse components before inventing them, wireframe the structure low-fi,
55
+ then render a real screen and **capture** it. That capture is the **design-confirm**
56
+ evidence — a real image the person approves *before* implementation, so the build
57
+ matches the layout instead of discovering it. The book keeps the *why*; the
58
+ operational recipe (the wireframe format, the token-bound mock, the capture engines)
59
+ lives in the `add` skill's `design.md` and `udd-wireframe.md`.
60
+
50
61
  These three foundation competencies, together with the **TDD ⇄ ADD** engine of
51
62
  [Part II](./02-the-flow.md), are ADD's five. The first four feed context to the
52
63
  fifth, where the AI executes on it:
@@ -108,6 +108,14 @@
108
108
 
109
109
  **Newest-first append-only** — every append-only foundation sequence prepends the newest record at the top; the rolled-up settled line anchors at the bottom (the oldest end), so compaction collapses upward.
110
110
 
111
+ **Wireframe** — the Stage-A low-fidelity, *structural* map of one screen: its regions and the component **slots** inside them, derived from `prototypes/<name>.json` *before* any color, type, or spacing — it answers "what goes where", not "what it looks like". Beat 3 of the UDD **design-definition loop**; the low-fi half of the two-stage fidelity that ends in a confirmed capture. See the `add` skill's `udd-wireframe.md` (Stage A).
112
+
113
+ **Design mock** — the Stage-B high-fidelity, **self-contained** HTML render of a screen: the `catalog.json` components as a reusable token-bound kit, bound to `tokens.json` and populated with mock data, openable offline and screenshot-able. The human-facing *visible* evidence the human confirms (the frozen `prototypes/<name>.json` tree is its machine-checkable twin). Beat 4's hi-fi artifact; the recipe lives in the `add` skill's `udd-wireframe.md` (Stage B).
114
+
115
+ **Capture** — the real rendered image (PNG/SVG) of a design mock: the **design-confirm evidence** artifact. Captures live at `.add/design/captures/<name>.<ext>` (one per prototype) and are attached or mentioned in the feature's `TASK.md`; `@json-render/image` (Satori → PNG/SVG, no browser) is the named default capture engine, otherwise the self-contained mock is screenshot headless. The engine never renders — it only MEASURES presence: `add.py check` raises a never-red `missing_capture` WARN for a prototype with no capture.
116
+
117
+ **Design-confirm** — the human touchpoint closing the UDD **design-definition loop** (`review-domain → research-components → wireframe → render-capture-confirm`, beat 4 of the `add` skill's `design.md`): approving the captured screen image **before build**, show-before-ask, so the implementation matches the layout the human has already seen instead of discovering it.
118
+
111
119
  ---
112
120
 
113
121
  ## Optional mapping to formal phase names
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pilotspace/add",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "ADD (AI-Driven Development) — a minimal, state-tracked Claude Code skill that drives every feature through Specify → Scenarios → Contract → Tests → Build → Verify → Observe. Ships the AIDD book as its trust layer.",
5
5
  "bin": {
6
6
  "add": "bin/cli.js"
@@ -106,6 +106,11 @@ template, the tier pick — read `advisor.md`; and at any decision point self-sc
106
106
  (0–1 across six dimensions, refine if any < 0.9) with `confidence.md`. Both are advisory: the
107
107
  engine never spawns, and the self-score is never a gate.
108
108
 
109
+ When a **UI feature** reaches specify, run the **design-definition loop** in `design.md` (UDD):
110
+ review the domain → research and reuse components → wireframe → render a real captured screen the
111
+ human confirms **before** build — so the build matches the expected layout. Tool-agnostic; the
112
+ engine never renders.
113
+
109
114
  When a milestone's tasks are all done but its **goal** (the `MILESTONE.md` exit criteria) is not
110
115
  yet met, `milestone-done` holds the milestone open — read `loop.md` for the dynamic loop that turns
111
116
  open deltas + extras into the next tasks, proposed by you and confirmed by the human, until the goal is met.
@@ -0,0 +1,92 @@
1
+ # Design — the design-definition loop (UDD)
2
+
3
+ When a **UI feature** reaches specify, design it before you build it. This loop takes the
4
+ feature from the **domain** to a screen the human has **seen and confirmed** — a real captured
5
+ image — *before* any implementation, so the build matches the expected layout instead of
6
+ discovering it. It is loaded on demand (like `advisor.md` / `confidence.md`); the engine never
7
+ runs it for you.
8
+
9
+ Design before code is the UDD half of the method. The token + component foundation a UI project
10
+ draws from already exists — `tokens.json` (the compact-DTCG dialect, `udd-tokens.md`),
11
+ `catalog.json` + `prototypes/<name>.json` (`udd-catalog.md`). This loop is how you *fill* that
12
+ foundation for a feature and earn the human's sign-off on the look before build.
13
+
14
+ ## The loop — four beats
15
+
16
+ ```
17
+ review-domain → research-components → wireframe → render-capture-confirm
18
+ ```
19
+
20
+ Run the beats in order. Each feeds the next; the last ends at a human design-confirm.
21
+
22
+ ### 1 · review-domain
23
+ Start from the **domain**, not from a blank canvas. Read the domain model — entities, flows, the
24
+ ubiquitous language in `PROJECT.md` / `GLOSSARY.md` — and derive **which screens** the feature
25
+ needs and the **regions** each screen holds. Map each domain entity to a *presentational*
26
+ component (it shows state; it does not own a domain decision). The screen list + per-screen
27
+ regions are this beat's output, and they are grounded in the domain you just read.
28
+
29
+ ### 2 · research-components (reuse before you invent)
30
+ Check `catalog.json` **first** and **reuse** the components already there — that is what keeps
31
+ screens consistent. Research a reference UI (a websearch over pattern galleries / component
32
+ libraries for this kind of screen) only to fill a **genuine gap**, and propose a **new** catalog
33
+ component for that gap with a **cited** reference. Reuse before invention; a new component is the
34
+ exception, named and justified, not the default.
35
+
36
+ ### 3 · wireframe
37
+ Draw a **low-fi**, **structural** layout for each screen — regions and component slots, no
38
+ styling, no color. This is the cheapest possible artifact that shows the *expected layout*, so
39
+ the human can correct the structure before a pixel is styled. Confirm the wireframe, then move on.
40
+
41
+ ### 4 · render-capture-confirm
42
+ Render the screen as a **self-contained HTML mock** — the project's component library via CDN,
43
+ bound to `tokens.json` (resolved to CSS variables), composed from the **reusable per-component
44
+ kit** (one token-bound partial per catalog component), populated with realistic **mock** data.
45
+ **Capture** a real image of it (a headless screenshot) and present that image to the human for
46
+ **design-confirm** — show-before-ask, **before build**. On confirm, record the layout back to
47
+ `prototypes/<name>.json` + `catalog.json`, save the captured image to
48
+ `.add/design/captures/<name>.<ext>`, and **attach or mention it in the feature's `TASK.md`**
49
+ (alongside the §6 evidence) — so the screen the human approved is traceable from the task that
50
+ builds it. The HTML mock is the *visible evidence*; the json-render tree is the
51
+ *machine-checkable* record of the same screen.
52
+
53
+ ## Tool-agnostic capture
54
+
55
+ How you render and capture is **your** choice, not the engine's: a headless browser
56
+ (Playwright / Puppeteer), an `html2image`-style renderer, a browser-automation skill, a design
57
+ tool, or a hosted screenshot service — whatever the agent has. The recommended default is the
58
+ self-contained HTML mock above, captured headless, because it needs no app build yet still wears
59
+ the project's real tokens and component vocabulary. For a project that renders json-render, the
60
+ recommended default is **`@json-render/image`** (Satori → PNG/SVG, no browser) — a deterministic
61
+ `Spec` → image. The captured image is a **design-confirm evidence** artifact the human approves;
62
+ it is never an engine output, and the engine never renders. This keeps the loop tool-agnostic and
63
+ the method renderer-free.
64
+
65
+ Captures live at **`.add/design/captures/<name>.<ext>`** (one per prototype) and are
66
+ attached/mentioned in the feature's `TASK.md`. `add.py check` raises a never-red
67
+ `missing_capture` WARN for any prototype under `.add/design/prototypes/` that still lacks a
68
+ capture — a nudge to render + confirm it, never a blocker.
69
+
70
+ The loop **binds** the existing UDD contracts **read-only**: `tokens.json`, `catalog.json`, and
71
+ `prototypes/<name>.json` are read and composed, never reshaped — the `prototypes/<name>.json`
72
+ data contract stays **unchanged** (a change to it is a change request, not a design step). And
73
+ **identity** values — brand color, palette, typeface — stay **human-owned**: surface them for the
74
+ human to decide, never auto-pick a brand value (`udd-tokens.md`).
75
+
76
+ ## The hard rules
77
+
78
+ <constraints>
79
+ - **Domain first.** A screen is derived from the domain (beat 1), never sketched blind.
80
+ - **Reuse before invent.** Beat 2 checks the catalog first; a new component is a justified,
81
+ cited exception — never the reflex.
82
+ - **Confirm before build.** The captured image is approved by the human *before* implementation;
83
+ a design-confirm placed at or after build defeats the loop.
84
+ - **The engine never renders.** Capture is a recommended, tool-agnostic recipe run by the
85
+ agent's own tools; the image is evidence, not an engine artifact.
86
+ - **Bind, don't break.** The loop reads `tokens.json` / `catalog.json` / `prototypes/<name>.json`
87
+ read-only; the data contract is unchanged, and identity values stay human-owned.
88
+ </constraints>
89
+
90
+ > Used at specify for a UI feature: `phases/0-setup.md` scaffolds `DESIGN.md`, and
91
+ > `phases/1-specify.md` points here when the feature has a screen — run the four beats, then
92
+ > carry the confirmed layout into the contract.
@@ -74,7 +74,8 @@ gate: auto-complete NEVER skips the human baseline approval — the `lock` (§4)
74
74
  1. **Fill the living documentation** (it outlives all code): `.add/PROJECT.md` (the foundation — Domain · Spec/active
75
75
  milestone · UI/UX · Key Decisions, one screen), `CONVENTIONS.md`, `GLOSSARY.md`, `MODEL_REGISTRY.md`,
76
76
  `dependencies.allowlist`, and — for a UI project — `DESIGN.md` (the design source of truth: identity ·
77
- principles · screens · the named-set foundation pointers + render recipe; delete it if there's no UI).
77
+ principles · screens · the named-set foundation pointers + render recipe; delete it if there's no UI;
78
+ the design-definition loop that fills it — domain → components → wireframe → a captured screen confirmed before build — is `design.md`).
78
79
  Brownfield: from the code. Greenfield: from the interview, gaps flagged `guessed`.
79
80
  2. **Propose, then size it.** You just read the codebase (brownfield) or interviewed (greenfield) — so
80
81
  don't silently draft. First float a **kickoff suggestion** for the first milestone the human reacts to:
@@ -18,7 +18,9 @@ understand the feature — that is information, not an obstacle. Stop and ask.
18
18
  **Identity is direction, not default (UDD).** For UI/design work, identity values — the brand
19
19
  color, the core palette, the typeface — are human-owned. Surface them for discussion during
20
20
  Diverge; never assume a brand value. The UDD token dialect checks a token's *shape*; its *value*
21
- is the user's call (`udd-tokens.md`).
21
+ is the user's call (`udd-tokens.md`). For a UI feature with a screen, run the design-definition
22
+ loop in `design.md` — domain → research and reuse components → wireframe → a real captured screen
23
+ the human confirms before build — and carry the confirmed layout into the contract.
22
24
 
23
25
  ## Produce (in TASK.md §1)
24
26
 
package/tooling/add.py CHANGED
@@ -1606,6 +1606,27 @@ def _udd_named_set_checks(root: Path) -> list[tuple[bool, str, str]]:
1606
1606
  return out
1607
1607
 
1608
1608
 
1609
+ _CAPTURE_EXTS = ("png", "svg", "jpg", "jpeg", "webp")
1610
+
1611
+
1612
+ def _missing_captures(root: Path) -> list[str]:
1613
+ """Prototype names under `.add/design/prototypes/` lacking a design-confirm capture.
1614
+
1615
+ A prototype `<name>.json` is CAPTURED iff a file `.add/design/captures/<name>.<ext>`
1616
+ exists (ext in _CAPTURE_EXTS). Returns the uncaptured names in document (sorted) order.
1617
+ PURE · TOTAL (missing dirs -> []) · READ-ONLY (never writes, never renders): the engine
1618
+ MEASURES capture presence; producing the image is the agent's tool-agnostic choice
1619
+ (design.md beat 4; default `@json-render/image`). [] == every prototype captured / none exist.
1620
+ """
1621
+ proto_dir = root / "design" / "prototypes"
1622
+ cap_dir = root / "design" / "captures"
1623
+ if not proto_dir.is_dir():
1624
+ return []
1625
+ names = sorted(p.stem for p in proto_dir.glob("*.json") if p.is_file())
1626
+ return [n for n in names
1627
+ if not any((cap_dir / f"{n}.{ext}").is_file() for ext in _CAPTURE_EXTS)]
1628
+
1629
+
1609
1630
  def cmd_check(args: argparse.Namespace) -> None:
1610
1631
  """Read-only integrity check of the .add project. Exit 1 if anything fails."""
1611
1632
  as_json = getattr(args, "json", False)
@@ -1772,6 +1793,16 @@ def cmd_check(args: argparse.Namespace) -> None:
1772
1793
  # Silent when absent; read-only; fail-closed on malformed JSON.
1773
1794
  checks.extend(_udd_named_set_checks(root))
1774
1795
 
1796
+ # capture-evidence: a never-red WARN naming each prototype with no design-confirm capture
1797
+ # at .add/design/captures/<name>.<ext>. Measure-never-block — rides `warnings`, NEVER
1798
+ # `checks` (so never feeds `failed`); silent-when-absent (no prototypes -> []). The engine
1799
+ # MEASURES capture presence; producing the image is the agent's tool-agnostic choice.
1800
+ for _pname in _missing_captures(root):
1801
+ warnings.append(("missing_capture",
1802
+ f"prototype '{_pname}' has no design-confirm capture at "
1803
+ f".add/design/captures/{_pname}.<png|svg|…> — render + confirm it "
1804
+ "before build (design.md beat 4)"))
1805
+
1775
1806
  passed = sum(1 for ok, _, _ in checks if ok)
1776
1807
  failed = len(checks) - passed
1777
1808
  if as_json:
@@ -0,0 +1,53 @@
1
+ /* kit.sample.css — one class per catalog.sample.json component (the reusable kit).
2
+ Every visual value resolves a var(--…) from tokens.sample.css — no literals here, so
3
+ a token flip in tokens.sample.css restyles every screen that composes from this kit.
4
+ Screens use these classes and style nothing inline. */
5
+
6
+ /* Screen — the root viewport container */
7
+ .screen {
8
+ display: flex;
9
+ flex-direction: column;
10
+ align-items: center;
11
+ min-height: 100vh;
12
+ gap: var(--semantic-space-inset-md);
13
+ padding: var(--semantic-space-inset-md);
14
+ background: var(--semantic-color-surface);
15
+ font-family: var(--primitive-font-family-sans);
16
+ }
17
+
18
+ /* Card — a surface that groups related content */
19
+ .card {
20
+ display: flex;
21
+ flex-direction: column;
22
+ gap: var(--semantic-space-inset-sm);
23
+ width: 100%;
24
+ max-width: 360px;
25
+ padding: var(--semantic-space-inset-md);
26
+ background: var(--semantic-color-surface);
27
+ border-radius: var(--semantic-space-inset-sm);
28
+ }
29
+
30
+ /* Text — a run of styled text */
31
+ .text {
32
+ margin: 0;
33
+ line-height: 1.5;
34
+ color: var(--semantic-color-text);
35
+ font-family: var(--primitive-font-family-sans);
36
+ }
37
+ .text--bold { font-weight: var(--primitive-font-weight-bold); }
38
+ .text--regular { font-weight: var(--primitive-font-weight-regular); }
39
+
40
+ /* Button — a primary call-to-action */
41
+ .button {
42
+ display: inline-flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ padding: var(--semantic-space-inset-sm) var(--semantic-space-inset-md);
46
+ border: 0;
47
+ border-radius: var(--semantic-space-inset-sm);
48
+ background: var(--semantic-color-accent);
49
+ color: var(--semantic-color-surface);
50
+ font-family: var(--primitive-font-family-sans);
51
+ font-weight: var(--primitive-font-weight-bold);
52
+ cursor: pointer;
53
+ }
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <!-- settings.sample.html — a SECOND screen that proves REUSE. It composes from the SAME
3
+ kit classes (screen/card/text/button) and links the SAME tokens.sample.css +
4
+ kit.sample.css as welcome. It redefines nothing — no per-screen stylesheet, no inline
5
+ styles — so a single semantic-token flip in tokens.sample.css re-renders BOTH screens
6
+ identically. This is consistency by construction. -->
7
+ <html lang="en">
8
+ <head>
9
+ <meta charset="utf-8">
10
+ <meta name="viewport" content="width=device-width, initial-scale=1">
11
+ <title>Settings — design mock</title>
12
+ <link rel="stylesheet" href="tokens.sample.css">
13
+ <link rel="stylesheet" href="kit.sample.css">
14
+ </head>
15
+ <body>
16
+ <!-- reuses the welcome kit: Screen > Card > {Text, Text, Button} -->
17
+ <main class="screen">
18
+ <section class="card">
19
+ <h1 class="text text--bold">Settings</h1>
20
+ <p class="text text--regular">Manage your workspace preferences.</p>
21
+ <button class="button" type="button">Save changes</button>
22
+ </section>
23
+ </main>
24
+ </body>
25
+ </html>
@@ -0,0 +1,23 @@
1
+ /* tokens.sample.css — tokens.sample.json resolved to CSS custom properties.
2
+ The SINGLE source of token values. Literals live ONLY here; the kit and the
3
+ screens reference var(--semantic-*). Flip one --semantic-* line below and EVERY
4
+ screen that links this file re-renders the same way. */
5
+ :root {
6
+ /* primitive — raw values (the only literals in the whole sample) */
7
+ --primitive-color-blue-500: #3B82F6;
8
+ --primitive-color-slate-900: #0F172A;
9
+ --primitive-color-white: #FFFFFF;
10
+ --primitive-space-2: 8px;
11
+ --primitive-space-4: 16px;
12
+ --primitive-font-family-sans: "Inter", system-ui, sans-serif;
13
+ --primitive-font-weight-regular: 400;
14
+ --primitive-font-weight-bold: 700;
15
+
16
+ /* semantic — alias the primitives; THIS is the layer screens bind to.
17
+ Repoint one of these to re-theme every screen at once. */
18
+ --semantic-color-accent: var(--primitive-color-blue-500);
19
+ --semantic-color-text: var(--primitive-color-slate-900);
20
+ --semantic-color-surface: var(--primitive-color-white);
21
+ --semantic-space-inset-sm: var(--primitive-space-2);
22
+ --semantic-space-inset-md: var(--primitive-space-4);
23
+ }
@@ -0,0 +1,118 @@
1
+ # UDD wireframe + HTML mock — make the layout visible before build
2
+
3
+ `udd-tokens.md` says what a UI is *made of*; `udd-catalog.md` says what it is *built
4
+ from*. Both are abstract JSON. This doc closes the last gap design.md names: turn a
5
+ prototype tree into a **real, captured screen the human confirms BEFORE build** — so
6
+ the build matches the expected layout instead of discovering it.
7
+
8
+ Two stages, low-fi → hi-fi:
9
+
10
+ - **Stage A — wireframe**: a fast, low-fi *structural* map. No styling.
11
+ - **Stage B — HTML mock**: a self-contained screen the human (or a headless tool)
12
+ actually renders and screenshots. The image is the design-confirm evidence.
13
+
14
+ The engine never renders. This is a recommendation + a worked sample, tool-agnostic
15
+ (consistent with `udd-catalog.md`'s render recipe). A worked pair ships beside it —
16
+ `welcome.sample.html` + `settings.sample.html` — that you can open in any browser.
17
+
18
+ ## Stage A — wireframe (low-fi, structural)
19
+
20
+ A **wireframe** is a low-fidelity, *structural* map of one screen — regions and the
21
+ component **slots** inside them — derived directly from the prototype tree, **before**
22
+ any color, type scale, or spacing is decided. It answers "what goes where", not "what
23
+ it looks like".
24
+
25
+ Derive it mechanically from `prototypes/<name>.json`: each container element is a
26
+ region, each leaf element is a slot, the tree's nesting is the layout nesting. Keep it
27
+ in plain text or boxes — the point is speed and a shared structural picture, not paint.
28
+
29
+ Worked example: `wireframe.sample.txt` is the Stage-A map of the welcome screen
30
+ (`Screen > Card > {Text, Text, Button}`), with each slot mapped 1:1 to its prototype
31
+ element. No colors, no pixel values — those arrive in Stage B.
32
+
33
+ ## Stage B — HTML mock (hi-fi, self-contained, screenshot-able)
34
+
35
+ The mock is a real screen built from the design foundation in **four moves**:
36
+
37
+ 1. **Resolve `tokens.json`'s `semantic` layer → CSS custom properties.** Each
38
+ `{semantic.dotted.path}` alias becomes a `--semantic-dotted-path` variable in a
39
+ `:root` block. This file is the single source of token values — see
40
+ `tokens.sample.css`.
41
+ 2. **One kit class per `catalog.json` component.** Each component (Screen, Card, Text,
42
+ Button, …) gets exactly one CSS class whose every visual value is a `var(--…)` from
43
+ step 1 — never a literal. This is the reusable **kit** — see `kit.sample.css`.
44
+ 3. **Compose the prototype tree into HTML using the kit classes.** Walk
45
+ `prototypes/<name>.json`: each element becomes an HTML node carrying its
46
+ component's kit class; nesting follows `children`. Style nothing inline.
47
+ 4. **Populate with mock data.** Fill the `Text`/`Button` content from the prototype's
48
+ props (or representative stand-ins). The result is a **self-contained** screen —
49
+ *no network*: it links only local sibling files — that opens offline and a
50
+ **headless** tool can **screenshot** directly (Playwright, `html2image`,
51
+ an agent browser, or a SaaS renderer — pick one; the engine never renders).
52
+
53
+ `welcome.sample.html` is the worked Stage-B mock of `prototype.sample.json`.
54
+
55
+ ## Fast path — render via json-render (for JS-ecosystem projects)
56
+
57
+ Your `prototypes/<name>.json` is already a **json-render `Spec`** — the exact schema
58
+ `udd-catalog.md` pins. If your project renders json-render (React, Vue, Svelte, Solid,
59
+ React Native, …) you can skip the hand-authored kit and render the prototype through
60
+ your *real* catalog, so the mock **is** the product and cannot drift from it:
61
+
62
+ - **Render** — feed `prototype.json` into your `defineCatalog(…)` (see `udd-catalog.md`'s
63
+ "Render recipe"), or use a pre-built catalog such as `@json-render/shadcn` (36
64
+ shadcn/ui components) — no hand-written components for those stacks.
65
+ - **Capture** — `@json-render/image` renders a `Spec` straight to **PNG / SVG** (Satori,
66
+ no browser), a deterministic captured image with no headless-screenshot step. That
67
+ image is the same design-confirm evidence (see "Capture is evidence").
68
+
69
+ Trade-off — this is the *fast path*, not the floor. json-render needs the JS/npm
70
+ toolchain + a renderer package, so it does NOT cover a native (SwiftUI / Flutter / …)
71
+ project, and it has **no wireframe mode** (Stage A stays a separate, renderer-agnostic
72
+ structural artifact). When there is no toolchain, or the stack is not JS, the
73
+ self-contained HTML + CSS mock above is the universal default.
74
+
75
+ ## Reuse & consistency (by construction)
76
+
77
+ Screens compose **only** from the shared kit + token vars — never hand-styled per
78
+ screen. Because every screen links the *same* `tokens.sample.css` + `kit.sample.css`,
79
+ a single **semantic-token flip** (one line in `tokens.sample.css`) re-renders **every**
80
+ screen the same way. Reuse before invent: pull an existing kit class first; add a new
81
+ one only for a genuine new `catalog.json` component.
82
+
83
+ `settings.sample.html` is a SECOND screen that **reuses** the welcome kit classes
84
+ (screen/card/text/button) without redefining them — proving the consistency: flip
85
+ `--semantic-color-surface` once and both screens change together.
86
+
87
+ ## Capture is evidence
88
+
89
+ The screenshot of a Stage-B mock is **design-confirm evidence** — the human-facing
90
+ proof of beat 4 in `design.md`. Captures live at **`.add/design/captures/<name>.<ext>`**
91
+ (one per prototype) and are **attached or mentioned in the feature's `TASK.md`**
92
+ (alongside the §6 evidence), so the screen the human approved stays traceable from the
93
+ task that builds it. The recommended default capture engine for a json-render project is
94
+ **`@json-render/image`** (Satori → PNG/SVG, no browser); otherwise capture the
95
+ self-contained HTML mock headless. The engine never produces this image — it only
96
+ MEASURES presence (`add.py check` raises a never-red `missing_capture` WARN for a
97
+ prototype with no capture); the capture recipe is a recommendation, not an engine feature.
98
+
99
+ ## Binds (read-only)
100
+
101
+ This recipe **consumes** the UDD contracts and never reshapes them:
102
+
103
+ - `tokens.json` — the semantic layer is the source of the CSS variables (unchanged).
104
+ - `catalog.json` — its component set is the source of the kit classes (unchanged).
105
+ - `prototypes/<name>.json` — the json-render tree is the structure both stages walk
106
+ (unchanged; the frozen data contract is read-only — a change there is a separate
107
+ change-request).
108
+
109
+ The mock (`*.sample.html`) is the human-facing *visible* view; the frozen
110
+ `prototypes/<name>.json` tree is the *machine-checkable* record. They are two views of
111
+ one screen.
112
+
113
+ ## Ships byte-identical
114
+
115
+ `udd-wireframe.md` and its five sample files ship **byte-identical** in both template
116
+ trees (canonical `tooling/templates/` and the `_bundled` mirror) — enforced by
117
+ `test_bundle_parity`. A file present in one tree but missing from the other is a
118
+ `parity_break`.
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <!-- welcome.sample.html — Stage-B HTML mock of prototype.sample.json (the welcome screen).
3
+ Self-contained (no network): links only the local shared stylesheets. Composes ONLY
4
+ from the kit classes in kit.sample.css and styles nothing inline. A headless tool
5
+ screenshots this file directly; that image is the design-confirm evidence
6
+ (see udd-wireframe.md, "Capture is evidence"). -->
7
+ <html lang="en">
8
+ <head>
9
+ <meta charset="utf-8">
10
+ <meta name="viewport" content="width=device-width, initial-scale=1">
11
+ <title>Welcome — design mock</title>
12
+ <link rel="stylesheet" href="tokens.sample.css">
13
+ <link rel="stylesheet" href="kit.sample.css">
14
+ </head>
15
+ <body>
16
+ <!-- prototype tree: Screen > welcome-card(Card) > {title(Text), subtitle(Text), cta(Button)} -->
17
+ <main class="screen">
18
+ <section class="card">
19
+ <h1 class="text text--bold">Welcome to ADD</h1>
20
+ <p class="text text--regular">Spec-and-tests-first, render-ready.</p>
21
+ <button class="button" type="button">Get started</button>
22
+ </section>
23
+ </main>
24
+ </body>
25
+ </html>
@@ -0,0 +1,27 @@
1
+ WIREFRAME — welcome screen (Stage A · low-fi · pre-styling)
2
+ derived from: prototypes/welcome.json (Screen > Card > Text, Text, Button)
3
+
4
+ +--------------------------------------------------+
5
+ | SCREEN [region: full viewport] |
6
+ | |
7
+ | +--------------------------------------+ |
8
+ | | CARD [region: centered group] | |
9
+ | | | |
10
+ | | [ Text slot ] title (bold) | |
11
+ | | [ Text slot ] subtitle | |
12
+ | | [ Button slot ] primary CTA | |
13
+ | | | |
14
+ | +--------------------------------------+ |
15
+ | |
16
+ +--------------------------------------------------+
17
+
18
+ slots map one-to-one to prototype elements:
19
+ SCREEN -> Screen (root)
20
+ CARD -> Card (welcome-card)
21
+ Text -> Text (title, subtitle)
22
+ Button -> Button (cta)
23
+
24
+ notes:
25
+ - structure only — no color, no type scale, no spacing values yet
26
+ - styling arrives in Stage B (kit.sample.css bound to tokens.sample.css)
27
+ - confirm the STRUCTURE here is right before investing in the hi-fi mock