qualia-framework 4.4.0 → 4.5.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.
@@ -0,0 +1,153 @@
1
+ # Design Rubric
2
+
3
+ Anchored 1-5 scoring across 8 dimensions. Used by the verifier agent to score frontend phases. Used by `/qualia-polish --critique` for read-only audits.
4
+
5
+ ## How to score
6
+
7
+ Every dimension is scored 1-5 with EVIDENCE on the next line. Score without evidence is rejected.
8
+
9
+ Anchored definitions:
10
+ - **1** — Fails. Hard violation. WCAG fails, broken layout, absolute-ban hit.
11
+ - **2** — Below acceptable. Functions but signals "AI generated this."
12
+ - **3** — Acceptable. Ships. Not memorable, not embarrassing.
13
+ - **4** — Good. Specific choices visible. A designer would approve.
14
+ - **5** — Excellent. Distinctive. Worth screenshotting and sharing.
15
+
16
+ **Default to 3.** Only score above 3 if you can cite a specific design principle the work excels at. Only score below 3 if you can quote evidence of a violation.
17
+
18
+ If a vision model is critiquing screenshots, it must score against this rubric. Without anchoring, vision models say "looks great!" to everything.
19
+
20
+ ## Scope guard
21
+
22
+ Score only what is scope-relevant. A `/qualia-polish src/components/Button.tsx` review scores Typography, Color, States, Motion, Microcopy. Skip Layout Originality and Container Depth — they're component-internal concerns at most.
23
+
24
+ A whole-app `/qualia-polish` scores all 8 dimensions across multiple representative routes.
25
+
26
+ ## The 8 dimensions
27
+
28
+ ### 1. Typography
29
+
30
+ | Score | Criteria |
31
+ |---|---|
32
+ | 1 | Inter / Roboto / Arial / system-ui / Space Grotesk as primary. Or single weight throughout. |
33
+ | 2 | Project font loaded but only one weight, no scale, no letter-spacing variation. |
34
+ | 3 | Project font with 2-3 weights, basic scale (h1/h2/body), readable. |
35
+ | 4 | Distinctive display + refined body pair. Letter-spacing varied semantically (tight headlines, open labels). Tabular numerals on numeric data. |
36
+ | 5 | Variable font with axis-driven weight/optical-size. Hierarchy through weight + scale + letter-spacing combined. Line lengths capped at 65-75ch. |
37
+
38
+ Evidence format: `font-family: "<name>" used at line N, scale 14/16/24/40 visible, weights 400/500/700`
39
+
40
+ ### 2. Color cohesion
41
+
42
+ | Score | Criteria |
43
+ |---|---|
44
+ | 1 | Hex values scattered in JSX. No CSS variables. Pure `#000` or `#fff`. |
45
+ | 2 | CSS variables defined but unused (raw hex still appears). RGB used. |
46
+ | 3 | All colors as CSS variables. Tinted neutrals (no pure black/white). One color strategy implied. |
47
+ | 4 | OKLCH throughout. Strategy explicit (Restrained / Committed / Full / Drenched). WCAG AA verified. |
48
+ | 5 | OKLCH with documented strategy. Chroma reduced at extremes. Brand-tinted shadows. APCA contrast verified for dense text. |
49
+
50
+ Evidence: count of CSS custom properties for color, presence of OKLCH, evidence of strategy commitment
51
+
52
+ ### 3. Spatial rhythm
53
+
54
+ | Score | Criteria |
55
+ |---|---|
56
+ | 1 | Arbitrary px values everywhere. No system. |
57
+ | 2 | 8px grid roughly followed. Same padding everywhere. |
58
+ | 3 | 8px grid consistently. Tight within groups, generous between sections. |
59
+ | 4 | Fluid `clamp()` padding. Spacing varies by content type. Vertical rhythm identifiable. |
60
+ | 5 | Spatial system reads as composed — different spacing for different relationships. Generous negative space. Asymmetry where intentional. |
61
+
62
+ Evidence: presence of spacing tokens, padding values divisible by 4, `clamp()` usage
63
+
64
+ ### 4. Layout originality
65
+
66
+ | Score | Criteria |
67
+ |---|---|
68
+ | 1 | Three-column feature grid in section 2. Card grid of 3 identical items. Centered hero with gradient. |
69
+ | 2 | Standard hero + sections + footer. Symmetric throughout. |
70
+ | 3 | Some layout variation across sections. No card monotony. |
71
+ | 4 | Asymmetry, full-bleed, varied component sizes within a section. Negative space used. |
72
+ | 5 | Layout reads as composed by a designer. Diagonal flow, overlap, scale contrast. Each section a different shape. |
73
+
74
+ Evidence: file:line references showing layout choices
75
+
76
+ ### 5. Shadow & depth hierarchy
77
+
78
+ | Score | Criteria |
79
+ |---|---|
80
+ | 1 | Single shadow value applied to everything (or no shadows). Nested cards. |
81
+ | 2 | 2 shadow levels but applied inconsistently. |
82
+ | 3 | 3 elevation levels (subtle / medium / pronounced). Brand-tinted, not pure gray. |
83
+ | 4 | Shadows match elevation semantically. Different shadow for hover than rest. |
84
+ | 5 | Multi-layer shadows (offset + ambient + directional). Brand-hue tinted at chroma 0.02-0.04. Spatial logic clear. |
85
+
86
+ Evidence: count of distinct `box-shadow` values, OKLCH chroma in shadow color
87
+
88
+ ### 6. Motion intent
89
+
90
+ | Score | Criteria |
91
+ |---|---|
92
+ | 1 | No transitions. Or: bounce/elastic everywhere. Animates layout properties. |
93
+ | 2 | Default browser transitions on hover. No stagger. |
94
+ | 3 | Considered transitions on interactive elements. Respects `prefers-reduced-motion`. |
95
+ | 4 | One signature motion identified and executed. Stagger on entrance. Easing curves chosen (ease-out-quart or expo). |
96
+ | 5 | Orchestrated motion that communicates structure. Scroll-driven if appropriate. Restraint elsewhere. |
97
+
98
+ Evidence: easing curves used, presence of `prefers-reduced-motion`, file:line of signature motion
99
+
100
+ ### 7. Microcopy specificity
101
+
102
+ | Score | Criteria |
103
+ |---|---|
104
+ | 1 | "Get Started" / "Learn More" / "Welcome to <product>" / "Click here". Lorem ipsum. |
105
+ | 2 | Generic but functional ("Save", "Cancel", "Submit"). Empty states say "No results." |
106
+ | 3 | Action-named CTAs ("Download invoice"). Empty states with one-sentence context. |
107
+ | 4 | Voice consistent with brand. Errors specific and actionable ("This file is 12MB; max is 10MB. Compress and retry."). |
108
+ | 5 | Microcopy you'd quote. Voice unmistakable. Every word earned. |
109
+
110
+ Evidence: grep for banned phrases, sample of empty/error states
111
+
112
+ ### 8. Container depth & nesting
113
+
114
+ | Score | Criteria |
115
+ |---|---|
116
+ | 1 | Card → panel → pill → content (depth ≥ 4). Side-stripe borders. Gradient text. |
117
+ | 2 | Card-on-card pattern (depth 3). Most things wrapped in containers. |
118
+ | 3 | Container depth ≤ 2. No decorative side-stripes. |
119
+ | 4 | Containers used semantically only. Things that don't need a container don't have one. |
120
+ | 5 | Layout reads as elements arranged on a surface, not boxes inside boxes. |
121
+
122
+ Evidence: max DOM nesting depth on cards/panels, grep for `border-left` decorative usage
123
+
124
+ ## Aggregate score
125
+
126
+ ```
127
+ total = sum of dimension scores (max 40)
128
+ average = total / count_of_scored_dimensions
129
+ phase_pass = ALL scored dimensions ≥ 3
130
+ phase_fail = ANY scored dimension < 3
131
+ ```
132
+
133
+ A phase fails if any dimension is below 3. Same gate as functional verification.
134
+
135
+ ## Output format (verifier agent contract)
136
+
137
+ ```markdown
138
+ ## Design Rubric — Phase {N}
139
+
140
+ | Dim | Score | Evidence |
141
+ |---|---|---|
142
+ | Typography | 4 | `app/page.tsx:14` Fraunces + JetBrains Mono pair, weights 400/500/700, clamp() scale visible |
143
+ | Color cohesion | 3 | All CSS vars in `app/globals.css:8-22`. OKLCH used. Strategy: Restrained. WCAG AA verified |
144
+ | Spatial rhythm | 5 | Fluid clamp padding throughout, varied within section, generous between |
145
+ | Layout originality | 2 | `app/page.tsx:42-78` is a three-column feature grid in section 2 — first-order slop. Rework. |
146
+ | ... | ... | ... |
147
+
148
+ **Aggregate:** 28/40 (avg 3.5)
149
+ **Phase verdict:** FAIL — Layout Originality at 2 blocks the phase.
150
+ **Fix priority:** Rework section 2. Replace three-column grid with varied-height layout per `design-brand.md` §Layout.
151
+ ```
152
+
153
+ If the score < 3, the verifier writes the diagnosis. The fix is the next builder's task.
@@ -107,6 +107,25 @@ git add .planning/PROJECT.md
107
107
  git commit -m "docs: initialize project"
108
108
  ```
109
109
 
110
+ ### Step 5b. Write PRODUCT.md (v4.5.0 — REQUIRED)
111
+
112
+ `PRODUCT.md` is the "who and why" every road agent reads before designing or building. It is **required** — the planner, builder, and verifier all load it as substrate.
113
+
114
+ Ask the user 5 short questions (one at a time, each with a sensible default they can `[Enter]` past):
115
+
116
+ 1. **Register** — "Is this design IS the product (marketing/landing/portfolio → `brand`) or design SERVES the product (app/admin/dashboard → `product`)?" Default: infer from project type.
117
+ 2. **Three users** — "Name 3 specific humans who will use this. Not personas — real names + their workflow scenario." Default: project type defaults.
118
+ 3. **Brand voice** — "Three adjectives, then one paragraph showing the voice in motion (an error message, a confirmation, an empty state)." Default: derive from PROJECT.md.
119
+ 4. **Anti-references** — "Three sites this should NOT look like, with why." Required, no defaults — anti-references are more useful than positive references.
120
+ 5. **One-sentence differentiation** — "What does someone remember 24 hours after first using this?" Required.
121
+
122
+ Write `.planning/PRODUCT.md` from `templates/PRODUCT.md`, filling the user's answers.
123
+
124
+ ```bash
125
+ git add .planning/PRODUCT.md
126
+ git commit -m "docs: PRODUCT.md — register, users, voice, anti-references"
127
+ ```
128
+
110
129
  ### Step 6. Create config.json
111
130
 
112
131
  ```json
@@ -124,13 +143,31 @@ git commit -m "docs: initialize project"
124
143
 
125
144
  **Note:** `workflow.research` is ALWAYS `true` for v4. It exists for telemetry but is no longer read as a gate.
126
145
 
127
- ### Step 7. Create DESIGN.md (frontend projects)
146
+ ### Step 7. Create DESIGN.md (frontend projects — v4.5.0 OKLCH-first)
147
+
148
+ If frontend work is involved, generate `.planning/DESIGN.md` from `templates/DESIGN.md`. The generation MUST commit to four things upfront (these go in §1 of DESIGN.md):
149
+
150
+ 1. **Aesthetic direction** — pick ONE: `editorial · brutalist · luxury · maximalist · retro-futuristic · organic · terminal-native · sci-fi · pastoral · industrial · ...`. Don't hedge ("modern minimal" is hedging — pick one extreme).
151
+ 2. **Color strategy** — pick ONE: `Restrained · Committed · Full palette · Drenched`. See `rules/design-laws.md` §2.
152
+ 3. **Scene sentence** — one concrete sentence: who uses this, where, ambient light, mood. NOT "observability dashboard" — "SRE glancing at incident severity on a 27-inch monitor at 2am in a dim room." Run the sentence, not the category.
153
+ 4. **Differentiation** — one sentence: what someone remembers 24 hours later.
154
+
155
+ Then fill the rest of DESIGN.md:
156
+ - §2 Color: OKLCH only, no `#000`/`#fff`, neutrals tinted toward brand hue (chroma 0.005-0.015), accent within the chosen strategy
157
+ - §3 Typography: distinctive display + refined body pair. **NEVER** Inter, Roboto, Arial, Helvetica, system-ui, Space Grotesk
158
+ - §4 Spacing: 8px grid + fluid `clamp()` for page padding
159
+ - §5 Components: token-driven button/input/card/table specs
160
+ - §6 Depth: 3-level shadow elevation, OKLCH-tinted (not gray)
161
+ - §7 Motion: easing tokens (ease-out-quart/expo), no bounce, `prefers-reduced-motion` respected
162
+ - §8 Iconography: ONE family
163
+ - §9 Responsive: mobile-first
164
+ - §10 Anti-pattern checklist (the auto-runnable one)
128
165
 
129
- If frontend work is involved, generate `.planning/DESIGN.md` from the template with concrete palette, distinctive typography (NEVER Inter/Roboto/system-ui), 8px spacing grid, motion approach, component patterns.
166
+ Cross-check the result against `rules/design-laws.md` §8 absolute bans BEFORE writing the design must not propose any banned pattern.
130
167
 
131
168
  ```bash
132
169
  git add .planning/DESIGN.md .planning/config.json
133
- git commit -m "docs: design direction + config"
170
+ git commit -m "docs: DESIGN.md direction commit + OKLCH palette + tokens"
134
171
  ```
135
172
 
136
173
  ### Step 8. Run Research (ALWAYS, no permission ask)
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: qualia-polish
3
- description: "Design and UX pass — anti-AI-slop, genuine craft, responsive, accessible. Run after all phases are verified."
3
+ description: "Scope-adaptive design pass — works on a single component, a route, the whole app, or a ground-up redesign. Trigger on 'polish', 'design pass', 'fix the design', 'redesign', 'critique', 'audit design', 'looks ugly', 'make it look better'. Replaces both /qualia-polish and /qualia-design from earlier versions."
4
4
  allowed-tools:
5
5
  - Bash
6
6
  - Read
@@ -9,207 +9,251 @@ allowed-tools:
9
9
  - Grep
10
10
  - Glob
11
11
  - Agent
12
+ argument-hint: "[file|route|--redesign|--critique|--quick] [--register=brand|product]"
12
13
  ---
13
14
 
14
- # /qualia-polish — Design Pass
15
+ # /qualia-polish — Scope-Adaptive Design Pass
15
16
 
16
- Makes it look like a human designer built it. Kills AI slop. Run after all feature phases are verified.
17
+ One command. Six scopes. Use it whenever you need design work from a 30-second component touch-up to a 30-minute ground-up redesign.
17
18
 
18
- ## The Standard
19
+ ## Scopes
19
20
 
20
- Every site Qualia ships must feel **designed, not generated.** AI-generated sites have tells:
21
- - Identical card grids with rounded corners and soft shadows
22
- - Blue-purple gradients on everything
23
- - Inter/system-ui font with no hierarchy
24
- - Generic hero with centered text and a stock gradient background
25
- - Fixed-width containers leaving dead space on wide screens
26
- - No motion, no personality, no opinion
27
- - Perfect symmetry everywhere (real design has tension)
21
+ The first argument selects the scope. Stage selection follows from scope.
28
22
 
29
- **Kill all of these.** A Qualia site should make someone ask "who designed this?" — not "which template is this?"
23
+ | Invocation | Scope | Runtime | Stages |
24
+ |---|---|---|---|
25
+ | `/qualia-polish src/components/Button.tsx` | **Component** | ~30s | 0, 2, 3, 7 |
26
+ | `/qualia-polish app/dashboard` | **Section** | ~3m | 0, 1 (light), 2, 3, 4, 7 |
27
+ | `/qualia-polish` | **App** | ~12m | all 7 (fan-out batches of 5) |
28
+ | `/qualia-polish --redesign` | **Redesign** | ~30m | all + Stage 1 mandatory + 2 vision iterations |
29
+ | `/qualia-polish --critique` | **Critique** | read-only | 0, 4, 5 (no edits) |
30
+ | `/qualia-polish --quick` | **Quick** | ~1m | 0, 2, 7 (gates only, no vision loop) |
30
31
 
31
- ## Process
32
+ Other flags: `--register=brand|product` to override register inference.
32
33
 
33
- ```bash
34
- node ~/.claude/bin/qualia-ui.js banner polish
34
+ ## Setup gates (non-optional, every scope)
35
+
36
+ Before any work — design or otherwise — pass these gates. Skipping them produces generic output that ignores the project.
37
+
38
+ | Gate | Required check | If fail |
39
+ |---|---|---|
40
+ | Substrate | `rules/design-laws.md`, `design-brand.md`, `design-product.md`, `design-rubric.md` exist and have been read | Read them. |
41
+ | PRODUCT | `PRODUCT.md` exists at project root, has `register:` field, and is not placeholder (`[TODO]` markers, &lt; 200 chars) | Run setup: ask 5 questions and generate it. Never synthesize from prompt alone. |
42
+ | DESIGN | `DESIGN.md` exists. If missing on App / Redesign scope, BLOCK and run setup. If missing on Component / Section / Critique / Quick scope, NUDGE and proceed. | Generate from PRODUCT.md + 3 questions. |
43
+ | Slop-detect | `bin/slop-detect.mjs` is callable | Install or pull from framework. |
44
+ | Mutation | All gates above pass | Do not edit project files yet. |
45
+
46
+ State this preflight explicitly before editing:
47
+
48
+ ```
49
+ POLISH_PREFLIGHT: substrate=pass product=pass design=pass|nudged slop_detect=pass mutation=open
35
50
  ```
36
51
 
37
- ### 0. Load Design Context
52
+ ## Process
38
53
 
39
54
  ```bash
40
- cat .planning/DESIGN.md 2>/dev/null || echo "NO_DESIGN"
55
+ node ~/.claude/bin/qualia-ui.js banner polish
41
56
  ```
42
57
 
43
- If DESIGN.md exists it's the standard. Read ALL 12 sections. Key sections for polish:
44
- - §1 Visual Theme — the feel and signature details
45
- - §2 Color Palette — exact hex values, CSS variables, contrast ratios
46
- - §3 Typography — hierarchy table with exact sizes/weights/spacing
47
- - §4 Components — exact button/card/input/badge specs
48
- - §5 Layout — spacing scale, grid strategy
49
- - §6 Depth & Elevation — shadow levels with exact rgba values
50
- - §7 Do's/Don'ts — brand-specific guardrails
51
- - §9 Agent Prompt Guide — quick reference for common patterns
52
- - §10 Accessibility — WCAG checklist
53
- - §11 Hardening — stress-test criteria
54
- - §12 Anti-Slop Detection — grep patterns for automated checks
58
+ ### Stage 0 Direction commit (mandatory; light on small scopes)
55
59
 
56
- If no DESIGN.md use `rules/frontend.md` defaults.
60
+ Read PRODUCT.md and DESIGN.md. Identify the **register** — Brand (marketing/landing/portfolio) or Product (app/admin/dashboard). Priority for register inference:
57
61
 
58
- Read EVERY frontend file before modifying. No blind edits.
62
+ 1. The path of the target file/route (e.g., `/marketing/*` brand; `/app/*` → product)
63
+ 2. `register:` field in PRODUCT.md
64
+ 3. `--register` flag override
59
65
 
60
- ### 1. AI Slop Detector
66
+ For App / Redesign scope, write the brief BEFORE any code (use `ultrathink`):
61
67
 
62
- Run these checks first. Any hits = mandatory fixes.
68
+ ```
69
+ Aesthetic direction: {editorial · brutalist · luxury · maximalist · retro-futuristic · organic · terminal-native · ...}
70
+ Color strategy: {Restrained · Committed · Full palette · Drenched}
71
+ Scene sentence: {who uses this, where, ambient light, mood — concrete}
72
+ Differentiation: {what someone remembers 24 hours later}
73
+ ```
63
74
 
64
- ```bash
65
- # Generic fonts (the #1 AI tell)
66
- grep -rn "Inter\|Roboto\|Arial\|Helvetica\|system-ui\|Space.Grotesk" --include="*.tsx" --include="*.css" --include="*.scss" --include="tailwind*" app/ components/ src/ 2>/dev/null | grep -v node_modules
75
+ For Component / Section / Quick scope, the brief is implicit (loaded from DESIGN.md). Skip the ultrathink step but cite the relevant DESIGN.md tokens you'll touch.
67
76
 
68
- # Hardcoded max-width containers (screams template)
69
- grep -rn "max-w-7xl\|max-w-\[1200\|max-w-\[1280\|max-width.*1200\|max-width.*1280" --include="*.tsx" --include="*.css" app/ components/ src/ 2>/dev/null
77
+ For Critique scope, no commit needed — you're scoring, not editing.
70
78
 
71
- # Blue-purple gradients
72
- grep -rn "from-blue.*to-purple\|from-purple.*to-blue\|linear-gradient.*blue.*purple\|linear-gradient.*purple.*blue\|from-indigo.*to-violet" --include="*.tsx" --include="*.css" app/ components/ src/ 2>/dev/null
79
+ ### Stage 1 — Static gates (no browser, deterministic)
73
80
 
74
- # Card grid monotony (same card component repeated in a grid)
75
- grep -rn "grid-cols-3\|grid-cols-4" --include="*.tsx" app/ components/ src/ 2>/dev/null | head -5
81
+ ```bash
82
+ # Anti-pattern scan (the slop-detect script)
83
+ node bin/slop-detect.mjs {target_paths}
76
84
 
77
- # Generic hero patterns
78
- grep -rn "text-center.*mx-auto\|Hero\|hero" --include="*.tsx" app/ components/ src/ 2>/dev/null | head -5
85
+ # TypeScript still compiles?
86
+ npx tsc --noEmit 2>&1 | head -20
79
87
 
80
- # Scattered hardcoded colors (no design system)
81
- grep -rn "text-\[#\|bg-\[#\|border-\[#\|color:.*#\|background:.*#" --include="*.tsx" app/ components/ src/ 2>/dev/null | wc -l
88
+ # Token enforcement (if Stylelint configured)
89
+ npx stylelint "src/**/*.css" 2>&1 | head -20 # optional, skip silently if not configured
82
90
  ```
83
91
 
84
- **Every hit gets fixed.** Not flagged fixed.
92
+ ANY critical-severity slop hit = mandatory fix before proceeding. Don't stage anything until critical findings are zero.
85
93
 
86
- ### 2. Typography Pass
94
+ ### Stage 2 Generation (forked subagents, batches of 5 files)
87
95
 
88
- **Goal:** A reader should feel the type was chosen, not defaulted.
96
+ For App / Redesign / Section scope on multi-file work:
89
97
 
90
- - Pick a distinctive display font. Not Inter, not Roboto, not system. Something with character: Clash Display, Cabinet Grotesk, General Sans, Satoshi, Plus Jakarta Sans, Outfit, Sora, Manrope. Pair with a clean body font.
91
- - Establish clear hierarchy: display (hero text) h1 h2 h3 body caption
92
- - Body: 16px minimum, line-height 1.5-1.7
93
- - Headings: tighter line-height (1.1-1.3), negative letter-spacing (-0.02em) for display sizes
94
- - Weight hierarchy: Regular (400) for body, Medium (500) for labels, Semibold (600) for headings, Bold (700) for display
95
- - Prose content: `max-width: 65ch`. Everything else: fluid full-width.
96
- - Use `clamp()` for fluid sizing: `clamp(2rem, 1rem + 3vw, 3.75rem)` for h1
98
+ - Count target files. If 5, process in main context.
99
+ - If &gt; 5, fan out: spawn one Agent per batch of 5 files IN THE SAME RESPONSE TURN (parallel execution).
100
+ - If the conversation already contains design-taste discussion (font/color/motion preferences threaded across multiple turns), prefer **forked subagents** (`--fork-session`) so they inherit the taste context. Otherwise, blank-context fan-out is fine for mechanical fixes.
97
101
 
98
- ### 3. Color & Surfaces
102
+ Each agent receives:
103
+ - `rules/design-laws.md` + the matching register file
104
+ - `PRODUCT.md` + `DESIGN.md` (inlined)
105
+ - Its 5 files (paths + contents)
106
+ - Instruction: apply the Design Quality Rubric per file. Fix every dimension scoring &lt; 3. Make literal edits. Do NOT change logic — only styling.
99
107
 
100
- **Goal:** A palette that looks intentional, not random.
108
+ For Component scope: do the work in main context. Read, fix, verify.
101
109
 
102
- - Define all colors as CSS variables or Tailwind config — zero scattered hex values
103
- - One dominant brand color. One sharp accent for CTAs that pops against the page.
104
- - Surfaces: layer them. Background → card → elevated card. Use subtle shade differences, not just white-on-white.
105
- - Dark mode (if present): rethink surfaces, don't just invert. Slightly reduce contrast. Use darker brand colors, not just white→black swap.
106
- - Semantic colors with non-color indicators: success (green + checkmark), error (red + icon), warning (amber + triangle)
107
- - Verify WCAG AA: 4.5:1 for normal text, 3:1 for large text (18px+ bold or 24px+)
110
+ **Apply fixes scoped by what's missing:**
108
111
 
109
- ### 4. Layout & Spacing
112
+ | If the file scores low on… | Apply fix from… |
113
+ |---|---|
114
+ | Typography | DESIGN.md §3 — font tokens, scale, weight hierarchy, tabular numerals |
115
+ | Color cohesion | DESIGN.md §2 — OKLCH tokens, replace hex, verify contrast |
116
+ | Spatial rhythm | DESIGN.md §4 — fluid spacing scale, vary by content |
117
+ | Layout originality | register file (brand or product) — kill three-column grids, vary layout |
118
+ | Shadow hierarchy | DESIGN.md §6 — elevation tokens, brand-tinted shadows |
119
+ | Motion intent | DESIGN.md §7 — easing, stagger, signature motion |
120
+ | Microcopy | rename "Get Started" / "Learn More" to action-named CTAs |
121
+ | Container depth | flatten card-on-card; remove side-stripe borders |
110
122
 
111
- **Goal:** Full-width, fluid, generous. No dead space gutters.
123
+ ### Stage 3 Runtime gates (App / Section / Redesign only — needs dev server)
112
124
 
113
- - Full-width layouts with fluid padding: `clamp(1rem, 5vw, 4rem)` horizontal
114
- - 8px spacing grid: 4, 8, 12, 16, 24, 32, 48, 64, 96
115
- - Tight spacing within groups (related items). Generous spacing between sections.
116
- - Break symmetry where it serves the design — offset grids, overlapping elements, diagonal flow
117
- - Varied layouts: not every section should be a centered-text-with-cards-below. Use side-by-side, staggered, asymmetric, full-bleed.
118
- - Section spacing: `clamp(2rem, 8vw, 6rem)` vertical padding
125
+ If a dev server is up at `http://localhost:3000` (or detected via `lsof` on common ports):
119
126
 
120
- ### 5. Interactive States
127
+ ```bash
128
+ # Lighthouse-CI — numeric a11y/perf/best-practices
129
+ npx lhci autorun \
130
+ --collect.url=http://localhost:3000{route} \
131
+ --collect.numberOfRuns=1 \
132
+ --assert.assertions='{
133
+ "categories:accessibility": ["error", {"minScore": 0.9}],
134
+ "categories:performance": ["warn", {"minScore": 0.7}],
135
+ "categories:best-practices": ["warn", {"minScore": 0.8}]
136
+ }' 2>&1 | tail -30
137
+
138
+ # axe-core direct (catches what Lighthouse misses)
139
+ npx @axe-core/cli http://localhost:3000{route} --exit 2>&1 | tail -30
140
+ ```
141
+
142
+ If Lighthouse/axe not installed, skip silently and note in the report. Don't fail the polish over missing tooling.
121
143
 
122
- **Goal:** Every clickable thing responds. Every async operation shows progress.
144
+ If a11y &lt; 90 OR axe critical/serious violations: **fix programmatically** (these are deterministic no vision needed). Re-run to confirm.
123
145
 
124
- - **Hover:** color shift or underline within 150ms ease-out. `cursor: pointer` on ALL clickables.
125
- - **Focus:** visible ring (2px+ offset, contrasting color). Never `outline: none` without replacement.
126
- - **Active/pressed:** subtle scale down (`transform: scale(0.98)`) or color shift.
127
- - **Disabled:** opacity 0.5 + `cursor: not-allowed` + `aria-disabled="true"`
128
- - **Loading:** skeleton shimmer or spinner on every async operation. Never a blank void.
129
- - **Empty:** helpful message + CTA on empty lists/tables. Not just "No results."
130
- - **Error:** user-friendly message + recovery action. Not raw error text. Use `aria-live="assertive"`.
146
+ ### Stage 4 Vision loop (Redesign scope only max 2 iterations)
131
147
 
132
- ### 6. Motion & Personality
148
+ Use Anthropic's `webapp-testing` skill (Playwright). Capture screenshots at 3 viewports: 375 / 768 / 1280. Single browser (Chromium) is fine in 2026 — cross-browser CSS rendering differences are vanishingly rare.
133
149
 
134
- **Goal:** The site feels alive, not static. But tasteful — not a circus.
150
+ ```
151
+ viewports: [
152
+ { width: 375, height: 812, name: 'mobile' },
153
+ { width: 768, height: 1024, name: 'tablet' },
154
+ { width: 1280, height: 800, name: 'desktop' }
155
+ ]
156
+ ```
135
157
 
136
- - Page load: stagger children entrance (50-80ms delay between items, `fadeUp` animation, 300ms)
137
- - Hover transitions: 150-200ms ease-out
138
- - Section transitions: 300-500ms with `cubic-bezier(0.4, 0, 0.2, 1)`
139
- - One signature motion that gives the site personality (parallax, scroll-triggered reveal, magnetic buttons, morphing shapes)
140
- - **Always** `prefers-reduced-motion: reduce` — disable non-essential animation
141
- - CSS-only for static sites, `motion/react` (formerly Framer Motion) for React
158
+ For each iteration:
142
159
 
143
- ### 7. Accessibility (Non-Negotiable)
160
+ 1. Capture all 3 viewports
161
+ 2. Pass to a vision-model agent with `rules/design-rubric.md` as the prompt anchor + DESIGN.md as the spec
162
+ 3. The agent scores 8 dimensions, anchored 1-5, with evidence per dimension
163
+ 4. Apply fixes ONLY to dimensions scored 1 or 2 (don't nitpick 3s; prevents oscillation)
164
+ 5. STOP if: all dimensions ≥ 3 (success), OR any dimension regressed from previous iteration (regression-stop), OR 2 iterations reached (hard cap)
144
165
 
145
- - Semantic HTML: `nav`, `main`, `section`, `article`, `header`, `footer` not div soup
146
- - One `h1` per page, sequential heading order (no h1 → h3 skip)
147
- - All images: descriptive `alt` (or `alt=""` + `aria-hidden` if decorative)
148
- - All form inputs: visible `<label>` with `htmlFor` — not placeholder-only
149
- - All interactive elements: keyboard accessible (Tab, Enter, Escape, Arrow keys)
150
- - Touch targets: 44x44px minimum
151
- - Skip link: `<a href="#main" class="sr-only focus:not-sr-only">` as first focusable element
152
- - `<html lang="en">` set
153
- - Color never the sole information carrier — icons, text, patterns as supplements
154
- - `aria-live="polite"` for toast notifications and dynamic content updates
166
+ **The anchored rubric is mandatory.** Without it, vision models say "looks great!" to everything. Quote from the rubric prompt: "Score 3 = acceptable. Only 1-2 = must fix. 4-5 = exceeds. Default to 3 unless you can cite specific evidence."
155
167
 
156
- ### 8. Responsive (Mobile-First)
168
+ ### Stage 5 — Drift audit (App / Redesign / Critique scope)
157
169
 
158
- - Base styles for mobile (320px), scale up with `min-width` breakpoints
159
- - Test at: 320px (small phone), 375px (iPhone), 768px (iPad), 1024px (laptop), 1440px (desktop)
160
- - No horizontal scroll at any viewport
161
- - Navigation: hamburger/drawer on mobile, full horizontal on desktop
162
- - Stack on mobile, expand on desktop
163
- - Fluid typography with `clamp()`
164
- - Images: `max-width: 100%`, responsive `srcset`, `next/image` with width/height
165
- - Tables: card layout or horizontal scroll on mobile
170
+ Compare the implementation against DESIGN.md as source of truth. Flag deltas.
166
171
 
167
- ### 9. Harden (Edge Cases)
172
+ ```bash
173
+ # Find tokens used in code that don't exist in DESIGN.md
174
+ grep -rE "var\(--[a-z-]+\)" src/ app/ components/ 2>/dev/null | \
175
+ awk -F'var\\(--' '{print $2}' | awk -F'\\)' '{print $1}' | sort -u > /tmp/used-tokens
176
+ grep -E "^\s*--[a-z-]+:" templates/DESIGN.md | sed -E 's/.*--([a-z-]+):.*/\1/' | sort -u > /tmp/declared-tokens
177
+ comm -23 /tmp/used-tokens /tmp/declared-tokens > /tmp/orphan-tokens
178
+ [ -s /tmp/orphan-tokens ] && echo "── orphan tokens (used in code, missing from DESIGN.md) ──" && cat /tmp/orphan-tokens
179
+
180
+ # Find raw hex still appearing
181
+ grep -rnE "#[0-9a-fA-F]{6}\b" src/ app/ components/ --include="*.tsx" --include="*.css" 2>/dev/null | \
182
+ grep -v "shadow\|outline\|currentColor" | head -20
183
+ ```
168
184
 
169
- After all visual work, stress-test:
170
- - Long text: does a 200-character username break the layout?
171
- - Empty everywhere: all lists empty, all data missing — does it still make sense?
172
- - Error everywhere: every fetch fails — are error states visible and helpful?
173
- - 320px viewport: nothing overflows, nothing clips, nothing overlaps
174
- - Keyboard only: Tab through the entire app — can you reach everything? Is focus visible?
175
- - Slow network: are loading states visible? Does content stream in or flash?
185
+ Drift findings get reported, not auto-fixed (drift may be intentional). For Critique scope, this IS the deliverable.
176
186
 
177
- ### 10. Verify & Ship
187
+ ### Stage 6 — Verify (every scope)
178
188
 
179
189
  ```bash
180
- npx tsc --noEmit 2>&1 | head -20
190
+ # Re-run Stage 1 all critical findings must be zero
191
+ node bin/slop-detect.mjs {target_paths}
192
+ [ $? -eq 0 ] || { echo "polish failed — slop-detect still finds critical issues"; exit 1; }
193
+
194
+ # TypeScript clean
195
+ npx tsc --noEmit 2>&1 | tail -10
181
196
  ```
182
197
 
183
- Fix any TypeScript errors.
198
+ ### Stage 7 — Commit & state
199
+
200
+ For Critique scope: write the report to `.planning/polish-critique-{timestamp}.md` and STOP. Do not edit, do not commit.
201
+
202
+ For all other scopes:
184
203
 
185
204
  ```bash
186
- git add {changed files}
187
- git commit -m "polish: design pass typography, color, states, motion, responsive, a11y"
205
+ git add {modified files}
206
+ git -c user.name="Qualia Solutions" -c user.email="info@qualiasolutions.net" commit -m "$(cat <<'EOF'
207
+ polish({scope}): {brief summary}
208
+
209
+ - {key change 1}
210
+ - {key change 2}
211
+ - rubric scores: typography {N}, color {N}, ..., aggregate {N}/40
212
+
213
+ Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
214
+ EOF
215
+ )"
188
216
  ```
189
217
 
218
+ If this is the FINAL polish before deploy (Handoff milestone, last phase):
219
+
190
220
  ```bash
191
221
  node ~/.claude/bin/state.js transition --to polished
192
222
  ```
193
223
 
224
+ Otherwise, no state transition (polish is now a normal verb, not a phase boundary).
225
+
226
+ ### Output
227
+
194
228
  ```bash
195
229
  node ~/.claude/bin/qualia-ui.js divider
196
- node ~/.claude/bin/qualia-ui.js ok "AI slop: killed"
197
- node ~/.claude/bin/qualia-ui.js ok "Typography: {brief}"
198
- node ~/.claude/bin/qualia-ui.js ok "Color: {brief}"
199
- node ~/.claude/bin/qualia-ui.js ok "Layout: {brief}"
200
- node ~/.claude/bin/qualia-ui.js ok "States: {brief}"
201
- node ~/.claude/bin/qualia-ui.js ok "Motion: {brief}"
202
- node ~/.claude/bin/qualia-ui.js ok "Accessibility: {brief}"
203
- node ~/.claude/bin/qualia-ui.js ok "Responsive: {brief}"
204
- node ~/.claude/bin/qualia-ui.js ok "Hardened: {brief}"
205
- node ~/.claude/bin/qualia-ui.js end "POLISHED" "/qualia-ship"
230
+ node ~/.claude/bin/qualia-ui.js ok "Scope: {component|section|app|redesign|critique|quick}"
231
+ node ~/.claude/bin/qualia-ui.js ok "Files: {N}"
232
+ node ~/.claude/bin/qualia-ui.js ok "Slop-detect: {N critical, M high, K medium}"
233
+ node ~/.claude/bin/qualia-ui.js ok "Rubric aggregate: {N}/40 (avg {N})"
234
+ node ~/.claude/bin/qualia-ui.js ok "Vision iterations: {0|1|2}"
235
+ node ~/.claude/bin/qualia-ui.js ok "Drift findings: {N}"
236
+ node ~/.claude/bin/qualia-ui.js end "POLISHED" "{next command — depends on context}"
206
237
  ```
207
238
 
208
239
  ## Rules
209
240
 
210
241
  1. **Read before write.** Understand every file before changing it.
211
- 2. **DESIGN.md is law.** If it exists, follow it. Don't override client decisions.
242
+ 2. **DESIGN.md is law.** If a project decision exists, follow it. Don't override.
212
243
  3. **Don't break functionality.** Only change styling, never logic.
213
- 4. **AI slop is a bug.** Generic fonts, card grids, blue-purple gradients, centered-everything treat these as defects, not preferences.
244
+ 4. **Slop is a bug.** Critical-severity findings block commit. No overriding the script.
214
245
  5. **TypeScript must pass** after every change.
215
- 6. **One commit** at the end — not per category.
246
+ 6. **One commit per polish run** — not per category, not per file.
247
+ 7. **Forked subagents inherit taste.** When the conversation has design discussion, fork. Otherwise blank-context.
248
+ 8. **The rubric is anchored.** Score = 3 means ships. Default there. Justify deviations.
249
+
250
+ ## Failure modes (handle gracefully)
251
+
252
+ | Symptom | Likely cause | Action |
253
+ |---|---|---|
254
+ | `bin/slop-detect.mjs not found` | Framework not installed in project | Run `npx qualia install` or pull script from framework repo |
255
+ | `PRODUCT.md missing` | Pre-v4.5.0 project | Run setup (ask 5 questions, generate). For Component scope, can proceed with nudge. |
256
+ | `Lighthouse not installed` | Optional tool | Skip Stage 3 numeric gates, note in report. Don't fail. |
257
+ | `webapp-testing skill not present` | Optional Anthropic skill | Skip Stage 4 vision loop on Redesign scope. Note in report. Recommend installing. |
258
+ | Vision loop oscillates between iterations | Rubric not anchored properly | Verify rubric prompt instructs "default to 3, only 1-2 = fix". Hard cap at 2 iterations. |
259
+ | User says "you missed X" after polish completes | Scope was too narrow | Re-run with wider scope (`/qualia-polish` whole-app). Don't argue scope. |