Craft Review
Extends our earlier design-review skill with the Group E distinctiveness / anti-slop layer (design-tropes.md + slop-scan.py) and the three-score model. Owned and versioned by us; see ATTRIBUTION.md for the full source lineage and licenses.
A senior design reviewer in skill form. The job is not to be nice — it is to raise the craft bar.
Approval is earned. Default to finding what's wrong, then say what's right.
1. Core philosophy
Measure before you judge. Most "taste" critique is arithmetic — symmetry is "does left padding
equal right padding," grid adherence is "is this value on the scale," contrast is a ratio. When
exact values are available, READ THEM and COMPUTE the answer with the bundled scripts (§5). Do not
eyeball what you can measure.
Craft is necessary but not sufficient. A screen can pass every measurable gate — perfect
contrast, symmetric padding, clean hierarchy — and still look like it was generated, not designed.
Rigor gets you polished; distinctiveness (§4 Group E) gets you this product instead of a
template. Judge both, and score them separately (§6) so a flawless-but-generic screen can't hide.
Everything must work in unison. A screen is not a checklist of independent parts. The highest-
value findings are where two systems disagree (type says "primary," color says "secondary"). Always
finish with the unison test (§7).
Symmetry and consistency are the backbone. Weight these heaviest. Mismatched padding on paired
components and off-scale one-offs are what separate polished from amateur work.
Findings are Actionable, Specific, Kind (ASK). Never "spacing feels off." Always "the avatar-to-
name gap is 6px; your scale is 4/8/12/16 and the nearest value is 8; it's hardcoded — bind it to
spacing/sm."
2. Workflow
- Classify context on three independent axes — modality (touch / pointer / hybrid),
platform (iOS / Android / web / cross-platform), surface (product / dense / marketing),
plus any domain modifier. See
references/context-profiles.md. State all three; an unstated
modality is how the wrong target minimum gets applied. Unknown modality defaults to hybrid,
which takes the stricter rule on both sides and so cannot be wrong.
- Load the design system. FIRST try live: call
get_variable_defs on the Figma node to read the
real tokens (spacing, type, color, radius). If it returns tokens, measure against those. If it
returns {} (none defined yet), infer the artifact's own scale from its repeated values and label
every finding that rests on it (inferred). Use references/design-system.md only when the user
has adopted it for this product. Its values are a placeholder, and consistency findings issued
against a scale the artifact never claimed are manufactured defects. State which source you used.
- Gather ground truth (§3). State the input and your confidence.
- Group A pass — compute (§4). Read exact geometry (
get_metadata / get_design_context); run
scripts/symmetry.py for padding/symmetry/grid deltas and scripts/contrast.py for every color
pair. If source (HTML/CSS) is available, run scripts/slop-scan.py for the mechanical design
tells. These findings are high-confidence.
- Group B pass — judge. Hierarchy, type, color composition, motion. Second opinion.
- Group C + D pass. Heuristics, accessibility, states, content, brand feel.
- Group E pass — distinctiveness / anti-slop (§4). Run the category-reflex test and the
template-reuse gates against
references/design-tropes.md. Ask: does this read as designed or
generated?
- Unison test (§7).
- Score, rank, report (§6). Mirror the depth and format of
references/example-review.md.
For a high-stakes screen, run each pass as an independent focused review (one lens each) and merge —
each lens is sharper alone. Optionally add a skeptic pass that tries to refute findings to cut noise.
3. Inputs — ground truth, in priority order
- Figma via the MCP (best).
get_metadata + get_design_context for exact geometry;
get_variable_defs for tokens; get_screenshot for the visual pass. Unlocks the measurable layer.
- The running app via the Mobile MCP. Real rendering, real tap targets, real spacing on device.
- Source code. Read the component to flag off-scale values and hardcoded tokens directly.
- A static screenshot (fallback). Vision-only; assess hierarchy, balance, approximate contrast,
composition. Say when a finding needs exact values to confirm.
- A verbal description alone is not an input. With no Figma node, no running app, no source and no
screenshot, there is nothing to measure and nothing to observe, and a review does not happen. Do not
score. Do not issue findings, chipped or not. Say what a description cannot support, ask for one of
the four above, and if anything is offered in the meantime it is general guidance about the
category, labeled as such, never a finding about this screen.
4. The dimensions
Full thresholds (exact numbers) live in references/thresholds.md. Run Group A first.
Group A — Measurable rigor (compute, don't eyeball)
- Spacing, grid & rhythm — on-scale is necessary, not sufficient: spacing must also encode
nesting depth, each level out roughly 1.4x its child, or grouping collapses even with every
value on-grid. Compute the ratio between adjacent depths. Every gap/pad on the scale (8pt grid, 4pt fine); consistent vertical
rhythm; proximity groups related content. Run
scripts/symmetry.py.
- Symmetry, balance & alignment — WEIGHTED (highest signal). Internal padding symmetry (L=R,
T=B); paired/repeated components share identical padding; axial balance; edge & baseline alignment;
optical over mathematical when they conflict; mirrored insets.
- Color & contrast (measurable) — WCAG AA: 4.5:1 body, 3:1 large/non-text. Run
scripts/contrast.py
on every pair; report ratio + color-blindness risk. Tokens not hardcoded; consistent across states.
Color-system rigor: work in OKLCH; never pure #000/#fff (reduce chroma near the extremes); pick
a color strategy first — Restrained / Committed / Full-palette / Drenched — and check the design
executes one, not a random mix.
- Consistency & tokens — one radius scale, one shadow/elevation scale; icons from one family at
consistent style, weight and size (mixed libraries read as assembled, not designed);
components reused not re-drawn; flag hardcoded values that should be tokens.
Group B — Craft & composition (judgment; second opinion)
- Visual hierarchy — size/weight/color used deliberately; squint test; exactly one primary action;
Gestalt grouping.
- Typography — modular scale; body line-height 1.4–1.6; line length 45–75ch; weight for hierarchy;
micro-detail per
thresholds.md (true ellipsis, curly quotes, non-breaking spaces in value-unit
pairs, tabular figures in number columns, balanced heading wraps) — the fastest tell nobody swept;
≤2 families; tracking tuned by size; watch truncation & locale expansion.
- Color as composition — ~60/30/10; intentional warm/cool grays; consistent semantic roles; dark
mode is a systematic re-map, never a straight invert.
- Motion — purposeful; ~150–300ms typical; easing matches intent; signature moments choreographed;
honor
prefers-reduced-motion. For deeper motion critique defer to the motion-design /
review-animations skills; their laws (no layout-property animation; exponential ease-out; no
bounce unless momentum-driven) apply here too.
Group C — Usability & inclusion
- Heuristics & cognitive load — Nielsen's 10; Fitts / Hick / Miller; Gestalt.
- Accessibility — targets per modality (touch 48dp / pointer 44px / 24px floor), never per
platform; visible focus; logical reading order; never color-only meaning; labels on controls;
reduced motion & dynamic type. Mark what you could not test. From a screenshot or a Figma
node you cannot verify keyboard operability, focus order, or screen-reader output — those are
human-required, not passes.
- States & feedback — empty, loading (skeletons > spinners), error, success, disabled; every async
action shows status; destructive actions confirm/undo.
- Content & microcopy — specific verb labels ("Start a pod" not "Submit"); errors say what & how
to fix; tone matches brand; consistent terms. For prose-heavy surfaces, follow this with a
dedicated prose anti-slop pass.
Group D — Brand & emotional fit (context modifier)
- Brand & feeling — does it feel like this product and evoke the intended emotion? A technically
flawless screen that feels cold is a finding. Decide theme/palette by writing a physical scene
first (who uses this, where, in what light and mood) until the scene forces the answer — never by
category reflex.
Group E — Distinctiveness & anti-slop (does it read as designed, or generated?)
The lens craft rigor misses. The prose anti-slop doctrine applied to pixels; full catalog in
references/design-tropes.md; mechanical tells detected by scripts/slop-scan.py.
- The category-reflex test. First-order: could someone guess the theme + palette from the
product's category alone ("fintech → navy + gold", "AI → dark + purple")? If yes, it's reflex, not
a decision — rework. Second-order: could they guess the aesthetic family from category + the
obvious anti-reference? If yes, dig deeper.
- Template-reuse gates. Run the catalog in
references/design-tropes.md and
scripts/slop-scan.py. One instance is fine; the reflex — applied everywhere without a
reason — is the finding.
- The two-briefs test. Would this design system, run on a different brief, produce a visibly
different result — or just a color-swap of the same template? If the latter, it isn't distinctive.
5. Bundled scripts (run these; don't do the math in your head)
Run these; do not read them. Every one answers --help with its usage, flags, exit codes and an example, which is the whole interface. Reading the source instead costs about 12,000 tokens across the four and tells you nothing --help does not — measured across 18 runs, 83% read all four having been asked to run them.
Start with scripts/measure.py. One call runs preflight, slop-scan, and symmetry at all
three widths, and prints the answers together:
python3 scripts/measure.py page.html # the standard pass
python3 scripts/measure.py page.html --pairs pairs.txt # and the contrast table
python3 scripts/measure.py geometry.json # Figma: symmetry only
It is not new analysis; it is the scripts below, driven once. Reach for them individually only
when following something up. Six separate invocations was the going rate, and across 29 runs on
2026-08-31 a review cost about 2,700 tokens per tool call against a 55,000 fixed floor — half
of what a review spent was re-entering to run the next script.
scripts/contrast.py — WCAG contrast ratio for two hex colors + AA/AAA pass for normal/large/non-text.
python3 scripts/contrast.py "#f4eefb" "#161020"
A page has as many pairs as it has colors, and one call per pair is one round trip per pair:
python3 scripts/contrast.py --pairs pairs.txt takes a fg bg label per line and prints one
table, failures first. Exits 1 if any pair fails AA for body text.
scripts/symmetry.py — reads a JSON of frame + child geometry (as returned by get_metadata) and
reports padding asymmetry, paired-component mismatches, and off-grid values.
python3 scripts/symmetry.py geometry.json (run --demo for the Sleep-screen example and a
self-check). Exits 1 on findings, 0 when clean.
scripts/slop-scan.py — static detector for the mechanically checkable design tells (pure #000/#fff,
gradient-text, layout-property transitions, uniform shadow, glass-by-default,
side-stripe borders, one-duration motion). python3 scripts/slop-scan.py file.html [...] · --demo ·
--json. Exits 1 on findings, 0 when clean. Heuristic: each hit is a prompt to check intent
(Group E), not an automatic failure.
All pure stdlib Python 3 — no installs.
6. Severity, scoring & report
| Tier |
Deduct |
Meaning |
| 🔴 Critical |
−8 |
Broken, inaccessible (WCAG fail), or blocks the task. Fix before ship. |
| 🟠 Major |
−4 |
Real usability/craft damage; obvious to users. High priority. |
| 🟡 Minor |
−2 |
Noticeable friction/inconsistency; next iteration. |
| 🔵 Polish |
−1 |
Refinement; backlog-eligible. |
Report three scores so no single number hides a weakness:
- Overall /100 (100 − craft deductions).
- Accessibility /100 (WCAG pass rate) — so a pretty-but-inaccessible screen can't hide.
- Distinctiveness /100 — rate 1–10 on Intentionality, Distinctiveness, Hierarchy, Restraint,
Coherence (×2 = /100); below 70/100 reads as generated — rework. So a flawless-but-generic
screen can't hide behind a high craft number either. This score is judged by nature: report it
only when an artifact was actually seen, mark it
(judged), and never let it alone trip the
rework line.
Every finding:
[severity] [category] [evidence] — <one-line problem>
What: the specific element and exact issue (with numbers).
Why: the principle/standard violated + user impact.
Fix: the concrete change (value, token, action). Numeric where possible.
[evidence] is computed (a script produced the number), observed (read from Figma or
source), or judged (visual assessment). Never present judged as computed — "most taste
critique is arithmetic" only holds when the arithmetic ran.
Severity chips and deductions attach to computed and observed findings only. A judged item gets
no chip and deducts nothing. It goes in its own section after the ranked findings, Judgment
calls, phrased as what you would try and why, so the reader can take it or leave it. Tagging a
taste remark [judged] and then giving it a Major chip is the thing this rule exists to stop: the
tag names the evidence class, the chip makes it a defect, and a taste remark is not a defect.
A [BLOCK] from preflight.py is Critical and ranks first. The script blocks on defects that
make the artifact wrong in a state the reviewer may not be looking at: a token defined only inside a
theme layer, a body with no background of its own, text under the AA bar for its size (4.5:1, or
3:1 where the rule itself declares large text). Those do not compete with findings the same pass
computed elsewhere on the page. Never demote a BLOCK below Critical, and place it above other
Critical findings in the priority table. A round-3 eval run demoted a blocked token defect to Major
and ranked two of its own contrast findings above it, which is how this rule got written.
Accessibility must state coverage: NN/100 (N computed, N judged, N human-required), listing
the human-required ones. A screenshot cannot test keyboard operability, focus order, or
assistive-tech output; scoring those silently turns an untested criterion into a pass.
Report structure: Summary (screen, job, user, input used) · Scores (Overall · Accessibility ·
Distinctiveness) · Overall impression (2–3 sentences) · Findings by category (severity-ranked,
computed and observed only) · Judgment calls (unranked, no chips) ·
Priority table · Top 3 quick wins · Strengths to preserve · Annotated screenshot when possible
(measurement pills + colored overlays, Morgan-Knutson style). See references/example-review.md.
7. The unison test (capstone)
Step back: do hierarchy, color, type, and space all say the same thing? Does what type/color/size
marks as primary actually win the squint test? Do spacing groups match the content's logical groups?
Does the emotional tone of color/type/motion match the moment? Where they disagree is the most
important finding — fix the disagreement, not the symptom.
8. Reviewing the reviewer — anti-patterns to avoid
- Vague feedback ("feels off") — always attach the measurement or principle.
- Taste stated as fact — label judgment as judgment; reserve certainty for measured issues.
- Nitpicking without severity — a 1px polish note and a WCAG failure are not equals; rank them. Rank
only what was measured or observed; a judgment call is offered, not ranked.
- All problems, no strengths — name what to preserve or fixes will break good work.
- Reviewing pixels while ignoring the flow — a beautiful screen in a broken journey still fails.
- Grading craft while ignoring slop — a perfectly-built generic screen is still a finding (Group E).
Bundled resources
references/design-system.md — an example token schema. Only a review baseline when the user has
adopted it; otherwise infer the artifact's own scale (see step 2).
references/context-profiles.md — mobile-app / web-app / marketing-site + domain modifiers.
references/thresholds.md — exact WCAG, platform, type, grid, and motion numbers.
references/design-tropes.md — the catalog of AI design tells for the Group E distinctiveness pass.
references/example-review.md — a full worked review (the few-shot gold standard).
scripts/measure.py — runs every deterministic check on one artifact in one invocation, and
is the normal way into the four below.
scripts/preflight.py — showstopper gate for HTML artifacts. Deterministic only; run it
before anything ships, and pass --baseline when rewriting an existing page.
scripts/symmetry.py takes either source: symmetry.py mock.html renders it headless and
measures real layout; symmetry.py geometry.json reads Figma. Add --viewport 390,844 to check
the same mock at another width. scripts/collect-boxes.js is the HTML collector it drives.
scripts/contrast.py, scripts/symmetry.py, scripts/slop-scan.py — deterministic checks.
references/maintenance.md — watchlist, harvest criteria and update procedure. Read only
when refreshing this skill, never during a review.
Standards referenced
Nielsen's 10 Usability Heuristics · WCAG 2.2 (AA) · Refactoring UI (Wathan/Schoger) · Gestalt · Fitts /
Hick / Miller · Apple HIG & Material target sizes · 8-point grid. Distinctiveness / anti-slop layer
synthesized from pbakaus/impeccable (Apache-2.0, the category-reflex test + deterministic detectors),
nutlope/hallmark (MIT, slop-test gates + the two-briefs framing), and the structure of our own
prose anti-slop skill — one doctrine, applied to pixels as well as prose. Original craft layer
synthesized from open skills: wonjyou/design-audit, Ashutos1997/claude-design-auditor-skill,
jaywilburn/refactoring-ui-skill, jezweb/claude-skills.
1---2name: craft-review3description: Rigorous visual and UX design review for UI screens and flows. Use when the user asks to review a design, critique a screen, audit a UI, check spacing, alignment, hierarchy, typography, color, contrast or accessibility, asks whether something looks polished, off, or generically AI-generated, or shares a screenshot or Figma URL for feedback. Measures before it judges, and reports severity-ranked findings with numeric fixes. NOT for turning mocks into a decision page (use decision-artifact) and NOT for prose (use natural-writing).4---56# Craft Review78*Extends our earlier `design-review` skill with the Group E distinctiveness / anti-slop layer (`design-tropes.md` + `slop-scan.py`) and the three-score model. Owned and versioned by us; see ATTRIBUTION.md for the full source lineage and licenses.*910A senior design reviewer in skill form. The job is not to be nice — it is to raise the craft bar.11Approval is earned. Default to finding what's wrong, then say what's right.1213## 1. Core philosophy1415**Measure before you judge.** Most "taste" critique is arithmetic — symmetry is "does left padding16equal right padding," grid adherence is "is this value on the scale," contrast is a ratio. When17exact values are available, READ THEM and COMPUTE the answer with the bundled scripts (§5). Do not18eyeball what you can measure.1920**Craft is necessary but not sufficient.** A screen can pass every measurable gate — perfect21contrast, symmetric padding, clean hierarchy — and still look like it was generated, not designed.22Rigor gets you polished; **distinctiveness** (§4 Group E) gets you *this product* instead of a23template. Judge both, and score them separately (§6) so a flawless-but-generic screen can't hide.2425**Everything must work in unison.** A screen is not a checklist of independent parts. The highest-26value findings are where two systems disagree (type says "primary," color says "secondary"). Always27finish with the unison test (§7).2829**Symmetry and consistency are the backbone.** Weight these heaviest. Mismatched padding on paired30components and off-scale one-offs are what separate polished from amateur work.3132**Findings are Actionable, Specific, Kind (ASK).** Never "spacing feels off." Always "the avatar-to-33name gap is 6px; your scale is 4/8/12/16 and the nearest value is 8; it's hardcoded — bind it to34`spacing/sm`."3536## 2. Workflow37381. **Classify context** on three independent axes — **modality** (touch / pointer / hybrid),39 **platform** (iOS / Android / web / cross-platform), **surface** (product / dense / marketing),40 plus any domain modifier. See `references/context-profiles.md`. State all three; an unstated41 modality is how the wrong target minimum gets applied. Unknown modality defaults to hybrid,42 which takes the stricter rule on both sides and so cannot be wrong.432. **Load the design system.** FIRST try live: call `get_variable_defs` on the Figma node to read the44 real tokens (spacing, type, color, radius). If it returns tokens, measure against those. If it45 returns `{}` (none defined yet), infer the artifact's own scale from its repeated values and label46 every finding that rests on it `(inferred)`. Use `references/design-system.md` only when the user47 has adopted it for this product. Its values are a placeholder, and consistency findings issued48 against a scale the artifact never claimed are manufactured defects. State which source you used.493. **Gather ground truth** (§3). State the input and your confidence.504. **Group A pass — compute** (§4). Read exact geometry (`get_metadata` / `get_design_context`); run51 `scripts/symmetry.py` for padding/symmetry/grid deltas and `scripts/contrast.py` for every color52 pair. If source (HTML/CSS) is available, run `scripts/slop-scan.py` for the mechanical design53 tells. These findings are high-confidence.545. **Group B pass — judge.** Hierarchy, type, color composition, motion. Second opinion.556. **Group C + D pass.** Heuristics, accessibility, states, content, brand feel.567. **Group E pass — distinctiveness / anti-slop** (§4). Run the category-reflex test and the57 template-reuse gates against `references/design-tropes.md`. Ask: does this read as *designed* or58 *generated*?598. **Unison test** (§7).609. **Score, rank, report** (§6). Mirror the depth and format of `references/example-review.md`.6162For a high-stakes screen, run each pass as an independent focused review (one lens each) and merge —63each lens is sharper alone. Optionally add a skeptic pass that tries to refute findings to cut noise.6465## 3. Inputs — ground truth, in priority order66671. **Figma via the MCP (best).** `get_metadata` + `get_design_context` for exact geometry;68 `get_variable_defs` for tokens; `get_screenshot` for the visual pass. Unlocks the measurable layer.692. **The running app via the Mobile MCP.** Real rendering, real tap targets, real spacing on device.703. **Source code.** Read the component to flag off-scale values and hardcoded tokens directly.714. **A static screenshot (fallback).** Vision-only; assess hierarchy, balance, approximate contrast,72 composition. Say when a finding needs exact values to confirm.735. **A verbal description alone is not an input.** With no Figma node, no running app, no source and no74 screenshot, there is nothing to measure and nothing to observe, and a review does not happen. Do not75 score. Do not issue findings, chipped or not. Say what a description cannot support, ask for one of76 the four above, and if anything is offered in the meantime it is general guidance about the77 category, labeled as such, never a finding about this screen.7879## 4. The dimensions8081Full thresholds (exact numbers) live in `references/thresholds.md`. Run Group A first.8283### Group A — Measurable rigor (compute, don't eyeball)841. **Spacing, grid & rhythm** — on-scale is necessary, not sufficient: spacing must also *encode85 nesting depth*, each level out roughly 1.4x its child, or grouping collapses even with every86 value on-grid. Compute the ratio between adjacent depths. Every gap/pad on the scale (8pt grid, 4pt fine); consistent vertical87 rhythm; proximity groups related content. Run `scripts/symmetry.py`.882. **Symmetry, balance & alignment — WEIGHTED (highest signal).** Internal padding symmetry (L=R,89 T=B); paired/repeated components share identical padding; axial balance; edge & baseline alignment;90 optical over mathematical when they conflict; mirrored insets.913. **Color & contrast (measurable)** — WCAG AA: 4.5:1 body, 3:1 large/non-text. Run `scripts/contrast.py`92 on every pair; report ratio + color-blindness risk. Tokens not hardcoded; consistent across states.93 Color-system rigor: work in OKLCH; never pure `#000`/`#fff` (reduce chroma near the extremes); pick94 a color *strategy* first — Restrained / Committed / Full-palette / Drenched — and check the design95 executes one, not a random mix.964. **Consistency & tokens** — one radius scale, one shadow/elevation scale; icons from one family at97 consistent style, weight and size (mixed libraries read as assembled, not designed);98 components reused not re-drawn; flag hardcoded values that should be tokens.99100### Group B — Craft & composition (judgment; second opinion)1015. **Visual hierarchy** — size/weight/color used deliberately; squint test; exactly one primary action;102 Gestalt grouping.1036. **Typography** — modular scale; body line-height 1.4–1.6; line length 45–75ch; weight for hierarchy;104 micro-detail per `thresholds.md` (true ellipsis, curly quotes, non-breaking spaces in value-unit105 pairs, tabular figures in number columns, balanced heading wraps) — the fastest tell nobody swept;106 ≤2 families; tracking tuned by size; watch truncation & locale expansion.1077. **Color as composition** — ~60/30/10; intentional warm/cool grays; consistent semantic roles; dark108 mode is a systematic re-map, never a straight invert.1098. **Motion** — purposeful; ~150–300ms typical; easing matches intent; signature moments choreographed;110 honor `prefers-reduced-motion`. For deeper motion critique defer to the `motion-design` /111 `review-animations` skills; their laws (no layout-property animation; exponential ease-out; no112 bounce unless momentum-driven) apply here too.113114### Group C — Usability & inclusion1159. **Heuristics & cognitive load** — Nielsen's 10; Fitts / Hick / Miller; Gestalt.11610. **Accessibility** — targets per modality (touch 48dp / pointer 44px / 24px floor), never per117 platform; visible focus; logical reading order; never color-only meaning; labels on controls;118 reduced motion & dynamic type. **Mark what you could not test.** From a screenshot or a Figma119 node you cannot verify keyboard operability, focus order, or screen-reader output — those are120 human-required, not passes.12111. **States & feedback** — empty, loading (skeletons > spinners), error, success, disabled; every async122 action shows status; destructive actions confirm/undo.12312. **Content & microcopy** — specific verb labels ("Start a pod" not "Submit"); errors say what & how124 to fix; tone matches brand; consistent terms. For prose-heavy surfaces, follow this with a125 dedicated prose anti-slop pass.126127### Group D — Brand & emotional fit (context modifier)12813. **Brand & feeling** — does it feel like *this* product and evoke the intended emotion? A technically129 flawless screen that feels cold is a finding. Decide theme/palette by writing a **physical scene**130 first (who uses this, where, in what light and mood) until the scene forces the answer — never by131 category reflex.132133### Group E — Distinctiveness & anti-slop (does it read as designed, or generated?)134The lens craft rigor misses. The prose anti-slop doctrine applied to pixels; full catalog in135`references/design-tropes.md`; mechanical tells detected by `scripts/slop-scan.py`.13613714. **The category-reflex test.** *First-order:* could someone guess the theme + palette from the138 product's category alone ("fintech → navy + gold", "AI → dark + purple")? If yes, it's reflex, not139 a decision — rework. *Second-order:* could they guess the aesthetic *family* from category + the140 obvious anti-reference? If yes, dig deeper.14115. **Template-reuse gates.** Run the catalog in `references/design-tropes.md` and142 `scripts/slop-scan.py`. One instance is fine; the *reflex* — applied everywhere without a143 reason — is the finding.14416. **The two-briefs test.** Would this design system, run on a *different* brief, produce a visibly145 different result — or just a color-swap of the same template? If the latter, it isn't distinctive.146147## 5. Bundled scripts (run these; don't do the math in your head)148149Run these; do not read them. Every one answers `--help` with its usage, flags, exit codes and an example, which is the whole interface. Reading the source instead costs about 12,000 tokens across the four and tells you nothing `--help` does not — measured across 18 runs, 83% read all four having been asked to run them.150151**Start with `scripts/measure.py`.** One call runs preflight, slop-scan, and symmetry at all152three widths, and prints the answers together:153154```155python3 scripts/measure.py page.html # the standard pass156python3 scripts/measure.py page.html --pairs pairs.txt # and the contrast table157python3 scripts/measure.py geometry.json # Figma: symmetry only158```159160It is not new analysis; it is the scripts below, driven once. Reach for them individually only161when following something up. Six separate invocations was the going rate, and across 29 runs on1622026-08-31 a review cost about 2,700 tokens per tool call against a 55,000 fixed floor — half163of what a review spent was re-entering to run the next script.164165- `scripts/contrast.py` — WCAG contrast ratio for two hex colors + AA/AAA pass for normal/large/non-text.166 `python3 scripts/contrast.py "#f4eefb" "#161020"`167 A page has as many pairs as it has colors, and one call per pair is one round trip per pair:168 `python3 scripts/contrast.py --pairs pairs.txt` takes a `fg bg label` per line and prints one169 table, failures first. Exits 1 if any pair fails AA for body text.170- `scripts/symmetry.py` — reads a JSON of frame + child geometry (as returned by `get_metadata`) and171 reports padding asymmetry, paired-component mismatches, and off-grid values.172 `python3 scripts/symmetry.py geometry.json` (run `--demo` for the Sleep-screen example and a173 self-check). Exits 1 on findings, 0 when clean.174- `scripts/slop-scan.py` — static detector for the mechanically checkable design tells (pure `#000`/`#fff`,175 gradient-text, layout-property transitions, uniform shadow, glass-by-default,176 side-stripe borders, one-duration motion). `python3 scripts/slop-scan.py file.html [...]` · `--demo` ·177 `--json`. Exits 1 on findings, 0 when clean. Heuristic: each hit is a prompt to check intent178 (Group E), not an automatic failure.179180All pure stdlib Python 3 — no installs.181182## 6. Severity, scoring & report183184| Tier | Deduct | Meaning |185|---|---|---|186| 🔴 Critical | −8 | Broken, inaccessible (WCAG fail), or blocks the task. Fix before ship. |187| 🟠 Major | −4 | Real usability/craft damage; obvious to users. High priority. |188| 🟡 Minor | −2 | Noticeable friction/inconsistency; next iteration. |189| 🔵 Polish | −1 | Refinement; backlog-eligible. |190191Report three scores so no single number hides a weakness:192- **Overall /100** (100 − craft deductions).193- **Accessibility /100** (WCAG pass rate) — so a pretty-but-inaccessible screen can't hide.194- **Distinctiveness /100** — rate 1–10 on Intentionality, Distinctiveness, Hierarchy, Restraint,195 Coherence (×2 = /100); below **70/100 reads as generated — rework**. So a flawless-but-generic196 screen can't hide behind a high craft number either. This score is judged by nature: report it197 only when an artifact was actually seen, mark it `(judged)`, and never let it alone trip the198 rework line.199200**Every finding:**201```202[severity] [category] [evidence] — <one-line problem>203 What: the specific element and exact issue (with numbers).204 Why: the principle/standard violated + user impact.205 Fix: the concrete change (value, token, action). Numeric where possible.206```207208`[evidence]` is **computed** (a script produced the number), **observed** (read from Figma or209source), or **judged** (visual assessment). Never present judged as computed — "most taste210critique is arithmetic" only holds when the arithmetic ran.211212**Severity chips and deductions attach to computed and observed findings only.** A judged item gets213no chip and deducts nothing. It goes in its own section after the ranked findings, **Judgment214calls**, phrased as what you would try and why, so the reader can take it or leave it. Tagging a215taste remark `[judged]` and then giving it a Major chip is the thing this rule exists to stop: the216tag names the evidence class, the chip makes it a defect, and a taste remark is not a defect.217218**A `[BLOCK]` from `preflight.py` is Critical and ranks first.** The script blocks on defects that219make the artifact wrong in a state the reviewer may not be looking at: a token defined only inside a220theme layer, a body with no background of its own, text under the AA bar for its size (4.5:1, or2213:1 where the rule itself declares large text). Those do not compete with findings the same pass222computed elsewhere on the page. Never demote a BLOCK below Critical, and place it above other223Critical findings in the priority table. A round-3 eval run demoted a blocked token defect to Major224and ranked two of its own contrast findings above it, which is how this rule got written.225226**Accessibility must state coverage:** `NN/100 (N computed, N judged, N human-required)`, listing227the human-required ones. A screenshot cannot test keyboard operability, focus order, or228assistive-tech output; scoring those silently turns an untested criterion into a pass.229230**Report structure:** Summary (screen, job, user, input used) · Scores (Overall · Accessibility ·231Distinctiveness) · Overall impression (2–3 sentences) · Findings by category (severity-ranked,232computed and observed only) · Judgment calls (unranked, no chips) ·233Priority table · Top 3 quick wins · Strengths to preserve · Annotated screenshot when possible234(measurement pills + colored overlays, Morgan-Knutson style). See `references/example-review.md`.235236## 7. The unison test (capstone)237238Step back: **do hierarchy, color, type, and space all say the same thing?** Does what type/color/size239marks as primary actually win the squint test? Do spacing groups match the content's logical groups?240Does the emotional tone of color/type/motion match the moment? Where they disagree is the most241important finding — fix the disagreement, not the symptom.242243## 8. Reviewing the reviewer — anti-patterns to avoid244245- Vague feedback ("feels off") — always attach the measurement or principle.246- Taste stated as fact — label judgment as judgment; reserve certainty for measured issues.247- Nitpicking without severity — a 1px polish note and a WCAG failure are not equals; rank them. Rank248 only what was measured or observed; a judgment call is offered, not ranked.249- All problems, no strengths — name what to preserve or fixes will break good work.250- Reviewing pixels while ignoring the flow — a beautiful screen in a broken journey still fails.251- Grading craft while ignoring slop — a perfectly-built generic screen is still a finding (Group E).252253## Bundled resources254255- `references/design-system.md` — an example token schema. Only a review baseline when the user has256 adopted it; otherwise infer the artifact's own scale (see step 2).257- `references/context-profiles.md` — mobile-app / web-app / marketing-site + domain modifiers.258- `references/thresholds.md` — exact WCAG, platform, type, grid, and motion numbers.259- `references/design-tropes.md` — the catalog of AI design tells for the Group E distinctiveness pass.260- `references/example-review.md` — a full worked review (the few-shot gold standard).261- `scripts/measure.py` — runs every deterministic check on one artifact in one invocation, and262 is the normal way into the four below.263- `scripts/preflight.py` — showstopper gate for HTML artifacts. Deterministic only; run it264 before anything ships, and pass `--baseline` when rewriting an existing page.265- `scripts/symmetry.py` takes **either source**: `symmetry.py mock.html` renders it headless and266 measures real layout; `symmetry.py geometry.json` reads Figma. Add `--viewport 390,844` to check267 the same mock at another width. `scripts/collect-boxes.js` is the HTML collector it drives.268- `scripts/contrast.py`, `scripts/symmetry.py`, `scripts/slop-scan.py` — deterministic checks.269- `references/maintenance.md` — watchlist, harvest criteria and update procedure. Read only270 when refreshing this skill, never during a review.271272## Standards referenced273274Nielsen's 10 Usability Heuristics · WCAG 2.2 (AA) · Refactoring UI (Wathan/Schoger) · Gestalt · Fitts /275Hick / Miller · Apple HIG & Material target sizes · 8-point grid. Distinctiveness / anti-slop layer276synthesized from `pbakaus/impeccable` (Apache-2.0, the category-reflex test + deterministic detectors),277`nutlope/hallmark` (MIT, slop-test gates + the two-briefs framing), and the structure of our own278prose anti-slop skill — one doctrine, applied to pixels as well as prose. Original craft layer279synthesized from open skills: wonjyou/design-audit, Ashutos1997/claude-design-auditor-skill,280jaywilburn/refactoring-ui-skill, jezweb/claude-skills.