@fugood/bricks-ctor 2.25.0-beta.11 → 2.25.0-beta.13

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.
Files changed (29) hide show
  1. package/compile/__tests__/util.test.js +278 -0
  2. package/compile/index.ts +2 -0
  3. package/package.json +3 -3
  4. package/skills/bricks-design/SKILL.md +172 -45
  5. package/skills/bricks-design/references/architecture-truths.md +125 -0
  6. package/skills/bricks-design/references/avoiding-complexity.md +91 -0
  7. package/skills/bricks-design/references/design-critique.md +195 -0
  8. package/skills/bricks-design/references/design-languages.md +265 -0
  9. package/skills/bricks-design/references/performance.md +116 -0
  10. package/skills/bricks-design/references/presentation-and-slideshow.md +137 -0
  11. package/skills/bricks-design/references/translating-inputs.md +152 -0
  12. package/skills/bricks-design/references/variations-and-tweaks.md +124 -0
  13. package/skills/bricks-design/references/verification-toolchain.md +213 -0
  14. package/skills/bricks-design/references/when-the-brief-is-branded.md +284 -0
  15. package/skills/bricks-design/references/when-the-brief-is-vague.md +85 -0
  16. package/skills/bricks-design/references/workflow.md +134 -0
  17. package/skills/bricks-ux/SKILL.md +120 -0
  18. package/skills/bricks-ux/references/accessibility.md +162 -0
  19. package/skills/bricks-ux/references/flow-states.md +175 -0
  20. package/skills/bricks-ux/references/interaction-archetypes.md +189 -0
  21. package/skills/bricks-ux/references/monitoring-screens.md +153 -0
  22. package/skills/bricks-ux/references/pressable-composition.md +126 -0
  23. package/skills/bricks-ux/references/user-journey.md +168 -0
  24. package/skills/bricks-ux/references/ux-critique.md +256 -0
  25. package/tools/deploy.ts +4 -0
  26. package/tools/pull.ts +42 -2
  27. package/types/automation.ts +1 -0
  28. package/types/data-calc.ts +1 -0
  29. package/skills/bricks-design/LICENSE.txt +0 -180
@@ -0,0 +1,278 @@
1
+ import { generateCalulationMap, validateConfig } from '../util'
2
+
3
+ const baseConfig = (overrides = {}) => ({
4
+ inputs: {},
5
+ enable_async: false,
6
+ disabled_triggers: {},
7
+ output: null,
8
+ outputs: {},
9
+ error: null,
10
+ code: 'return inputs',
11
+ ...overrides,
12
+ })
13
+
14
+ const SANDBOX_PREFIX = 'PROPERTY_BANK_COMMAND_NODE_'
15
+
16
+ const sandboxNodeIds = (map) =>
17
+ Object.entries(map)
18
+ .filter(([id, node]) => id.startsWith(SANDBOX_PREFIX) && node.type === 'command-node-sandbox')
19
+ .map(([id, node]) => ({ id, command: node.properties.command }))
20
+
21
+ const findSandboxIds = (map) => {
22
+ const sandbox = sandboxNodeIds(map)
23
+ return {
24
+ run: sandbox.find((s) => s.command === 'SANDBOX_RUN_JAVASCRIPT')?.id,
25
+ error: sandbox.find((s) => s.command === 'SANDBOX_GET_ERROR')?.id,
26
+ result: sandbox.find((s) => s.command === 'SANDBOX_GET_RETURN_VALUE')?.id,
27
+ }
28
+ }
29
+
30
+ describe('validateConfig', () => {
31
+ test('returns without throwing for a clean config', () => {
32
+ expect(() => validateConfig(baseConfig({ inputs: { a: 'foo' } }))).not.toThrow()
33
+ })
34
+
35
+ test('skips overlap checks in manual trigger mode', () => {
36
+ const config = baseConfig({
37
+ trigger_mode: 'manual',
38
+ inputs: { a: 'foo' },
39
+ output: 'a',
40
+ error: 'a',
41
+ outputs: { x: ['a'] },
42
+ })
43
+ expect(() => validateConfig(config)).not.toThrow()
44
+ })
45
+
46
+ test('throws when error key collides with an input id', () => {
47
+ const config = baseConfig({ inputs: { a: 'foo' }, error: 'a' })
48
+ expect(() => validateConfig(config)).toThrow(/key: error/)
49
+ })
50
+
51
+ test('throws when output key collides with an input id', () => {
52
+ const config = baseConfig({ inputs: { a: 'foo' }, output: 'a' })
53
+ expect(() => validateConfig(config)).toThrow(/key: output/)
54
+ })
55
+
56
+ test('throws when any outputs entry references an input id', () => {
57
+ const config = baseConfig({
58
+ inputs: { a: 'foo', b: 'bar' },
59
+ outputs: { x: ['c', 'b'] },
60
+ })
61
+ expect(() => validateConfig(config)).toThrow(/key: outputs/)
62
+ })
63
+
64
+ test('does not throw when error/output are falsy and inputs are empty', () => {
65
+ expect(() => validateConfig(baseConfig())).not.toThrow()
66
+ })
67
+ })
68
+
69
+ describe('generateCalulationMap', () => {
70
+ test('produces only the three sandbox nodes for an empty config', () => {
71
+ const result = generateCalulationMap(baseConfig())
72
+
73
+ expect(Object.keys(result.map)).toHaveLength(3)
74
+ const { run, error, result: returnValue } = findSandboxIds(result.map)
75
+
76
+ expect(result.map[run].in.inputs).toEqual([])
77
+ expect(result.map[error].out.result).toEqual([])
78
+ expect(result.map[returnValue].out.result).toEqual([])
79
+ expect(Object.keys(result.editor_info)).toHaveLength(3)
80
+ })
81
+
82
+ test('chains multiple inputs through OBJECT_SET commands', () => {
83
+ const result = generateCalulationMap(baseConfig({ inputs: { a: 'foo.bar', b: 'baz' } }))
84
+
85
+ const { run } = findSandboxIds(result.map)
86
+
87
+ // Each input gets a data-node + an OBJECT_SET command-node.
88
+ expect(result.map.a.type).toBe('data-node')
89
+ expect(result.map.b.type).toBe('data-node')
90
+
91
+ const aCommandId = result.map.a.out.value[0].id
92
+ const bCommandId = result.map.b.out.value[0].id
93
+ expect(aCommandId).not.toBe(bCommandId)
94
+
95
+ const aCmd = result.map[aCommandId]
96
+ const bCmd = result.map[bCommandId]
97
+ expect(aCmd.properties.command).toBe('OBJECT_SET')
98
+ expect(aCmd.properties.args.path).toBe('foo.bar')
99
+ expect(bCmd.properties.command).toBe('OBJECT_SET')
100
+ expect(bCmd.properties.args.path).toBe('baz')
101
+
102
+ // First command has no upstream obj; second command's obj input is the first command.
103
+ expect(aCmd.in.obj).toBeNull()
104
+ expect(bCmd.in.obj).toEqual([{ id: aCommandId, port: 'result' }])
105
+ // First command forwards its result to the second command's `obj` input.
106
+ expect(aCmd.out.result).toEqual([{ id: bCommandId, port: 'obj' }])
107
+ // The last command feeds the SANDBOX_RUN_JAVASCRIPT `inputs` port.
108
+ expect(bCmd.out.result).toEqual([{ id: run, port: 'inputs' }])
109
+ expect(result.map[run].in.inputs).toEqual([{ id: bCommandId, port: 'result' }])
110
+ })
111
+
112
+ test('builds OBJECT_GET commands and target data-nodes for outputs', () => {
113
+ const result = generateCalulationMap(baseConfig({ outputs: { resultPath: ['pb1', 'pb2'] } }))
114
+
115
+ const { result: returnValue } = findSandboxIds(result.map)
116
+
117
+ // Both target property-bank nodes are created as data-nodes.
118
+ expect(result.map.pb1.type).toBe('data-node')
119
+ expect(result.map.pb2.type).toBe('data-node')
120
+
121
+ // The SANDBOX_GET_RETURN_VALUE forwards to the OBJECT_GET command for the output entry.
122
+ const objectGetRefs = result.map[returnValue].out.result
123
+ expect(objectGetRefs).toHaveLength(1)
124
+ const getCommandId = objectGetRefs[0].id
125
+ expect(objectGetRefs[0].port).toBe('obj')
126
+
127
+ const getCmd = result.map[getCommandId]
128
+ expect(getCmd.type).toBe('command-node-object')
129
+ expect(getCmd.properties.command).toBe('OBJECT_GET')
130
+ expect(getCmd.properties.args.path).toBe('resultPath')
131
+ expect(getCmd.in.obj).toEqual([{ id: returnValue, port: 'result' }])
132
+
133
+ // OBJECT_GET feeds both target data-nodes' `change` ports.
134
+ expect(getCmd.out.result).toEqual([
135
+ { id: 'pb1', port: 'change' },
136
+ { id: 'pb2', port: 'change' },
137
+ ])
138
+ // Target data-nodes consume the OBJECT_GET result via their `change` port.
139
+ expect(result.map.pb1.in.change).toEqual([{ id: getCommandId, port: 'result' }])
140
+ expect(result.map.pb2.in.change).toEqual([{ id: getCommandId, port: 'result' }])
141
+
142
+ // Without input usage their `out.value` defaults to null.
143
+ expect(result.map.pb1.out.value).toBeNull()
144
+ expect(result.map.pb2.out.value).toBeNull()
145
+ })
146
+
147
+ // Manual mode is the only mode that lets an output target reuse an input id
148
+ // (see validateConfig tests). When that happens, generateCalulationMap must
149
+ // keep the input-side `out.value` so the data-node remains a usable input.
150
+ test.each([
151
+ ['outputs', { outputs: { result: ['shared'] } }],
152
+ ['output', { output: 'shared' }],
153
+ ['error', { error: 'shared' }],
154
+ ])('preserves input out.value when %s target reuses an input id', (_, overrides) => {
155
+ const result = generateCalulationMap(
156
+ baseConfig({ trigger_mode: 'manual', inputs: { shared: 'foo' }, ...overrides }),
157
+ )
158
+ expect(Array.isArray(result.map.shared.out.value)).toBe(true)
159
+ expect(result.map[result.map.shared.out.value[0].id].properties.command).toBe('OBJECT_SET')
160
+ })
161
+
162
+ test('also rewires in.change to OBJECT_GET when an outputs target reuses an input id', () => {
163
+ const result = generateCalulationMap(
164
+ baseConfig({
165
+ trigger_mode: 'manual',
166
+ inputs: { shared: 'foo' },
167
+ outputs: { result: ['shared'] },
168
+ }),
169
+ )
170
+ expect(result.map.shared.in.change).toHaveLength(1)
171
+ expect(result.map[result.map.shared.in.change[0].id].properties.command).toBe('OBJECT_GET')
172
+ })
173
+
174
+ test('preserves out.value when the same pb appears in multiple outputs entries', () => {
175
+ // Two outputs entries both target `pb1`. The reduce visits each entry in turn
176
+ // and must preserve the accumulated `out.value` from the first iteration via
177
+ // `acc.map[pb]` rather than wiping it on the second.
178
+ const result = generateCalulationMap(
179
+ baseConfig({ outputs: { first: ['pb1'], second: ['pb1'] } }),
180
+ )
181
+ expect(result.map.pb1.type).toBe('data-node')
182
+ // Without an input, out.value remains null after both passes.
183
+ expect(result.map.pb1.out.value).toBeNull()
184
+ // The latest OBJECT_GET wins as the change source — each iteration overwrites
185
+ // `in.change`, so we end up pointing at the second outputs entry's command.
186
+ expect(result.map.pb1.in.change).toHaveLength(1)
187
+ })
188
+
189
+ test('wires the error data-node when error is configured', () => {
190
+ const result = generateCalulationMap(baseConfig({ error: 'errNode' }))
191
+
192
+ const { error } = findSandboxIds(result.map)
193
+ // SANDBOX_GET_ERROR now broadcasts to the error data-node's `change` port.
194
+ expect(result.map[error].out.result).toEqual([{ id: 'errNode', port: 'change' }])
195
+ expect(result.map.errNode.type).toBe('data-node')
196
+ expect(result.map.errNode.in.change).toEqual([{ id: error, port: 'result' }])
197
+ // No upstream input → out.value falls back to null.
198
+ expect(result.map.errNode.out.value).toBeNull()
199
+ // editor_info contains the new node.
200
+ expect(result.editor_info.errNode).toBeDefined()
201
+ })
202
+
203
+ test('wires the output data-node when output is configured', () => {
204
+ const result = generateCalulationMap(baseConfig({ output: 'outNode' }))
205
+
206
+ const { result: returnValue } = findSandboxIds(result.map)
207
+ expect(result.map[returnValue].out.result).toEqual([{ id: 'outNode', port: 'change' }])
208
+ expect(result.map.outNode.type).toBe('data-node')
209
+ expect(result.map.outNode.in.change).toEqual([{ id: returnValue, port: 'result' }])
210
+ expect(result.editor_info.outNode).toBeDefined()
211
+ })
212
+
213
+ test('manual trigger mode sets disable_trigger_command on input value ports', () => {
214
+ const result = generateCalulationMap(
215
+ baseConfig({
216
+ trigger_mode: 'manual',
217
+ inputs: { a: 'foo', b: 'bar' },
218
+ }),
219
+ )
220
+ const aCmdId = result.map.a.out.value[0].id
221
+ const bCmdId = result.map.b.out.value[0].id
222
+ expect(result.map[aCmdId].in.value[0].disable_trigger_command).toBe(true)
223
+ expect(result.map[bCmdId].in.value[0].disable_trigger_command).toBe(true)
224
+ })
225
+
226
+ test('auto trigger mode honours per-key disabled_triggers', () => {
227
+ const result = generateCalulationMap(
228
+ baseConfig({
229
+ inputs: { a: 'foo', b: 'bar' },
230
+ disabled_triggers: { a: true, b: false },
231
+ }),
232
+ )
233
+ const aCmdId = result.map.a.out.value[0].id
234
+ const bCmdId = result.map.b.out.value[0].id
235
+ expect(result.map[aCmdId].in.value[0].disable_trigger_command).toBe(true)
236
+ // Falsy disabled_triggers entry → property is not set (or set to undefined).
237
+ expect(result.map[bCmdId].in.value[0].disable_trigger_command).toBeUndefined()
238
+ })
239
+
240
+ test('auto trigger mode without disabled_triggers leaves disable_trigger_command undefined', () => {
241
+ const result = generateCalulationMap(baseConfig({ inputs: { a: 'foo' } }))
242
+ const aCmdId = result.map.a.out.value[0].id
243
+ expect(result.map[aCmdId].in.value[0].disable_trigger_command).toBeUndefined()
244
+ })
245
+
246
+ test('snapshotMode forwards to makeId so generated ids are sequential', () => {
247
+ const result = generateCalulationMap(baseConfig({ inputs: { a: 'foo' } }), {
248
+ snapshotMode: true,
249
+ })
250
+ const sandboxIds = sandboxNodeIds(result.map).map((s) => s.id)
251
+ // Snapshot-mode ids embed a 12-digit counter — stable suffix lets us assert order.
252
+ sandboxIds.forEach((id) => {
253
+ expect(id).toMatch(/^PROPERTY_BANK_COMMAND_NODE_00000000-0000-0000-0000-\d{12}$/)
254
+ })
255
+ })
256
+
257
+ test('validateConfig errors propagate out of generateCalulationMap', () => {
258
+ expect(() => generateCalulationMap(baseConfig({ inputs: { a: 'foo' }, error: 'a' }))).toThrow(
259
+ /key: error/,
260
+ )
261
+ })
262
+
263
+ test('SANDBOX_GET_RETURN_VALUE broadcasts to both output target and outputs commands', () => {
264
+ const result = generateCalulationMap(
265
+ baseConfig({
266
+ output: 'outNode',
267
+ outputs: { foo: ['pb1'] },
268
+ }),
269
+ )
270
+ const { result: returnValue } = findSandboxIds(result.map)
271
+ const refs = result.map[returnValue].out.result
272
+ // First entry is the output data-node's `change` port; remainder are OBJECT_GET ids.
273
+ expect(refs[0]).toEqual({ id: 'outNode', port: 'change' })
274
+ expect(refs).toHaveLength(2)
275
+ expect(refs[1].port).toBe('obj')
276
+ expect(result.map[refs[1].id].properties.command).toBe('OBJECT_GET')
277
+ })
278
+ })
package/compile/index.ts CHANGED
@@ -641,6 +641,7 @@ const compileAutomationTest = (
641
641
 
642
642
  return {
643
643
  id: testId,
644
+ alias: test.alias,
644
645
  title: test.title,
645
646
  hide_short_ref: test.hideShortRef,
646
647
  timeout: test.timeout,
@@ -1209,6 +1210,7 @@ export const compile = async (app: Application) => {
1209
1210
  )
1210
1211
 
1211
1212
  const calc: any = {
1213
+ alias: dataCalc.alias,
1212
1214
  title: dataCalc.title,
1213
1215
  description: dataCalc.description,
1214
1216
  hide_short_ref: dataCalc.hideShortRef,
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@fugood/bricks-ctor",
3
- "version": "2.25.0-beta.11",
3
+ "version": "2.25.0-beta.13",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "typecheck": "tsc --noEmit",
7
7
  "build": "bun scripts/build.js"
8
8
  },
9
9
  "dependencies": {
10
- "@fugood/bricks-cli": "^2.25.0-beta.11",
10
+ "@fugood/bricks-cli": "^2.25.0-beta.12",
11
11
  "@huggingface/gguf": "^0.3.2",
12
12
  "@iarna/toml": "^3.0.0",
13
13
  "@modelcontextprotocol/sdk": "^1.15.0",
@@ -25,5 +25,5 @@
25
25
  "peerDependencies": {
26
26
  "oxfmt": "^0.36.0"
27
27
  },
28
- "gitHead": "701de04bd2b569a5fe446a1c89ac776bb79f89f7"
28
+ "gitHead": "c3b77c39d10f0149b943e6ab92b02cdddd6a628b"
29
29
  }
@@ -1,66 +1,193 @@
1
1
  ---
2
2
  name: bricks-design
3
- description: Create distinctive, production-grade BRICKS application interfaces with high design quality. Use this skill when the user asks to build BRICKS canvases, screens, layouts, or applications. Generates creative, polished BRICKS code that avoids generic aesthetics.
4
- license: Complete terms in LICENSE.txt (Apache-2.0, based on github.com/anthropics/skills)
3
+ description: >-
4
+ Visual design discipline for Applications and Subspaces type,
5
+ palette, asset acquisition, design language, system commitment,
6
+ visual rhythm, brand. TRIGGER for visual / aesthetic / system /
7
+ style / brand-asset work even when the user names the surface in
8
+ product terms — slideshow / pitch deck / introduction / explainer
9
+ / storyboard; kiosk / signage / menu board / lobby / reception /
10
+ wayfinding / retail / hospitality / museum / transit; translate /
11
+ port / rebuild from Figma / HTML / screenshot / website / PDF /
12
+ brand book; vague creative brief ("design something for the
13
+ lobby"); branded scene work; iteration on existing Subspace
14
+ (rework, redesign, audit visual system, tighten the type / palette
15
+ / motion / rhythm). For end-to-end briefs (kiosk, dashboard,
16
+ interactive screen) this skill invokes in parallel with bricks-ux,
17
+ which carries the interaction / flow / usability layer. SKIP for
18
+ pure usability / flow / journey / affordance / feedback / recovery
19
+ / accessibility / multilingual audits — those go to bricks-ux. SKIP
20
+ for single-Brick or Generator template work
21
+ (create-brick-or-generator), debugging or refactoring with no
22
+ design intent, or non-display deliverables (CLI, server, tooling).
23
+ Encodes architecture truths, performance and complexity guardrails,
24
+ input-translation rules, visual languages library, Direction
25
+ Advisor for vague briefs, Media Flow protocol for branded work,
26
+ verification toolchain (Electron preview MCP, on-device CDP,
27
+ Automations).
5
28
  ---
6
29
 
7
- This skill guides creation of distinctive, production-grade BRICKS application interfaces that avoid generic aesthetics. Implement working code with exceptional attention to visual design and creative choices.
30
+ # BRICKS Design
8
31
 
9
- The user provides interface requirements: a screen, layout, application, or component to build. They may include context about the purpose, audience, platform, or technical constraints.
32
+ You are a BRICKS **visual designer**. Your output is the visual surface of a runnable Subspace — the type, palette, asset, motion vocabulary, rhythm, and system commitment that makes the work read as one designed thing. Interaction shape (flows, journeys, affordance, feedback, accessibility) is the companion `bricks-ux` skill's domain; the two run in parallel on most briefs.
10
33
 
11
- ## Design Thinking
34
+ Every visual decision is downstream of the deployment — hardware, scene, network, language, brand, peripherals, watchdog. Web habits (scroll, hover, modals-as-overlays-by-default, semantic links) do not transfer; surface them as tells when input arrives in those shapes.
12
35
 
13
- Before coding, understand the context and commit to a **bold** aesthetic direction:
14
- - **Purpose**: What problem does this interface solve? Who uses it? What platform(s)?
15
- - **Tone**: Pick a strong direction: brutally minimal, maximalist, retro-futuristic, organic/natural, luxury/refined, playful, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. Use these for inspiration but design one true to the aesthetic.
16
- - **Constraints**: Target platform (mobile, TV, desktop, kiosk), screen dimensions, accessibility needs.
17
- - **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
36
+ The user-facing primitive is **Data** (legacy alias: Property Bank — kept in some internal action names like `PROPERTY_BANK`). Surface "Data" in your prose. Other primitives keep their names: Application, Subspace, Canvas, Brick, Generator, DataCalculation, Switch, Animation, Standby Transition, Media Flow, Automation.
18
37
 
19
- **CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work the key is intentionality, not intensity.
38
+ ## Priority #0Verify deployment context
20
39
 
21
- Then implement working BRICKS TypeScript code that is:
22
- - Production-grade and functional
23
- - Visually striking and memorable
24
- - Cohesive with a clear aesthetic point-of-view
25
- - Meticulously refined in every detail
40
+ Before any design exploration, confirm: **hardware** (size, resolution, orientation, touch, viewing distance), **scene** (where the screen lives, what the user does), **network** (always-on / intermittent / offline), **language(s)**, **brand**, **peripherals** (camera, BLE, MQTT, NFC, payment, printer, sensors), **watchdog / fleet management**. If any of the first five is missing, stop and ask in a single batch — improvising on hardware or scene is the most expensive mistake in BRICKS work.
26
41
 
27
- ## Aesthetics Guidelines
42
+ ## Priority #0.5 — Visually inspect every reference, in full
28
43
 
29
- ### Typography
30
- Choose fonts that are beautiful, unique, and interesting. Avoid defaulting to system fonts — opt for distinctive choices that elevate the interface. Pair a characterful display font with a refined body font. Create clear typographic hierarchy through weight, size, spacing, and alignment. Use auto-scaling (`fontSizeVector`) when text should fill its container proportionally.
44
+ If the user supplies any reference material — a website URL, a docs site, a Figma link, an HTML project, a screenshot, an image, a PDF, a brand book, a video walkthrough, a competitor's product — you must **visually inspect every page, frame, and state of it**, not skim a text summary or rely on a markdown extraction. Translating from material you have not actually seen is the single fastest path to designs that miss obvious cues (layout rhythm, photography style, motion language, brand temperature) that no text description preserves.
31
45
 
32
- ### Color & Theme
33
- Commit to a cohesive palette. Dominant colors with sharp accents outperform timid, evenly-distributed palettes. Use gradients for rich, atmospheric surfaces — multi-stop linear gradients create far more depth than flat fills. Use Data nodes as a shared color store for consistency across bricks.
46
+ Hard rule: a markdown extraction (e.g., `WebFetch`, an `llms.txt`, a `README.md`) is **not** visual inspection. It captures words and loses everything that makes the reference design-relevant. Use it only as a navigation aid — a list of pages to then visit visually.
34
47
 
35
- ### Motion & Animation
36
- Focus on high-impact moments: one well-orchestrated canvas enter with staggered standby reveals creates more delight than scattered micro-interactions. Use spring animations for natural, bouncy UI elements. Use composed animations (parallel/sequence) for coordinated entrance choreography. Reserve looping animations (`breatheStart`) for attention-drawing elements — overuse dulls their impact.
48
+ How to inspect, by source type:
37
49
 
38
- ### Spatial Composition
39
- Absolute positioning gives total control — use it creatively. Overlap bricks. Create asymmetric layouts. Use generous negative space OR controlled density. Break grid expectations. Consider rotation for diagonal flow and perspective. Vary scale dramatically between elements for visual tension.
50
+ - **Website / docs site URL** — drive a browser automation tool (browser-MCP, Playwright/Puppeteer-style MCP server, `agent-browser`-equivalent skill, or any host-provided browser tool). Visit the home page, every primary navigation entry, every page the user explicitly named, and every page that looks like it carries the brand's visual signature (hero, product, gallery, customers). Capture a full-page screenshot of each. Then read each screenshot back via the host's image-reading capability so you actually *see* it. If no browser automation is available, ask the user for screenshots before proceeding.
51
+ - **Figma / design-tool link** — use a Figma-MCP / design-tool MCP if available to enumerate every frame and image-export each; otherwise ask the user for PNG exports of every frame. Inspect each image.
52
+ - **HTML project on disk** — serve and screenshot every route via a browser tool, the same way as a public URL. Don't infer visuals from the source HTML/CSS.
53
+ - **PDF / brand book / slide deck** — read every page via the host's PDF-reading capability (page-by-page if the document is long). Do not summarize from a text extraction.
54
+ - **Local images / screenshots** — read each one via the image-reading tool.
55
+ - **Video walkthrough** — ask the user to provide key-frame screenshots, or to describe each state explicitly. Do not claim to "watch" a video you cannot actually frame-step.
40
56
 
41
- ### Depth & Atmosphere
42
- Create atmosphere through layered elements rather than flat solid colors:
43
- - **Gradients** with multiple color stops for rich backgrounds
44
- - **Shadows** for elevation and hierarchy
45
- - **Blur effects** (blur, progressive blur, liquid glass) for glass morphism on native platforms
46
- - **Opacity layering** — stack semi-transparent rects for texture and depth
47
- - **Border details** — per-side colors, styles, and widths for decorative framing
57
+ Coverage check before continuing: list — out loud, in your reply — every reference artifact and the count of pages / frames / images you actually saw. If anything is unseen, name the gap and ask. Translating from incomplete reference inspection is grounds for rework.
48
58
 
49
- ### Interactive Polish
50
- Design interactions that feel tactile and responsive:
51
- - Scale/opacity animations on press for physical feedback
52
- - Focus states for TV/controller navigation
53
- - Outlet-driven switches for state-dependent visual changes
54
- - Deliberate long-press patterns for secondary actions
59
+ ## Workflow spine
55
60
 
56
- ## What to NEVER Do
61
+ Pass-based delivery, not sprint-to-finished. Full discipline in [`references/workflow.md`](references/workflow.md) (ask-vs-build heuristic, batched question playbook by axis, five passes with checkpoints).
57
62
 
58
- - **No generic aesthetics**: Avoid the same tired palette, the same safe layout, the same system font on every screen. Each design should feel distinct and intentional.
59
- - **No flat sameness**: Don't make every canvas look like the same template with different text. Vary spatial composition, color weight, animation timing, and typographic scale.
60
- - **No placeholder layouts**: Don't just center everything in a grid. Use the absolute positioning system to create spatial interest — overlap, offset, scale contrast.
63
+ 1. **Verify deployment context** (Priority #0) and branch on input shape:
64
+ - Vague brief [`references/when-the-brief-is-vague.md`](references/when-the-brief-is-vague.md) (Direction Advisor interaction archetype × visual language × Canvas-graph shape for sequenced work).
65
+ - Branded brief [`references/when-the-brief-is-branded.md`](references/when-the-brief-is-branded.md) (Media Flow protocol).
66
+ - Figma / HTML / screenshot input → [`references/translating-inputs.md`](references/translating-inputs.md).
67
+ - Presentation / slideshow / intro / explainer / storyboard → [`references/presentation-and-slideshow.md`](references/presentation-and-slideshow.md) (Canvas-graph shape decision, hero continuity).
68
+ 2. **Pass 0** — Declare the system as a comment block at the top of the Subspace file: type scale, palette, **spacing scale in grid units**, motion vocabulary, grid stance (lean / break / breathe), hero Brick ids. The grid substrate is given by the runtime (Truth #6); the design decisions sit on top.
69
+ 3. **Pass 1 — Showcase Canvas lockdown.** Build one Canvas fully lit, verify, show the user. This is the cheapest moment to redirect; do not build the full Canvas graph before sign-off.
70
+ 4. **Pass 2** — Build out the full Canvas graph with hero ids shared across Canvases (Truth #3 as narrative principle). Mid-review checkpoint partway through.
71
+ 5. **Pass 3** — Polish: spacing-scale adherence, density rhythm, Standby Transition vocabulary consistent, multilingual fits.
72
+ 6. **Variations**, if exploring options — three patterns ordered by token cost, default Pattern 1. See [`references/variations-and-tweaks.md`](references/variations-and-tweaks.md). Comparison surface is chat + source tree, not the Canvas.
73
+ 7. **Pass 4** — Verification gate (below) + self-critique (5 dimensions + first-viewer rubric for sequenced work). Never declare done off a single screenshot.
61
74
 
62
- Vary between light and dark themes, different fonts, different aesthetics across generations. NEVER converge on common choices across designs.
75
+ ## The 10 architecture truths
63
76
 
64
- **IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate animations, layered rects, and rich gradients. Minimalist designs need restraint, precision in spacing, and carefully chosen typography. Elegance comes from executing the vision well.
77
+ The load-bearing laws. Each is unpacked in [`references/architecture-truths.md`](references/architecture-truths.md).
65
78
 
66
- Remember: The agent is capable of extraordinary creative work. Don't hold back show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
79
+ 1. **Canvas is a state, not a screen.** A Subspace is a state machine; Canvases are states; Brick events / Data changes are transitions. Treat Canvases as web pages and you'll fight the runtime.
80
+ 2. **Data is the conduit for *dynamic* values.** Anything that varies at runtime (content, i18n, Generator inputs/outputs, Subspace boundaries, event payloads) flows through Data. Hardcoded values in genuinely-static, single-use Bricks are fine — convention is loose, not enforced. The rule kicks in the moment the value can change.
81
+ 3. **Shared Brick ids across Canvases auto-tween.** Use the same Brick on Canvas A and Canvas B with different frames — the runtime animates position/size for free. This is the highest-leverage technique for a polished feel; rewriting per Canvas throws it away.
82
+ 4. **Switches compare; Data Hit/Not-Hit only matches.** Canvas / Brick / Generator Switches support `==` `!=` `>` `<` `>=` `<=` against Data values (`SwitchCondData`). Data events `valueHit` / `valueNotHit` only support equal-match (`hit_equal`) or regex-match (`hit_regex`). Threshold-driven UI lives on Switches, not on Data event subscriptions. Don't confuse them.
83
+ 5. **Generators are headless, async, event-driven.** Wire them via events; never as synchronous calls. Every chain needs a termination condition. Generators that hit hardware/network must not block the canvas thread.
84
+ 6. **Frames are grid units.** Off-grid placement is legal but only ever intentional (overflow effects, anchor-at-origin tricks). It is never a nudge to escape the grid. Bricks fully outside the grid are auto-culled.
85
+ 7. **Standby Transition is part of the design language.** Every visible Brick gets an entrance offset (`standbyMode` + `standbyOpacity` + `standbyDelay`); the runtime's auto-tween handles in-flight motion. Snap-cuts are reserved for emphasis (alarm states), never for routine navigation.
86
+ 8. **Subspace is a typed module.** Inputs are call-by-value-on-host-change; outlets emit update + value-change events on the host. Extract a Subspace only when the same flow appears 2+ times or when the boundary scopes Data meaningfully — never as a "tidy up" tactic.
87
+ 9. **DataCalculation is for derivation only.** Pure inputs → outputs (DataCalculationScript or DataCalculationMap). If your transformation has side effects, navigation, or async I/O, it belongs in an Event Action chain or a Generator. DataCalc orchestrating DataCalc is the wrong primitive.
88
+ 10. **No scroll, no overflow, no responsive reflow.** Frames are fixed; what doesn't fit doesn't show. Design within the Canvas; don't import web habits.
89
+
90
+ ## Commit to a design language
91
+
92
+ A BRICKS Application that doesn't commit to a design language reads as generic regardless of how well it runs. After Direction Advisor (or directly, when the brief is concrete enough), pick a visual language from [`references/design-languages.md`](references/design-languages.md) — Swiss Editorial / Kenya Hara emptiness / Field.io motion poetics / Brutalist web / Y2K futurist-retro / etc. — and write its system declaration as a comment block at the top of the Subspace file. Every subsequent choice cites the block; adding a value not in the block requires updating the block first. That's what makes the system structural rather than aspirational.
93
+
94
+ The commitment principle: when unsure, do *more* of what defines the chosen language, not less. A style executed at 30% reads as hesitant; at 80% it reads as deliberate. Soften signature moves and you've abandoned the language for nowhere.
95
+
96
+ The picked language is orthogonal to the picked **interaction archetype** (glance / browse / interact / transact / monitor / dwell — see [`references/when-the-brief-is-vague.md`](references/when-the-brief-is-vague.md)). Together they define the work. Pick both deliberately; combine awkward pairings (transact + Sagmeister, monitor + Magazine editorial) only as a deliberate brand statement, not by accident.
97
+
98
+ ## Pressable composition
99
+
100
+ Composite-button wiring (where `on_press` sits, which Bricks bypass) is an interaction concern — see the companion `bricks-ux` skill's `pressable-composition.md`. The visual-design responsibility here is making pressable affordance *visually distinct*: a tile that's pressable should not look identical to a tile that's decorative. Affordance reads through the visual language; the wiring lands the press.
101
+
102
+ ## Performance & complexity guardrails
103
+
104
+ Two reference files cover the second-order rules. Read them when the design is non-trivial.
105
+
106
+ - [`references/performance.md`](references/performance.md) — throttle at the Generator boundary, bound Data history explicitly, `persistData: true` is for last-known-good and idempotency keys (not transient flow state), boot Canvas must render in < 1 s using only cached/persisted Data, `renderOutOfViewport: false` for legitimate off-grid Bricks, offline-first cache + queue + status-Data on every networked Generator. **Media bound through Media Flow is preloaded to the device and is offline-safe by default — image / video / Lottie / Rive / brand reel are not "offline risk" categories. The offline wrap is for Generators fetching dynamic runtime data, not for design-time media.**
107
+ - [`references/avoiding-complexity.md`](references/avoiding-complexity.md) — Subspace abuse (single-instance Subspaces are usually directories), Switch fanout (4+ on one node = state machine in disguise; promote to Canvases), DataCalc chains (orchestration in the wrong primitive), animation overuse (one orchestrated entrance > scattered micro-anims; `loop` only for attention draws), Canvas inflation (each Canvas is a state the user can be stuck in).
108
+
109
+ ## Asset discipline
110
+
111
+ Brand work succeeds or fails on assets, not on colors. Logo, product photography, UI screenshots, scene photography, and motion assets are first-class — colors and fonts are auxiliary. Acquire them through the protocol in [`references/when-the-brief-is-branded.md`](references/when-the-brief-is-branded.md): five steps, the 5-10-2-8 quality bar with five named scoring dimensions, three fallback paths per asset category, and structural enforcement that Bricks reference Media Flow Data via DataLink rather than embed, redraw, or skip.
112
+
113
+ When an asset category genuinely cannot be acquired and the user has no plan to provide one, the priority is: stop and ask (always for logo) → compose the host environment's image / motion generators (canvas-design / imagen / generative MCP), brand-reference-anchored, scored at the same bar → labeled placeholder with the gap tracked in `brand-spec.md`. **This skill does not duplicate generative or composition skills — it composes them.** Where the host has none, surface the constraint to the user; don't silently degrade.
114
+
115
+ ## Anti-slop, terse
116
+
117
+ Snap canvas transitions on routine navigation. Hardcoded *dynamic* strings (content, i18n) bypassing Data. Hover affordances on no-touch hardware. Sketch-drawn imitations of real brand assets. Aggregator-sourced logos shipped as final. Generated brand imagery without a real brand-reference anchor. Subspaces extracted for "neatness". Switch fanout standing in for state. DataCalc chains standing in for orchestration. Animation everywhere. Stock-photo grounds behind real product photography. CSS-style scroll containers.
118
+
119
+ ## Variations
120
+
121
+ When exploring options for the user to choose from, default 3, differentiated on a real axis (visual language / interaction archetype / Canvas-graph shape / motion language / content rhythm). Three colour-swap variants is not three variants.
122
+
123
+ **The comparison surface is chat + source tree, never the Canvas.** No in-Canvas palette pickers, no "choose your theme" toggles, no demo-mode switches left in production. Default to Pattern 1 (Data-preset variations — one Canvas tree, flat preset map, single-line preset switch, screenshot grid in chat). Escalate to shared module or separate Subspaces only when the variation can't be expressed by the cheaper pattern. Full protocol with token-saving discipline and knob filter in [`references/variations-and-tweaks.md`](references/variations-and-tweaks.md).
124
+
125
+ Ship a one-paragraph trade-off note alongside so the user can pick or blend with full context.
126
+
127
+ ## Verification gate
128
+
129
+ **Definition of done — non-negotiable.** Before declaring a design complete, every one of the following must be true:
130
+
131
+ 1. The latest source compiles cleanly (`compile` MCP).
132
+ 2. You have produced a rendered screenshot of **every Canvas** in the deliverable via the `preview` MCP with `responseImage: true`, captured at the target hardware resolution and orientation. Cover every reachable state — Canvases gated behind events get reached by running an Automation (`testId` / `testTitleLike`).
133
+ 3. You have **viewed** each of those screenshots back through the host's image-reading capability — not just saved them. The agent that designed the Canvas must also have seen the rendered result.
134
+ 4. If the user supplied any reference material (Figma / website / HTML / screenshot / PDF / brand book), you have done a side-by-side visual comparison between each Canvas screenshot and the corresponding reference, and have written a short delta report listing:
135
+ - What matches.
136
+ - What intentionally diverges, and why (deployment constraint, system commitment, BRICKS-runtime limitation).
137
+ - What unintentionally diverges, and how you will fix it.
138
+ 5. The verification path appropriate to the deployment has executed: Path 1 (Electron preview MCP) by default; Path 2 (on-device DevTools) when the deployment depends on real hardware behaviour, or whenever the brief touches payment, identity capture, peripherals, or LocalSync.
139
+ 6. The browser / runtime console is clean — no 404s, no Data-key-undefined warnings, no Generator init failures.
140
+
141
+ A single hero-Canvas screenshot is **not** done. A "looks roughly like the reference" handwave is **not** done. A claim of done without screenshots in evidence is **not** done. If you have not produced and reviewed a screenshot of every Canvas, you are still mid-iteration and must say so explicitly to the user.
142
+
143
+ **Default loop — Path 1 (Electron preview, no device):**
144
+
145
+ 1. `bricks-ctor` MCP `compile` — typecheck + compile gate.
146
+ 2. `bricks-ctor` MCP `preview` with `responseImage: true` — screenshot + visual sanity. Add `testId` / `testTitleLike` to run a named Automation in the project (`brick_press`, `wait_until_canvas_change`, `assert_property`, `wait_property_update`, `match_screenshot`, ...).
147
+ 3. Repeat step 2 for every Canvas. Single-Canvas Subspaces still require a captured + reviewed screenshot.
148
+ 4. For sustained dev, `bun preview` exposes CDP at `localhost:19852`; drive it with `bricks devtools …` (screenshot, brick tree/query, input tap/type/key, storage data-bank, runtime eval, network list).
149
+ 5. **Self-critique pass before declaring done** — every Canvas scored on 5 dimensions (system commitment / visual hierarchy / craft / functional fit / originality), anti-slop top-10 swept clean, < 8 scores either fixed or surfaced as accepted trade-offs. See [`references/design-critique.md`](references/design-critique.md). Verification proves it runs; critique proves it's good — both required.
150
+
151
+ **Escalate to Path 2 (device-bound DevTools)** before declaring done if the deployment depends on hardware behaviour the Electron preview cannot reproduce: physical orientation/DPI, real touch hardware, peripherals (camera/BLE/MQTT/NFC/payment/printer/sensors), watchdog cycles on the actual launcher build, LocalSync across multiple devices. **Always** Path 2 when the brief touches payment, identity capture, or peripherals.
152
+
153
+ Path 2 setup is **manual** and the agent cannot do it: ask the user to open the device's **Settings → advanced → Chrome DevTools** toggle (requires BRICKS Foundation ≥ 2.24). The device starts CDP on `:19851`. Then `bricks devtools scan` / `open` / `screenshot` / `brick …` / `input …` / `storage …` / `runtime eval` work against the device address. The device's MCP endpoint can also be bridged into Claude Code with `npx mcporter --url http://<ip>:19851/mcp --header "Authorization: Bearer <passcode>"`.
154
+
155
+ Path 3 (Remote Debugging via BRICKS Controller, off-LAN) exists for ops scenarios — out of scope for the design loop.
156
+
157
+ Full toolchain table, decision rule, and concrete invocations: [`references/verification-toolchain.md`](references/verification-toolchain.md).
158
+
159
+ ## Boundaries
160
+
161
+ - Do not recreate copyrighted UIs. Build an original design that respects the IP.
162
+ - Do not invent brand assets. Use a labeled placeholder Brick + tracked gap list.
163
+ - Do not bypass Data for dynamic values.
164
+ - Do not carry web-frame habits across (scroll, hover, semantic links, modals-by-default, responsive reflow).
165
+ - Treat real-device runs as side-effecting — peripherals fire for real, payment terminals charge for real, MQTT/BLE may broadcast on shared topics. Use a staging device for verification cycles.
166
+
167
+ ## Companion skill: `bricks-ux`
168
+
169
+ Interaction / flow / journey / affordance / feedback / recovery / accessibility / multilingual concerns live in `bricks-ux`. For end-to-end briefs ("design a kiosk for X", "build a presentation introducing Y") both skills invoke in parallel — `bricks-design` carries the visual layer, `bricks-ux` carries the interaction layer. Cross-references in this skill point to `bricks-ux/references/...` where the interaction discipline matters.
170
+
171
+ ## Reference index
172
+
173
+ | When you need to... | Read |
174
+ |---|---|
175
+ | Decide when to ask vs build; pace the work across passes | [`references/workflow.md`](references/workflow.md) |
176
+ | Deepen any of the 10 truths | [`references/architecture-truths.md`](references/architecture-truths.md) |
177
+ | Tune for performance / offline | [`references/performance.md`](references/performance.md) |
178
+ | Resist over-engineering | [`references/avoiding-complexity.md`](references/avoiding-complexity.md) |
179
+ | Translate a Figma / HTML / screenshot | [`references/translating-inputs.md`](references/translating-inputs.md) |
180
+ | Pick and commit to a design language | [`references/design-languages.md`](references/design-languages.md) |
181
+ | Design a presentation / pitch deck / intro / explainer / slideshow (visual rhythm + hero continuity) | [`references/presentation-and-slideshow.md`](references/presentation-and-slideshow.md) |
182
+ | Offer variations / pick what becomes a Data knob | [`references/variations-and-tweaks.md`](references/variations-and-tweaks.md) |
183
+ | Self-critique on the visual dimensions | [`references/design-critique.md`](references/design-critique.md) |
184
+ | Verify a design before shipping | [`references/verification-toolchain.md`](references/verification-toolchain.md) |
185
+ | Propose visual directions for a vague brief | [`references/when-the-brief-is-vague.md`](references/when-the-brief-is-vague.md) |
186
+ | Acquire and bind brand assets | [`references/when-the-brief-is-branded.md`](references/when-the-brief-is-branded.md) |
187
+ | Compose a button so taps land where intended | `bricks-ux/references/pressable-composition.md` (companion skill) |
188
+ | Walk the universal interaction journey | `bricks-ux/references/user-journey.md` (companion skill) |
189
+ | Apply interaction-archetype rule sets | `bricks-ux/references/interaction-archetypes.md` (companion skill) |
190
+ | Design idle / loading / empty / error / boot / maintenance states | `bricks-ux/references/flow-states.md` (companion skill) |
191
+ | Design monitoring / dashboard UX | `bricks-ux/references/monitoring-screens.md` (companion skill) |
192
+ | Accessibility floors at deployment-relative thresholds | `bricks-ux/references/accessibility.md` (companion skill) |
193
+ | Tiered UX critique | `bricks-ux/references/ux-critique.md` (companion skill) |