@ethlete/agent-rules 0.1.0-next.31 → 0.1.0-next.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +7 -1
- package/content/hooks/background-design-commands.py +140 -0
- package/content/hooks/builder-chat-words.py +74 -0
- package/content/hooks/context-warning.py +47 -19
- package/content/hooks/git-safety.py +181 -0
- package/content/mods/plugins/e2e-progress/.claude-plugin/plugin.json +1 -1
- package/content/rules/nx-layout.md +5 -2
- package/content/rules/subagent-models.md +2 -2
- package/content/skills/agent-sessions/SKILL.md +5 -3
- package/content/skills/agent-sessions/agent-sessions.mjs +20 -4
- package/content/skills/design-exploration/SKILL.md +47 -547
- package/content/skills/design-exploration/reference-check-and-notes.md +92 -0
- package/content/skills/design-exploration/reference-flows-and-wireframes.md +78 -0
- package/content/skills/design-exploration/reference-inbox-and-mcp.md +54 -0
- package/content/skills/design-exploration/reference-order-and-design-system.md +124 -0
- package/content/skills/design-exploration/reference-products-and-sketches.md +199 -0
- package/content/skills/design-exploration/reference-shots.md +25 -0
- package/content/skills/git-commit/SKILL.md +10 -0
- package/content/skills/grilling/SKILL.md +1 -0
- package/content/skills/handoff/SKILL.md +20 -4
- package/package.json +1 -1
- package/src/index.js +2 -1
- package/src/index.js.map +1 -1
- package/src/lib/git-flow-repair.d.ts +1 -1
- package/src/lib/git-flow-start.d.ts +1 -1
- package/src/lib/migrate.js +2 -1
- package/src/lib/migrate.js.map +1 -1
- package/src/lib/output-style-command.d.ts +1 -1
- package/src/lib/prettier.d.ts +21 -0
- package/src/lib/prettier.js +51 -0
- package/src/lib/prettier.js.map +1 -0
- package/src/lib/sync.d.ts +1 -1
- package/src/lib/sync.js +9 -2
- package/src/lib/sync.js.map +1 -1
- package/src/lib/targets/hooks-shared.d.ts +3 -3
- package/src/lib/targets/hooks-shared.js +58 -20
- package/src/lib/targets/hooks-shared.js.map +1 -1
|
@@ -35,6 +35,11 @@ or loses only against the other variants of its question.
|
|
|
35
35
|
for literal copies. Derive the composition from the product's own visual language; a new palette
|
|
36
36
|
or spacing on the reference's layout is not a different concept.
|
|
37
37
|
|
|
38
|
+
7. **Visible UI is built only from a sketch the user picked.** A new or changed element, label,
|
|
39
|
+
badge or layout needs a picked sketch, and the build brief names its id. "Decision" and
|
|
40
|
+
"regression" items are no exception. Without a picked sketch, build data and specs only and
|
|
41
|
+
stop at the UI.
|
|
42
|
+
|
|
38
43
|
Confirm the step size once, at the start. Do not ask again at every stop. A task is not
|
|
39
44
|
finished while the user is still talking about it.
|
|
40
45
|
|
|
@@ -46,13 +51,10 @@ finished while the user is still talking about it.
|
|
|
46
51
|
- Your pick, one line on why.
|
|
47
52
|
- Nothing else. No next step, no second finding.
|
|
48
53
|
|
|
49
|
-
**Do not send a screenshot.** The user keeps the call open. Screenshot only for your own
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
the pixels that differ from the merged state in red, or says "no pixel change" (with ", but the markup differs" when only the markup changed, e.g. both sides miss the same content). It prints the PNG path last. `--scale 2` enlarges a small part; `--crop x,y,w,h` cuts each cell to that CSS-pixel box, to judge hairlines. `--interaction hover` forces an interaction on every cell. `--state a,b` draws only those states, to compare them side by side. With `--variants`, `--round r2` or `--variant i,j` draws only those variants next to the merged row, so the current round stays readable; it filters the picture, never the checks. With `--variants`, `--diff-props` compares each variant with the merged part drawn with the variant's state props, so changed props do not paint the diff red. It draws
|
|
54
|
-
undimmed, whatever Studio shows. Do not write a scratch script for batch shots.
|
|
55
|
-
`et design motion shots <layer>/<name> <motion>` draws a motion at its keyframes, in full and reduced motion, into one sheet, and writes its tracks (element, properties, start, duration, easing) as JSON next to it.
|
|
54
|
+
**Do not send a screenshot.** The user keeps the call open. Screenshot only for your own check that a
|
|
55
|
+
variant renders: `et design shot <layer>/<name> --states [--variants]` draws one contact sheet. Every
|
|
56
|
+
flag, the motion shots and the raw screenshot script are in {%resource:reference-shots.md%}. Do not
|
|
57
|
+
write a scratch script for batch shots.
|
|
56
58
|
|
|
57
59
|
If a second defect appears, add it to the open list and give it one line. Do not draw it.
|
|
58
60
|
|
|
@@ -80,530 +82,44 @@ Studio no longer takes new calls. **New work goes to a product, never to a new c
|
|
|
80
82
|
`et design new`. Old calls stay in Studio's Legacy tab as reference for moving them into a
|
|
81
83
|
product. They take no picks and no new variants.
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
`
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
et design sketch new <layer>/<name> --variants a,b --by <model id> [--like <layer>/<name>] [--variant-note a=<text>]… [--product <p>] # each variant starts as a copy of the part
|
|
124
|
-
et design sketch new <layer>/<name> <layer>/<name>… --variants a --by <model id> # one change across several parts: one sketch, one ready, one merge
|
|
125
|
-
et design sketch target add <layer>/<name> <layer>/<name> --by <model id> # add a part to an open sketch's targets, seeded into each variant
|
|
126
|
-
et design sketch report <layer>/<name> --variant b --by <model id> "phone" # tell Studio what you build now
|
|
127
|
-
et design sketch report <layer>/<name> --variant b --by <model id> --done # you stopped drawing b; Studio shows its frames
|
|
128
|
-
et design sketch check [<layer>/<name>] [--fix] # each variant laid over the product
|
|
129
|
-
et design sketch ready <layer>/<name> --by <model id> # now the user can pick
|
|
130
|
-
et design sketch reject <layer>/<name> --variant b [--reason <text>] --by <model id> # only when the user rejected b; no pick or merge until reopened
|
|
131
|
-
et design sketch reopen <layer>/<name> --variant b [--reason <text>] --by <model id> # only when the user takes b back; the rejection stays in the history
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
One change across several parts (an alias removal, a token rename) is one sketch with several targets: each
|
|
135
|
-
variant holds every target, and `ready` compares them all. `ready` and `preview` also name every part a `shared/`
|
|
136
|
-
edit reaches.
|
|
137
|
-
|
|
138
|
-
Variants are alternatives. A variant never stands for a state of another variant: a hidden or
|
|
139
|
-
collapsed mode of variant d is a further state of d, not a variant e. Before you draw a new control,
|
|
140
|
-
look for a control that already does the job (an active rail button that toggles its panel), and
|
|
141
|
-
draw that first.
|
|
142
|
-
|
|
143
|
-
A section of an app is a page under `pages/`, never a state of the shell. An element holds its
|
|
144
|
-
own chrome only. A sketch on an element adds no state whose difference is page content in a slot.
|
|
145
|
-
|
|
146
|
-
A variant mirrors the product layout and holds only the parts it changes. Draw two to four
|
|
147
|
-
variants, each with what it costs, and run `sketch check` before `ready`. A variant with problems
|
|
148
|
-
cannot be picked. A part in a variant keeps every state the part has in the product: `sketch check`
|
|
149
|
-
and `sketch ready` fail on a dropped state, and warn when two stylesheets of one part define the same class. A problem the product already had prints as `NOTE (was there before)` and fails
|
|
150
|
-
neither. Use `sketch list` to see the open ones.
|
|
151
|
-
`sketch check` also runs tsc over each variant with its `@shared/` and `@system/` imports, so never write a
|
|
152
|
-
tsconfig of your own. It warns of a variant stylesheet that restyles a class of `shared/`, of a
|
|
153
|
-
variant file nothing imports, and of a `shared/` export the variant does not import; `design check` warns of
|
|
154
|
-
an export in a merged part's `shared/` that nothing imports, and (`STALE-REPLACE`) of a `.replace('<…')` or
|
|
155
|
-
`.replace(/<…/)` on markup that neither the part nor a part it uses draws. To delete a file of a part, delete it in the variant: a merge deletes the
|
|
156
|
-
product file the picked variant no longer holds.
|
|
157
|
-
|
|
158
|
-
Each variant's note, what it is and what it costs, goes in with `sketch new --variant-note a=<text>`, once
|
|
159
|
-
per variant: `sketch.json` keeps it apart from the part's `definePart({ note })`, and Studio shows it in the
|
|
160
|
-
variant's head. A merge keeps the part's note, takes its `--note`, or gives a new part the picked variant's note.
|
|
161
|
-
`sketch new` and `sketch variant` write their files in the checkout's Prettier format; after an edit,
|
|
162
|
-
`sketch check --fix` formats the variants before it checks them. A sketch command
|
|
163
|
-
without `--product` takes the product that holds the sketch.
|
|
164
|
-
|
|
165
|
-
Start a new part from a close one with `--like`: `sketch new pages/inbox --like pages/system`
|
|
166
|
-
copies the product's `pages/system` into each variant, renamed to the target and without its
|
|
167
|
-
`madeBy`; `--like pages/system:b` copies variant b of the open sketch on it, with that sketch's
|
|
168
|
-
`shared/` folder.
|
|
169
|
-
|
|
170
|
-
Rendering for one variant lives in that variant's files. `shared/` holds only code every variant
|
|
171
|
-
uses: do not give a shared helper a parameter, branch, import or style rule that only one variant, or
|
|
172
|
-
a variant you dropped, needs. A merge takes `shared/` whole, so what stays there ships with the pick.
|
|
173
|
-
|
|
174
|
-
Code the variants of one sketch have in common (sample data, a switch, a helper) goes in the
|
|
175
|
-
sketch's `shared/` folder, next to the variant folders, never into copies per variant. A part in a
|
|
176
|
-
variant imports it as `@shared/<path>`, and a shared file may import `@system/...` and
|
|
177
|
-
`@shared/...`. A part outside a sketch may not import `@shared/`. A variant that needs a shared file
|
|
178
|
-
changed holds its own copy at `<variant>/shared/<path>`; `@shared/<path>` finds that copy first, and a merge
|
|
179
|
-
of that variant takes it. On a merge, `shared/` moves into
|
|
180
|
-
the target's folder as `shared/` with its imports made relative; when no part imports it, it is
|
|
181
|
-
dropped. With several targets, each takes only the files it imports, directly or through another
|
|
182
|
-
shared file; a file nobody imports goes back to the target that held it, and the merge refuses one no
|
|
183
|
-
target held. `sketch new` refuses targets whose `shared/` folders hold one path with different contents. Only the target may import it: a merge refuses while another part of the picked variant
|
|
184
|
-
does, so move that code into the part. `sketch new` prints each file it puts in `shared/`, for example
|
|
185
|
-
the `shared/` folder of a merged page: edit it there, as part of the sketch, not in a variant copy.
|
|
186
|
-
|
|
187
|
-
```ts
|
|
188
|
-
// sketches/pages-flows/shared/flow-data.ts
|
|
189
|
-
export const flows = [{ name: 'Checkout', steps: 4 }];
|
|
190
|
-
|
|
191
|
-
// sketches/pages-flows/a/pages/flows/flows.ts
|
|
192
|
-
import { flows } from '@shared/flow-data';
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
An asset (a mark, logo, icon, picture or font) is one file in `.ethlete/design/<product>/assets/`,
|
|
196
|
-
never a copy inlined into parts. A part imports it as `@assets/<file>`: the default import is a URL
|
|
197
|
-
for `<img src>`; an SVG that must follow tokens (`currentColor`, `var(--accent)`) imports with
|
|
198
|
-
`?raw` and goes inline, for example `@assets/icons/<name>.svg?raw`. A stylesheet, the product's
|
|
199
|
-
`styles.css` or a part's, uses `url('@assets/<file>')`, for example in an `@font-face`. A foundation
|
|
200
|
-
part may wrap an asset in a named export. A product finds its base product's assets too. A sketch
|
|
201
|
-
variant adds or changes an asset in its own `<variant>/assets/` folder (`sketch new` and `sketch variant`
|
|
202
|
-
print it next to the part file), and a merge copies it into the product's. Size an inline SVG with
|
|
203
|
-
`svgAsset(mark, { size: 32 })` from `@design-system`, never by replacing its `width`/`height` as a
|
|
204
|
-
string; `class` and `attrs` (`{ 'aria-hidden': 'true' }`) set the rest of the root's attributes. `design check` fails an SVG asset with no root `<svg>` or without
|
|
205
|
-
`xmlns="http://www.w3.org/2000/svg"` (an `<img src>` and an image viewer do not draw it). The part hash behind `design check` and "changed outside a sketch" counts the bytes of
|
|
206
|
-
the assets a part uses.
|
|
207
|
-
|
|
208
|
-
Every change to a merged part goes through a sketch, also a small one: new copy, sample data, an
|
|
209
|
-
added state. When there is nothing to choose, the sketch has one variant (`--variants a`), and the
|
|
210
|
-
user merges it or comments on it. Never edit a merged part directly, or the user cannot compare or
|
|
211
|
-
comment on the change in Studio. `design check` warns, and Studio marks the part "changed", when a
|
|
212
|
-
merged part changed outside a sketch; only a merged sketch on that part clears it.
|
|
213
|
-
|
|
214
|
-
A sketch on a foundations part such as `foundations/tokens` keeps the part's overview drawing: the
|
|
215
|
-
variant adds its token group as a state, or extends that group's state. It never replaces the
|
|
216
|
-
drawing with a demo scene, since the merge would drop every other group. A demo may be an extra state.
|
|
217
|
-
|
|
218
|
-
Name the variant you work on with `--variant`. Studio marks it as drawing, and hides its frames,
|
|
219
|
-
while the latest report names it. `sketch new` starts no report, so `report --done` follows only a report
|
|
220
|
-
of your own; it prints the next steps. `sketch new`, `sketch variant` and each report record your
|
|
221
|
-
model id as an author of the variants they write, and `sketch ready` records it on every variant
|
|
222
|
-
that has no author yet. A merge adds the picked variant's authors to the `madeBy` the part file
|
|
223
|
-
already holds, and never removes it.
|
|
224
|
-
|
|
225
|
-
### Combine variants in a new round
|
|
226
|
-
|
|
227
|
-
Studio never combines variants. When the user asks for one in a comment ("solid like a, outline
|
|
228
|
-
like b"), draw it as a new variant in a new round:
|
|
229
|
-
|
|
230
|
-
```bash
|
|
231
|
-
et design sketch variant <layer>/<name> c --from a --by <model id> --round "Solid a, outline b" --note "r1 showed pill and square; the user wants a's solid with b's outline"
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
`--from` copies a variant into the new one, sets the sketch back to in progress and clears the
|
|
235
|
-
pick; it refuses while the decision is a discard (the user picks a variant first). Without `--round` the new variant joins the running round; with it, `--note` is required and
|
|
236
|
-
goes on the running round: what it showed and why its variants lost. Older variants stay pickable.
|
|
237
|
-
The command prints the notes of the previous round. Fix a round's title or note later with `sketch round <layer>/<name> <round> --title … --note … --by <model id>`; `sketch list` shows each sketch's rounds.
|
|
238
|
-
Letters continue across rounds (r1: a, b; r2: c, d). `sketch variant <layer>/<name> c,d --from a` adds
|
|
239
|
-
several variants at once; with `--round` they all start the new round. A new round answers the comments on the
|
|
240
|
-
`--from` variant and marks them "addressed in round" with the new round's key. A variant without `--round` fails while the sketch has open comments and lists them: a variant that answers a comment starts a new round. Draw the combined
|
|
241
|
-
variant and mark the sketch `ready` again. `sketch new --round <title> --note <text>` names
|
|
242
|
-
round 1 and sets its note; `--round` without `--note` fails. `sketch ready` refuses while the running round has no note; set it with `sketch round`.
|
|
243
|
-
`sketch ready` also shoots every state of every variant and of the product's part: when not one pixel differs
|
|
244
|
-
in any of them, it merges the sketch itself and logs it as an `auto` entry in the product's `accepted.json`
|
|
245
|
-
("No visible change in any state: merged automatically."). Any difference or failed shot leaves it `ready`.
|
|
246
|
-
A problem the product already had before the merge does not block it (the check prints it as a note); only a problem the merge adds does.
|
|
247
|
-
Run `sketch ready` again on a `ready` sketch to repeat the check and the auto merge.
|
|
248
|
-
|
|
249
|
-
Mark a sketch `ready` only when no change to it waits on anything: no open decision, no helper still to
|
|
250
|
-
land, no "once X is decided I adapt the sketch". A pending change keeps the sketch in work and out of the
|
|
251
|
-
merge queue: ask first, make the change, then mark it `ready`. Record the wait with
|
|
252
|
-
`et design sketch hold <layer>/<name> --until "<what it waits on>" --by <model id>` (a `ready` sketch goes back
|
|
253
|
-
in progress) and `sketch release` it once the change is in.
|
|
254
|
-
|
|
255
|
-
### Your model id: `--by`
|
|
256
|
-
|
|
257
|
-
Every command that writes takes `--by <model id>` and fails without it: `sketch new`, `variant`, `report`,
|
|
258
|
-
`ready`, `rebase`, `merge`, `discard`, `inbox done` and `comment reply`. The id is the exact model
|
|
259
|
-
id as free text, for example `claude-opus-5-5`, `gpt-6.1-sol` or `gemini-3-argon`. Studio shows it
|
|
260
|
-
on the variant, the reply and the part, so the user sees which model made what.
|
|
261
|
-
|
|
262
|
-
**Never guess your id.** Use the one your prompt names. If your prompt names none and you do not
|
|
263
|
-
know your own exact id, ask the coordinator or the user before you write.
|
|
264
|
-
|
|
265
|
-
### The user decides, Studio merges
|
|
266
|
-
|
|
267
|
-
The user picks a variant, or discards the sketch, in Studio. **Studio merges on the user's click.
|
|
268
|
-
Never run `sketch merge` or `sketch discard` yourself, and never pick a variant.** Both mark
|
|
269
|
-
the open comments on the sketch's variants addressed: the user's click answers them. Comments on the
|
|
270
|
-
product's parts stay. If a part the variant replaces changed
|
|
271
|
-
in the product since the sketch was created, the merge refuses: bring each variant up to date, run
|
|
272
|
-
`et design sketch rebase <layer>/<name>`, and mark it `ready` again. `sketch preview <layer>/<name>
|
|
273
|
-
<variant>` lists the elements and pages a merge changes. The note on a part records why it has its
|
|
274
|
-
current shape. The user's reason is optional: with one, the merge sets the note from it; without
|
|
275
|
-
one, the part keeps the `note` the picked variant file holds, so write that note while you draw.
|
|
276
|
-
|
|
277
|
-
After the user approves a direct edit of a merged part (no sketch), run `et design accept <layer>/<name> --product <p> --by <model id> --note <why>` so `design check` stops warning `changed outside a sketch`. Never accept an edit the user did not approve.
|
|
278
|
-
|
|
279
|
-
To drop a merged part the user no longer wants (folded back into its host, say), run `et design part remove <layer>/<name> --product <p> --by <model id>`: it deletes the folder, its `merged.json` entry and its tsconfig path, and resolves its comments. It refuses while another part imports it or an open sketch targets it. Never `git rm` a part by hand.
|
|
280
|
-
|
|
281
|
-
### Read the inbox
|
|
282
|
-
|
|
283
|
-
The user comments on a state of a part in Studio, at a point, or on a sketch variant. The sketch of
|
|
284
|
-
an element also shows each page that uses it, with each variant swapped in: a comment there names
|
|
285
|
-
the page as its part and the element's sketch variant, so change the variant, not the page.
|
|
286
|
-
|
|
287
|
-
```bash
|
|
288
|
-
et design inbox [--json] [--product <p>] # open comments and rebases, then what waits for the user
|
|
289
|
-
et design inbox done <id> --note <text> --by <model id> # set the part note, mark the thread addressed
|
|
290
|
-
et design comment reply <id> --by <model id> <text> [--question] # answer a comment thread (takes --product)
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
Read the inbox at the start of a session and after each sketch you mark `ready`. Answer a comment
|
|
294
|
-
by changing the sketch or the part, then `inbox done <id> --note "…"`. The note replaces the `note` of the part the comment was made on (for a sketch variant, the product's part), so write it to explain the whole shape of the part, and pass the old note unchanged when it still holds. `done` fails without `--note`; only the user withdraws a comment without one, in Studio. `done` also stores your `--by` where the comment sat: in the authors of the sketch variant, or in the `madeBy` of the part. A pick or discard decision is listed as waiting
|
|
295
|
-
for the user: Studio merges or discards on the user's click, so never run `sketch merge` after a pick.
|
|
296
|
-
|
|
297
|
-
A comment is a thread: the user and you both reply. When a comment is unclear, ask with
|
|
298
|
-
`comment reply --question` instead of guessing. The thread then moves to the "waiting for the user" group
|
|
299
|
-
(`waitingForUser` in `--json`) and returns to the inbox when the user answers. A thread there is
|
|
300
|
-
not work for you.
|
|
301
|
-
|
|
302
|
-
A thread has three states. **Open** waits for an answer. **Addressed** (`addressed`: who, when, why,
|
|
303
|
-
the round) means `inbox done`, a new round, a merge or a discard answered it: it leaves the inbox and
|
|
304
|
-
the check, Studio shows it with an "addressed" badge, and you may still `comment reply` on it to say
|
|
305
|
-
what you changed. A reply by the user opens it again. **Resolved** means the user closed it in Studio -
|
|
306
|
-
only the user resolves. The file stays so the user can look back at it; a reply or `done` on it fails.
|
|
307
|
-
|
|
308
|
-
Pass `--question` only when you cannot go on without the user's answer. Studio lists only those
|
|
309
|
-
threads under "Questions for you". A report of what you did is no question: reply without the
|
|
310
|
-
flag, and the thread shows as "answered" until the user withdraws it or replies.
|
|
311
|
-
|
|
312
|
-
### The `ethlete-design` MCP server
|
|
313
|
-
|
|
314
|
-
`ethlete-agents sync` registers `et design mcp` as `ethlete-design` in `.mcp.json` and
|
|
315
|
-
`.codex/config.toml` when `@ethlete/cli` is installed. When the tools are in your tool list, use them
|
|
316
|
-
instead of the CLI: each runs the `et design` command of the same name in the session's working
|
|
317
|
-
directory, takes its flags as arguments, and every write takes `by` (your model id). `product` may be
|
|
318
|
-
left out when the workspace has one. `shot` and `motion_shots` return the sheet image itself, so you
|
|
319
|
-
look at it without opening a PNG path.
|
|
320
|
-
|
|
321
|
-
- **Read:** `parts` (every part, as JSON), `call` (a call's `call.ts`, `fixture.ts`, the variant file to draw into and the frame URL; never change the fixture).
|
|
322
|
-
- **Check:** `check` (a product; with `call` and `variant` it lints, type-checks and renders that variant - run it after every edit of a variant), `sketch_check` (each variant laid over the product), `sketch_preview` (what a merge of a variant changes).
|
|
323
|
-
- **Shots:** `shot` (a part's states, `variants` for the open sketch), `motion_shots` (a motion at its keyframes, full and reduced, plus its tracks as JSON).
|
|
324
|
-
- **Sketch lifecycle:** `sketch_new`, `sketch_variant`, `sketch_round`, `sketch_report`, `sketch_ready`, `sketch_rebase`, `sketch_list`. `sketch_merge` and `sketch_discard` exist, but Studio runs them on the user's click; do not call them.
|
|
325
|
-
- **Comments:** `inbox` (what waits for you, then for the user), `comment_reply` (`question` waits for the user's answer), `inbox_done` (needs the new part `note`).
|
|
326
|
-
|
|
327
|
-
Part files are written with your own file tools; the server has no write tool for them. Call
|
|
328
|
-
`sketch_report` before every variant edit: it tells Studio what you build, and it moves a `ready`
|
|
329
|
-
sketch back to in progress, so call `sketch_ready` again when you are done. `sketch_ready` runs the
|
|
330
|
-
render check and refuses on any render issue; mark an element that renders wrong on purpose with
|
|
331
|
-
`data-et-skip="<rule>"`. A tool that fails returns the CLI's output; fix it and call again.
|
|
332
|
-
|
|
333
|
-
### Draw a flow
|
|
334
|
-
|
|
335
|
-
A flow joins states of pages into a path the user reads left to right in Studio's Flows view.
|
|
336
|
-
It is `<product>/flows/<name>.json`; `position` and `label` are optional:
|
|
337
|
-
|
|
338
|
-
```json
|
|
339
|
-
{
|
|
340
|
-
"frames": [{ "part": "pages/library", "state": "empty", "position": { "x": 0, "y": 0 } }],
|
|
341
|
-
"lines": [
|
|
342
|
-
{
|
|
343
|
-
"from": { "part": "pages/library", "state": "empty" },
|
|
344
|
-
"to": { "part": "pages/film-detail", "state": "default" },
|
|
345
|
-
"label": "user adds a film"
|
|
346
|
-
}
|
|
347
|
-
]
|
|
348
|
-
}
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
Every flow line is labelled, and the element the label names is visible in the frame before it: a line
|
|
352
|
-
labelled "user clicks 'Log in'" starts from a frame that shows a "Log in" button. A line that names
|
|
353
|
-
nothing the reader can see, or a label for a control the page lacks, is a defect.
|
|
354
|
-
|
|
355
|
-
A line may join two states of one page. A frame may name a page that exists only as an open sketch;
|
|
356
|
-
the flow then shows its first variant. Lines hold for every preset. Without `position`, Studio
|
|
357
|
-
lays the frames out along the lines.
|
|
358
|
-
|
|
359
|
-
### Draw a wireframe
|
|
360
|
-
|
|
361
|
-
A wireframe exists to iterate fast, in minutes per round, rough enough to redraw with a client at
|
|
362
|
-
the table. It answers one thing: which regions a screen has and what each region holds. These
|
|
363
|
-
rules are strict:
|
|
364
|
-
|
|
365
|
-
- **Keep what exists.** Before a sketch, list what the running app already does on that screen.
|
|
366
|
-
Keep it as a labelled box, and draw only what is still open.
|
|
367
|
-
- **One sketch per screen or flow**, never one per region or per detail. The variants differ in
|
|
368
|
-
layout: where the regions sit and how big they are.
|
|
369
|
-
- **Regions and names only.** A region is a box with a label; a list shows item names. Draw no
|
|
370
|
-
counts, badges, status markers, inspectors, size labels or field lists. If a detail matters,
|
|
371
|
-
write it as a word in the region label.
|
|
372
|
-
- **Never polish.** Do not fix alignment, spacing or a kit gap. When the kit lacks a shape, draw a
|
|
373
|
-
labelled box. Look at each shot only for a broken frame: overflow, a scroll bar, clipped text.
|
|
374
|
-
- **Draw it yourself.** A wireframe round is small work: no subagent, no friction report.
|
|
375
|
-
- **Stop early.** When the regions of the main screens are settled, the stage ends. Comments on
|
|
376
|
-
the look of a wireframe belong to the next stage, not to a new wireframe round.
|
|
377
|
-
|
|
378
|
-
A page may not import another page. To show a page inside a page ("in context"), embed it:
|
|
379
|
-
`embedPage('pages/system', { state, width, height, scale })` from `@design-system` answers a
|
|
380
|
-
drawing whose `body` is a frame of that page, drawn in the same product, sketch variant and theme
|
|
381
|
-
as the embedding frame. `width` and `height` are the viewport the page is drawn at (default
|
|
382
|
-
1280 x 800; `height: 'auto'` fits its content), `scale` shrinks the frame. Never rebuild a page
|
|
383
|
-
from its elements to show it.
|
|
384
|
-
|
|
385
|
-
A page that has no parts yet draws grey stand-ins from the wireframe kit; pages and elements may
|
|
386
|
-
import it, components and foundations may not:
|
|
387
|
-
|
|
388
|
-
```ts
|
|
389
|
-
import { box, heading, textLines, image, button, input, icon, select } from '@design-system/kit';
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
Signatures are in `libs/cli/design/wireframe-kit.ts`: `box(children, { direction, gap, padding, width, height, grow, plain, stackBelow, fill })`,
|
|
393
|
-
`heading(text, { size })`, `textLines({ lines, width, size })`, `image({ width, height, ratio })`,
|
|
394
|
-
`button(label, { primary })`, `input({ label, placeholder, width })`, `icon({ size, glyph })`,
|
|
395
|
-
`select({ label, value, width })`, `tabs(labels, { active })`, `segmented(options, { active })`,
|
|
396
|
-
`checkbox(label, { checked })`, `badge(text)` and `dot({ hollow, size })`. Draw a control as its
|
|
397
|
-
type: a picker is a `select`, a section switch `tabs`, a size switch `segmented`, a count a `badge`,
|
|
398
|
-
a status a `dot`, never a row of buttons or an empty `icon`. Give an icon a `glyph` (`'plus'`,
|
|
399
|
-
`'close'`, `'menu'`, `'more'`, …; another name draws its first letter). Give the root box of a page or a
|
|
400
|
-
shell `fill: true` so it is as tall as the frame, instead of a hand-written `min-height`. Draw for
|
|
401
|
-
every preset, not one width: give a picture a `ratio` (`'2/3'`) instead of a fixed height, and give
|
|
402
|
-
a row `stackBelow: <px>`, the width below which it stacks its children, instead of fixed widths
|
|
403
|
-
that only fit the desktop. Never use `vh`, `dvh` or `svh` in a part: a part has no viewport of its own, so the unit measures Studio's frame, not the page. A full page is a frame of a fixed size. Put titles in `heading`, never in hand-written markup. Studio lists such a page under
|
|
404
|
-
"Wireframes" with its kit-use count. A shell is a normal element named by purpose (`shell-main`); draw a rough one with the kit, so each
|
|
405
|
-
page imports the shell instead of repeating it, and a shell pick lands in one file.
|
|
406
|
-
A dialog without its own URL is an element that a page state shows ("login open"). Examples in
|
|
407
|
-
`.ethlete/design/studio-lab`: `pages/film-detail`, `elements/shell-main`, `elements/login-dialog`,
|
|
408
|
-
`flows/sign-in.json`.
|
|
409
|
-
|
|
410
|
-
### Check a product
|
|
411
|
-
|
|
412
|
-
```bash
|
|
413
|
-
et design check --product <name> # layer dependencies, hard-coded colours, undefined tokens, copied components, scripted motion, tsc (open sketch variants too), render
|
|
414
|
-
et design system --json # each part's origin, note, states, presets and problems
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
Without `--product`, `check` covers every product. A part may only use its own layer and the
|
|
418
|
-
layers below it (see "The order of a design"). Rule `FLOW` reports a misshaped flow file, a frame
|
|
419
|
-
naming a part or state that exists neither in the product nor in an open sketch of that part, a duplicate state, and a line to a state that is not a frame of
|
|
420
|
-
the flow. Rule `WIREFRAME-KIT` reports a component or foundation importing the kit. Pass the changed files to the check below as before.
|
|
421
|
-
|
|
422
|
-
Once the other rules pass, the check draws every state in a headless Chromium on a server of its own
|
|
423
|
-
(pages at each preset, a part with `widths` at each width, any other part fitted), and
|
|
424
|
-
`sketch check` does the same for the open variants and the pages they show in. Each line names
|
|
425
|
-
product, part, state, size and a selector path:
|
|
426
|
-
|
|
427
|
-
- `OVERFLOW` - the frame scrolls: content wider than the frame, or taller than a preset height.
|
|
428
|
-
- `CLIPPED` - an element with `overflow: hidden|clip` cuts its content, unless it sets
|
|
429
|
-
`text-overflow: ellipsis` or a line clamp.
|
|
430
|
-
- `WRAP` - text in a button, tab, badge, chip or `white-space: nowrap` box runs onto a second line.
|
|
431
|
-
- `ZERO-SIZE` - the part root has no width or no height.
|
|
432
|
-
- `UNKNOWN-THEME` - a `et-color--<name>` class names a colour theme no stylesheet of the frame defines, so it draws in the fallback colour.
|
|
433
|
-
- `RENDER` - the frame refused to draw, or the part did not load.
|
|
434
|
-
|
|
435
|
-
A `WARNING` line does not fail the check:
|
|
436
|
-
|
|
437
|
-
- `UNDEFINED-CLASS` - a class carries a prefix the product's part CSS uses (`st-`, not the SDK's
|
|
438
|
-
`et-`), but no stylesheet of the frame defines it. Named once, at the first part that draws it.
|
|
439
|
-
- `GRID-COVERAGE` - some `grid` rows fill every interaction column (`rest`, `hover`, `active`,
|
|
440
|
-
`focus-visible`, `disabled`) and others leave some out, so a state can break there unseen.
|
|
441
|
-
|
|
442
|
-
A part that breaks a rule on purpose names it: `definePart({ checks: { skip: ['CLIPPED'] }, … })`;
|
|
443
|
-
the skip covers the part wherever it is drawn. Without Playwright Chromium the check prints
|
|
444
|
-
`RENDER CHECK SKIPPED` and passes on the other rules.
|
|
445
|
-
|
|
446
|
-
A project's `config.json` entry can name `themes`, `{ "surface": [...], "color": [...] }`; a
|
|
447
|
-
frame asked for a theme gets the `et-surface--<name>` and `et-color--<name>` classes on its root,
|
|
448
|
-
so a drawing must take its colours from the theme tokens and never set a surface or colour class
|
|
449
|
-
on its own root. An inner panel may set `et-surface--<name>`.
|
|
450
|
-
|
|
451
|
-
`et design [checkout]` serves the frames; the checkout defaults to the working directory and
|
|
452
|
-
`DE_PORT` overrules the port. In the ethlete SDK the user reads Studio, started with `yarn studio`,
|
|
453
|
-
which serves the frames itself: do not start `yarn design` next to it. Studio carries its own copy
|
|
454
|
-
of the tool, so a checkout that installs nothing still draws.
|
|
455
|
-
|
|
456
|
-
Three constraints on a drawing file:
|
|
457
|
-
|
|
458
|
-
- **Never import a package barrel.** The libraries resolve to source, so one barrel makes the
|
|
459
|
-
browser request every module and the requests fail with `ERR_INSUFFICIENT_RESOURCES`. Import
|
|
460
|
-
the one file you need.
|
|
461
|
-
- **The fixture is shared, and a variant may not change it.**
|
|
462
|
-
- **One file per variant**, so a broken variant breaks its own frame only.
|
|
463
|
-
|
|
464
|
-
A `<script>` in a drawing never runs. For behavior give the drawing a `setup(root)` function
|
|
465
|
-
(called once after the markup is in `root`, no cleanup, wire one delegated listener). Render each
|
|
466
|
-
state of a prototype with `ngStates({ closed: …, open: … }, { imports })` and swap them with
|
|
467
|
-
`setup: flow.on([{ click: '.trigger', go: 'open' }])`. To draw an open overlay, open it in the
|
|
468
|
-
template (`<et-select [open]="true">`); `ng()` returns the real panel and the frame places it.
|
|
469
|
-
`ngStates` wraps the states in `<div data-de-states style="display: contents">`, so a selector
|
|
470
|
-
rule must not depend on that wrapper.
|
|
471
|
-
|
|
472
|
-
**A repository with a sketch Storybook** draws every variant in the **same** story, side by
|
|
473
|
-
side, under the real geometry the thing ships in. The default Storybook is
|
|
474
|
-
{%storybookUrl%}; an app with its own sketch Storybook names its port in the plan file.
|
|
475
|
-
|
|
476
|
-
Either way:
|
|
477
|
-
|
|
478
|
-
- Sketches take inputs only and stay out of the application's build.
|
|
479
|
-
- Prototype, never refactor. Do not touch the shipped component until the treatment is
|
|
480
|
-
settled.
|
|
481
|
-
- Keep the rejected variants drawn, marked as rejected.
|
|
482
|
-
|
|
483
|
-
### Notes
|
|
484
|
-
|
|
485
|
-
A note explains a state: why it looks this way, what it shows. A comment is feedback that needs
|
|
486
|
-
an answer. Write a note when nothing is asked of the reader.
|
|
487
|
-
|
|
488
|
-
A note is `<product>/notes/<timestamp>-<id>.json`:
|
|
489
|
-
|
|
490
|
-
```json
|
|
491
|
-
{ "part": "button", "state": "disabled", "point": { "x": 24, "y": 8 }, "size": "mobile", "text": "Muted, not hidden." }
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
- `part`, `state` and `text` are required. `point` is optional, in CSS pixels.
|
|
495
|
-
- `size` is required when `point` is set: the preset, the CSS pixel width, or `"fitted"` the note was written at. A
|
|
496
|
-
pointed note shows only at that size; a note without a point shows at every size.
|
|
497
|
-
- A free note on a flow is an entry in the `notes` array of `flows/<name>.json`:
|
|
498
|
-
`{ "id": "…", "text": "…", "at": { "x": 0, "y": -40 } }`. `at` is optional, the note's top-left
|
|
499
|
-
corner on the flow canvas, and may be negative.
|
|
500
|
-
|
|
501
|
-
## The order of a design
|
|
502
|
-
|
|
503
|
-
A product design runs in this order. Each stage settles in calls before the next starts, and
|
|
504
|
-
each stage draws with what the stages before it settled (the wireframes draw with the kit only):
|
|
505
|
-
|
|
506
|
-
1. **Wireframes**: early, rough concepts of the main flows (a legacy call with `mode: 'wireframe'`;
|
|
507
|
-
in a product, draw them with the wireframe kit, see "Draw a wireframe"). They show
|
|
508
|
-
which components the product needs, not how they look. The stage ends with an inventory in
|
|
509
|
-
the wireframe call: every part the wireframes need, each mapped to the SDK component it
|
|
510
|
-
starts from, or marked new with the component call that draws it. The inventory is the
|
|
511
|
-
queue of component calls:
|
|
512
|
-
|
|
513
|
-
```ts
|
|
514
|
-
inventory: [
|
|
515
|
-
{ part: 'Search field', sdk: 'et-input' },
|
|
516
|
-
{ part: 'Match card', new: true, call: 'tomflix/components/match-card' },
|
|
517
|
-
],
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
2. **Foundations**: colours, colour themes and surface themes (the project's `themes` in
|
|
521
|
-
`config.json`), plus the type scale, spacing and radius.
|
|
522
|
-
3. **Logo and CI**, if the project needs them.
|
|
523
|
-
4. **Components**, the inventory is their queue, from the SDK ones rendered with `ng()`, themed and set up for the project.
|
|
524
|
-
Each accepted one becomes a design-system entry.
|
|
525
|
-
5. **Larger elements**: the shell, the navigation, headers, lists, built from the entries.
|
|
526
|
-
6. **Pages**, built from the elements and the entries.
|
|
527
|
-
7. **The working prototype**: the pages joined with `ngStates` and `flow.on`.
|
|
528
|
-
|
|
529
|
-
Do not start a stage before the one above it is settled, and do not draw a page from parts that
|
|
530
|
-
are not in the design system. If the user asks for a later stage first, say which earlier stage
|
|
531
|
-
is missing, and draw that first.
|
|
532
|
-
|
|
533
|
-
The stages map onto the layers of a product: wireframes, foundations, components, elements, pages. A settled
|
|
534
|
-
Legacy call with a stage counts for that stage in this order.
|
|
535
|
-
|
|
536
|
-
A later stage can show that an earlier one is incomplete. If a page needs a part that the system
|
|
537
|
-
does not have, add it to the inventory. A part becomes a component only when at least two hosts
|
|
538
|
-
draw the same case. Until then it stays in the one element or page that draws it. When a second
|
|
539
|
-
host draws it, open a component sketch, and list in its brief every host and every case each one
|
|
540
|
-
draws, so the component covers them all.
|
|
541
|
-
|
|
542
|
-
A component documents its states per axis, not every combination: for example kind, end mark and
|
|
543
|
-
interaction (rest, hover, focus-visible, selected, inert), plus only the combinations that look
|
|
544
|
-
different. A smaller piece with no states of its own, such as an icon set, is a foundation asset,
|
|
545
|
-
not a component.
|
|
546
|
-
|
|
547
|
-
When each of several cases is drawn at rest and in the same interactions, build the states and their grid with
|
|
548
|
-
`interactionRows(rows, { interactions: ['hover', 'active'], force: (props, interaction) => ({ ...props, interaction }) })`
|
|
549
|
-
from `@design-system` and spread the result into `definePart`; never write those states and the grid by hand.
|
|
550
|
-
`sketch check` prints `grid <rows> x <columns> ok`, or the states the grid leaves out; a state in two cells
|
|
551
|
-
fails it as `GRID`, in `design check` too.
|
|
552
|
-
Interaction states (a state name whose last word is hover, focus, pressed, active or selected, such as `row-hover`) live only on a control
|
|
553
|
-
part, one whose `controls` declare a control of a checked kind. On a shell, element or page they fail as
|
|
554
|
-
`CONTROL-STATE`: declare the component's controls (Q164), or extract the button or row as its own control part and draw its states there.
|
|
555
|
-
A drawn `button`, `a[href]`, `input`, `select`, `textarea` or control role without `data-et-control` on it or around
|
|
556
|
-
it is `CONTROL-PART-INPUT`: no control check sees it. Wrap it in `control(markup, name)` from
|
|
557
|
-
`@ethlete/components/design/control` and declare the name in `controls`; a sketch fails on one it adds,
|
|
558
|
-
`design check` only warns of one a merged part already draws. On a reused control part's render,
|
|
559
|
-
`control(drawn.body, name)` renames its control: never string-replace `data-et-control`.
|
|
560
|
-
`definePart({ interactions })` forces an interaction on the part's root only. To draw one element of the part
|
|
561
|
-
hovered, focused, pressed or disabled, such as one row of a list, wrap that element's markup in
|
|
562
|
-
`forceInteraction(markup, 'hover')` from `@design-system` inside `render`, driven by a prop; never write
|
|
563
|
-
`data-et-force` by hand.
|
|
564
|
-
|
|
565
|
-
## Draw from the design system
|
|
566
|
-
|
|
567
|
-
A call that invents its own button, field or row does not match the calls beside it. **Before
|
|
568
|
-
you draw a part, look for it in this order, and draw new only when none of them has it:**
|
|
569
|
-
|
|
570
|
-
1. The product's design system, `.ethlete/design/<product>/` (and its base).
|
|
571
|
-
2. The real SDK components, rendered on the design server with `ng()` from `@design-explore`:
|
|
572
|
-
|
|
573
|
-
```ts
|
|
574
|
-
const field = await ng(`<et-form-field><et-label>Name</et-label><et-input /></et-form-field>`, {
|
|
575
|
-
imports: ['FORM_FIELD_IMPORTS', 'INPUT_IMPORTS'],
|
|
576
|
-
});
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
The template is a real Angular template, and `imports` names exports of
|
|
580
|
-
`@ethlete/components`. The project's `providers` module in `config.json` supplies the themes.
|
|
581
|
-
Render every component of a drawing in **one** `ng()` call: each call is a new app, so two
|
|
582
|
-
calls repeat element ids. The server renders the built package, so in the SDK rebuild
|
|
583
|
-
`dist` after a component change.
|
|
584
|
-
|
|
585
|
-
To draw a form state (a value, an error, a touched field), give `ng()` (or `ngStates()`)
|
|
586
|
-
`fields`. Each entry becomes a signal form field the template binds as
|
|
587
|
-
`[formField]="fields.<name>"`. An error is a kind (`'required'`) or a kind and a message. A
|
|
588
|
-
field shows its errors only when it is touched:
|
|
589
|
-
|
|
590
|
-
```ts
|
|
591
|
-
const form = await ng(
|
|
592
|
-
`<et-form-field><et-label>Email</et-label><et-input [formField]="fields.email" /></et-form-field>`,
|
|
593
|
-
{
|
|
594
|
-
imports: ['FORM_FIELD_IMPORTS', 'INPUT_IMPORTS'],
|
|
595
|
-
fields: { email: { value: 'ada@', errors: [{ kind: 'email', message: 'Not an email' }], touched: true } },
|
|
596
|
-
},
|
|
597
|
-
);
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
3. Only then a new drawing. Build it from the two above, and say in the variant's `claim`
|
|
601
|
-
that the part is new.
|
|
602
|
-
|
|
603
|
-
A part is one folder, `<product>/<layer>/<part>/`, with its drawing and states. Read the parts of
|
|
604
|
-
the product before the first drawing of a session. **A part exists only because the user picked a
|
|
605
|
-
sketch.** A `chosen` verdict in an old call is not enough. Never change a part's look without a
|
|
606
|
-
sketch the user decided.
|
|
85
|
+
## Hard rules for products and sketches
|
|
86
|
+
|
|
87
|
+
- A change to a merged part, also a small one, is a **sketch**; never edit a merged part directly. When
|
|
88
|
+
nothing is to choose, the sketch has one variant (`--variants a`). Variants are alternatives, never a state
|
|
89
|
+
of another variant. Two to four variants, each with its cost; run `sketch check` before `sketch ready`.
|
|
90
|
+
- **Never run `sketch merge` or `sketch discard`, and never pick a variant.** Studio merges on the user's
|
|
91
|
+
click. After a pick or discard, do not merge. Run `sketch reject` or `reopen` only when the user did.
|
|
92
|
+
- Mark a sketch `ready` only when no change to it waits on anything; otherwise `sketch hold`.
|
|
93
|
+
- Every write command takes `--by <model id>`. **Never guess your id**: use the one your prompt names, or ask
|
|
94
|
+
the coordinator or the user before you write.
|
|
95
|
+
- Run `et design accept` only after the user approved a direct edit. Remove a part only with
|
|
96
|
+
`et design part remove`, never `git rm`.
|
|
97
|
+
- Studio takes no new calls: never run `et design new`. New work goes to a product.
|
|
98
|
+
- Share code between variants in the sketch's `shared/` folder only; no shared parameter or branch for one
|
|
99
|
+
variant. An asset is one file in `<product>/assets/`, never inlined.
|
|
100
|
+
- A user comment to combine variants is a new variant in a new round (`sketch variant --from --round --note`).
|
|
101
|
+
- Read the inbox at the start of a session and after each `ready`. Answer with `inbox done <id> --note`,
|
|
102
|
+
ask with `comment reply --question` only when you cannot go on. Only the user resolves a thread.
|
|
103
|
+
- Use the `ethlete-design` MCP tools when they are in your tool list, and call `sketch_report` before every
|
|
104
|
+
variant edit.
|
|
105
|
+
- Draw from the design system, never invent a button or field: the product's parts, then SDK components via
|
|
106
|
+
`ng()`, then new. Colours come from the SDK theming systems, never your own tokens. A part exists only
|
|
107
|
+
because the user picked a sketch.
|
|
108
|
+
- A wireframe is rough and fast: regions and names only, no polish, no subagent, one sketch per screen.
|
|
109
|
+
- Do not start a design stage before the one above it is settled: wireframes, foundations, logo and CI,
|
|
110
|
+
components, elements, pages, prototype.
|
|
111
|
+
|
|
112
|
+
Details, commands and examples, read on demand:
|
|
113
|
+
|
|
114
|
+
- {%resource:reference-products-and-sketches.md%}: creating a product, every `sketch` command, shared code,
|
|
115
|
+
assets, rounds, `--by`, the merge and accept flow. Read before the first sketch command.
|
|
116
|
+
- {%resource:reference-inbox-and-mcp.md%}: reading and answering comments, thread states, the MCP tools.
|
|
117
|
+
- {%resource:reference-flows-and-wireframes.md%}: flow JSON, the wireframe kit and its rules.
|
|
118
|
+
- {%resource:reference-check-and-notes.md%}: `design check` rules and warnings, drawing-file constraints,
|
|
119
|
+
`setup`, `ngStates`, notes.
|
|
120
|
+
- {%resource:reference-order-and-design-system.md%}: the stage order, component states and
|
|
121
|
+
`interactionRows`, `ng()` and form fields, theming rules.
|
|
122
|
+
- {%resource:reference-shots.md%}: every `shot` flag, motion shots, the screenshot script.
|
|
607
123
|
|
|
608
124
|
## Check before you look
|
|
609
125
|
|
|
@@ -663,22 +179,6 @@ command." You know the id because you chose the model; the sub-agent does not, a
|
|
|
663
179
|
variant's `verdict` in an old call's `call.ts` (a product sketch needs none; the merge sets the note). It runs while you open
|
|
664
180
|
the next call.
|
|
665
181
|
|
|
666
|
-
## Screenshots
|
|
667
|
-
|
|
668
|
-
**Off by default.** The user has the call open and sends you a picture when something looks
|
|
669
|
-
wrong. Take one only when the code cannot tell you whether two variants really differ, and
|
|
670
|
-
never to put in front of the user. Copy {%resource:shoot-template.mjs%} to the repository
|
|
671
|
-
root.
|
|
672
|
-
|
|
673
|
-
```bash
|
|
674
|
-
node shoot.mjs <story-id> 1100 760 out.png
|
|
675
|
-
```
|
|
676
|
-
|
|
677
|
-
- `waitUntil: 'networkidle'` never settles on an iframe that holds a live dev server
|
|
678
|
-
connection. Use `'domcontentloaded'`.
|
|
679
|
-
- `:hover`, `:focus-visible` and `:active` need a CDP session and `CSS.forcePseudoState`.
|
|
680
|
-
Several hold open at once, so one image shows them all. The template does this.
|
|
681
|
-
|
|
682
182
|
## Writing it down
|
|
683
183
|
|
|
684
184
|
Every settled call goes in the exploration's plan file: what won, what lost, and why. Keep
|