# YuqingNicole@variant-design-skill

> Variant Design

- Skill: `gabrielmoreira/yuqingnicole-variant-design-skill` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add gabrielmoreira/yuqingnicole-variant-design-skill`
- Raw SKILL.md: https://api.skillmd.com/api/skills/gabrielmoreira/yuqingnicole-variant-design-skill/raw
- Safety review: pending (external: skill-scanner PASS, skillspector FAIL)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: gabrielmoreira (https://skillmd.com/u/gabrielmoreira)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/gabrielmoreira/yuqingnicole-variant-design-skill

---


# Variant Design

Solve the blank canvas problem. Prompt → 3 fully-formed distinct designs → vary → export.

## About

Inspired by the [Variant](https://variant.com) design community — a space where designers share divergent takes on the same brief. This skill brings that practice into Claude Code: every prompt yields three designs that feel like they came from different studios, then lets you iterate with one-word actions.

Built on the **Impeccable design system** — a comprehensive set of design references covering typography, color theory, spatial design, motion, interaction patterns, responsive design, and UX writing. Every design decision is grounded in these principles.

**Supports:** Context-aware output (HTML default · React .tsx when React project detected) · Framer Motion (when installed) · 10 domain reference libraries · 39 palettes · design system references · micro-interaction library · interactive pattern library · style audit & token extraction · variation actions · **Design Declaration → Product Integrity Contract** for product-critical UI

---

## CLI Workflow (Claude Code)

This skill runs inside Claude Code — a terminal. Design decisions must account for the fact that the user **cannot see the output** without opening a browser. Every step of the workflow should minimize friction between "idea" and "eyes on pixels."

### Output Format Detection

Before generating any design, detect the output format. Run this detection once per session and cache the result.

**Step 1: Read package.json**

```bash
cat package.json 2>/dev/null
```

If absent or unreadable → **HTML output** (fail-safe), print warning if unreadable. Do not traverse parent directories — check cwd only.

**Step 2: Walk the decision tree**

Parse dependencies / devDependencies / peerDependencies / optionalDependencies. Check for **exact keys only** — never substring-match (`react-scripts` ≠ `react`, `@vitejs/plugin-react` ≠ `vite`).

```
package.json exists?
│
├─ no  →  HTML (zero-dep default)
│
└─ yes → check keys:
    │
    ├─ "react" present?
    │   ├─ yes → React branch:
    │   │         ├─ "next" present?          → Next.js App Router .tsx
    │   │         │                              add "use client" on components
    │   │         │                              using hooks/animations/browser APIs
    │   │         ├─ "vite" or               → Vite .tsx
    │   │         │  "@vitejs/plugin-react"     preview: read scripts.dev → npm run dev
    │   │         └─ neither                 → Generic React .tsx
    │   │
    │   └─ no → non-React branch:
    │           ├─ "vue" present?             → Vue 3 .vue SFC
    │           │                               <script setup> + <template> + <style scoped>
    │           │                               preview: npm run dev (Vite assumed)
    │           ├─ "astro" present?           → Astro .astro component
    │           │                               frontmatter + HTML template
    │           │                               no client-side JS unless :is="client:load"
    │           ├─ "svelte" or               → Svelte .svelte component
    │           │  "@sveltejs/kit" present?     <script> + markup + <style>
    │           │                               SvelteKit if @sveltejs/kit detected
    │           └─ none of the above         → HTML (zero-dep default)
```

**Step 3: Check for animation library (React branch only)**

- `"framer-motion"` or `"motion"` in deps → use Framer Motion (`motion.div`, `AnimatePresence`, `useInView`)
- Not found → CSS animations only — do **not** import Framer Motion (missing package = runtime error)

**Step 4: Apply user override**

Explicit user instruction always wins over detection:

| User says | Output |
|---|---|
| `--react` or `react [A/B/C]` | Force React (auto-detect Next/Vite sub-type) |
| `--html` | Force zero-dep HTML |
| `--vue` | Force Vue 3 SFC |
| `--astro` | Force Astro component |
| `--svelte` | Force Svelte component |
| `export to next/vite/astro/svelte` | Force that framework |

**Step 5: Announce the format**

Print one line before generating:

```
✦ Output format: Next.js .tsx — detected next in package.json
✦ Output format: Vue 3 SFC .vue — detected vue in package.json
✦ Output format: Astro .astro — detected astro in package.json
✦ Output format: Svelte .svelte — detected @sveltejs/kit in package.json
✦ Output format: Interactive HTML — no framework detected in cwd
✦ Output format: React .tsx — user requested --react
```

**Edge cases:**
- `.tsx` files exist but no `react` key → HTML output (Preact/Solid/stale files don't count)
- Both `vue` and `nuxt` detected → treat as Nuxt 3 (same SFC format, note `useNuxtApp` available)
- Monorepo: check cwd only, never traverse to parent `package.json`
- Multiple frameworks in same `package.json` (unusual) → print ambiguity warning, ask user to pass `--[framework]`

---

### Framework Output Templates

Each framework has its own file template, preview command, and import note.

#### Next.js App Router

```tsx
// variant-output/VariantA.tsx
// Generated by variant-design — move to app/components/ or src/components/
// Preview: npm run dev (then import this component in your page)
"use client"; // include when component uses hooks, animations, or browser APIs

import { useState, useEffect, useRef } from "react";
// import { motion } from "framer-motion"; // only if framer-motion detected

export default function VariantA() {
  // ...
}
```

Preview instruction after writing file:
```
✦ Written: variant-output/VariantA.tsx
  Move to app/components/VariantA.tsx, then import in your page:
  import VariantA from "@/components/VariantA"
  Preview: npm run dev
```

#### Vite React

```tsx
// variant-output/VariantA.tsx
// Generated by variant-design — move to src/components/
// Preview: npm run dev (Vite), then import this component

import { useState, useEffect, useRef } from "react";

export default function VariantA() {
  // ...
}
```

Preview: read `package.json scripts` → use `npm run dev` / `pnpm dev` / `yarn dev` based on detected package manager. Fallback: `npx vite`.

#### Generic React

Same as Vite template without Vite-specific notes. Preview: `npx vite` as fallback.

#### Vue 3 SFC

```vue
<!-- variant-output/VariantA.vue -->
<!-- Generated by variant-design — move to src/components/ -->
<!-- Preview: npm run dev -->

<script setup lang="ts">
import { ref, onMounted } from "vue";
// animations: use CSS transitions/animations (no framer-motion in Vue)
// for complex motion: @vueuse/motion or vanilla CSS
</script>

<template>
  <div class="variant-a">
    <!-- ... -->
  </div>
</template>

<style scoped>
/* OKLCH colors as CSS custom properties */
.variant-a {
  --color-primary: oklch(65% 0.2 250);
  /* ... */
}
</style>
```

**Vue rules:**
- `<script setup>` always — no Options API
- `lang="ts"` unless project has no TypeScript
- Animations via CSS transitions + `v-enter-active` / `v-leave-active` transition classes
- No Framer Motion — Vue has its own `<Transition>` and `<TransitionGroup>`
- Reactivity: `ref()` for primitives, `reactive()` for objects, `computed()` for derived state

#### Astro Component

```astro
---
// variant-output/VariantA.astro
// Generated by variant-design — move to src/components/ or src/pages/
// Preview: npm run dev

// Astro components have no client-side reactivity by default
// Use client:load / client:visible for interactive islands
interface Props {
  title?: string;
}
const { title = "Default Title" } = Astro.props;
---

<section class="variant-a">
  <!-- ... -->
</section>

<style>
  /* Scoped by default in Astro */
  .variant-a {
    --color-primary: oklch(65% 0.2 250);
  }
</style>

<!-- Add client:load only for interactive sections -->
<!-- <InteractiveIsland client:load /> -->
```

**Astro rules:**
- Frontmatter (`---`) for server-side logic only — no `useState`, no `useEffect`
- Styles scoped by default — no need for CSS modules
- Interactive sections: extract to a separate `.tsx` / `.vue` / `.svelte` island, import with `client:load` or `client:visible`
- No JavaScript in `<script>` unless truly necessary — Astro ships zero JS by default

#### Svelte / SvelteKit

```svelte
<!-- variant-output/VariantA.svelte -->
<!-- Generated by variant-design — move to src/lib/components/ -->
<!-- Preview: npm run dev -->

<script lang="ts">
  import { onMount } from "svelte";
  // animations: svelte/transition and svelte/animate built-in
  import { fade, fly, slide } from "svelte/transition";
  import { tweened } from "svelte/motion";

  let visible = false;
  onMount(() => { visible = true; });
</script>

<div class="variant-a">
  {#if visible}
    <section transition:fly={{ y: 20, duration: 400 }}>
      <!-- ... -->
    </section>
  {/if}
</div>

<style>
  .variant-a {
    --color-primary: oklch(65% 0.2 250);
  }
</style>
```

**Svelte rules:**
- Use built-in `svelte/transition` and `svelte/animate` — no Framer Motion
- `tweened()` and `spring()` from `svelte/motion` for number animations (counters, progress bars)
- `{#if}` / `{#each}` / `{#await}` blocks — no JSX
- Reactivity is assignment-based: `count += 1` triggers re-render automatically
- SvelteKit: routes in `src/routes/`, components in `src/lib/components/`

### Output Convention

**File naming:** `variant-[scenario]-[variation].html` (e.g., `variant-dashboard-A.html`)

**Output directory:** Write to `./variant-output/` in the current working directory. Create the directory if it doesn't exist. This keeps design files separate from project source code.

```
variant-output/
├── variant-dashboard-A.html
├── variant-dashboard-B.html
├── variant-dashboard-C.html
└── tokens/
    └── dashboard-A-tokens.css    (when user extracts tokens)
```

**Iteration files:** On variation actions, overwrite the same file (e.g., `variant-dashboard-A.html`) rather than creating `variant-dashboard-A-v2.html`. The user is iterating on one design, not collecting versions. Git handles history.

### Auto-Preview

**After every file write, immediately open it in the user's default browser:**

```bash
# macOS
open variant-output/variant-dashboard-A.html

# Linux
xdg-open variant-output/variant-dashboard-A.html
```

This is non-negotiable. The user should never have to manually find and open the file. When iterating (Vary subtle, Remix colors, etc.), the browser tab auto-refreshes because the file is overwritten — just re-run `open` to bring it to focus.

### Live Preview Server (Optional)

If the user asks for live preview or says "watch mode", start a lightweight file server with auto-reload:

```bash
# Using Python (available on most systems)
cd variant-output && python3 -c "
import http.server, socketserver, os, time, threading

class ReloadHandler(http.server.SimpleHTTPRequestHandler):
    def end_headers(self):
        self.send_header('Cache-Control', 'no-store')
        super().end_headers()

    def do_GET(self):
        if self.path == '/_poll':
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            self.wfile.write(str(os.path.getmtime('.')).encode())
            return
        super().do_GET()

with socketserver.TCPServer(('', 3333), ReloadHandler) as httpd:
    print('Preview: http://localhost:3333')
    httpd.serve_forever()
" &
```

Then inject a tiny auto-reload script at the bottom of every generated HTML:
```html
<script>
// Auto-reload in dev (remove for production)
(async function poll() {
  try {
    const r = await fetch('/_poll');
    const t = await r.text();
    if (window._lastMod && t !== window._lastMod) location.reload();
    window._lastMod = t;
  } catch(e) {}
  setTimeout(poll, 800);
})();
</script>
```

Only include this script when the preview server is running. Remove it on export.

### Compact CLI Output

Terminal space is precious. Keep text responses short and structured:

**On initial generation (3 variations):**
```
✦ Detected: coffee brand landing page → loading food-beverage.md + micro-interactions.md

  A — Terroir Warm       Fraunces + Instrument Sans    Minimal/Editorial
  B — Espresso Dark      DM Serif Display + DM Sans    Dark/Premium
  C — Fresh Market       Crimson Pro + Plus Jakarta     Warm/Human

  Interactions: scroll reveal, counter animation, card lift, filter chips, lightbox

  Files written:
    variant-output/variant-coffee-A.html  ← opened in browser
    variant-output/variant-coffee-B.html
    variant-output/variant-coffee-C.html

  Pick a variation to iterate, or an action:
  Reshape — Vary strong · Distill · Shuffle layout · Change style
  Tune    — Vary subtle · Remix colors · Mix (A+B)
  Animate — Add motion · Dramatize · Make interactive
  Refine  — Polish · Critique · See other views
  Export  — Extract tokens · react A · react B · react C
```

After initial generation, write context with detected scenario, the chosen palettes, and fonts for all 3 variations. Do not write `picked` yet — user hasn't chosen.

**On iteration:**
```
✦ Variation A — Vary subtle · iteration 2  [Terroir Warm · Editorial]

  Changed: tightened spacing to 4pt grid, added tabular-nums on stats,
  hover now lifts 4px→6px with shadow, scroll stagger 60ms→80ms

  variant-output/variant-coffee-A.html  ← updated & opened

  Next action? (react A to export as React component)
```

After each iteration, update context: increment `iterations`, update `picked` if the user is iterating on a specific variation (implies selection).

**Never dump the full HTML in the chat.** Write to file, open in browser, show a 2-3 line summary of what changed. The user reads code in their editor, not in the terminal.

### Quick Triggers

Support shorthand prompts for fast iteration in the terminal:

| User types | Expands to |
|---|---|
| `A vary strong` | Apply "Vary strong" to Variation A |
| `B remix colors` | Apply "Remix colors" to Variation B |
| `C → mobile` | Show Variation C as mobile viewport |
| `pick A` | Select Variation A as the winner, archive B and C |
| `A + B colors` | Mix: A's layout with B's color palette |
| `tokens A` | Extract design tokens from Variation A to CSS file |
| `open B` | Re-open Variation B in browser |
| `dark mode A` | Generate dark ↔ light toggle variant of A |
| `compare` | Open all 3 variations side-by-side (writes a comparison HTML) |
| `react A` | Export Variation A as React .tsx component (alias for `export to react`, Variation A) |
| `react B` | Export Variation B as React .tsx component |
| `react C` | Export Variation C as React .tsx component |
| `reset context` | Delete `.variant-context.json` and start fresh — next generation ignores all persisted preferences |
| `show context` | Print the current `.variant-context.json` contents in the terminal |
| `A vary strong — hero` | Zone-level: vary strong on hero section only, rest unchanged |
| `B remix colors — card` | Zone-level: remix colors on card zone only |
| `zones A` | List all `data-zone` sections found in Variation A |
| `component button` | Component mode: button system with all variants and states |
| `component form` | Component mode: form components |
| `component card` | Component mode: card variants |
| `ds` | Design System mode: generate tokens → preview |
| `ds confirm` | Lock design system — constrains all future outputs |
| `ds show` | Print design system summary |
| `ds edit palette` | Regenerate palette section only |
| `ds reset` | Unlock design system — allow aesthetic invention again |
| `compose [page]` | Assemble page from registered components, 3 layout variations |
| `registry` | Print which components have been built |

### Context Commands

**`show context`** — Print the current context:

```bash
cat ./variant-output/.variant-context.json 2>/dev/null || echo "(no context saved yet)"
```

Display as a formatted single-line summary, e.g.:
```
✦ Context: Amber Warm · Editorial · Instrument Serif + Instrument Sans · picked B · 4 iterations
  Framework: next · Scenario: landing-page
  Notes: user prefers high contrast, no dark mode
```

**`reset context`** — Delete the context file and confirm:

```bash
rm -f ./variant-output/.variant-context.json
```

Print: `✦ Context cleared — next generation starts fresh.`

### Comparison View

When the user says "compare" or wants to see all variations together, generate a single `variant-output/_compare.html` that displays all 3 side-by-side in iframes:

```html
<style>
  body { margin:0; display:grid; grid-template-columns:1fr 1fr 1fr; height:100vh; gap:2px; background:#111; }
  iframe { width:100%; height:100%; border:none; }
  .label { position:absolute; top:8px; left:12px; background:#111; color:#fff; padding:4px 12px;
    font:12px/1 monospace; border-radius:4px; z-index:10; }
  .frame { position:relative; }
</style>
<div class="frame"><span class="label">A</span><iframe src="variant-coffee-A.html"></iframe></div>
<div class="frame"><span class="label">B</span><iframe src="variant-coffee-B.html"></iframe></div>
<div class="frame"><span class="label">C</span><iframe src="variant-coffee-C.html"></iframe></div>
```

### Framework Export

When the user says "export to [framework]" or `react [A/B/C]`, transform the winning variation into the target structure:

| Target | Action |
|---|---|
| `export to next` | Next.js App Router .tsx — `"use client"` where needed, tokens in CSS file |
| `export to vite` | Vite React .tsx — `src/App.tsx` structure, preview via `npm run dev` |
| `export to vue` | Vue 3 SFC .vue — `<script setup lang="ts">` + scoped styles + `svelte/transition` equivalents via CSS |
| `export to astro` | Astro .astro — frontmatter + template + scoped styles, interactive parts as `client:load` islands |
| `export to svelte` | Svelte .svelte — `svelte/transition` animations, `tweened()` for counters, no Framer Motion |
| `export to static` | Clean HTML — remove dev scripts, inline critical CSS |
| `react [A/B/C]` | Shorthand for `export to react` — auto-detects Next vs Vite vs generic from cwd |
| `vue [A/B/C]` | Shorthand for `export to vue` on the specified variation |
| `astro [A/B/C]` | Shorthand for `export to astro` on the specified variation |
| `svelte [A/B/C]` | Shorthand for `export to svelte` on the specified variation |

Always ask which variation to export if the user hasn't picked one yet.

**Preview after React export:** Do not run `vite --open` directly — it may bypass project config. Instead, read `package.json.scripts` and print the correct dev command:
- If scripts contains `"dev"` → print `npm run dev` (or `pnpm dev` / `yarn dev` / `bun dev` based on detected package manager)
- If scripts contains `"start"` → print `npm start`
- If no scripts found → print `npx vite` as fallback, with a note

Example output after React export:
```
✦ Exported: variant-output/VariantA.tsx
  Move to src/components/ to include in your project's build.
  Preview: npm run dev  (then open the page that imports this component)
```

### Clipboard Mode

If the user says "copy" or "clipboard", copy the HTML to system clipboard instead of (or in addition to) writing the file:

```bash
# macOS
cat variant-output/variant-coffee-A.html | pbcopy
```

Useful for pasting into CodePen, Claude.ai artifacts, or other tools.

---

## Mode 0 — Design Declaration (product-critical UI)

Use this layer **before** visual generation for a new product, a workflow redesign, or any page involving user trust, money, privacy, irreversible actions, or AI-generated conclusions. It is not a PRD and does not replace the existing Design Read: Design Read confirms the prompt; this declaration locks the human product judgments that the skill must not invent.

**Skip only** for an explicitly exploratory visual exercise (`surprise me`, poster, moodboard, or brand exploration). Label that output: `exploratory — no product decision locked`.

### Minimal declaration

Ask at most two questions total; first infer from the README, product copy, flows, and existing UI. Mark unconfirmed fields as `assumption`, never as research fact.

```yaml
design_declaration:
  user_context: [who, in what moment]
  primary_job: [the one task this page/flow must complete]
  success_moment: [when the user has clearly received value]
  trust_boundary: [uncertain data, payment, deletion, privacy, financial/medical risk]
  hierarchy: [one must-see item, then at most three secondary items]
  chosen_tension: [e.g. evidence > delight; speed > exploration]
  non_negotiables: [maximum three]
  evidence_status: [real | mock-clearly-labeled | unknown]
```

Read `references/design-declaration.md` whenever this mode applies.

### Product Integrity Contract

When a design system is confirmed, compile the declaration into `variant-output/design-contract.md`; read it before every Generate, Component, Compose, Analyze, or UX Review action. The contract has priority over aesthetic defaults.

**Must:** make the primary job and one primary CTA legible in the first view; make trust boundaries explicit through source/state/confirmation/undo/limits; include loading, empty, error, and success behavior; use confirmed tokens.

**Must not:** mix real, mock, and AI-inferred data without labels; conceal price, risk, source, recovery, or irreversible consequences; create competing primary CTAs; add decoration that contradicts hierarchy.

After `ds confirm`, the declaration is frozen alongside the system. Variations may change layout and information organization, but must not silently change `primary_job`, `trust_boundary`, or `non_negotiables`.

---

## Project Context Initialization

### Session Start: Read Persisted Context

**Before doing anything else**, check for a context file in the output directory:

```bash
cat ./variant-output/.variant-context.json 2>/dev/null
```

If the file exists and is valid JSON, load it silently and print one line:

```
✦ Resuming context: [palette] · [direction] · picked [variation] · iteration [n]
  (reset context to start fresh)
```

Use all fields as constraints for the current session — the user should not need to re-specify preferences they've already confirmed.

If the file does not exist, proceed to the first-use questions below.

### First Use: Gather Context

On first use in a project, gather design context to ground all future generations. Ask the user:

1. **Users & Purpose** — Who uses this? What problem does it solve? What's the core task?
2. **Brand & Personality** — Existing brand colors? Tone (playful / serious / technical / warm)? Any sites you admire?
3. **Aesthetic Preferences** — Light or dark? Minimal or dense? Any direction from the aesthetic table you're drawn to?
4. **Constraints** — Framework requirements? Accessibility standards beyond baseline? Target devices?

If the user can't answer, infer from their codebase: scan for existing color variables, font imports, component patterns, and README/brand docs. Confirm inferences before proceeding.

### Persist Context After Each Decision

Write `./variant-output/.variant-context.json` whenever the user makes a meaningful choice. Create `variant-output/` first if it doesn't exist.

**Schema:**

```json
{
  "palette": "Amber Warm",
  "fonts": ["Instrument Serif", "Instrument Sans"],
  "direction": "Editorial",
  "scenario": "landing-page",
  "picked": "B",
  "iterations": 3,
  "framework": "next",
  "notes": "user prefers high contrast, no dark mode",
  "designDeclaration": {
    "user_context": "...",
    "primary_job": "...",
    "success_moment": "...",
    "trust_boundary": "...",
    "hierarchy": ["..."],
    "chosen_tension": "evidence > delight",
    "non_negotiables": ["..."],
    "evidence_status": "mock-clearly-labeled",
    "frozenAt": "2026-08-13T10:00:00Z"
  },
  "designSystem": {
    "confirmed": true,
    "file": "variant-output/design-system.css",
    "palette": "Amber Warm",
    "fonts": ["DM Sans", "Newsreader"],
    "confirmedAt": "2026-05-27T10:00:00Z"
  },
  "components": {
    "button": "variant-output/component-button.html",
    "card":   "variant-output/component-card.html",
    "form":   "variant-output/component-form.html"
  }
}
```

`designSystem.confirmed: true` is the gating flag. When true, all Generate/Component/Compose outputs read `variant-output/design-system.css` and must not introduce tokens outside it. When absent or false, full aesthetic invention is allowed.

**When to update:**
- After user picks a palette or confirms a direction → update `palette`, `direction`, `fonts`
- After user says `pick A/B/C` → update `picked`
- After each variation action (vary, remix, shuffle) → increment `iterations`
- After scenario is detected and confirmed → update `scenario`
- After framework is detected → update `framework`
- After user gives a preference constraint → append to `notes`
- After Design Declaration is confirmed → write `designDeclaration`; after `ds confirm`, add `frozenAt` and generate `variant-output/design-contract.md`
- After `ds confirm` → write `designSystem` object with `confirmed: true`, `file`, `palette`, `fonts`, `confirmedAt`
- After each `component [name]` build → add entry to `components` map
- After `ds reset` → set `designSystem.confirmed: false`, clear `components`

**Fields are optional** — write only what's known. Do not guess or fill in defaults.

Write the file silently (no terminal output). If write fails (e.g. no write permission), continue silently — context persistence is best-effort, never blocking.

---

## Site Analysis Mode

When the user points to existing code (file paths, a directory, or says "analyze/audit/check my site"), switch from generation mode to analysis mode. Load `references/design-system/style-audit.md` for the full methodology.

### Triggers

| User says | Action |
|---|---|
| "analyze my site" / "audit this" / "check consistency" | Full style audit → report |
| "match this style" / "follow existing design" / "extend my site" | Extract tokens → generate matching pages |
| "extract tokens" (on existing files, not a generated variation) | Token extraction → CSS custom properties file |
| "what's wrong with this design" / "review my CSS" | Style consistency check → findings list |
| "migrate" / "consolidate" / "clean up" | Audit → token generation → migration plan |
| "add a [page] to my site" / "new page matching my existing design" | Extract → match → generate |

### Analysis Workflow

**Step 1: Scan** — Read the files the user points to. If no specific files given, scan for:
```bash
# Auto-detect entry points
find . -name "*.html" -o -name "*.css" -o -name "*.tsx" -o -name "*.jsx" \
  -o -name "*.vue" -o -name "*.svelte" | head -20
# Also check for:
# - tailwind.config.* (Tailwind projects)
# - globals.css / index.css / app.css (common entry CSS)
# - tokens.css / variables.css / theme.* (existing token files)
```

**Step 2: Extract** — Pull all design primitives following the Token Extraction schema in `style-audit.md`: colors, typography, spacing, components, transitions. Group by semantic role.

**Step 3: Detect** — Run all consistency checks from `style-audit.md` Section 2. For each finding, record severity (error/warning/info), the specific values, file locations, and a concrete fix.

**Step 3.5: Visual Quality Audit** — In addition to consistency checks from `style-audit.md`, run this anti-slop checklist. Flag any item that fails with severity **warning** or **error**:

**Typography**
- [ ] Display font is NOT Inter/Roboto/Arial/Open Sans — use something with character
- [ ] Headlines have presence: tight tracking, compressed line-height, strong weight contrast
- [ ] Body text max-width ~65ch; line-height ≥ 1.5
- [ ] Weight range uses at least 3 stops (e.g. 400 / 500 / 700) — not just Regular + Bold
- [ ] Numbers in data contexts use `font-variant-numeric: tabular-nums` or monospace
- [ ] No orphaned single words on last line — use `text-wrap: balance` / `text-wrap: pretty`
- [ ] Headers use sentence case — not Title Case On Every Word

**Color & Surfaces**
- [ ] No pure `#000000` background — use off-black / dark charcoal / tinted dark
- [ ] Accent saturation below 80% — no neon or screaming accents
- [ ] Only one accent color — remove all others
- [ ] Grays are from one family — no mixing warm and cool grays
- [ ] No purple-to-blue "AI gradient" aesthetic
- [ ] Shadows are tinted to match background hue — not pure black at low opacity
- [ ] No random isolated dark section in a light-mode page (or vice versa)

**Layout**
- [ ] Not everything centered and symmetrical — break with offset, left-align, or asymmetry
- [ ] No 3 equal-column feature card row — use zig-zag, asymmetric grid, or horizontal scroll
- [ ] Uses `min-height: 100dvh` not `height: 100vh` (iOS Safari viewport jump)
- [ ] Has `max-width` container constraint — content doesn't stretch edge-to-edge
- [ ] Cards vary in size or weight — not uniformly identical
- [ ] Card group CTAs pin to bottom so buttons align across variable-length cards

**Interactivity & States**
- [ ] All buttons/links/cards have hover state (not just `opacity: 0.8`)
- [ ] Active/pressed feedback: `scale(0.98)` or `translateY(1px)`
- [ ] Transitions have non-zero duration (200-300ms)
- [ ] Visible `:focus-visible` ring — never `outline: none` alone
- [ ] Loading state exists — skeleton loaders, not generic spinners
- [ ] Empty state has content: acknowledge → explain value → CTA
- [ ] Error state has inline message — no `window.alert()`

**Content**
- [ ] No generic names: John Doe, Acme Corp, Nexus, SmartFlow
- [ ] No fake round numbers: `99.99%`, `$100.00`, `50,000 users`
- [ ] No AI clichés: Elevate, Seamless, Unleash, Next-Gen, Game-changer, Delve
- [ ] No Lorem Ipsum
- [ ] No exclamation marks in success/confirmation messages
- [ ] No passive voice in errors

**Iconography**
- [ ] Not using only Lucide/Feather icons — consider Phosphor or Radix UI Icons
- [ ] Consistent stroke width across all icons
- [ ] Favicon exists

**Code Quality**
- [ ] Semantic HTML: `<nav>`, `<main>`, `<article>`, `<section>` — not div soup
- [ ] No arbitrary z-index values (`9999`)
- [ ] All `<img>` have meaningful `alt` text
- [ ] Animations use only `transform` and `opacity` — no `top`/`left`/`width`/`height`

Score: subtract 2 points per failed item from 100. Present as `Quality Score: XX/100`.

**Step 4: Report** — Present findings using the compact terminal format from `style-audit.md` Section 3. Score out of 100. List priority fixes.

**Step 5: Act** — Based on what the user wants:
- **Audit only**: Stop after the report. Offer to generate a token file or migration plan.
- **Extract tokens**: Generate a `tokens.css` file consolidating all values (see `style-audit.md` Section 4).
- **Generate matching page**: Lock extracted tokens as constraints, generate new pages that match (see below).
- **Migration plan**: Generate phased checklist for consolidating the codebase (see `style-audit.md` Section 6).

### Style-Matched Generation

When generating new pages for an existing project, the workflow changes:

1. **Extract first** — Always analyze existing code before generating. Never guess the style.
2. **Lock tokens** — All generated code must use `var(--*)` referencing the existing token system. If no token system exists, generate one first and get user approval.
3. **Match patterns** — Study existing component shapes (card radius, shadow, padding), interaction patterns (transition durations, hover effects), layout patterns (container width, grid), and naming conventions (BEM, Tailwind, CSS modules).
4. **Show diff from existing** — In the Summary Card, note which tokens/patterns are being reused vs. which are new additions.
5. **Flag deviations** — If the design system principles (from Impeccable) conflict with the existing style, flag it: *"Your existing buttons have no hover state — I've added one following your color palette. OK?"*

**Summary Card for style-matched generation:**
```
✦ New page: /pricing — matching existing site style

  Reusing: --bg, --surface, --card, --border, --text, --muted, --accent
  Reusing: Plus Jakarta Sans 400/600, 4 font sizes, 8px grid
  Reusing: .card (24px padding, 8px radius, 1px border)
  Reusing: .btn (100px radius, 200ms transition)

  New additions:
  + Pricing toggle (monthly/annual) — uses existing .btn style
  + FAQ accordion — uses existing .card + new grid height animation
  + Comparison table — new component, follows existing spacing/color

  File: variant-output/pricing-matched.html ← opened in browser
```

### Quick Triggers for Analysis

| User types | Action |
|---|---|
| `audit` | Full style audit on current project |
| `audit src/styles/` | Audit specific directory |
| `tokens` | Extract tokens from existing code → CSS file |
| `match` | Enter style-matched generation mode |
| `new page pricing` | Generate /pricing page matching existing style |
| `migrate` | Generate migration plan for token consolidation |
| `compare old new` | Side-by-side: existing page vs. redesigned version |

---

## UX Review Mode

When the user wants to evaluate usability rather than generate visuals, switch to UX Review mode. Load `references/ux-heuristics.md` and `references/ux-psychology.md`. Load additional references as the review scope demands (see "When to Load Which Reference" below).

### Triggers

| User says | Action | Load |
|---|---|---|
| "ux review" / "heuristic review" / "usability audit" | Full heuristic evaluation against Nielsen's 10 | `ux-heuristics.md` + `ux-psychology.md` |
| "review this design" / "what's wrong with this UI" | Heuristic scan → findings list with severity | `ux-heuristics.md` |
| "check usability" / "is this good UX" | Walk through flow, flag violations | `ux-heuristics.md` + `ux-psychology.md` |
| "cognitive load" / "too complex?" | Cognitive load analysis → reduction suggestions | `ux-psychology.md` |
| "why do users get confused here" | Mental model analysis → mismatch diagnosis | `ux-psychology.md` |
| "affordances" / "does this look clickable" | Affordance/signifier audit | `ux-psychology.md` |
| "dark patterns" / "is this ethical" | Dark pattern scan | `ux-psychology.md` |
| "navigation" / "can't find" / "information architecture" / "IA" | IA audit — labels, hierarchy, findability | `ux-information-architecture.md` |
| "site structure" / "how to organize" / "card sort" / "tree test" | IA design or validation | `ux-information-architecture.md` |
| "accessibility" / "a11y" / "screen reader" / "keyboard navigation" | Accessibility audit against WCAG 2.1 AA | `ux-accessibility.md` |
| "WCAG" / "alt text" / "aria" / "focus" | Specific accessibility check | `ux-accessibility.md` |
| "user testing" / "how to test this" / "usability test" | Research method recommendation + test plan | `ux-research-methods.md` |
| "what do users think" / "how do I get feedback" | Research method selection | `ux-research-methods.md` |
| "NPS" / "SUS" / "survey" / "interview users" | Measurement framework or interview guidance | `ux-research-methods.md` |
| "transition feels wrong" / "animation timing" / "state choreography" / "loading feels laggy" | Component transition audit | `ux-interaction-transitions.md` |
| "touch target" / "thumb zone" / "mobile gesture" / "iOS vs Android" | Mobile interaction audit | `ux-mobile-patterns.md` |
| "onboarding" / "empty state" / "first use" / "aha moment" / "activation" | Onboarding flow review | `ux-onboarding.md` |
| "chart" / "dashboard" / "data viz" / "KPI card" / "which chart" | Data visualization audit or recommendation | `ux-data-visualization.md` |
| "content model" / "taxonomy" / "multilingual" / "RTL" / "localization" | Content structure review | `ux-content-strategy.md` |
| "design tokens" / "token naming" / "theming" / "dark mode architecture" | Token architecture review | `ux-design-tokens.md` |
| "component spec" / "button states" / "modal behavior" / "ARIA" | Component spec review | `ux-component-specs.md` |
| "design critique" / "feedback on design" / "design review meeting" | Critique framework guidance | `ux-design-critique.md` |
| "conversion" / "landing page" / "trust signals" / "CTA copy" / "pricing page" | Conversion UX audit | `ux-conversion-patterns.md` |
| "error message" / "error state" / "form error" / "validation" / "recovery path" / "prevent errors" | Error design audit — classification, messaging, prevention | `ux-error-design.md` |
| "empty state" / "no data" / "blank state" / "nothing here" / "zero state" | Empty state design — all 4 types | `ux-empty-states.md` |
| "notification" / "toast" / "banner" / "badge" / "push notification" / "alert priority" | Notification system design and priority rules | `ux-notifications.md` |
| "table" / "data table" / "sorting" / "filtering" / "pagination" / "bulk select" / "row actions" | Table and list interaction design | `ux-tables-lists.md` |
| "search" / "autocomplete" / "search results" / "search bar" / "faceted search" / "command palette" | Search pattern design — input, suggestions, results | `ux-search-patterns.md` |

### UX Review Workflow

Two paths depending on what's available:
- **Code in cwd** → run Code Scan (Steps 1a–1b) first, then layer conceptual analysis
- **No code / screenshots / description only** → skip to Step 2

**Step 1a: Auto-detect project files**

```bash
# Find component files in cwd (skip node_modules, .git, dist)
find . \( -name "*.tsx" -o -name "*.jsx" -o -name "*.vue" -o -name "*.svelte" -o -name "*.html" \) \
  -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/dist/*" | head -30
```

If files found, proceed to Step 1b. Otherwise skip to Step 2.

**Step 1b: Code-level heuristic scan**

Run these greps against the found files. Each maps to a specific heuristic:

```bash
# H9 — Generic error messages (critical pattern)
grep -rn "error occurred\|something went wrong\|invalid input\|please try again\|An error\|Unknown error" \
  --include="*.tsx" --include="*.jsx" --include="*.vue" --include="*.html" \
  --exclude-dir=node_modules --exclude-dir=dist . 2>/dev/null

# H1 — Missing loading states: async handlers without loading flag
grep -rn "onClick\|onSubmit\|handleSubmit" \
  --include="*.tsx" --include="*.jsx" --exclude-dir=node_modules . 2>/dev/null | head -20
# (then read those files to check if loading/disabled state is managed)

# H3 — Destructive actions: delete/remove calls without confirmation guard
grep -rn "delete\|remove\|destroy\|clearAll\|reset" \
  --include="*.tsx" --include="*.jsx" -i --exclude-dir=node_modules . 2>/dev/null | \
  grep -iv "confirm\|modal\|dialog\|undo\|trash\|soft" | head -20

# H4 — Terminology inconsistency: mixed action words for same concept
grep -rn '"Delete"\|"Remove"\|"Erase"\|"Discard"\|"Clear"' \
  --include="*.tsx" --include="*.jsx" --exclude-dir=node_modules . 2>/dev/null
# Flag if multiple terms coexist in same codebase

# H6 — Icon-only buttons missing accessible label
grep -rn "<button\|<Button\|<IconButton" \
  --include="*.tsx" --include="*.jsx" --exclude-dir=node_modules . 2>/dev/null | \
  grep -v "aria-label\|title=\|children\|tooltip" | head -20

# H5 — Forms missing inline validation
grep -rn "<form\|<Form\|onSubmit" \
  --include="*.tsx" --include="*.jsx" --exclude-dir=node_modules . 2>/dev/null | head -10
# (then read those files to check for inline validation vs. submit-only)

# H10 — Empty states: no empty state handling
grep -rn "\.length === 0\|\.length == 0\|items\.length\|data\.length" \
  --include="*.tsx" --include="*.jsx" --exclude-dir=node_modules . 2>/dev/null | \
  grep -v "EmptyState\|empty\|nothing\|no items\|no results" | head -15

# A11y — Images missing alt text
grep -rn "<img " \
  --include="*.tsx" --include="*.jsx" --include="*.html" \
  --exclude-dir=node_modules . 2>/dev/null | grep -v "alt=" | head -10

# A11y — Buttons missing accessible name (icon-only)
grep -rn "<button\|<Button\|<IconButton" \
  --include="*.tsx" --include="*.jsx" --exclude-dir=node_modules . 2>/dev/null | \
  grep -v "aria-label\|aria-labelledby\|title=" | head -15

# A11y — onClick on non-interacti

…(truncated)
