jig-ui 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/README.md +221 -5
- package/dist/index.js +449 -57
- package/package.json +2 -2
- package/rules/00-anti-patterns.md +101 -0
- package/rules/01-modes.md +1 -1
- package/rules/03-patterns.md +34 -0
- package/rules.index.json +105 -0
- package/templates/COMMAND.md.tmpl +242 -14
- package/templates/command-metadata.json +5 -0
|
@@ -6,7 +6,7 @@ these, say so, list them, and stop.
|
|
|
6
6
|
|
|
7
7
|
There are two kinds of subcommand, and they are not run the same way.
|
|
8
8
|
|
|
9
|
-
**CLI-backed** — `install`, `update`, `init`, `check`, `explain`, `verdicts`, `gate`, `probe`. Run the
|
|
9
|
+
**CLI-backed** — `install`, `update`, `init`, `check`, `explain`, `verdicts`, `gate`, `probe`, `seo`. Run the
|
|
10
10
|
matching command with `{{scripts_path}}`, passing the flags through unchanged,
|
|
11
11
|
then do the work below for that subcommand. Read the command's full output —
|
|
12
12
|
findings are ordered by severity, not position, so `head`, `tail`, `grep` and
|
|
@@ -218,6 +218,33 @@ Read `DECISIONS.md` before asking anything. Do not re-ask what it already record
|
|
|
218
218
|
cite it instead. If the screen touches an item in its **Unresolved** section, ask the user
|
|
219
219
|
about it by name; do not settle it in the spec.
|
|
220
220
|
|
|
221
|
+
### 0. If the page already exists, describe it before you change anything
|
|
222
|
+
|
|
223
|
+
An existing page is specified from what is there, not redesigned on the way past.
|
|
224
|
+
Read the page and its stylesheet, render it at each size the spec will name, and
|
|
225
|
+
write the frontmatter from what you find: the regions in their real order, the
|
|
226
|
+
hierarchy as built, the navigation at each width. Then ask the user the questions
|
|
227
|
+
below only where the page does not answer them — what it is for, who arrives, what
|
|
228
|
+
is deferred — and show them the description to confirm or correct.
|
|
229
|
+
|
|
230
|
+
Two things this is not. It is not a redesign: a region you would have arranged
|
|
231
|
+
differently is still recorded as it is, and `critique` is where that argument
|
|
232
|
+
belongs, with the rules behind it. And it is not a rubber stamp: a page that
|
|
233
|
+
contradicts `DECISIONS.md` is described accurately and the contradiction noted in
|
|
234
|
+
the prose, because the spec is a record of what is, and the review is what says
|
|
235
|
+
whether that is right.
|
|
236
|
+
|
|
237
|
+
**Asked to redesign it instead, run this command normally.** The difference is
|
|
238
|
+
what the old page counts as: its content is the brief — the copy, the real data,
|
|
239
|
+
the questions its FAQ answers — and its structure is not. Decide the composition
|
|
240
|
+
from the rules and the answers, not from what the markup happens to do now, or
|
|
241
|
+
the redesign is the same page in new colours. Anything that genuinely must
|
|
242
|
+
survive is a constraint and belongs in the spec by name: a URL linked from
|
|
243
|
+
elsewhere, a field order the back end depends on, wording somebody signed off.
|
|
244
|
+
Ask which of those exist; do not assume the whole page is one.
|
|
245
|
+
|
|
246
|
+
The commands after this run unchanged.
|
|
247
|
+
|
|
221
248
|
### 1. Ask, two or three questions at a time
|
|
222
249
|
|
|
223
250
|
**This is a required interaction, not a suggestion.** Ask two or three questions,
|
|
@@ -231,9 +258,17 @@ settled at `init` and live in `{{config_file}}` and the token layer; re-deciding
|
|
|
231
258
|
them per screen creates a second source of truth for the values Jig exists to
|
|
232
259
|
centralise. If the user raises appearance, record it and move on.
|
|
233
260
|
|
|
261
|
+
**Every question carries an example answer**, for the same reason `decide`'s do: a
|
|
262
|
+
question someone has to decode gets a worse answer than one they can react to, and
|
|
263
|
+
the example shows the shape. Say it is an example, not a suggestion.
|
|
264
|
+
|
|
234
265
|
- Round 1 — what is it for? What does the user need to do there ("create an
|
|
235
266
|
invoice")? Who arrives, and what is the single most important thing they must be
|
|
236
267
|
able to see or do?
|
|
268
|
+
> *For example: "comprehension first, sign-up second. They arrive from the
|
|
269
|
+
> product page having already decided to try it, so no explainer above the
|
|
270
|
+
> cards. The most important thing is the limits — the price matters equally and
|
|
271
|
+
> must never dominate."*
|
|
237
272
|
- **Then scope it — be a pessimist.** Of everything this could include,
|
|
238
273
|
what is the smallest version that is useful on its own? Ask that plainly and
|
|
239
274
|
expect to cut. "Comments with attachments, mentions, reactions, editing,
|
|
@@ -242,11 +277,20 @@ centralise. If the user raises appearance, record it and move on.
|
|
|
242
277
|
forgotten. Everything after this designs V1 only.
|
|
243
278
|
- Round 2 — what content and states does it carry? Empty, loading, error,
|
|
244
279
|
first-run, and the realistic range (0 items, 5, 500)?
|
|
280
|
+
> *For example: "three plans, a monthly/annual choice, four FAQ questions, a
|
|
281
|
+
> footer. The billing choice is the only state — the page is static, nothing
|
|
282
|
+
> loads, nothing fails."*
|
|
245
283
|
- Round 3 — only what is still unresolved: entry points, where it leads, what
|
|
246
284
|
must not happen here.
|
|
285
|
+
> *For example: "they arrive from the product page or a docs search, and every
|
|
286
|
+
> plan goes straight to sign-up. Nothing on this page may ask for a sales
|
|
287
|
+
> call."*
|
|
247
288
|
|
|
248
289
|
**Ask about the phone by name.** What does the reader see first on a phone, and
|
|
249
|
-
what moves, stacks, or goes behind a control?
|
|
290
|
+
what moves, stacks, or goes behind a control?
|
|
291
|
+
> *For example: "the plans come first on the phone" — that is the answer this
|
|
292
|
+
> question wants, and everything else about the narrow composition is the
|
|
293
|
+
> system's to settle.* If the conversation only ever
|
|
250
294
|
describes the wide screen, the phone composition will be derived from it rather
|
|
251
295
|
than designed — and a derived phone composition is a squeezed desktop.
|
|
252
296
|
|
|
@@ -296,9 +340,15 @@ sizes: # phone first. Each size is a whole composition, not
|
|
|
296
340
|
grouping: { form: proximity, brand: common region }
|
|
297
341
|
grid: { columns: 12, form: 5, brand: 6 }
|
|
298
342
|
nav: none on this screen
|
|
343
|
+
wide: # judged at 1600px — where a layout with no upper bound shows itself
|
|
344
|
+
same-as: desktop
|
|
345
|
+
why: "content is capped at 1200px, so 1600 adds margin and nothing else"
|
|
299
346
|
states: [default, loading, error, success]
|
|
300
347
|
decisions: [The Engineer Reads First] # every DECISIONS.md entry this screen implements, by name
|
|
301
348
|
later: [social sign-in, remember this device] # cut from V1, by name — the next specs start here
|
|
349
|
+
indexable: true # from the mode — editorial yes, product/operator no. Say why when you override it.
|
|
350
|
+
title: "Pricing — Hoistline" # ≤ 60 characters, the search result's first line
|
|
351
|
+
description: "Three plans, every price visible. No sales call." # ≤ 155
|
|
302
352
|
mockup: pending # `mockup` sets approved or skipped, from the user's own words
|
|
303
353
|
mockup_at: # where the approved drawing is: a .jig/mockups path, or a Figma or Stitch link
|
|
304
354
|
deviations: [] # `make` writes here; `spec` leaves it empty
|
|
@@ -307,6 +357,24 @@ deviations: [] # `make` writes here; `spec` leaves it empty
|
|
|
307
357
|
|
|
308
358
|
- **`phone` is written first, and in full.** It is the most common screen, and the
|
|
309
359
|
one a derived composition fails on worst.
|
|
360
|
+
- **`indexable:`, `title:` and `description:` are copy, decided here.** The mode
|
|
361
|
+
sets the default — `editorial` is first-visit content and is indexable,
|
|
362
|
+
`product` and `operator` are what somebody reaches after signing in and are
|
|
363
|
+
not — and a page overrides it with a reason: a CV shared by link, a
|
|
364
|
+
confirmation page, a page that exists for one recipient. A page that is not
|
|
365
|
+
indexable needs no title or description here and must carry `noindex` when
|
|
366
|
+
built (`J-123`).
|
|
367
|
+
- **`wide` is required too, and is where an unbounded layout shows itself.** A
|
|
368
|
+
page judged only to 1280 never reveals that its content has no cap: at 1600 a
|
|
369
|
+
three-column grid becomes four thin ones, a header's logo and nav drift apart,
|
|
370
|
+
and a line of prose runs past its measure (`B-11`). `same-as: desktop` with a
|
|
371
|
+
`why:` is the right answer for a page that caps its content — and saying so is
|
|
372
|
+
the point.
|
|
373
|
+
- **`landscape` is optional, judged at 900px.** Write it only when the
|
|
374
|
+
composition genuinely changes between tablet and desktop — a navigation that
|
|
375
|
+
expands there, a grid that goes three to two. Most pages do not, and a size
|
|
376
|
+
written to be written costs a composition, a frame, a render and a row of
|
|
377
|
+
verdicts on every page afterwards.
|
|
310
378
|
- **`tablet` and `desktop` are written in full too.** `same-as: <size>` is allowed
|
|
311
379
|
when nothing changes, but only with `why:`. It is a claim that the composition
|
|
312
380
|
holds at that width — `critique` checks it on a render — not a way to leave the
|
|
@@ -433,7 +501,7 @@ before drawing. Do not switch to HTML on their behalf; offer it, and let them
|
|
|
433
501
|
choose.
|
|
434
502
|
|
|
435
503
|
- **Drawing in Figma.** One page named for the feature, one frame per size at the
|
|
436
|
-
spec's widths — 360, 768, 1280 — phone first. Grey fills and strokes only; no
|
|
504
|
+
spec's widths — 360, 768, 1280, 1600 — phone first. Grey fills and strokes only; no
|
|
437
505
|
library components, styles or variables from the product's design system, for
|
|
438
506
|
the same reason the HTML carries no tokens.
|
|
439
507
|
- **Drawing in Stitch.** Ask for a low-fidelity grayscale wireframe of this one
|
|
@@ -488,7 +556,7 @@ look. So the drawing contains:
|
|
|
488
556
|
what goes there. An icon is its name in brackets: `[search]`.
|
|
489
557
|
- **Real words, not lorem ipsum.** Labels, headings and button text are part of the
|
|
490
558
|
structure — "Create invoice" versus "Submit" is a decision worth reviewing.
|
|
491
|
-
- **Every size the spec names, as its own frame** — phone, then tablet, then desktop,
|
|
559
|
+
- **Every size the spec names, as its own frame** — phone, then tablet, then desktop, then wide,
|
|
492
560
|
stacked top to bottom, each drawn with its own markup. Size is structure, not
|
|
493
561
|
detail: a phone composition that is only the desktop one narrower is the failure
|
|
494
562
|
specs are written per size to prevent. A `same-as:` size is drawn anyway, so the
|
|
@@ -515,6 +583,8 @@ look. So the drawing contains:
|
|
|
515
583
|
.frame[data-size="phone"] { width: 360px; }
|
|
516
584
|
.frame[data-size="tablet"] { width: 768px; }
|
|
517
585
|
.frame[data-size="desktop"] { width: 1280px; }
|
|
586
|
+
.frame[data-size="wide"] { width: 1600px; }
|
|
587
|
+
.frame[data-size="landscape"] { width: 900px; }
|
|
518
588
|
.region { border: 1px dashed #aaa; padding: 12px; margin: 0 0 12px; }
|
|
519
589
|
.region > .name { display: block; font-size: 12px; color: #777; margin: 0 0 8px; }
|
|
520
590
|
.media { background: #ddd; color: #555; display: grid; place-items: center; min-height: 120px; }
|
|
@@ -654,6 +724,12 @@ describe the content accurately? Only when nothing fits is a generic container
|
|
|
654
724
|
right. The page must read as what it is with the stylesheet off, in an order
|
|
655
725
|
that makes sense; CSS then arranges it, and never the reverse.
|
|
656
726
|
|
|
727
|
+
**Write the metadata in this change, not the next one** (`J-120`). The title,
|
|
728
|
+
description and preview text are copy: they come from the spec, they are written
|
|
729
|
+
by whoever wrote the headline, and they move when it moves. A page that is not
|
|
730
|
+
indexable carries `noindex` instead, from its own metadata rather than from
|
|
731
|
+
`robots.txt`, which is public and advisory and protects nothing.
|
|
732
|
+
|
|
657
733
|
Then the ordinary rules apply: tokens by semantic name, the relevant
|
|
658
734
|
`03-patterns.md` section for each component, `05-copy.md` for every string.
|
|
659
735
|
|
|
@@ -688,7 +764,7 @@ one. A report with no `JIG_CHECK:` line, or one you typed yourself, is not a fin
|
|
|
688
764
|
build.
|
|
689
765
|
|
|
690
766
|
**2. The build matches the approved mockup at each size.** Skip only when
|
|
691
|
-
`mockup: skipped`. Render the page at 360px, 768px and
|
|
767
|
+
`mockup: skipped`. Render the page at 360px, 768px, 1280px and 1600px — with a browser, not in
|
|
692
768
|
your head — and set each render beside the mockup at the same width. Go region by
|
|
693
769
|
region, in the mockup's order:
|
|
694
770
|
|
|
@@ -755,7 +831,9 @@ conversation that built the page. Running them in one head anchors them to each
|
|
|
755
831
|
other; do not shortcut it for cost, speed or context size.
|
|
756
832
|
|
|
757
833
|
- **A — the reader.** Delegate to a subagent. Give it the URL or file, the spec,
|
|
758
|
-
the approved mockup (from `mockup_at:`), `DECISIONS.md`, and the corpus. It
|
|
834
|
+
the approved mockup (from `mockup_at:`), `DECISIONS.md`, and the corpus. It also
|
|
835
|
+
judges every decision in `DECISIONS.md` against the page and writes
|
|
836
|
+
`decisions.json` (step 1c). It judges the `pass: screen` rules against the render, **and the `P-` patterns the spec's regions use** — a navigation region means `P-14`. Those patterns are not in `rules.index.json`, so walking the index alone never reaches them. It writes its verdicts to `.jig/critique/<surface>/screen.json` (step 1c). Do
|
|
759
837
|
**not** give it the build conversation. If it needs that conversation, it is
|
|
760
838
|
not reviewing the page, it is agreeing with itself.
|
|
761
839
|
- **B — the machine.** Run `check`. Deterministic, same input same output. It
|
|
@@ -850,9 +928,9 @@ Each reader arm writes its own file. The arm reports back only that it wrote it.
|
|
|
850
928
|
```json
|
|
851
929
|
{
|
|
852
930
|
"rendered": true,
|
|
853
|
-
"artefacts": [".jig/critique/pricing/360.png", ".jig/critique/pricing/768.png", ".jig/critique/pricing/1280.png"],
|
|
931
|
+
"artefacts": [".jig/critique/pricing/360.png", ".jig/critique/pricing/768.png", ".jig/critique/pricing/1280.png", ".jig/critique/pricing/1600.png"],
|
|
854
932
|
"verdicts": [
|
|
855
|
-
{ "id": "D-115", "verdict": "ok", "reason": "no sideways scroll at 360, 768 or
|
|
933
|
+
{ "id": "D-115", "verdict": "ok", "reason": "no sideways scroll at 360, 768, 1280 or 1600" },
|
|
856
934
|
{ "id": "P-14", "verdict": "finding", "reason": "menu button at 360 does not open; aria-expanded never set" },
|
|
857
935
|
{ "id": "A-60", "verdict": "n/a", "reason": "A-60 is about competing icons; this page has none" }
|
|
858
936
|
]
|
|
@@ -861,7 +939,28 @@ Each reader arm writes its own file. The arm reports back only that it wrote it.
|
|
|
861
939
|
|
|
862
940
|
`screen.json` carries `rendered` and `artefacts`; `code.json` needs only `verdicts`.
|
|
863
941
|
|
|
864
|
-
**
|
|
942
|
+
**And the project's own decisions, one verdict each**, in
|
|
943
|
+
`.jig/critique/<surface>/decisions.json`:
|
|
944
|
+
|
|
945
|
+
```json
|
|
946
|
+
{
|
|
947
|
+
"verdicts": [
|
|
948
|
+
{ "decision": "Voice", "verdict": "finding", "reason": "headings and buttons are Title Case; the decision says lowercase" },
|
|
949
|
+
{ "decision": "Trial and onboarding", "verdict": "finding", "reason": "Team and Scale say \"start free trial\"; the trial was replaced by the free Solo plan" },
|
|
950
|
+
{ "decision": "Navigation", "verdict": "ok", "reason": "menu button top right at 360, five links at 768 and above" }
|
|
951
|
+
]
|
|
952
|
+
}
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
Every `##` and `###` heading in `DECISIONS.md` is a decision and gets exactly one
|
|
956
|
+
verdict, judged against the built page. `Unresolved` is not a decision. The rules
|
|
957
|
+
are the system's; these are the project's, and a page can satisfy all 115 rules
|
|
958
|
+
while breaking the file written to hold what this project chose. In a live round
|
|
959
|
+
one page shipped "start free trial" two commands after the owner had killed
|
|
960
|
+
trials, and another used Title Case against a lowercase decision. Both passed
|
|
961
|
+
every rule.
|
|
962
|
+
|
|
963
|
+
**A rendered review is measured, not only described.** At 360, 768, 1280 and 1600px, run the
|
|
865
964
|
probe in the browser and save what it returns beside the verdicts:
|
|
866
965
|
|
|
867
966
|
```
|
|
@@ -927,17 +1026,30 @@ source and imagining the page is not a render.
|
|
|
927
1026
|
that works: in a live run four of six pages shipped a phone menu that did not open,
|
|
928
1027
|
or no menu at all, and every review that only looked passed them.
|
|
929
1028
|
- **Render at every size the spec names** — phone at 360px, tablet at 768px,
|
|
930
|
-
desktop at 1280px — and judge each size's fields against its own render. A
|
|
1029
|
+
desktop at 1280px, wide at 1600px — and judge each size's fields against its own render. A
|
|
931
1030
|
`same-as:` claim is checked like any other field: render that size and see
|
|
932
1031
|
whether the composition really does hold.
|
|
933
1032
|
- At every size, measure `document.documentElement.scrollWidth` against
|
|
934
1033
|
`clientWidth`. Greater means the page scrolls sideways at that width, which is a
|
|
935
1034
|
finding however good the rest of it looks.
|
|
1035
|
+
- **Judge the collapse, not only the sizes** (`L-01` step 6). Between one width
|
|
1036
|
+
and the next: did the column count drop rather than the columns shrink, did the
|
|
1037
|
+
reading order hold, did an emphasised item stay distinguishable once everything
|
|
1038
|
+
was in one column, did anything genuinely wider scroll inside itself rather
|
|
1039
|
+
than taking the page with it?
|
|
936
1040
|
- Compare the sizes. Did the phone change the **composition**, or only the
|
|
937
1041
|
**dimensions**? Reordering, stacking, collapsing, a different control — that is
|
|
938
1042
|
composition. The same layout with smaller numbers is not.
|
|
939
1043
|
- Check the page is styled at all. A stylesheet that 404s renders a page that
|
|
940
1044
|
passes every file-based check ever written.
|
|
1045
|
+
- **Read what a stranger meets first** (`J-120`). Open the head: does the title
|
|
1046
|
+
still describe this page, does the description still say what the page now
|
|
1047
|
+
says, and would either have survived the last copy change? A page whose
|
|
1048
|
+
metadata contradicts its own headline is the commonest drift there is, because
|
|
1049
|
+
a copy pass reads pages and nobody reads the head. Run `{{scripts_path}} seo`
|
|
1050
|
+
for what one page cannot see: a route that says `noindex` and sits in the
|
|
1051
|
+
sitemap, two pages claiming the same title, a site with neither sitemap nor
|
|
1052
|
+
robots.
|
|
941
1053
|
- **Read the markup as a document, not a layout** (`H-119`). For each region:
|
|
942
1054
|
does its element say what the content is? Would the page still read correctly
|
|
943
1055
|
with the stylesheet off, in this order? A row of links that is not a `<nav>`, a
|
|
@@ -984,10 +1096,10 @@ preserve while fixing them.
|
|
|
984
1096
|
Then the attestation:
|
|
985
1097
|
|
|
986
1098
|
```text
|
|
987
|
-
JIG_CRITIQUE: version=<version> mode=<mode> surface=<name> spec=<confirmed|missing|unconfirmed> mockup=<approved|skipped|missing> rendered=<yes|no> screen=<ran|skipped>:<n> code=<ran|skipped>:<n> mechanical=<pass|fail|skipped>:<n> warnings=<n>
|
|
1099
|
+
JIG_CRITIQUE: version=<version> mode=<mode> surface=<name> spec=<confirmed|missing|unconfirmed> mockup=<approved|skipped|missing> rendered=<yes|no> screen=<ran|skipped>:<n> code=<ran|skipped>:<n> decisions=<ran|incomplete|missing>:<n> mechanical=<pass|fail|skipped>:<n> warnings=<n>
|
|
988
1100
|
```
|
|
989
1101
|
|
|
990
|
-
**Take `screen=`, `code=` and `rendered=` from `jig verdicts`, never from your own
|
|
1102
|
+
**Take `screen=`, `code=`, `decisions=` and `rendered=` from `jig verdicts`, never from your own
|
|
991
1103
|
count.** If it reported an arm incomplete, that arm is `skipped` here with the reason,
|
|
992
1104
|
until it is re-run and passes.
|
|
993
1105
|
|
|
@@ -1042,6 +1154,22 @@ Run `{{scripts_path}} probe`. It prints one JavaScript expression — the render
|
|
|
1042
1154
|
for the critique's screen arm to evaluate in a browser at each width. See step 1c of
|
|
1043
1155
|
`critique`. It changes nothing on its own.
|
|
1044
1156
|
|
|
1157
|
+
## seo
|
|
1158
|
+
|
|
1159
|
+
Run `{{scripts_path}} seo` and report what it says. It needs no `DECISIONS.md`,
|
|
1160
|
+
no spec and no confirmation: it reads what the project already serves, so it is
|
|
1161
|
+
safe to run on the first day and on somebody else's codebase. It audits the whole project,
|
|
1162
|
+
which is what one file cannot: a route whose metadata says `noindex` sitting in
|
|
1163
|
+
the sitemap, two pages claiming the same title, indexable pages with no sitemap,
|
|
1164
|
+
a sitemap that lists nothing.
|
|
1165
|
+
|
|
1166
|
+
It is not a phase. The per-page half belongs where the copy is decided and
|
|
1167
|
+
written — `spec` records whether a page is indexable and what it claims, `make`
|
|
1168
|
+
writes the metadata in the same change as the headline, `check` enforces the
|
|
1169
|
+
budgets — because a pass you run afterwards is a pass that gets skipped on the
|
|
1170
|
+
day the copy changes, which is exactly how a live site ended up serving
|
|
1171
|
+
positioning it had already dropped.
|
|
1172
|
+
|
|
1045
1173
|
## gate
|
|
1046
1174
|
|
|
1047
1175
|
Not a command to run. In Claude Code, `install` adds a Stop hook that runs
|
|
@@ -1072,7 +1200,10 @@ wherever `brand` in `{{config_file}}` puts the token files.
|
|
|
1072
1200
|
|
|
1073
1201
|
`spec`, `mockup`, `make` and `critique` are blocked until this exists: `spec` and
|
|
1074
1202
|
`critique` refuse to start without it, and `mockup` and `make` need a confirmed spec.
|
|
1075
|
-
Nothing else is blocked — `install`, `init`, `check`
|
|
1203
|
+
Nothing else is blocked — `install`, `init`, `check`, `explain`, `seo`, `probe`
|
|
1204
|
+
and `verdicts` all run without it. `seo` in particular is an audit of what is
|
|
1205
|
+
already there, and a project with no decisions yet still has a sitemap that
|
|
1206
|
+
either contradicts its pages or does not.
|
|
1076
1207
|
`init` comes first, because this file sits beside the token files `init` writes.
|
|
1077
1208
|
|
|
1078
1209
|
### What belongs in it, and what does not
|
|
@@ -1116,14 +1247,87 @@ at all. If the design system has a position, it is in the rules; if it has none,
|
|
|
1116
1247
|
you are looking for is the places where this project has already chosen
|
|
1117
1248
|
something, or will have to:
|
|
1118
1249
|
|
|
1250
|
+
**Ask every question with an example answer attached.** A question someone has to
|
|
1251
|
+
decode gets a worse answer than one they can react to, and the example shows the
|
|
1252
|
+
shape you need — a sentence about this product, not an adjective. Say plainly
|
|
1253
|
+
that it is an example, not a suggestion.
|
|
1254
|
+
|
|
1119
1255
|
- Round 1 — what is this product, and who is it for in a sentence the team would
|
|
1120
1256
|
recognise? What should it never look like? Name real products, not adjectives.
|
|
1257
|
+
> *For example: "hosted log search — you point it at your cluster and ask in
|
|
1258
|
+
> plain text. For a backend engineer who has tried grep over SSH. It must never
|
|
1259
|
+
> look like an enterprise console: no SKU matrix, no 'contact us' pricing.
|
|
1260
|
+
> Closer to Fly.io than to a Datadog dashboard."*
|
|
1261
|
+
- Round 1b — **what the product is for, and what you give up for it.** This file
|
|
1262
|
+
is project-wide, so both answers are about the product, not a page. A page's
|
|
1263
|
+
own purpose is `spec`'s question, and it inherits its direction from here.
|
|
1264
|
+
- *"If this product works, what can someone do that they could not before?"*
|
|
1265
|
+
That is the north star: one outcome, in the product's own words, that every
|
|
1266
|
+
later argument is settled against. A design direction without one drifts
|
|
1267
|
+
screen by screen, each change defensible on its own.
|
|
1268
|
+
> *For example: "an engineer finds the line in their logs without learning a
|
|
1269
|
+
> query language" — not "be the best log tool", which no screen can serve or
|
|
1270
|
+
> fail. The test: could you look at a design and say whether it moves toward
|
|
1271
|
+
> that sentence?*
|
|
1272
|
+
- *"When two good options conflict here, which side do you take?"* Fast over
|
|
1273
|
+
complete, plain over clever, fewer choices over more, density over comfort.
|
|
1274
|
+
> *For example: "comprehension wins over persuasion — if the clearer page
|
|
1275
|
+
> converts worse, we ship the clearer page", or "recovery wins over speed:
|
|
1276
|
+
> every destructive action is undoable, even where that costs a step".*
|
|
1277
|
+
Jig's own tiebreakers settle the system's conflicts; this settles the
|
|
1278
|
+
project's, and without it the agent settles them alone. In a live run a
|
|
1279
|
+
decision about where the accent may appear collided with a component rule
|
|
1280
|
+
and the agent resolved it on its own, correctly as it happens, and recorded
|
|
1281
|
+
the collision as a deviation. One line here would have decided it.
|
|
1282
|
+
|
|
1283
|
+
**Refuse an adjective, ask again.** "Bold", "human", "trustworthy" and
|
|
1284
|
+
"premium" cannot be checked against a page, and every decision in this file is
|
|
1285
|
+
now judged against one. Push for the form that can: what it is closer to, what
|
|
1286
|
+
it would rather be than, what it refuses.
|
|
1287
|
+
- Round 1c — **the personality, asked through the four things that produce it.**
|
|
1288
|
+
Every interface has one whether it was chosen or not, and it is not a mood
|
|
1289
|
+
board: it is decided by type, colour, corners and language, each of which is a
|
|
1290
|
+
value this project is about to set. Ask about all four, one question each, and
|
|
1291
|
+
say what each answer will become.
|
|
1292
|
+
- **Type.** Serif reads classic or editorial; a rounded sans reads friendly; a
|
|
1293
|
+
neutral sans stays out of the way and lets everything else carry the
|
|
1294
|
+
personality. Which is this? *(Becomes `--font-text` and `--font-display`.)*
|
|
1295
|
+
- **Colour.** Which colour is this product's, and what does it mean here? The
|
|
1296
|
+
psychology matters less than the reason: blue is familiar and safe, gold
|
|
1297
|
+
reads expensive, pink reads unserious. *(Becomes `--color-brand`, and the
|
|
1298
|
+
contrast floors still apply — a palette that fails them is not a
|
|
1299
|
+
personality.)*
|
|
1300
|
+
- **Corners.** Square reads formal or technical, a small radius is neutral,
|
|
1301
|
+
a large one reads playful. One answer for the whole interface: mixing square
|
|
1302
|
+
and round in one screen looks worse than either. *(Becomes the `--radius-*`
|
|
1303
|
+
scale.)*
|
|
1304
|
+
- **Language.** Official and impersonal, or plain and conversational? Words
|
|
1305
|
+
appear in every screen, so this decides more of the personality than any
|
|
1306
|
+
single visual choice. *(Becomes a voice decision here, applied by
|
|
1307
|
+
`05-copy.md`.)*
|
|
1308
|
+
> *For example: "neutral sans — the type should disappear. One colour, a muted
|
|
1309
|
+
> olive, because it is the one thing on the page that is not a plan or a price.
|
|
1310
|
+
> Square corners; this is a tool, not a toy. Lowercase and technical: ingest,
|
|
1311
|
+
> retention, seat — plain words, undefined, no throat-clearing."*
|
|
1312
|
+
|
|
1313
|
+
**When they have no gut feeling, ask what the reader already uses.** The sites
|
|
1314
|
+
this audience spends its day in set the expectation; matching that is cheaper
|
|
1315
|
+
than teaching a new one. Take the direction, never the design: a project that
|
|
1316
|
+
borrows from a direct competitor looks like a second-rate version of it, which
|
|
1317
|
+
is also `A-01`'s point about invented decoration seen from the other side.
|
|
1121
1318
|
- Round 2 — for each thing the tokens already set, is there a rule about *how* it
|
|
1122
1319
|
is used? Where does the brand colour go, and where is it forbidden? What earns
|
|
1123
1320
|
emphasis?
|
|
1321
|
+
> *For example: "the accent appears exactly twice per page, both clickable —
|
|
1322
|
+
> the primary action and the active side of a control. Never on a checkmark, a
|
|
1323
|
+
> limit number or a feature list. Emphasis is earned by the one thing the
|
|
1324
|
+
> reader came to do."*
|
|
1124
1325
|
- Round 3 — what has the team already argued about, or reversed? A decision with
|
|
1125
1326
|
a history is the one most worth recording, because it is the one most likely to
|
|
1126
1327
|
be re-made wrongly.
|
|
1328
|
+
> *For example: "we shipped a 'most popular' badge for six weeks. Conversion
|
|
1329
|
+
> rose slightly; wrong-plan signups and support tickets rose more. We pulled
|
|
1330
|
+
> it, and that covers the effect, not the widget — no raised card either."*
|
|
1127
1331
|
|
|
1128
1332
|
**All three rounds run.** Do not write the file after round 2 because the answers
|
|
1129
1333
|
look complete. Round 3 asks for the one kind of decision a user does not volunteer
|
|
@@ -1132,7 +1336,10 @@ reason. In the arm that did ask, round 3 is where the unresolved items surfaced.
|
|
|
1132
1336
|
|
|
1133
1337
|
**Round 3 also asks, by name, what is still undecided.** "Is there anything the team
|
|
1134
1338
|
has not settled yet — something still argued about, or waiting on someone?" Ask it
|
|
1135
|
-
even when nothing so far suggests there is.
|
|
1339
|
+
even when nothing so far suggests there is.
|
|
1340
|
+
> *For example: "whether we publish a public status page. It is between showing
|
|
1341
|
+
> uptime on the pricing page and not mentioning it at all, and it waits on
|
|
1342
|
+
> whether support can staff it."* Whatever the answer names goes in the
|
|
1136
1343
|
**Unresolved** section below, not into a decision the user did not make. Four of six
|
|
1137
1344
|
files in a live run dropped the one open item the owner had named.
|
|
1138
1345
|
|
|
@@ -1154,6 +1361,27 @@ wrong.
|
|
|
1154
1361
|
A name gives the team something to cite in review. A reason lets a future agent
|
|
1155
1362
|
tell when the rule does not apply, which a bare instruction never can.
|
|
1156
1363
|
|
|
1364
|
+
**The north star and the tiebreaker are decisions like any other**, written with
|
|
1365
|
+
the same shape and judged against every page:
|
|
1366
|
+
|
|
1367
|
+
```markdown
|
|
1368
|
+
### What this page is for
|
|
1369
|
+
|
|
1370
|
+
A reader leaves knowing which plan fits them and which limit they would hit
|
|
1371
|
+
first. Nothing else on the page outranks that.
|
|
1372
|
+
|
|
1373
|
+
**Why:** they arrive from the product page already interested; the job is to
|
|
1374
|
+
remove the last doubt, not to sell again.
|
|
1375
|
+
|
|
1376
|
+
### When two options conflict
|
|
1377
|
+
|
|
1378
|
+
Comprehension wins over persuasion. If a clearer page converts worse, we ship
|
|
1379
|
+
the clearer page.
|
|
1380
|
+
|
|
1381
|
+
**Why:** the reader is an engineer who has been sold to badly before, and the
|
|
1382
|
+
support cost of a wrong-plan signup outweighs the signup.
|
|
1383
|
+
```
|
|
1384
|
+
|
|
1157
1385
|
**The reason is the owner's, or it is not written.** Write the `Why:` the user gave,
|
|
1158
1386
|
in their words or close to them. If they gave none, ask for it. If they still give
|
|
1159
1387
|
none, write `**Why:** not given` — never a reason you supplied. A live run invented
|
|
@@ -24,6 +24,11 @@
|
|
|
24
24
|
"argumentHint": "[--all] [--ci] [--json]",
|
|
25
25
|
"status": "available"
|
|
26
26
|
},
|
|
27
|
+
"seo": {
|
|
28
|
+
"description": "Audit what a search engine and a link preview read, across the whole project: a noindex route in the sitemap, two pages with one title, indexable pages with no sitemap, a sitemap that lists nothing. The per-page half lives in spec, make and check.",
|
|
29
|
+
"argumentHint": "[--json]",
|
|
30
|
+
"status": "available"
|
|
31
|
+
},
|
|
27
32
|
"verdicts": {
|
|
28
33
|
"description": "Verify a critique's verdict files: every rule in each pass judged once, no id that does not exist, no rule in the wrong arm, rendered only with a screenshot. Computes the counts the critique reports, so the agent never writes them.",
|
|
29
34
|
"argumentHint": "<surface>",
|