@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 +27 -0
- package/docs/14-foundation.md +11 -0
- package/docs/appendix-c-glossary.md +8 -0
- package/package.json +1 -1
- package/skill/add/SKILL.md +5 -0
- package/skill/add/design.md +92 -0
- package/skill/add/phases/0-setup.md +2 -1
- package/skill/add/phases/1-specify.md +3 -1
- package/tooling/add.py +31 -0
- package/tooling/templates/kit.sample.css +53 -0
- package/tooling/templates/settings.sample.html +25 -0
- package/tooling/templates/tokens.sample.css +23 -0
- package/tooling/templates/udd-wireframe.md +118 -0
- package/tooling/templates/welcome.sample.html +25 -0
- package/tooling/templates/wireframe.sample.txt +27 -0
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
|
package/docs/14-foundation.md
CHANGED
|
@@ -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.
|
|
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"
|
package/skill/add/SKILL.md
CHANGED
|
@@ -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
|