@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.
- package/compile/__tests__/util.test.js +278 -0
- package/compile/index.ts +2 -0
- package/package.json +3 -3
- package/skills/bricks-design/SKILL.md +172 -45
- package/skills/bricks-design/references/architecture-truths.md +125 -0
- package/skills/bricks-design/references/avoiding-complexity.md +91 -0
- package/skills/bricks-design/references/design-critique.md +195 -0
- package/skills/bricks-design/references/design-languages.md +265 -0
- package/skills/bricks-design/references/performance.md +116 -0
- package/skills/bricks-design/references/presentation-and-slideshow.md +137 -0
- package/skills/bricks-design/references/translating-inputs.md +152 -0
- package/skills/bricks-design/references/variations-and-tweaks.md +124 -0
- package/skills/bricks-design/references/verification-toolchain.md +213 -0
- package/skills/bricks-design/references/when-the-brief-is-branded.md +284 -0
- package/skills/bricks-design/references/when-the-brief-is-vague.md +85 -0
- package/skills/bricks-design/references/workflow.md +134 -0
- package/skills/bricks-ux/SKILL.md +120 -0
- package/skills/bricks-ux/references/accessibility.md +162 -0
- package/skills/bricks-ux/references/flow-states.md +175 -0
- package/skills/bricks-ux/references/interaction-archetypes.md +189 -0
- package/skills/bricks-ux/references/monitoring-screens.md +153 -0
- package/skills/bricks-ux/references/pressable-composition.md +126 -0
- package/skills/bricks-ux/references/user-journey.md +168 -0
- package/skills/bricks-ux/references/ux-critique.md +256 -0
- package/tools/deploy.ts +4 -0
- package/tools/pull.ts +42 -2
- package/types/automation.ts +1 -0
- package/types/data-calc.ts +1 -0
- package/skills/bricks-design/LICENSE.txt +0 -180
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Architecture Truths
|
|
2
|
+
|
|
3
|
+
The 10 load-bearing laws of BRICKS design. Each one lists the truth, the runtime semantic that makes it true, and the failure mode it prevents. Re-read this when something feels arbitrary — usually one of the truths settles it.
|
|
4
|
+
|
|
5
|
+
## 1. Canvas is a state, not a screen
|
|
6
|
+
|
|
7
|
+
A Subspace is implicitly a state machine: Canvases are states, Brick events / Data changes are transitions, the visible Canvas is the current state. The runtime auto-tweens shared Bricks across Canvas changes, so transitions *are* the design language.
|
|
8
|
+
|
|
9
|
+
**Failure mode:** treating each Canvas as an independent web page. Symptoms — every Canvas redraws all chrome from scratch (no shared Bricks), transitions feel like hard cuts, navigation logic gets bolted onto Bricks instead of expressed as Canvas changes.
|
|
10
|
+
|
|
11
|
+
**Tell:** if you have one Canvas with `if-then-else` Switches toggling Brick visibility based on a `flowStep` Data, you're emulating a state machine inside one Canvas. Promote to N Canvases.
|
|
12
|
+
|
|
13
|
+
## 2. Data is the conduit for dynamic values
|
|
14
|
+
|
|
15
|
+
Anything that varies at runtime — content (text, images, URLs), i18n strings, Generator inputs/outputs, Subspace Props/Outlets, event payloads, theme tokens you want to swap — flows through Data.
|
|
16
|
+
|
|
17
|
+
Hardcoded values in genuinely-static, single-use Bricks are *fine*. The convention is loose, not enforced. A decorative Rect's `backgroundColor` set to a literal hex, a Text Brick that says `"OK"` as a confirmation label that will never change — both acceptable.
|
|
18
|
+
|
|
19
|
+
**The rule kicks in the moment the value can change.** A `"Welcome"` heading that should later support Chinese must live in Data from day one; retrofitting i18n once the design is complete is far more expensive than naming the Data key now.
|
|
20
|
+
|
|
21
|
+
**Failure mode:** Bricks coupled directly (Brick A reads Brick B's prop), Generator A invoking Generator B by name, hardcoded URLs that should be config, hardcoded English where i18n is foreseeable.
|
|
22
|
+
|
|
23
|
+
**Misread to avoid:** "dynamic values flow through Data" does not mean "media is dynamic and therefore an offline risk". Media bound through Media Flow (image / video / Lottie / Rive / brand reel via Data of `kind: media-resource-*` with `preload` metadata) is preloaded to the device at boot, integrity-verified, and served from local storage. It works offline. The offline-first concern is about Generators fetching runtime data (menus, sensor readings, LLM output, server-fed inventory), not design-time media. Don't strip rich visuals "to be safe for offline" — that's a category error.
|
|
24
|
+
|
|
25
|
+
## 3. Shared Brick ids across Canvases auto-tween
|
|
26
|
+
|
|
27
|
+
If a Brick has the same id on Canvas A and Canvas B with different `frame`s, the runtime animates `x`/`y`/`width`/`height` between the two when the Canvas changes. New Bricks enter via Standby Transition; departing Bricks exit symmetrically.
|
|
28
|
+
|
|
29
|
+
**Use it for** brand chrome (logo, header), progress indicators, persistent CTAs, status footers — anything continuous across the flow.
|
|
30
|
+
|
|
31
|
+
**Narrative principle, not just a runtime fact.** Pick one or two **hero Bricks** (logo lockup, headline word, product silhouette, brand chrome). Give them the same id across every Canvas they appear on. Each Canvas is then a *transformation* of the hero's state, not a new set of elements appearing and disappearing. Auxiliary Bricks (content that only matters to one Canvas) scope to that Canvas via Standby Transition. Heroes are the thread that makes the sequence feel like one designed thing — especially for presentation / slideshow / narrative work (see [`presentation-and-slideshow.md`](presentation-and-slideshow.md)).
|
|
32
|
+
|
|
33
|
+
**Failure mode:** every Brick is unique to its Canvas. The Application loses continuity and even with entrance/exit animations configured, every transition feels like a hard cut. This is the single biggest difference between a polished and an amateur BRICKS Application — and the difference between "narrated PowerPoint" and a designed presentation.
|
|
34
|
+
|
|
35
|
+
## 4. Switches compare; Data Hit/Not-Hit only matches
|
|
36
|
+
|
|
37
|
+
Two distinct condition systems exist; do not confuse them.
|
|
38
|
+
|
|
39
|
+
**Switches** (`SwitchDef` on Canvas / Brick / Generator) support comparison operators against `SwitchCondData`:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
method: '==' | '!=' | '>' | '<' | '>=' | '<='
|
|
43
|
+
cond: SwitchCondData | SwitchCondInnerStateCurrentCanvas | SwitchCondInnerStateOutlet
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Use Switches for threshold-driven UI: hide a Brick when `flowProgress < 1`, switch a tile's color when `value >= threshold`, show a chrome variant when the current Canvas has a specific id.
|
|
47
|
+
|
|
48
|
+
**Data events** `valueHit` / `valueNotHit` only fire on equal-match (`hit_equal: any`) or regex-match (`hit_regex: string`). They do not support `>` `<` `>=` `<=`. Use them for state notifications: "alarm.active became true", "code matched the pin regex".
|
|
49
|
+
|
|
50
|
+
**Failure mode:** trying to express `value > threshold` via a Data Hit subscription. It will not fire as you expect. Move the comparison to a Switch.
|
|
51
|
+
|
|
52
|
+
## 5. Generators are headless, async, event-driven
|
|
53
|
+
|
|
54
|
+
Generators have no visible surface. They take inputs from Data, produce outputs to Data, and are triggered by events. They emit events. They run asynchronously against the canvas thread.
|
|
55
|
+
|
|
56
|
+
**Wire them via events**, never as synchronous calls. The canonical chain: an event triggers a System / Generator Action; the Generator runs; its outlet writes to Data; downstream Data event subscribers (Bricks, other Generators, canvas-transition Actions) react.
|
|
57
|
+
|
|
58
|
+
**Every chain needs a termination condition.** Idempotency keys, guarded conditions, hard-stop counters, retry caps. Surface termination in a comment or a Switch. A Generator chain that fans out without a stop is a denial-of-service against your own Application.
|
|
59
|
+
|
|
60
|
+
**Failure mode:** synchronous "fetch then render" patterns where the canvas waits on a Generator. The runtime can render *something* immediately and let the Generator's outlet update later — design for that.
|
|
61
|
+
|
|
62
|
+
## 6. Frames are grid units
|
|
63
|
+
|
|
64
|
+
Frames (`x`, `y`, `width`, `height`) are integers in the configured grid (`layout.width` × `layout.height`; default 96 × 54 in many projects, but confirm against the actual Subspace). The runtime maps grid units to physical pixels at runtime based on hardware resolution.
|
|
65
|
+
|
|
66
|
+
Off-grid placement is *legal*: position `(-2, -3)` size `(4, 6)` puts the Brick's center at the screen origin — a real composition technique. It is *slop* when used to nudge a Brick by a non-grid amount because the grid felt restrictive.
|
|
67
|
+
|
|
68
|
+
**Bricks fully outside the grid are auto-culled** for performance. Don't rely on that as a hide mechanism — use Switches or `hidden`.
|
|
69
|
+
|
|
70
|
+
**Failure mode:** copy-pasting pixel values from a Figma render into frame fields. Translate to grid units instead.
|
|
71
|
+
|
|
72
|
+
## 7. Standby Transition is the design language
|
|
73
|
+
|
|
74
|
+
Every visible Brick item on a Canvas can declare a Standby Transition (`standbyMode`, `standbyOpacity`, `standbyDelay`, `standbyDelayRandom`, `standbyEasing`, per-property easing on x/y/width/height/opacity). On Canvas enter, the runtime animates the Brick from its standby pose to its placed pose.
|
|
75
|
+
|
|
76
|
+
Combined with shared-Brick auto-tweens (Truth #3), this is the entire transition vocabulary of a BRICKS Application. Master it.
|
|
77
|
+
|
|
78
|
+
**Snap-cuts** (no Standby) are reserved for emphasis — alarm states, error overlays, deliberate hard moments. Routine navigation that snap-cuts feels broken.
|
|
79
|
+
|
|
80
|
+
**Failure mode:** every Brick gets the same fade-in. Boring is also slop. Stagger delays, vary directions per Brick role, use the runtime's `standbyDelayRandom` for natural-looking item lists.
|
|
81
|
+
|
|
82
|
+
## 8. Subspace is a typed module
|
|
83
|
+
|
|
84
|
+
A Subspace is a self-contained mini-Application: own Canvases, own Bricks, own Generators, own Data, own DataCalculation. It binds to a host via:
|
|
85
|
+
|
|
86
|
+
- **Inputs** (Props): host-provided Data values copied into Subspace Data on host change (call-by-value at the boundary). Triggers the Subspace's `valueChange` event internally.
|
|
87
|
+
- **Outlets**: Subspace-emitted values that fire `outlet update` (always) and `outlet value change` (on diff) events in the host.
|
|
88
|
+
- **Actions / Events**: explicit host-callable actions and Subspace-emitted events.
|
|
89
|
+
|
|
90
|
+
**Extract a Subspace only when**:
|
|
91
|
+
- The same flow appears 2+ times (login, OTP, payment, language picker, confirm dialog).
|
|
92
|
+
- The boundary scopes Data meaningfully (a sub-flow with its own complete state independent of the host).
|
|
93
|
+
- A Module distribution is intended (Subspace is also the unit of reuse via the BRICKS Module system).
|
|
94
|
+
|
|
95
|
+
**Do not extract** for "tidy up". Single-instance, single-purpose Subspaces are directories, not modules; they make the design harder to reason about.
|
|
96
|
+
|
|
97
|
+
**Failure mode:** Subspaces with leaky contracts (every host Data exposed as a Prop). Tighten the contract; if you can't, the boundary is wrong.
|
|
98
|
+
|
|
99
|
+
## 9. DataCalculation is for derivation only
|
|
100
|
+
|
|
101
|
+
Two flavours: `DataCalculationScript` (a JS function with named inputs / outputs) and `DataCalculationMap` (a node-graph of `DataCommand`s with sandbox primitives — string, math, collection, datetime, color, etc.). Both are pure transformations: inputs → outputs.
|
|
102
|
+
|
|
103
|
+
**Use it for**:
|
|
104
|
+
- Format conversion (date → human-readable, currency → localized string).
|
|
105
|
+
- Combining Data values into a derived display value.
|
|
106
|
+
- Reductions / iterations over a collection.
|
|
107
|
+
- Boolean conditions feeding a Switch.
|
|
108
|
+
|
|
109
|
+
**Triggering**: `triggerMode: 'auto'` re-runs on input change (watch for circular dependencies); `'manual'` only runs on `PROPERTY_BANK_COMMAND` action.
|
|
110
|
+
|
|
111
|
+
**Do not use** for orchestration, side effects, navigation, async I/O, network calls, or anything that should be in an Event Action chain or a Generator. A DataCalc that triggers DataCalc that triggers DataCalc is an orchestration system in the wrong primitive — promote to event chains.
|
|
112
|
+
|
|
113
|
+
**Failure mode:** spinning up a Generator just to do a string concat or unit conversion. That's a DataCalc job; the inverse misuse is just as common.
|
|
114
|
+
|
|
115
|
+
## 10. No scroll, no overflow, no responsive reflow
|
|
116
|
+
|
|
117
|
+
Subspace `layout` is fixed. Frames are fixed. There is no document flow, no `overflow: scroll`, no media-query reflow. What doesn't fit, doesn't show.
|
|
118
|
+
|
|
119
|
+
**Implications**:
|
|
120
|
+
- Long content lists → `Items` Brick (interactive virtualized list) or `Slideshow` Brick (timed rotation) or paginate across Canvases.
|
|
121
|
+
- Long forms → Canvas per question, not a scrollable form.
|
|
122
|
+
- Modal dialogs → Subspace overlay or Switch-driven Brick reveal — not a popup primitive.
|
|
123
|
+
- Different orientations → different Subspaces with different `layout`s, not a single design that "responds".
|
|
124
|
+
|
|
125
|
+
**Failure mode:** importing a long Figma artboard verbatim, expecting BRICKS to scroll the overflow. Redesign the information architecture; the runtime will not save you.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Avoiding Complexity
|
|
2
|
+
|
|
3
|
+
The "designer ego" guardrails. Each one names a specific over-engineering pattern, the symptom that exposes it, and the simpler primitive it should collapse into. When in doubt, delete.
|
|
4
|
+
|
|
5
|
+
## Subspace abuse
|
|
6
|
+
|
|
7
|
+
A Subspace is a typed module — own Canvases, own Data, own Generators, own contract. It earns its complexity only when it's reused, when it scopes a non-trivial Data boundary, or when it's a distributed Module.
|
|
8
|
+
|
|
9
|
+
**Symptoms of abuse**:
|
|
10
|
+
- Single-instance Subspace whose Props are "everything in the host's Data" — not a module, a leaky directory.
|
|
11
|
+
- Subspace extracted to "tidy up" a single Canvas with 8 Bricks — the cleanup made the design harder to reason about because state now crosses a boundary.
|
|
12
|
+
- Nesting > 2 Subspaces deep — the abstraction is wrong; flatten.
|
|
13
|
+
|
|
14
|
+
**Collapse rule**: if the Subspace appears once and its Props/Outlets cover most of its Data, inline it back into the host.
|
|
15
|
+
|
|
16
|
+
## Switch fanout
|
|
17
|
+
|
|
18
|
+
Switches are powerful — they let one Brick or Canvas have several conditional poses. They become slop when used to express what should be N Canvases.
|
|
19
|
+
|
|
20
|
+
**Symptoms**:
|
|
21
|
+
- 4+ Switches on one Canvas, each gating a different subset of Bricks based on a `flowStep` Data.
|
|
22
|
+
- Switches that toggle Brick `hidden` based on the same `flowStep` value — you've hand-rolled a state machine inside one Canvas.
|
|
23
|
+
- Switch conditions referencing Outlets from a Subspace just for navigation logic.
|
|
24
|
+
|
|
25
|
+
**Collapse rule**: if the Switches partition the Canvas into more than 2 visual states gated by the same Data, promote each state to its own Canvas. Use the runtime's auto-tween of shared chrome (Truth #3) to keep continuity.
|
|
26
|
+
|
|
27
|
+
## DataCalculation chains
|
|
28
|
+
|
|
29
|
+
DataCalc is for derivation. A single calc that produces a derived value is healthy. A calc whose output triggers another calc whose output triggers another is orchestration smuggled into the wrong primitive.
|
|
30
|
+
|
|
31
|
+
**Symptoms**:
|
|
32
|
+
- DataCalc A → Data X → DataCalc B → Data Y → DataCalc C → Data Z, all `triggerMode: 'auto'`.
|
|
33
|
+
- Calcs whose names sound like verbs ("submitForm", "validateInput", "navigateNext") instead of nouns ("formattedDate", "scoreSum", "displayLabel").
|
|
34
|
+
- Circular dependency warnings or fired-multiple-times-per-update behaviour.
|
|
35
|
+
|
|
36
|
+
**Collapse rule**: derivation lives in calcs; the *flow* connecting derivations to user-visible effects lives in Event Action chains and Generators. If a calc has a side effect or triggers navigation, it shouldn't be a calc.
|
|
37
|
+
|
|
38
|
+
## Animation everywhere
|
|
39
|
+
|
|
40
|
+
Standby Transitions are part of the design language (Truth #7). `loop` animations are an emphasis tool. Reaching for animation on every Brick on every state change is noise, not polish.
|
|
41
|
+
|
|
42
|
+
**Symptoms**:
|
|
43
|
+
- Every Brick on every Canvas has a Standby spec with the same easing and duration — uniform motion is no motion.
|
|
44
|
+
- 5+ `runType: 'loop'` animations idling on a Canvas.
|
|
45
|
+
- Animations that fight each other (a parent Brick scaling while children translate against the scale).
|
|
46
|
+
|
|
47
|
+
**Collapse rule**: vary motion intentionally — stagger Standby delays per Brick role, reserve loop for genuine attention draws, use shared-Brick auto-tween instead of separate exit + entrance animations for chrome that persists.
|
|
48
|
+
|
|
49
|
+
## Canvas inflation
|
|
50
|
+
|
|
51
|
+
Each Canvas is a state. Each state is a place the user can be stuck. More Canvases is rarely better UX.
|
|
52
|
+
|
|
53
|
+
**Symptoms**:
|
|
54
|
+
- Canvases with one Brick and one event chain that immediately CHANGE_CANVAS to the next — these are state machine steps that don't deserve a Canvas.
|
|
55
|
+
- Canvases that exist only to "loadingly transition" — that's what Standby and shared-Brick tweens are for.
|
|
56
|
+
- Canvases for every locale / every theme variant — variants belong in Switches or Data-bound props, not parallel Canvases.
|
|
57
|
+
|
|
58
|
+
**Collapse rule**: a Canvas earns its existence by being a stable state the user observes for at least a moment. Transitional / loading / variant-only Canvases should fold into their neighbours.
|
|
59
|
+
|
|
60
|
+
## Generator orchestration smell
|
|
61
|
+
|
|
62
|
+
Generators are I/O units triggered by events. Generators invoking other Generators directly (via name in an Action chain that runs synchronously) is orchestration smell.
|
|
63
|
+
|
|
64
|
+
**Symptoms**:
|
|
65
|
+
- Long Action chains with `waitAsync: true` chaining 4+ Generator calls.
|
|
66
|
+
- A Generator whose only job is to call another Generator and wait.
|
|
67
|
+
- Two Generators reading and writing the same Data inside one event chain.
|
|
68
|
+
|
|
69
|
+
**Collapse rule**: split the chain at Data boundaries. Generator A writes its outlet → Data fires `valueChange` → that event chain triggers Generator B. Each piece is independently inspectable, retryable, and cacheable.
|
|
70
|
+
|
|
71
|
+
## Module overreach
|
|
72
|
+
|
|
73
|
+
The BRICKS Module system lets a Subspace be packaged with version metadata and dependency requirements (`Subspace.module`). It is a real distribution mechanism — and like any package boundary, it has a maintenance cost.
|
|
74
|
+
|
|
75
|
+
**Symptoms**:
|
|
76
|
+
- Modularizing a Subspace that's only used in one Application.
|
|
77
|
+
- Modules whose contract changes every version because the host keeps adding Props.
|
|
78
|
+
- Bumping a Module version for purely cosmetic edits.
|
|
79
|
+
|
|
80
|
+
**Collapse rule**: keep Subspaces local until at least the second consumer asks for them. Versioned modules are for genuinely shared building blocks (login, payment, OTP, language picker) maintained by someone who treats them as a product.
|
|
81
|
+
|
|
82
|
+
## "Let's make it dynamic" overreach
|
|
83
|
+
|
|
84
|
+
Truth #2 says dynamic values flow through Data. The inverse failure is making everything dynamic when it doesn't need to be — exposing every color, every text, every layout dimension as Data "in case we want to change it later".
|
|
85
|
+
|
|
86
|
+
**Symptoms**:
|
|
87
|
+
- Subspace with 40 Data entries, half of them never read by a Generator and never written by anything but a default value.
|
|
88
|
+
- Theme tokens exposed as Data even though the design ships with one theme.
|
|
89
|
+
- A Generator whose job is to "set the title" of a Brick that always says the same thing.
|
|
90
|
+
|
|
91
|
+
**Collapse rule**: Data is the conduit for *currently dynamic* values. If a value is genuinely static and single-use, hardcode it. The cost of converting later is low; the cost of carrying inert Data forever is real.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Design Critique — self-review before "done"
|
|
2
|
+
|
|
3
|
+
The Verification gate proves the design *runs*. Critique proves it's *good*. Both are required before declaring done; neither substitutes for the other.
|
|
4
|
+
|
|
5
|
+
This file gives the agent a structured self-review pass: five scoring dimensions with concrete rubrics, a per-deployment-shape focus chart, and an extended anti-slop top-10 with BRICKS-specific failure modes. Run the pass after the screenshots are captured and viewed (per [`verification-toolchain.md`](verification-toolchain.md)), and before declaring done to the user.
|
|
6
|
+
|
|
7
|
+
The point isn't to be self-critical for its own sake. The point is to catch the specific failure modes that consistently ship if not actively rooted out.
|
|
8
|
+
|
|
9
|
+
## How to run the pass
|
|
10
|
+
|
|
11
|
+
1. **Verify** — compile clean + screenshot every Canvas + read screenshots back (see `verification-toolchain.md`).
|
|
12
|
+
2. **Score** — for each Canvas, rate the five dimensions below 0–10 against the rubrics.
|
|
13
|
+
3. **Anti-slop sweep** — walk the top-10 list; flag every match.
|
|
14
|
+
4. **Fix anything < 8** and any anti-slop matches; re-verify.
|
|
15
|
+
5. **Declare done** — only when every Canvas scores ≥ 8 on every dimension and the anti-slop list is clean.
|
|
16
|
+
|
|
17
|
+
If a dimension cannot be scored ≥ 8 within the deployment's constraints, surface it as an accepted trade-off in the trade-off note rather than silently shipping a 6.
|
|
18
|
+
|
|
19
|
+
## The five dimensions
|
|
20
|
+
|
|
21
|
+
### 1. System commitment
|
|
22
|
+
|
|
23
|
+
*Does the work cite the declared system (the comment block at the top of the Subspace), and does deviation have rationale?*
|
|
24
|
+
|
|
25
|
+
| Score | Rubric |
|
|
26
|
+
|---|---|
|
|
27
|
+
| 9–10 | Every brick property points back to a Data token, an `ApplicationFont` entry, or the system block. Deviations carry a one-line comment explaining why. |
|
|
28
|
+
| 7–8 | Direction is correct; 1–2 hardcoded values that should be tokens, or 1–2 deviations without rationale. |
|
|
29
|
+
| 5–6 | Visible drift — a third type family slipped in, a fourth color appeared mid-flow, or a brick redrew an asset that exists in Media Flow. |
|
|
30
|
+
| 3–4 | The system block is decorative; the work doesn't follow it. |
|
|
31
|
+
| 1–2 | No system block, or the block contradicts the work. |
|
|
32
|
+
|
|
33
|
+
**Audit moves:**
|
|
34
|
+
- Open the system block. Pick five values from it (a color, a type size, a Standby duration, a margin, a Brick template). For each, check that the work uses it consistently.
|
|
35
|
+
- Pick five values *from* the work (a `backgroundColor` literal, a `fontSize`, a Standby easing, a hex code in a Rect, a brick template choice). For each, check that the value traces back to the system block or has rationale.
|
|
36
|
+
- If signature moves of the chosen design language (per [`design-languages.md`](design-languages.md)) are absent, score drops regardless of token-discipline. Swiss Editorial without numbered folios and hairline rules is not Swiss Editorial; it's "vaguely minimal."
|
|
37
|
+
|
|
38
|
+
### 2. Visual hierarchy
|
|
39
|
+
|
|
40
|
+
*Does the user's eye flow where the designer intended? Is information findable in under 2 seconds?*
|
|
41
|
+
|
|
42
|
+
| Score | Rubric |
|
|
43
|
+
|---|---|
|
|
44
|
+
| 9–10 | Squint test passes — even at low resolution / low attention, primary / secondary / tertiary are unmistakable. Display:body scale ratio ≥ 2.5×. Three to four clear levels via size, weight, color, and space combined. |
|
|
45
|
+
| 7–8 | Hierarchy is clear with one or two muddy spots. |
|
|
46
|
+
| 5–6 | Title and body distinguished, but mid-levels collapse together; user has to read everything to find anything. |
|
|
47
|
+
| 3–4 | Information is uniform; no entry point. |
|
|
48
|
+
| 1–2 | The eye doesn't know where to land. |
|
|
49
|
+
|
|
50
|
+
**Audit moves:**
|
|
51
|
+
- The squint test. View the screenshot at 25% zoom or with eyes half-closed. The composition should still read.
|
|
52
|
+
- Measure the display:body scale ratio in grid units. < 2.5× = deduction.
|
|
53
|
+
- Count the levels distinguishable in the Canvas. < 3 = deduction; > 5 = different deduction (over-stratified).
|
|
54
|
+
- For the deployment's viewing distance, simulate the legibility floor (per the scale-floor table in `architecture-truths.md` Truth #6 + `performance.md`'s scale section). If body text won't read at that distance, hierarchy fails regardless of relative ratios.
|
|
55
|
+
|
|
56
|
+
### 3. Craft execution
|
|
57
|
+
|
|
58
|
+
*Alignment. Spacing rhythm. Colour discipline. Typography count. Motion vocabulary consistency.*
|
|
59
|
+
|
|
60
|
+
| Score | Rubric |
|
|
61
|
+
|---|---|
|
|
62
|
+
| 9–10 | Grid stance matches the chosen language (lean / break / breathe) deliberately throughout. Every inter-Brick gap comes from the declared spacing scale. Colours limited to the system tokens (typically ≤ 4). Typography limited (typically ≤ 2 families). Standby Transitions use a consistent easing and timing vocabulary. |
|
|
63
|
+
| 7–8 | Mostly clean; 1–2 alignment slips or one off-scale spacing. |
|
|
64
|
+
| 5–6 | Visible inconsistency — colours creeping past the token set, mixed Standby easings, asymmetric margins without intent, ad-hoc gap values. |
|
|
65
|
+
| 3–4 | Grid stance unclear; multiple type families; arbitrary motion timings; spacing drift. |
|
|
66
|
+
| 1–2 | Looks like a draft. |
|
|
67
|
+
|
|
68
|
+
**Audit moves:**
|
|
69
|
+
- **Grid stance match.** Off-grid placements should serve the declared language (Brutalist break, Sagmeister theatrical, Risograph hand-placed). Off-grid that drifted in accidentally — flag and snap. A Swiss Editorial Canvas with a Brick at `(3.5, 11.2)` is a tell.
|
|
70
|
+
- **Spacing-scale adherence.** Open the style declaration block. Read the declared spacing scale (e.g., `2 / 4 / 8 / 16 gu`). Pick ten inter-Brick gaps across the Canvas — every one must come from that set. Gaps of 7 / 9 / 11 / 13 across siblings = arithmetic drift, the agent picked values ad-hoc instead of from the scale. Snap to the nearest scale value or update the scale (and re-check everywhere).
|
|
71
|
+
- List every distinct colour used in the Canvas. > 4 = deduction (excluding intentional photography palette spreads).
|
|
72
|
+
- List every distinct type family. > 2 = deduction.
|
|
73
|
+
- List every distinct Standby easing / duration combination. > 3 = deduction.
|
|
74
|
+
|
|
75
|
+
### 4. Functional fit to deployment
|
|
76
|
+
|
|
77
|
+
*Does the design solve the deployment's actual constraints?*
|
|
78
|
+
|
|
79
|
+
This dimension overlaps with the companion `bricks-ux` skill — interaction / accessibility / flow-state correctness is critiqued in depth there (`bricks-ux/references/ux-critique.md`). What stays here is the visual-design contribution to functional fit: does the visual system *enable* the interaction layer to work, or does it actively disable it.
|
|
80
|
+
|
|
81
|
+
| Score | Rubric |
|
|
82
|
+
|---|---|
|
|
83
|
+
| 9–10 | Type meets legibility floor for viewing distance. Pressable Bricks are visually distinct from decorative. Contrast survives deployment conditions (sunlight / dim lobby / glare). Brand and asset choices accommodate languages in scope. Orientation respected. |
|
|
84
|
+
| 7–8 | One visual choice marginal — type at the floor instead of comfortably above; one asset that doesn't survive a locale; affordance distinction subtle but present. |
|
|
85
|
+
| 5–6 | One visual choice actively disables interaction — pressable tiles indistinguishable from decoration, body type below legibility floor for the distance, palette that fails contrast under deployment light. |
|
|
86
|
+
| 3–4 | Multiple visual-functional conflicts. |
|
|
87
|
+
| 1–2 | Visual design ignores deployment constraints entirely. |
|
|
88
|
+
|
|
89
|
+
**Audit moves:**
|
|
90
|
+
- Walk the deployment-context block (from Priority #0). For each visible item — what the user must read, find, press, distinguish — point to the visual choice that supports it.
|
|
91
|
+
- Squint test at 25% zoom: primary content readable, pressable elements visually distinct, severity tiers (if monitor) distinguishable.
|
|
92
|
+
- For interaction / accessibility / flow-state critique beyond the visual contribution, cross to `bricks-ux/references/ux-critique.md`. The two passes run in parallel; both block ship.
|
|
93
|
+
|
|
94
|
+
### 5. Originality within direction
|
|
95
|
+
|
|
96
|
+
*Is this the chosen design language done at 80% commitment, or 30%?*
|
|
97
|
+
|
|
98
|
+
| Score | Rubric |
|
|
99
|
+
|---|---|
|
|
100
|
+
| 9–10 | The signature moves of the chosen language are present and confident. The work would be recognized by a designer familiar with the language. There's at least one move that's specific to *this* brief, not just templated language application. |
|
|
101
|
+
| 7–8 | Direction is recognizable; mostly templated execution; one or two moves feel rote. |
|
|
102
|
+
| 5–6 | Recognizable as "the kind of thing that gets called Swiss Editorial / Kenya Hara / etc." but generically — could be any brand. |
|
|
103
|
+
| 3–4 | Cliché-mode application of the language; works that any agent might produce given the same prompt. |
|
|
104
|
+
| 1–2 | The language is unrecognizable in the work. |
|
|
105
|
+
|
|
106
|
+
**Audit moves:**
|
|
107
|
+
- For the chosen direction, list its top 3–5 signature moves (from `design-languages.md` or your own knowledge of the language). For each, check whether the work executes it.
|
|
108
|
+
- Where signature moves are absent, the direction has been softened toward generic. Restore them.
|
|
109
|
+
- Look for the inverse — moves that *aren't* in the language but the work has imported anyway (a Field.io-style gradient on a Swiss Editorial piece, a Risograph spot color on a Kenya Hara piece). These are the dilutions that drop scores.
|
|
110
|
+
|
|
111
|
+
## Deployment-shape focus
|
|
112
|
+
|
|
113
|
+
Different deployments weight the dimensions differently:
|
|
114
|
+
|
|
115
|
+
| Deployment shape | Strongest weight | Weaker weight |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| Glanceable signage (single canvas) | Visual hierarchy · Originality | Functional fit (low complexity) |
|
|
118
|
+
| Multi-canvas kiosk (transact / interact) | Functional fit · Craft execution | Originality (don't get cute with money or identity) |
|
|
119
|
+
| Reactive dashboard (monitor) | Visual hierarchy · Functional fit | Originality (data is the work) |
|
|
120
|
+
| Hospitality / lifestyle (dwell) | Originality · System commitment | Functional fit (low input complexity) |
|
|
121
|
+
| Wayfinding | Visual hierarchy · Functional fit (legibility floor) | Originality (recognition over flair) |
|
|
122
|
+
| Presentation / introduction loop | Originality · Visual hierarchy | Functional fit (no input) |
|
|
123
|
+
|
|
124
|
+
When focus weights diverge sharply, surface the trade-off in the trade-off note. A wayfinding screen that scores 10 on hierarchy and 6 on originality is *correct*; a wayfinding screen that scores 9 on originality and 6 on hierarchy is *wrong*.
|
|
125
|
+
|
|
126
|
+
## Anti-slop top-10 (BRICKS-specific)
|
|
127
|
+
|
|
128
|
+
Walk this list every time. Each is a pattern that consistently slips into agent-produced work and consistently degrades it.
|
|
129
|
+
|
|
130
|
+
### 1. Generic gradient backgrounds on a Rect
|
|
131
|
+
**Tell:** purple → pink → blue full-bleed on the boot Canvas. **Why bad:** it is the literal AI-generated-page tell; reviewers identify the work as machine-made instantly. **Fix:** use a single-color ground from the system tokens, or a reference-anchored gradient that's specific to the brand (declared as a Data token, used deliberately).
|
|
132
|
+
|
|
133
|
+
### 2. Decorative left-border-accent on every Rect
|
|
134
|
+
**Tell:** every card-shaped Rect carries a 4-grid-unit left border in the accent color. **Why bad:** it is the AI-dashboard-card signature; once seen it cannot be un-seen and it dates the work to the AI-tool era. **Fix:** distinguish cards via background contrast, weight, or composition; or commit to a different card vocabulary that matches the chosen language.
|
|
135
|
+
|
|
136
|
+
### 3. Emoji decoration in RichText
|
|
137
|
+
**Tell:** ✅, ⚡, 🚀, ✨ next to feature bullets or in headlines. **Why bad:** unless the brand actually uses emoji in its voice (rare, deliberate), this is decoration-as-substitute-for-design. **Fix:** real icon library (Lucide / Phosphor / Heroicons via `Icon` brick), or no icon at all.
|
|
138
|
+
|
|
139
|
+
### 4. Sketch / SVG-drawn imitations of real assets
|
|
140
|
+
**Tell:** a `Sketch` brick that approximates a logo, a CSS-shape product silhouette, a SVG hero illustration. **Why bad:** AI-drawn imagery reads as AI-drawn imagery. A labeled placeholder is more honest. **Fix:** acquire the real asset via the [Media Flow protocol](when-the-brief-is-branded.md), generate one anchored on real brand reference, or accept a labeled placeholder.
|
|
141
|
+
|
|
142
|
+
### 5. Fabricated stats / fake user counts
|
|
143
|
+
**Tell:** "10,000+ happy customers", "99.9% uptime", "trusted by Fortune 500" appearing without a source. **Why bad:** invented social proof is dishonest and reviewers usually catch it. **Fix:** request real numbers from the user or use a labeled placeholder ("[insert real metric]").
|
|
144
|
+
|
|
145
|
+
### 6. Default sans system fonts when the brand has its own
|
|
146
|
+
**Tell:** Inter / Roboto / Helvetica / system-ui shipped despite the brand having a documented type stack. **Why bad:** it leaks "I didn't bother sourcing the brand font" across the entire surface area of the design. **Fix:** declare the brand fonts as `ApplicationFont` entries with the licensed files in Media Flow.
|
|
147
|
+
|
|
148
|
+
### 7. Naive dark-mode by inverting Data values
|
|
149
|
+
**Tell:** the dark theme is "white background → black, black text → white" with no other adjustments. **Why bad:** a real dark theme rebalances saturation, contrast, accent intensity, and shadow. Inversion produces a theme that looks broken. **Fix:** if the brief wants dark mode, design it as a deliberate second theme — re-author the token Data, don't just toggle.
|
|
150
|
+
|
|
151
|
+
### 8. Animation `loop` on every visible element
|
|
152
|
+
**Tell:** every brick on every canvas has a `runType: 'loop'` Animation attached. **Why bad:** continuous motion everywhere is visual noise that burns frame budget and dulls genuine attention-draws. **Fix:** reserve `loop` for true attention-draws (alarm pulse, recording dot, hero motion in Field.io); use Standby Transitions and shared-Brick auto-tween for everything else.
|
|
153
|
+
|
|
154
|
+
### 9. Hover-state treatments imported to no-touch hardware
|
|
155
|
+
**Tell:** a brick's `pressable: 'enabled'` carries a press scale-down animation, but the deployment is a 75" no-touch signage panel. **Why bad:** the affordance promises something the hardware cannot deliver; the design reads as "ported from web." **Fix:** drop hover on no-touch; convert to a Switch driven by a non-pointer signal (sensor, timer, peripheral Generator) if the visual intent matters.
|
|
156
|
+
|
|
157
|
+
### 10. AI-generated brand imagery without a real brand-reference anchor
|
|
158
|
+
**Tell:** a generated "brand-appropriate" hero image that nobody at the brand has ever seen, produced from a prompt like "modern tech product on a gradient." **Why bad:** generation without anchoring produces uncanny-valley assets that feel adjacent to the brand without being the brand. **Fix:** anchor every generation on at least one verified brand asset (logo, real photo, official color sample); apply 5-10-2-8; log generation metadata in `brand-spec.md`. (See [Media Flow protocol § Creating assets when missing](when-the-brief-is-branded.md#creating-assets-when-missing).)
|
|
159
|
+
|
|
160
|
+
## Bonus failure modes (BRICKS-specific, less common)
|
|
161
|
+
|
|
162
|
+
- **Hardcoded English in a Subspace bound for multilingual deployment.** Every visible string should be a Data value, even when only one language is populated at first.
|
|
163
|
+
- **`persistData: true` on transient flow Data.** Resumes a half-complete flow after a watchdog reset and confuses the next user.
|
|
164
|
+
- **DataCalculation chains masquerading as orchestration.** See [`avoiding-complexity.md`](avoiding-complexity.md) — calc → calc → calc is the wrong primitive.
|
|
165
|
+
- **Subspace-as-tidiness.** A Subspace with a single instance and a leaky Props contract is a directory, not a module. See `architecture-truths.md` Truth #8.
|
|
166
|
+
- **Snap canvas transitions on routine navigation.** Reserved for emphasis only.
|
|
167
|
+
- **Inline brand binaries** (logo as base64 in a Brick prop, hero image embedded). Pollutes the Subspace and defeats Media Flow's offline + refresh model.
|
|
168
|
+
- **Pseudo-chrome contamination — page counters, progress bars, chapter numbers drawn into Canvas content.** A "Slide 3/12" Text Brick inside the design competes with the runtime's own transition affordances and reads as duplicated chrome. If the audience genuinely needs to know where they are, render it via a shared chrome Brick (so it auto-tweens with the rest of the chrome) — or drop it entirely. See [`presentation-and-slideshow.md`](presentation-and-slideshow.md).
|
|
169
|
+
- **Density-rhythm collapse — three or more consecutive Canvases at the same layout archetype.** Three "headline + bullet list" Canvases in a row reads as a single Canvas that didn't change. Alternate density across the sequence (full-bleed / two-column / pull-quote / data-figure / breather — see the rotation table in `presentation-and-slideshow.md`).
|
|
170
|
+
- **In-Canvas variation pickers — palette swatches, theme toggles, "choose your style" buttons left in production.** Same category as pseudo-chrome. The variation comparison surface is chat + source tree, not the Canvas. See [`variations-and-tweaks.md`](variations-and-tweaks.md).
|
|
171
|
+
- **Full-set unmount + remount per Canvas change.** Every Brick is Canvas-local; no shared ids; every transition is a hard cut even with Standby Transitions configured. This is what makes a sequence read as "narrated PowerPoint" instead of a designed flow. Pick 1–2 hero Bricks and share their ids across Canvases — see Truth #3.
|
|
172
|
+
|
|
173
|
+
## First-viewer reaction rubric (for sequenced / narrative work)
|
|
174
|
+
|
|
175
|
+
For presentations, slideshows, intro decks, explainers — anything sequenced. Predict (or directly ask) the first reaction. The rubric is a separate axis from the 5 dimensions and only applies when the work is a sequence ≥ 3 Canvases.
|
|
176
|
+
|
|
177
|
+
- *"This is narrated PowerPoint."* — Redesign. Hero architecture missing or broken. Likely full-set unmount per Canvas change. Back to Pass 1.
|
|
178
|
+
- *"Things were just moving."* — Motion is present but hierarchy isn't. Heroes exist but compete with auxiliaries. Quiet down everything except the hero.
|
|
179
|
+
- *"I wanted to keep watching."* — Baseline good. Pacing works, hero continuity reads. Polish from here.
|
|
180
|
+
- *"I wanted to screenshot that frame."* — Memorable keyframe achieved. At least one Canvas is doing more than its job.
|
|
181
|
+
|
|
182
|
+
Aim for the third reaction overall and the fourth on at least one Canvas in any sequence of ≥ 5 Canvases. Anything ≤ first is a structural failure, not a polish issue.
|
|
183
|
+
|
|
184
|
+
## Definition of "done" with critique applied
|
|
185
|
+
|
|
186
|
+
A design is done when:
|
|
187
|
+
|
|
188
|
+
1. The Verification gate (compile + every-Canvas screenshot + screenshots reviewed) passes.
|
|
189
|
+
2. Every Canvas scores ≥ 8 on every one of the five dimensions, or trade-offs are explicitly accepted with rationale.
|
|
190
|
+
3. The anti-slop top-10 + bonus-failure-modes walk produces zero unaddressed matches.
|
|
191
|
+
4. For sequenced / narrative work, the first-viewer rubric predicts ≥ "I wanted to keep watching."
|
|
192
|
+
5. Reference comparisons (where applicable) have a written delta report.
|
|
193
|
+
6. The trade-off note that ships alongside variations captures every accepted < 8.
|
|
194
|
+
|
|
195
|
+
If any item is unmet, the work is mid-iteration. Say so explicitly to the user; offer a precise list of what remains.
|