@fugood/bricks-ctor 2.24.10 → 2.24.12

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.
@@ -0,0 +1,225 @@
1
+ # DESIGN.md — the project's design-system artifact
2
+
3
+ Every BRICKS design project commits its system to a single durable file: **`DESIGN.md`**, at the project root. It is the source of truth for type, palette, spacing, motion, brand assets, and deployment context — written once in Pass 0, cited by every Brick afterward, and read back at the top of every later session.
4
+
5
+ The format rests on four ideas:
6
+
7
+ 1. **One named, durable markdown artifact** — not a system scattered across code comments that dies with the file. Markdown is the format an agent reads best; there is nothing to parse.
8
+ 2. **Named tokens in YAML frontmatter, referenced by name in the prose.** Declare `accent` once; write `{colors.accent}` everywhere. The body never restates a raw hex or size — one place to change, no drift.
9
+ 3. **Real design depth, not surface tokens.** Each token carries its *role* (which colour is CTA vs. body vs. hairline) and the system carries its *signature moves* (the one gesture that makes it recognisable) and the *why* behind each rule.
10
+ 4. **An agent guide** that tells the next agent how to *use* the file.
11
+
12
+ The nine-section schema below is the web-design convention reframed for BRICKS. BRICKS is a fixed-frame, grid-substrate, state-machine runtime, so three of the nine canonical sections are reframed rather than copied — see the mapping table. Importing web habits (breakpoints, scroll, CSS elevation) through this file is the fastest way to fight the runtime.
13
+
14
+ ## DESIGN.md replaces two older artifacts
15
+
16
+ This file is the merge point for what earlier versions of this skill kept apart:
17
+
18
+ - The **style-declaration comment block** at the top of the Subspace file → its tokens move into the DESIGN.md frontmatter. The Subspace comment shrinks to a one-line pointer (see [§ The Subspace pointer](#the-subspace-pointer)).
19
+ - **`brand-spec.md`** → its asset bindings, score log, and gaps become the **Assets & Brand** sections of DESIGN.md. One artifact, not two. (The acquisition *protocol* still lives in [`when-the-brief-is-branded.md`](when-the-brief-is-branded.md); DESIGN.md is where its output lands.)
20
+
21
+ A project has exactly one DESIGN.md. A multi-Subspace Application shares it; per-Subspace deviations are noted as scoped overrides inside it, never as a competing second file.
22
+
23
+ ## The nine sections, mapped to BRICKS
24
+
25
+ | Web section | BRICKS section | Why it changes |
26
+ |---|---|---|
27
+ | Visual Theme & Atmosphere | **1. Visual Theme & Atmosphere** | Unchanged in spirit — adds the picked visual language × interaction archetype. |
28
+ | Color Palette & Roles | **2. Colour Palette & Roles** | Colours used in 2+ places become theme-token Data bound via DataLink (Truth #2). |
29
+ | Typography Rules | **3. Typography** | Sizes are **grid units**, not px. Families are `ApplicationFont` entries with a fallback ladder. |
30
+ | Component Stylings | **4. Brick & Generator Stylings** | Bricks and Generators, not DOM components. Pressable affordance must read as visually distinct; Generators are headless/async (Truth #5). |
31
+ | Layout Principles | **5. Grid, Spacing & Rhythm** | Frames are grid units (Truth #6). No scroll, overflow, or reflow (Truth #10). |
32
+ | Depth & Elevation | **6. Motion, Standby & Depth** | No CSS z-index / box-shadow model. Depth = Brick draw order + Standby entrance offsets (Truth #7) + shared-id auto-tween (Truth #3). |
33
+ | Do's and Don'ts | **7. Do's & Don'ts** | Each rule tied to what it protects; folds in this system's anti-slop. |
34
+ | Responsive Behavior | **8. Hardware & Orientation** | **Not breakpoints.** Fixed target resolution + orientation; fleet variants are separate Canvas sets or device-scoped Data, never media queries. |
35
+ | Agent Prompt Guide | **9. Agent Guide** | How to cite tokens, add tokens, and verify against this file. |
36
+
37
+ Two BRICKS-native sections have no web equivalent and sit up front: **Deployment Context** (captures Priority #0 durably) and **Assets & Brand** (the merged `brand-spec.md`).
38
+
39
+ ## Token-reference discipline — the load-bearing habit
40
+
41
+ This is what separates a system from an accumulation:
42
+
43
+ - **Declare every reusable value as a named token in the frontmatter.** Reference it by name in the prose and in your reasoning: `{colors.ink}`, `{type.display}`, `{spacing.gap-m}`, `{heroes.brand-logo}`.
44
+ - **Never restate a raw value in the body.** Writing `#1A1A1A` inline instead of `{colors.ink}` forks the source of truth; the next edit updates one and not the other.
45
+ - **Adding a value not already in the tokens requires adding the token first.** Want a third colour or a fourth gap? Edit the frontmatter, then use it. The "first" is the whole mechanism — it forces a deliberate pause where averaging-toward-generic would otherwise sneak a value in.
46
+ - **Sizes and gaps are in grid units (`gu`), never pixels.** The grid substrate is given by the runtime (Truth #6); the design sits on top of it.
47
+ - **Shared colours (2+ uses) become theme-token Data** bound via DataLink, with the token name matching the DESIGN.md key. Single-use decorative colours may stay hardcoded (Truth #2 is loose by design).
48
+
49
+ ## The template
50
+
51
+ Copy this verbatim into `DESIGN.md` and fill it. Every section is required; an empty section is a declared gap, not an omission.
52
+
53
+ ````markdown
54
+ ---
55
+ name: <Application name> — design system
56
+ system: <visual language, e.g. Swiss Editorial (Pentagram lineage)>
57
+ archetype: <glance | browse | interact | transact | monitor | dwell>
58
+
59
+ deployment:
60
+ hardware: <size · resolution · orientation · touch? · viewing distance>
61
+ scene: <where the screen lives, what the user does in front of it>
62
+ network: <always-on | intermittent | offline>
63
+ languages: [<en>, <...>]
64
+ peripherals: [<camera | BLE | MQTT | NFC | payment | printer | sensors | none>]
65
+ watchdog: <fleet-managed | single-instance>
66
+
67
+ colors: # role in the comment; hex is the value
68
+ ink: "#1A1A1A" # body text — deep, never pure black
69
+ ground: "#F5F0E6" # default Canvas background
70
+ accent: "#FF3C00" # callouts only — at most one per Canvas
71
+ hairline: "#E3E0D6" # 1gu rules and card edges
72
+ # forbidden: [<colours the brand explicitly never uses>]
73
+
74
+ type: # sizes in grid units (gu)
75
+ display: { family: "<Brand Sans>", size: 16, weight: 300, tracking: -0.02 }
76
+ heading: { family: "<Brand Sans>", size: 8, weight: 400, tracking: 0 }
77
+ body: { family: "<Brand Sans>", size: 4, weight: 400, tracking: 0 }
78
+ caption: { family: "<Brand Sans>", size: 3, weight: 400, tracking: 0 }
79
+
80
+ spacing: # inter-Brick gaps come ONLY from this set (gu)
81
+ gap-s: 2
82
+ gap-m: 4
83
+ gap-l: 8
84
+ margin: 8
85
+
86
+ grid: lean # lean (strict align, generous margin) | break | breathe
87
+
88
+ motion: # Standby Transition vocabulary (Truth #7)
89
+ entrance: { standbyMode: "<offset, e.g. translateY 4gu>", ease: ease-out, ms: 280, stagger: 40 }
90
+ exit: { ease: ease-in, ms: 180 }
91
+ loops: <none | only on {brick-id}>
92
+
93
+ heroes: # Brick ids reused across Canvases → runtime auto-tweens them (Truth #3)
94
+ - brand-logo
95
+ - folio-num
96
+
97
+ fonts: # ApplicationFont entries → Application.applicationSettings.fonts
98
+ - { name: "<Brand Sans>", url: "<media-flow-or-cdn-url>", md5: "<optional>" }
99
+ ---
100
+
101
+ # <Application name> — Design System
102
+ > Captured: <YYYY-MM-DD> · Sources: <reference pages / Figma / brand book> · Coverage: <complete | partial | inferred>
103
+
104
+ ## Deployment Context
105
+ The five Priority #0 facts in prose, plus peripherals and watchdog. Every visual
106
+ decision below is downstream of these. If any of the first five was assumed rather
107
+ than confirmed, mark it **ASSUMED** here so the next agent knows what to re-check.
108
+
109
+ ## 1. Visual Theme & Atmosphere
110
+ What the system *says* in two or three sentences. Name the picked **visual language**
111
+ and **interaction archetype**, then the **signature moves** — the one or two gestures
112
+ that make this system recognisable at a glance (e.g. "oversized folio numerals + a
113
+ single hairline rule per Canvas"). When unsure, commit *harder* to these, not softer.
114
+
115
+ **Key characteristics:** 4–6 bullets, each a concrete, checkable rule.
116
+
117
+ ## 2. Colour Palette & Roles
118
+ Each token by name with its job. Reference `{colors.<name>}` — never the raw hex.
119
+ - `{colors.ink}` — body text on `{colors.ground}`. Deep charcoal, never pure black.
120
+ - `{colors.accent}` — callouts and the single emphasis per Canvas. Never a body colour.
121
+ - `{colors.hairline}` — 1gu rules, card edges.
122
+ - Forbidden: <colours the brand never uses>, if any.
123
+ Shared colours bind as theme-token Data; note which here.
124
+
125
+ ## 3. Typography
126
+ - Families and the **fallback ladder** — what to substitute when the licensed font is
127
+ absent (e.g. "Söhne → Inter weight 300 + tracking -0.02"). Declared as `fonts` entries.
128
+ - Each role (`{type.display}` … `{type.caption}`) with size in gu, weight, tracking,
129
+ and *where it is used*. Multilingual note: which scripts the families cover.
130
+
131
+ ## 4. Brick & Generator Stylings
132
+ - **Pressable affordance** — how a tile that responds to a press looks different from a
133
+ decorative one. A pressable that looks identical to décor is a bug. (Wiring lives in
134
+ `bricks-ux`; the *visual* distinction lives here.)
135
+ - **Hero Bricks** — the ids in `heroes`, what each is, and how it reads across Canvases.
136
+ - **Generator-driven components** — list / chart / feed surfaces fed by a headless,
137
+ async Generator (Truth #5). Note their loading, empty, and error appearance.
138
+ - **Media-bound Bricks** — every brand visual reads from Media Flow via DataLink (see
139
+ Assets & Brand); none is drawn, embedded, or set to a literal path.
140
+
141
+ ## 5. Grid, Spacing & Rhythm
142
+ - **Grid stance** `{grid}` — lean / break / breathe, and what that means in margins.
143
+ - **Spacing scale** — inter-Brick gaps come only from `{spacing.*}`. Ten gaps of
144
+ 7/9/11/13 across siblings is arithmetic drift; snap to the scale.
145
+ - **Density rhythm** — how consecutive Canvases vary (not three identical layouts).
146
+ - **No scroll, overflow, or reflow** (Truth #10). What does not fit does not show;
147
+ design within the Canvas at the target resolution.
148
+
149
+ ## 6. Motion, Standby & Depth
150
+ - **Standby Transition** `{motion.entrance}` / `{motion.exit}` — every visible Brick
151
+ gets an entrance offset; the runtime auto-tweens in-flight motion (Truth #7).
152
+ - **Shared-id auto-tween** — heroes keep their id across Canvases so position/size
153
+ animate for free (Truth #3). This is the highest-leverage polish technique.
154
+ - **Depth** is Brick draw order, not a z/shadow model. State the stacking intent.
155
+ - **Snap-cuts** are reserved for emphasis (alarms), never routine navigation.
156
+
157
+ ## 7. Do's & Don'ts
158
+ Each tied to what it protects. Examples:
159
+ - **Do** reserve `{colors.accent}` for one emphasis per Canvas — sparingness is the signal.
160
+ - **Don't** soften the signature moves "to be safe" — at 30% the language reads hesitant.
161
+ - **Don't** introduce a gap outside `{spacing.*}` — add the token first or don't add it.
162
+
163
+ ## 8. Hardware & Orientation
164
+ Not breakpoints — BRICKS frames are fixed.
165
+ - **Target** resolution and orientation (from Deployment Context). The design is built
166
+ for this exact frame.
167
+ - **Viewing distance → minimum legible size** in gu, especially for `glance` signage.
168
+ - **Fleet variants** — if the same Application runs on differing resolutions, say how:
169
+ a separate Canvas set, or device-scoped Data — *not* a media query or reflow.
170
+ - **Language fit** — longest-string behaviour; the design must hold without overflow.
171
+
172
+ ## 9. Agent Guide
173
+ - Reference tokens by name (`{colors.accent}`, `{spacing.gap-m}`); never inline a raw value.
174
+ - To add any value, add the token to the frontmatter first, then use it.
175
+ - Default body to `{type.body}`; default gap to `{spacing.gap-m}`.
176
+ - The Subspace's top comment points here; do not re-declare the system inline.
177
+ - Before declaring done, the design-critique pass cites this file section by section,
178
+ and every Canvas screenshot is compared against the tokens here.
179
+
180
+ ## Assets & Brand
181
+ (Merged brand spec — populated via the protocol in `when-the-brief-is-branded.md`.)
182
+
183
+ ### First-class assets
184
+ - **Logo** — light / dark / mono → Media Flow IDs → Data keys (`brandLogoDark` …),
185
+ clearspace, minimum size, source.
186
+ - **Product / UI / scene photography** (per brand type) → IDs → Data keys, each with
187
+ its 5-10-2-8 score `[R_ P_ B_ C_ N_ = _/10]`.
188
+ - **Motion** — brand reel / animated logo → IDs → Data keys.
189
+
190
+ ### Voice & tone
191
+ Register, capitalization, banned phrases — a constraint on every user-visible Data string.
192
+
193
+ ### Gaps & placeholders
194
+ `<category>: <why missing> → <ask user | generate-with-anchor | accept placeholder> [as of <date>]`
195
+
196
+ ### Score log
197
+ `<asset>: R_ P_ B_ C_ N_ = _/10` for every non-logo asset.
198
+ ````
199
+
200
+ ## The Subspace pointer
201
+
202
+ The Subspace file no longer carries the full system as a comment. It carries a one-line pointer so a reader knows where the system lives and what it is at a glance:
203
+
204
+ ```ts
205
+ /** System: Swiss Editorial · archetype: glance · tokens + assets in ../DESIGN.md */
206
+ ```
207
+
208
+ If a Subspace genuinely needs a scoped deviation (a darker ground for a single monitoring Subspace, say), note the override inside DESIGN.md under that Subspace's name and point the comment at it — never fork a second system silently.
209
+
210
+ ## How DESIGN.md threads through the workflow
211
+
212
+ - **Pass 0** writes DESIGN.md: frontmatter tokens + Deployment Context + section 1 at minimum. ([`workflow.md`](workflow.md))
213
+ - **Picking a visual language** fills sections 1–3 and `system`/`archetype`. ([`design-languages.md`](design-languages.md))
214
+ - **Branded work** fills Assets & Brand and the colour/type/voice tokens. ([`when-the-brief-is-branded.md`](when-the-brief-is-branded.md))
215
+ - **Variations** are alternate token sets, expressed as a flat preset map keyed to these tokens, not a second DESIGN.md. ([`variations-and-tweaks.md`](variations-and-tweaks.md))
216
+ - **Verification & critique** read DESIGN.md back and check the rendered Canvases against it section by section. ([`design-critique.md`](design-critique.md))
217
+
218
+ ## Anti-patterns specific to DESIGN.md
219
+
220
+ - **Inlining raw values in the body** instead of `{token}` references — forks the source of truth.
221
+ - **A breakpoint table** in section 8 — that is a web habit; BRICKS frames are fixed (Truth #10).
222
+ - **A CSS-style elevation model** in section 6 — depth is draw order + Standby, not z-index/shadow.
223
+ - **Two artifacts** — a `brand-spec.md` *and* a DESIGN.md, or per-Subspace system blocks competing with the file. One project, one DESIGN.md.
224
+ - **Writing DESIGN.md after the Canvases** — it is a Pass 0 commitment that the build cites, not a doc written to describe finished work.
225
+ - **Tokens with no roles** — `accent: "#FF3C00"` with no note on what it is for is a swatch, not a system. The role is the design depth.
@@ -20,13 +20,18 @@ How to inspect, by source type:
20
20
  | Public URL (website / docs / product page) | Drive a browser automation tool — browser-MCP, Playwright/Puppeteer-style MCP, an `agent-browser`-equivalent skill, or any host-provided browser tool — to navigate the page and capture full-page screenshots. Then read each screenshot back through the host's image-reading capability. `WebFetch` and similar text extractors are **not** visual inspection; use them only as navigation aids to enumerate which pages to visit. |
21
21
  | Figma / design-tool URL | Use a Figma-MCP / design-tool MCP if present to enumerate frames and image-export each. Otherwise ask the user for PNG exports of every relevant frame. |
22
22
  | HTML project on disk | Serve and screenshot every route via a browser tool, the same as a public URL. Do not infer visuals by reading source HTML/CSS — the rendered output is what you need. |
23
- | PDF / brand book / slide deck | Read every page through the host's PDF capability, page-by-page when the document is long. Cover all pages, not just the first few. |
23
+ | PDF / brand book / slide deck | Read every page through the host's PDF capability, page-by-page when the document is long. Cover all pages, not just the first few. If the host only shows a cover preview or has no PDF capability, use an installed PDF skill when available. If no PDF skill or local PDF tool is installed and you cannot inspect the PDF fully, stop and respond in chat with the limitation instead of designing from partial evidence. |
24
24
  | Local images / screenshots | Read each via the image tool. |
25
25
  | Video walkthrough | Ask the user for key-frame screenshots, or to describe each state. Do not claim to have "watched" a video you cannot frame-step. |
26
26
  | Live competitor product / app | Run it (or have the user run it and capture screen recordings); inspect the screenshots/states. |
27
27
 
28
28
  If a reference is partially inaccessible (paywalled page, unauthenticated content, broken link), name the gap explicitly. Don't extrapolate from the visible portion.
29
29
 
30
+ For PDF-derived page images, keep the artifacts sized for inspection. A giant
31
+ 4-13 MB PNG per page is a tool failure waiting to happen, not a useful
32
+ handoff. Prefer downsampled JPEG/PNG previews, page batches, and a simple
33
+ coverage checklist (`seen pages: 1-8 of 8`) before design work starts.
34
+
30
35
  Inspection comes before everything else in this file. The translation table below assumes you have already seen every relevant frame.
31
36
 
32
37
  ## A render is one state, not an Application
@@ -128,7 +133,7 @@ When the source contains brand binaries, you are inheriting them — but only at
128
133
  - A redrawn-in-Figma logo or product silhouette in the source design is a tell that the source designer didn't have the real asset either — start the asset hunt from scratch, don't carry the redraw across.
129
134
  - Embedded brand fonts may not be license-cleared for embedded display use; verify the license and switch to a documented alternative if the constraint isn't met.
130
135
 
131
- Score everything against 5-10-2-8 before binding. If the source's brand binaries are unclear, low-resolution, or stylized substitutes, surface as a gap in `brand-spec.md` and either acquire properly or — for non-logo categories — escalate to brand-reference-anchored generation per [`when-the-brief-is-branded.md`](when-the-brief-is-branded.md). **Don't ship Sketch-Brick imitations.**
136
+ Score everything against 5-10-2-8 before binding. If the source's brand binaries are unclear, low-resolution, or stylized substitutes, surface as a gap under DESIGN.md's **Gaps & placeholders** and either acquire properly or — for non-logo categories — escalate to brand-reference-anchored generation per [`when-the-brief-is-branded.md`](when-the-brief-is-branded.md). **Don't ship Sketch-Brick imitations.**
132
137
 
133
138
  ### Brand colors and tokens
134
139
 
@@ -136,6 +141,8 @@ Score everything against 5-10-2-8 before binding. If the source's brand binaries
136
141
  - One-off decorative color → hardcode (Truth #2's loose convention).
137
142
  - Token system from a brand book (light / dark / accent / semantic) → expose as Data tokens; switch theme by writing to the token Data values.
138
143
 
144
+ Extracted colors, type, and spacing become the named tokens in [`DESIGN.md`](design-md.md) (referenced by name thereafter), so the translated system is captured once rather than re-derived per Canvas.
145
+
139
146
  ### Long copy / paragraphs
140
147
 
141
148
  - A signage screen at 5 m has time for one claim. If the source design has paragraphs of body copy, the design is wrong for the deployment, not the runtime.
@@ -26,7 +26,7 @@ Use when variations differ only on values: palette, copy, asset paths, density f
26
26
  **Shape:**
27
27
 
28
28
  - One Canvas / Subspace. All variant-specific values are Data with initial constants.
29
- - Source has a `VARIATION_PRESETS` map near the top of the Subspace define file. Each preset is a flat map of token values. Keep the map flat — nested config trees make per-preset diffs noisy.
29
+ - Source has a `VARIATION_PRESETS` map near the top of the Subspace define file. Each preset is a flat map of the DESIGN.md token keys (`ground`, `ink`, `accent`, `gap-m`, …) — a variation is one alternate token set, not a second DESIGN.md. Keep the map flat — nested config trees make per-preset diffs noisy.
30
30
  - Active preset is selected by a single line near the top: `const ACTIVE = PRESETS.bauhaus`. Agent flips this line, runs preview, captures screenshot, repeats.
31
31
  - All hero Bricks keep **the same id** across all presets — preserves Shared Brick auto-tween if the user later wants to A/B them at runtime in a settings Canvas (different use case, but the door stays open).
32
32
 
@@ -128,9 +128,9 @@ The bar exists because cosmetic-quality drift is invisible until shipped, then o
128
128
  | **Composition / craft** | Lighting, framing, background all consistent with the rest of the asset set | Mixed lighting across "set"; orphan background colors; visible artifacts |
129
129
  | **Narrative weight** | Carries one story alone; can be a hero on its own merits | Only works as decoration / filler; needs surrounding chrome to read |
130
130
 
131
- **Logging the scores** in `brand-spec.md` (per category) is what makes the bar real. If you didn't log a score, you didn't apply the bar.
131
+ **Logging the scores** under DESIGN.md's **Score log** (per category) is what makes the bar real. If you didn't log a score, you didn't apply the bar.
132
132
 
133
- ### Step 5 — Bind into Media Flow + persist `brand-spec.md`
133
+ ### Step 5 — Bind into Media Flow + record in DESIGN.md
134
134
 
135
135
  Upload acquired assets into a Media Flow workspace (use the host's Media Flow MCP tools where available — `list_media_workspaces`, `get_media_workspace`, `media_box_upload`, `update_media_file_meta`). Reference each from the Subspace via Data with the appropriate `kind`:
136
136
 
@@ -145,17 +145,17 @@ Bricks bind via DataLink: `Image.property.source = linkData(() => brandLogoData)
145
145
 
146
146
  Fonts: declare each as an `ApplicationFont` entry in `Application.applicationSettings.fonts` (`name`, `url`, optional `md5`). Reference by name in Brick `property.fontFamily`.
147
147
 
148
- `brand-spec.md` lives next to the Subspace. Use this template verbatim — every section is required, even the gap section:
148
+ The brand spec is **not** a separate file — it is the **Assets & Brand** sections of the project's [`DESIGN.md`](design-md.md), alongside the colour/type/voice tokens. Use this structure verbatim under DESIGN.md's `## Assets & Brand` heading — every section is required, even the gap section:
149
149
 
150
150
  ```markdown
151
- # Brand spec — <brand name>
151
+ ## Assets & Brand
152
152
  > Captured: <YYYY-MM-DD>
153
153
  > Sources: <list>
154
154
  > Coverage: <complete / partial / inferred>
155
155
 
156
- ## First-class assets
156
+ ### First-class assets
157
157
 
158
- ### Logo
158
+ #### Logo
159
159
  - Primary (dark ground): <Media Flow ID> → Data: brandLogoDark
160
160
  - Primary (light ground): <Media Flow ID> → Data: brandLogoLight
161
161
  - Mono / reverse: <Media Flow ID> → Data: brandLogoMono
@@ -163,57 +163,56 @@ Fonts: declare each as an `ApplicationFont` entry in `Application.applicationSet
163
163
  - Minimum size: <e.g., 96 px wide>
164
164
  - Source: <press-kit URL / inline-svg from <url> / file from user>
165
165
 
166
- ### Product photography (if physical brand)
166
+ #### Product photography (if physical brand)
167
167
  - Hero front: <Media Flow ID> → Data: productHero (3000×2000, transparent) [score: R9 P9 B8 C9 N9]
168
168
  - Detail crop A: ... [score: ...]
169
169
  - Scene context: ... [score: ...]
170
170
 
171
- ### UI screenshots (if digital brand)
171
+ #### UI screenshots (if digital brand)
172
172
  - Home: ... [score: ...]
173
173
  - Core feature A: ... [score: ...]
174
174
 
175
- ### Scene / lifestyle (if relevant)
175
+ #### Scene / lifestyle (if relevant)
176
176
  - ...
177
177
 
178
- ### Motion
178
+ #### Motion
179
179
  - Brand reel clip: <Media Flow ID> → Data: brandReel (1920×1080, 12s, h264)
180
180
  - Animated logo: <Media Flow ID> → Data: brandLogoLottie
181
181
 
182
- ## Auxiliary
182
+ ### Auxiliary
183
183
 
184
- ### Colors (theme tokens — exposed as Data when shared)
185
- - --brand-primary #XXXXXX OKLCH(...) source: <where>
186
- - --brand-accent #XXXXXX
187
- - --brand-neutral-100 / -900
188
- - Forbidden: <colors the brand explicitly does not use>
184
+ #### Colours
185
+ The palette lives in the DESIGN.md frontmatter `colors` tokens (shared ones bound as theme-token Data). Record provenance and constraints here:
186
+ - `{colors.primary}` / `{colors.accent}` / neutrals — source: <where each was sampled / documented>
187
+ - Forbidden: <colours the brand explicitly does not use>
189
188
 
190
- ### Fonts (ApplicationFont entries)
191
- - Display: <family / weights / file location / license>
192
- - Body: <family / weights / file location / license>
189
+ #### Fonts (ApplicationFont entries)
190
+ - Display: <family / weights / file location / license> → frontmatter `type.display` + `fonts`
191
+ - Body: <family / weights / file location / license> → frontmatter `type.body` + `fonts`
193
192
 
194
- ### Voice & tone
193
+ #### Voice & tone
195
194
  - Register: <e.g., confident, terse, never effusive>
196
195
  - Capitalization: <e.g., sentence case>
197
196
  - Banned phrases: <e.g., "innovative", "revolutionary", "AI-powered">
198
197
 
199
- ### Signature details
198
+ #### Signature details
200
199
  - <One or two design moves the brand is known for — a specific corner radius, a hairline rule, a particular typographic treatment.>
201
200
 
202
- ## Gaps & placeholders
201
+ ### Gaps & placeholders
203
202
  - <category>: <why missing> → <action: ask user / AI generate / accept placeholder> [as of <date>]
204
203
 
205
- ## Score log (for non-logo assets)
204
+ ### Score log (for non-logo assets)
206
205
  - <asset>: R<n> P<n> B<n> C<n> N<n> = <avg>/10
207
206
  ```
208
207
 
209
208
  ## Structural enforcement — assets are referenced, not redrawn
210
209
 
211
- Once `brand-spec.md` exists, the discipline that keeps the design honest is structural, not behavioural. Encode it in the build:
210
+ Once DESIGN.md's Assets & Brand sections are populated, the discipline that keeps the design honest is structural, not behavioural. Encode it in the build:
212
211
 
213
212
  - **Every brand visual** is a Brick reading from a Media Flow Data via DataLink. No `Image.property.source` set to a literal URL or path. No `Sketch` Brick drawing a "logo-shaped" graphic. No `Svg` Brick reproducing the logo as a path. The pattern enforces "you cannot ship a redrawn logo because the project structure doesn't allow it."
214
213
  - **Brand colors used in 2+ places** become theme-token Data, bound via DataLink. Single-use decorative colors can stay hardcoded (Truth #2's loose convention).
215
214
  - **Theme tokens are the single source of truth.** Want to add a new color? Add a Data entry first, then bind. The "first" is what makes it a system instead of an accumulation.
216
- - **Every Brick that uses a brand asset** has its source traceable to a `brand-spec.md` line. Reviewing the spec is reviewing the design.
215
+ - **Every Brick that uses a brand asset** has its source traceable to a DESIGN.md Assets & Brand line. Reviewing DESIGN.md is reviewing the design.
217
216
 
218
217
  ## Creating assets when missing
219
218
 
@@ -221,13 +220,13 @@ When a category has no acquirable real asset and the user has no plan to provide
221
220
 
222
221
  1. **Stop and ask.** For logo, this is the only allowed option.
223
222
  2. **Compose the host environment's generative tools.** If a canvas-design / imagen / image-generation MCP / motion-generation MCP / Banana-style tool is available in the host, use it — *anchored on a verified brand reference*. This skill does not duplicate them; it composes them.
224
- 3. **Accept a labeled placeholder Brick** with the gap tracked in `brand-spec.md`. Use this when generation is unavailable or known to fail for the asset type (e.g., generating a "real product photo" for a niche industrial product almost always fails).
223
+ 3. **Accept a labeled placeholder Brick** with the gap tracked under DESIGN.md's **Gaps & placeholders**. Use this when generation is unavailable or known to fail for the asset type (e.g., generating a "real product photo" for a niche industrial product almost always fails).
225
224
 
226
225
  ### Generative discipline (when option 2)
227
226
 
228
227
  - **Anchor on real brand material.** Feed at least one verified brand asset — the logo, a verified product photo, a brand color sample — as conditioning to the generator. Generation from "the brand's general vibe" produces uncanny-valley assets that feel adjacent to the brand without being the brand. Almost always recognized as fake by reviewers.
229
228
  - **Generate at the 5-10-2-8 quantity bar.** 8–10 candidates per slot, scored on the same 5 dimensions, keep 2.
230
- - **Persist generation metadata** in `brand-spec.md`: prompt, seed (where supported), reference assets used, model version. Reproducibility matters when the user later asks for a refresh in the same style.
229
+ - **Persist generation metadata** under DESIGN.md's Assets & Brand: prompt, seed (where supported), reference assets used, model version. Reproducibility matters when the user later asks for a refresh in the same style.
231
230
  - **Never generate logos, wordmarks, or named characters.** These are identity, not imagery — generation produces look-alikes that legal will reject.
232
231
  - **Avoid AI-design tells.** Gradient orbs as "AI". Glassy translucent panels with no source. Generic happy-diverse-people-in-a-bright-office. Tech-y blue-purple gradients as backgrounds. Float / hover dot patterns. Watch for these in generated output and re-generate or discard.
233
232
  - **Motion generation is high-failure.** For Lottie / Rive / video, expect to discard 9 of 10 outputs. Budget the iteration; don't ship the first plausible result.
@@ -255,7 +254,7 @@ Some BRICKS deployments are for venues with no prior brand work — small clinic
255
254
 
256
255
  - Skip the protocol; admit the gap up front.
257
256
  - Switch into Direction Advisor mode ([`when-the-brief-is-vague.md`](when-the-brief-is-vague.md)) and propose 3 differentiated visual directions.
258
- - The picked direction *becomes* the brand spec for this Application. Persist the picked direction's tokens, motion language, photography style guidelines, and (if any) generated assets via the same `brand-spec.md` template — even when invented from scratch. Treat it as a real spec, not a working note. The next person to touch the deployment will need it.
257
+ - The picked direction *becomes* the brand spec for this Application. Persist the picked direction's tokens, motion language, photography style guidelines, and (if any) generated assets in DESIGN.md (tokens + Assets & Brand) — even when invented from scratch. Treat it as a real spec, not a working note. The next person to touch the deployment will need it.
259
258
 
260
259
  ## Voice & tone as a constraint on user-visible Data
261
260
 
@@ -274,11 +273,11 @@ You cannot move from this protocol back into design until all of the following a
274
273
  1. Logo — present in Media Flow with light + dark + mono where applicable; bound via Data.
275
274
  2. Product / UI / scene category appropriate to the brand type — present, scored ≥ 8/10 on each kept asset, bound via Data.
276
275
  3. Motion category — present where the brand has motion identity; absent and noted otherwise.
277
- 4. Colors — palette declared as theme-token Data (for shared colors) and / or as `brand-spec.md` entries.
276
+ 4. Colors — palette declared as DESIGN.md `colors` tokens (shared ones bound as theme-token Data).
278
277
  5. Fonts — declared as `ApplicationFont` entries; license confirmed.
279
278
  6. Voice & tone — captured as constraint or marked TBD with stakeholder + date.
280
279
  7. Gaps — every missing or placeholder asset listed under "Gaps & placeholders" with action and date.
281
280
  8. Score log — every non-logo asset scored on the 5 dimensions and logged.
282
- 9. Spec committed — `brand-spec.md` exists alongside the Subspace; not in a chat scrollback or a working file that will be lost.
281
+ 9. Spec committed — DESIGN.md's Assets & Brand sections are filled in the project root; not in a chat scrollback or a working file that will be lost.
283
282
 
284
283
  If any item is incomplete, name it in your reply and either resolve it or pause for user input. Don't proceed silently.
@@ -61,31 +61,27 @@ When you do ask, cover these axes — in one batch, omitting any already pinned:
61
61
 
62
62
  Don't sprint to a finished Subspace. Stage the work so wrong direction is caught at the cheapest point.
63
63
 
64
- ### Pass 0 — Deployment context + style declaration
64
+ ### Pass 0 — Deployment context + DESIGN.md
65
65
 
66
- Confirm Priority #0 verbatim. Write the style declaration block at the top of the Subspace file before placing any Brick:
66
+ Confirm Priority #0 verbatim, then write the project's **`DESIGN.md`** before placing any Brick. Full schema and template in [`design-md.md`](design-md.md); at Pass 0 you need at minimum:
67
+
68
+ - **Frontmatter tokens** — `system`, `archetype`, the `colors` / `type` (sizes in grid units) / `spacing` (grid units) / `motion` / `grid` / `heroes` maps. Each token carries its role in a comment.
69
+ - **Deployment Context** — the five Priority #0 facts in prose, with any assumed value flagged `ASSUMED`.
70
+ - **Visual Theme & Atmosphere** (section 1) — what the system says and its one or two signature moves.
71
+
72
+ The grid substrate is given (Truth #6). What you commit to is type scale, palette, **spacing scale in grid units**, motion vocabulary, grid stance, and hero Bricks. The spacing scale is a small enumeration (3–5 values); inter-Brick gaps come from this set by name (`{spacing.gap-m}`), not arbitrary integers. DESIGN.md keeps the agent's arithmetic consistent across many Bricks and is what the design-critique pass cites.
73
+
74
+ The Subspace file itself carries only a one-line pointer:
67
75
 
68
76
  ```ts
69
- /**
70
- * System: <picked design language, e.g., Swiss Editorial>
71
- * Archetype: <interaction archetype, e.g., glance>
72
- * Type: <font family> · <size scale in grid units, e.g., 2 / 4 / 8 / 16 gu>
73
- * Color: <ground> on <ink> · accent <#hex> (used only for …)
74
- * Spacing: <scale in grid units, e.g., 2 / 4 / 8 / 16 gu>
75
- * Grid stance: lean / break / breathe
76
- * Motion: <Standby easing + ms> entrance · <ms> exit · loops only on <element>
77
- * Heroes: <Brick id(s) that persist across Canvases via auto-tween>
78
- * Asset emphasis: <real photography / type-only / hero video / …>
79
- */
77
+ /** System: <picked design language> · archetype: <archetype> · tokens + assets in ../DESIGN.md */
80
78
  ```
81
79
 
82
- The grid substrate is given (Truth #6). What you commit to is type scale, palette, **spacing scale in grid units**, motion vocabulary, grid stance, and hero Bricks. The spacing scale is a small enumeration (3–5 values); inter-Brick gaps come from this set, not arbitrary integers. This block keeps the agent's arithmetic consistent across many Bricks and is what the design-critique pass cites.
83
-
84
80
  ### Pass 1 — Showcase Canvas (the lockdown moment)
85
81
 
86
82
  Build **one** Canvas, fully lit, that represents the work at its highest fidelity. Choose the hardest Canvas — the boot screen, the most content-dense state, or the moment that carries the brand most. Run through Verification (compile + screenshot + view back). Show the user.
87
83
 
88
- This is the cheapest point to discover the direction is wrong. If the user wants the type bigger, the photography swapped, the rhythm slower, the language different — fix the Canvas and the style declaration, not twelve Canvases.
84
+ This is the cheapest point to discover the direction is wrong. If the user wants the type bigger, the photography swapped, the rhythm slower, the language different — fix the Canvas and the DESIGN.md tokens, not twelve Canvases.
89
85
 
90
86
  **Do not** build the full Canvas graph before this checkpoint. The temptation is real because state-machine work feels productive; resist it. Sign-off on one Canvas first.
91
87
 
@@ -131,4 +127,4 @@ Don't compress passes on:
131
127
  - **Asking one question at a time.** Burns volleys, drains user energy.
132
128
  - **Asking nothing and inferring.** The five Priority #0 items are not inferrable; trying to is the most expensive mistake.
133
129
  - **Declaring done after Pass 2.** Pass 4 critique is what separates "runs" from "good."
134
- - **Re-declaring the style block on every iteration.** If you find yourself updating five values at once mid-Pass-3, you're rebuilding the system — back up to Pass 1.
130
+ - **Rewriting DESIGN.md tokens on every iteration.** If you find yourself updating five tokens at once mid-Pass-3, you're rebuilding the system — back up to Pass 1.
@@ -2,6 +2,7 @@ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
2
2
  import { readFile } from 'node:fs/promises'
3
3
  import { z } from 'zod'
4
4
  import { sh } from '../_shell'
5
+ import { appendSimulatorInspectionGuidance } from './simulator-guidance'
5
6
 
6
7
  // Disable ANSI color codes from spawned tools so MCP text output stays readable
7
8
  // (the host renders raw text; escape sequences leak into the result otherwise).
@@ -78,6 +79,7 @@ export function register(server: McpServer, projectDir: string) {
78
79
  log = [stdout, stderr].filter(Boolean).join('\n')
79
80
  error = true
80
81
  }
82
+ if (!error) log = appendSimulatorInspectionGuidance(log, { testId, testTitleLike })
81
83
  let screenshotBase64: string | null = null
82
84
  if (!error && responseImage) {
83
85
  const toolsDir = `${dirname}/..`
@@ -0,0 +1,31 @@
1
+ const quoteShellArg = (value: string) => `'${value.replace(/'/g, `'\\''`)}'`
2
+
3
+ const buildInteractiveSimulatorCommand = ({
4
+ testId,
5
+ testTitleLike,
6
+ }: {
7
+ testId?: string
8
+ testTitleLike?: string
9
+ } = {}) => {
10
+ const args = ['bun preview']
11
+ if (testId) args.push('--test-id', quoteShellArg(testId))
12
+ if (testTitleLike) args.push('--test-title-like', quoteShellArg(testTitleLike))
13
+ return args.join(' ')
14
+ }
15
+
16
+ export function appendSimulatorInspectionGuidance(
17
+ log: string,
18
+ options: { testId?: string; testTitleLike?: string } = {},
19
+ ) {
20
+ return [
21
+ log.trimEnd(),
22
+ '',
23
+ 'Inspection guidance:',
24
+ `- For interactive debugging of this same Preview runtime, run \`${buildInteractiveSimulatorCommand(options)}\` from the project directory. It exposes CDP on localhost:19852 by default and writes .bricks/devtools.json for CLI discovery.`,
25
+ '- Use `bricks devtools -p 19852 ...` from the project directory to inspect the Simulator. Plain `bricks devtools` may inspect another device on the default port.',
26
+ '- Useful commands: `bricks devtools -p 19852 brick tree`, `brick query <selector>`, `input tap <x> <y>`, `network list`, `storage data-bank get <S_xxxx>`, and `runtime eval "automation.list()" -j`.',
27
+ '- Prefer this Preview CDP/runtime path over a separate Playwright browser when validating BRICKS app state, logs, input, storage, or network behavior.',
28
+ '- If the `bricks-cli` skill is unavailable, run `bricks devtools --help`; the CLI help is authoritative.',
29
+ '',
30
+ ].join('\n')
31
+ }
@@ -269,6 +269,7 @@ Default property:
269
269
  y?: number | DataLink
270
270
  width?: number | DataLink
271
271
  height?: number | DataLink
272
+ type?: string | DataLink
272
273
  standbyMode?: 'custom' | 'top' | 'bottom' | 'left' | 'right' | DataLink
273
274
  standbyFrame?: DataLink | {}
274
275
  standbyOpacity?: number | DataLink
@@ -319,6 +320,7 @@ Default property:
319
320
  }
320
321
  show?: string | DataLink
321
322
  pressToOpenDetail?: boolean | DataLink
323
+ pressToBackList?: boolean | DataLink
322
324
  }
323
325
  >
324
326
  | DataLink
@@ -346,6 +348,7 @@ Default property:
346
348
  y?: number | DataLink
347
349
  width?: number | DataLink
348
350
  height?: number | DataLink
351
+ type?: string | DataLink
349
352
  standbyMode?: 'custom' | 'top' | 'bottom' | 'left' | 'right' | DataLink
350
353
  standbyFrame?: DataLink | {}
351
354
  standbyOpacity?: number | DataLink
@@ -395,6 +398,7 @@ Default property:
395
398
  renderOutOfViewport?: boolean | DataLink
396
399
  }
397
400
  show?: string | DataLink
401
+ pressToOpenDetail?: boolean | DataLink
398
402
  pressToBackList?: boolean | DataLink
399
403
  }
400
404
  >
@@ -36,7 +36,7 @@ Default property:
36
36
  property?: BrickBasicProperty & {
37
37
  /* The text content */
38
38
  text?: string | DataLink | number | DataLink | boolean | DataLink | string | DataLink | DataLink
39
- /* Data to be used in the text template (e.g. `Hello ${name}`). Supports nested data, such as `Hello ${user.name}`. */
39
+ /* Data to be used in the text template. Must be an OBJECT whose keys are the template variable names: `Hello ${name}` needs `{ name: ... }` (a linked data must resolve to such an object — linking a scalar leaves the template unresolved). Supports nested data, such as `Hello ${user.name}`. */
40
40
  templateData?: {} | DataLink
41
41
  /* The text template type */
42
42
  templateType?: '${}' | '{{}}' | DataLink
@@ -80,6 +80,14 @@ Default property:
80
80
  letterSpacing?: number | DataLink
81
81
  /* The line height of text content (grid) */
82
82
  lineHeight?: number | DataLink
83
+ /* The text top padding (grid) */
84
+ paddingTop?: number | DataLink
85
+ /* The text left padding (grid) */
86
+ paddingLeft?: number | DataLink
87
+ /* The text right padding (grid) */
88
+ paddingRight?: number | DataLink
89
+ /* The text bottom padding (grid) */
90
+ paddingBottom?: number | DataLink
83
91
  /* The line number limit of text content */
84
92
  lineNumber?: number | DataLink
85
93
  /* The text align */
@@ -177,7 +177,7 @@ Default property:
177
177
  onEmpty?: Array<EventAction>
178
178
  /* Event of the TextInput value change */
179
179
  onChange?: Array<EventAction<string & keyof TemplateEventPropsMap['TextInput']['onChange']>>
180
- /* Event of the TextInput submit */
180
+ /* Event of the TextInput submit. Fires on EVERY submit attempt, even when the value does not match `regex` — to react only to a valid submit, gate on a data updated from the result outlet (e.g. `valueHit`), or handle the invalid case via `onResultNotMatch` */
181
181
  onSubmit?: Array<EventAction<string & keyof TemplateEventPropsMap['TextInput']['onSubmit']>>
182
182
  /* Event of the TextInput match regex (check every value change) */
183
183
  onMatch?: Array<EventAction<string & keyof TemplateEventPropsMap['TextInput']['onMatch']>>