mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-19 01:26:29 +03:00
Migrate site from Bun to Astro (#130)
* feat(site): scaffold Astro migration, convert 3 pages Phase 1+2 of the Astro migration: - Astro v6.2.1 installed, srcDir: 'site', static output to build/ - Shared layout: Base.astro (head, fonts, meta, slots), Header.astro (star count in one place: 23k), Footer.astro - CSS moved from public/css/ to site/styles/ (9 files, @import chains resolve via Vite) - Three pages converted: privacy, cases/neo-mirai, live-mode (all return 200 on astro dev) Remaining: designing, slop, homepage, content collections (docs), JS migration, server/index.js deletion, build.js cleanup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(site): migrate all 6 main pages to Astro Converts the remaining pages: - designing/index.html → site/pages/designing/index.astro (551 lines) - slop/index.html → site/pages/slop/index.astro (909 lines) - index.html → site/pages/index.astro (1278 lines, the homepage) Base.astro gains OG meta tag props, before-header/after-header slots (for grain overlay and section nav), and configurable mainId. Homepage uses link tags to public/css/ instead of frontmatter CSS imports to avoid esbuild choking on :has() in main.css. Curly braces inside <code> elements (CSS snippets in changelog) escaped with HTML entities to prevent Astro JSX expression parsing. All 6 pages return 200 on astro dev. Branch: feat/astro-migration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(site): content collections for docs and tutorials Replaces the 1532-line build-sub-pages.js generator with Astro v6 content collections: - 24 skill editorial files move to site/content/skills/ - 4 tutorial files move to site/content/tutorials/ - site/content.config.ts defines both collections with glob loaders - site/pages/docs/[...slug].astro reads skills collection + command metadata from source/skills/ at build time - site/pages/docs/index.astro renders the command grid grouped by category (create, evaluate, refine, simplify, harden, system) - site/pages/tutorials/ mirrors the pattern with ordered index - Doc.astro layout provides sidebar nav, breadcrumbs, and related- command chips from the COMMAND_RELATIONSHIPS data - Category/relationship data extracted to site/data/sub-pages-data.ts All 15 tested pages return 200: 6 main pages + 5 docs + 2 tutorials + 2 index pages. The old generator is not yet deleted (Task #6). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(site): move JS source from public/js/ to site/scripts/ Moves all 49 JS files (app.js + 48 in js/) into site/scripts/. Vite now processes them through its module bundler instead of serving them raw from public/. app.js import paths updated from ./js/X to ./X (the js/ nesting is gone since app.js now lives alongside the subdirectories). Homepage and live-mode page switch from <script is:inline src="/app.js"> to Vite-processed <script> imports, so tree-shaking, bundling, and minification happen automatically at build time. public/js/ still exists for now (cleanup in Task #6) and the generated/counts.js build output path needs updating there too. @paper-design/shaders added to npm dependencies (was missing). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(site): delete old Bun server, generator, and duplicated files Cleanup after the Astro migration: Deleted: - server/index.js (233 lines, replaced by `astro dev`) - scripts/build-sub-pages.js (1532 lines, replaced by content collections) - scripts/lib/render-page.js (247 lines, replaced by Base.astro layout) - content/site/partials/header.html (replaced by Header.astro component) - public/index.html, privacy.html, designing/, live-mode/, cases/ (replaced by .astro pages in site/pages/) - public/css/ (moved to site/styles/) - public/js/ old source files (moved to site/scripts/) - public/app.js (moved to site/scripts/app.js) Kept in public/: - antipattern-examples/ (standalone HTML demos, not Astro pages) - antipattern-images/, assets/, neo-mirai/ (static assets) - js/detect-antipatterns-browser.js (referenced by antipattern examples) - js/generated/counts.js (build output from scripts/build.js) - _data/api/ (generated API data, now written to public/ so Astro passes it through to build/) Updated: - astro.config.mjs: added redirects (skills->docs, cheatsheet->docs, gallery->slop, neon-mirai->neo-mirai, etc.) - package.json: dev->astro dev, build->build:skills+build:site, preview->astro preview - scripts/build.js: removed buildStaticSite(), generateSubPages(), static-asset copying. API data writes to public/_data/ instead of build/_data/. Site-header validator is a no-op (shared component). Em-dash validator scans site/components + site/layouts, not pages (pages contain content from other sources like detector descriptions). - .gitignore: removed public/slop/ entry Tests: 186/186 pass. Skills build: clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(site): fix redirect config for Astro compatibility Move the dynamic /skills/:id -> /docs/:id redirect to public/_redirects (Cloudflare Pages native format) since Astro's redirect config can't handle dynamic routes that don't match existing page patterns. Remove duplicate trailing-slash redirect entries that caused warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(site): switch remaining pages from /css/ link tags to frontmatter imports Doc.astro, docs/index, tutorials/index, and tutorials/[slug] were still using <link href="/css/sub-pages.css"> which pointed at the deleted public/css/ directory. Switched to frontmatter CSS imports (import '../../styles/sub-pages.css') which Vite resolves from site/styles/. Homepage also switches from link tags to frontmatter imports for main.css and sub-pages.css — the esbuild error that originally forced the link-tag workaround was caused by unescaped curly braces in the HTML content (since fixed), not by the CSS itself. All pages verified visually in Chrome: homepage hero, foundation grid, docs index (card grid with categories), docs detail (sidebar + editorial content + visual mockups), designing (core loop diagram), privacy, tutorials. Header renders with 23k stars on every page. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(site): fix edge-to-edge sections, broken API paths, CSS links Three fixes: 1. Homepage sections sat on the viewport edge because Base.astro's <main> lacked the site-content class (provides max-width + padding). Added mainClass prop to Base.astro; homepage sets mainClass="site-content". 2. "Failed to load commands" because app.js fetched /api/commands which only existed in the old Bun server's routing. Updated to fetch from /_data/api/commands.json (the static JSON files that build:skills writes to public/_data/). 3. CSS reference fix (previous commit was incomplete): Doc.astro, docs/index, tutorials pages all used <link href="/css/sub-pages.css"> pointing at deleted public/css/. Switched to frontmatter imports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(site): add sidebar to docs index page The docs index was using Base.astro directly without the skills-layout grid, so it rendered without a sidebar. Added the same sidebar structure from Doc.astro (category-grouped command list) and wrapped the content in the skills-layout grid. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(site): extract footer CSS to shared file, import in Base.astro Footer was unstyled on sub-pages because footer CSS lived only in main.css (loaded by the homepage) not in sub-pages.css. Extracted the 95 lines of footer rules into site/styles/footer.css and imported it in Base.astro so every page gets footer styles regardless of which page-specific CSS it loads. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(demos): move landing-demo into repo, add as slop specimens Moves ~/code/landing-demo/ into demos/landing-demo/ (without node_modules or the redundant .claude/.agents skill copies — the repo root's skill is found by walking up). PRODUCT.md, DESIGN.md, DESIGN.json, PROMPT.md, and SCRIPT.md stay in place so running Claude from demos/landing-demo/ picks up the project context. Also copies both pages as slop specimens to public/antipattern-examples/ with the detector script baked in: - new-slop-2026.html (Fraunces + warm cream editorial monoculture) - old-slop-2022.html (purple gradient + glassmorphism + neon glow) These can be linked from the slop page gallery alongside the existing 11 synthetic specimens. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(slop): replace single demo iframe with Then vs Now comparison The "See it" section (01) on the slop page now shows two side-by-side browser frames: 2022 slop (purple gradients, glassmorphism, neon glow) and 2026 slop (Fraunces, warm cream, editorial restraint). Both run the detector overlay live — hover either to see which rules fire. Replaces the single visual-mode-demo.html iframe. Responsive: stacks vertically on viewports below 900px. Caption: "Same engine, different decade, both flagged." Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(slop): switch to single-frame era toggle, center the section Replaces the side-by-side dual-iframe layout with a single large frame and a segmented 2022/2026 toggle. Clicking the toggle swaps which iframe is visible (both pre-loaded, instant switch). Browser chrome title updates to match the active era. Centers the lede text and toggle above the frame for visual cohesion with the full-width iframe below. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(slop): left-align See It section, toggle inline with lede Moves the era toggle to the right of the lede paragraph using a flex row (align-items: flex-end). Left-aligned text + right-docked toggle matches the rest of the page's flow instead of standing out as a centered island. Stacks vertically on narrow viewports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(slop): left-align iframe, remove max-width and auto margin The visual-mode-preview had max-width: 1040px + margin: 0 auto which centered it within the column. Override both in the .slop-then-now context so the frame fills the full content width flush with the text above. Caption left-aligned to match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(site): update star count to 24k (24,062) One file, one edit. The Astro migration working as intended. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(build): regenerate pnpm-lock.yaml for astro + shaders deps Cloudflare Pages uses pnpm with frozen-lockfile. The lockfile was stale after adding astro, @astrojs/cloudflare, and @paper-design/shaders via npm. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(build): resolve 3 bugbot review issues 1. Restore public/slop/ to .gitignore — prevents accidental legacy generator output from conflicting with the Astro page. 2. Move astro and @paper-design/shaders to devDependencies — these are site-build tools, not CLI runtime deps. Removes @astrojs/cloudflare entirely (unused; static output mode needs no adapter). 3. Fix Astro wiping build:skills output — CF config (_headers, _redirects, _routes.json) and API data now write to public/ so Astro copies them through. Dist ZIPs copy to build/_data/dist/ as a post-build step (after Astro finishes). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(build): merge duplicate devDependencies, use npx for astro CLI The previous commit created a second devDependencies key in package.json. JSON doesn't support duplicate keys — pnpm ignored the first block (with astro), so `astro build` wasn't found. Merged astro and @paper-design/shaders into the existing devDependencies block. Changed `astro build/dev/preview` to `npx astro build/dev/preview` so pnpm finds the local binary on Cloudflare Pages (which doesn't add node_modules/.bin to PATH by default). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(demos): remove private demo script and prompt from public repo SCRIPT.md contained a detailed conference talk script with personal delivery strategies, rehearsed Q&A answers, and venue details. PROMPT.md contained the origin brief for the demo page. Neither belongs in a public repo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(build): gitignore generated public/ artifacts, consolidate redirects 1. Generated files written to public/ by build:skills (API data, CF config, browser detector, counts.js) are now gitignored. Prevents noisy diffs and merge conflicts from committed build artifacts. 2. Removed duplicate redirects from astro.config.mjs. All redirects now live in one place: the _redirects file generated by scripts/build.js (which Cloudflare Pages processes natively). Eliminates the dual-maintenance risk where the two sources could drift apart. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
a312da5ec7
commit
b8f09c8142
@@ -0,0 +1,130 @@
|
||||
---
|
||||
title: Brand vs product, pick a register
|
||||
tagline: "Two worlds, two sets of defaults. Pick the right one and every command downstream benefits."
|
||||
order: 3
|
||||
description: "Impeccable treats brand work (landing pages, campaigns, portfolios) and product work (app UI, dashboards, tools) as different worlds with different defaults. Learn how to pick a register and how it shapes every command that reads it."
|
||||
---
|
||||
|
||||
## See the divergence
|
||||
|
||||
Same element, one register each. A newsletter signup, twice.
|
||||
|
||||
<div class="docs-viz-hero docs-viz-hero--plain">
|
||||
<div class="docs-viz-register">
|
||||
<div class="docs-viz-register-side">
|
||||
<div class="docs-viz-register-label">
|
||||
<span class="docs-viz-register-name">Brand</span>
|
||||
<span class="docs-viz-register-lane">Editorial-magazine</span>
|
||||
</div>
|
||||
<div class="docs-viz-register-frame docs-viz-register-frame--brand">
|
||||
<span class="docs-viz-reg-kicker">No. 04 · Dispatch</span>
|
||||
<h3 class="docs-viz-reg-title">Letters, occasionally.</h3>
|
||||
<p class="docs-viz-reg-body">A postcard from the editor, once a month. No tracking pixels, no "just checking in."</p>
|
||||
<span class="docs-viz-reg-btn">Send me one</span>
|
||||
</div>
|
||||
<div class="docs-viz-register-notes">
|
||||
<span>Serif display, italic display weight</span>
|
||||
<span>Drenched in the primary hue</span>
|
||||
<span>Monospaced kicker, editorial voice</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="docs-viz-register-side">
|
||||
<div class="docs-viz-register-label">
|
||||
<span class="docs-viz-register-name">Product</span>
|
||||
<span class="docs-viz-register-lane">Utility / app shell</span>
|
||||
</div>
|
||||
<div class="docs-viz-register-frame docs-viz-register-frame--product">
|
||||
<span class="docs-viz-reg-kicker">Newsletter</span>
|
||||
<h3 class="docs-viz-reg-title">Subscribe to updates</h3>
|
||||
<p class="docs-viz-reg-body">Product changes and release notes, once a month. Unsubscribe at any time.</p>
|
||||
<span class="docs-viz-reg-btn">Subscribe</span>
|
||||
</div>
|
||||
<div class="docs-viz-register-notes">
|
||||
<span>Neutral sans, semibold for hierarchy</span>
|
||||
<span>Restrained palette, accent only on state</span>
|
||||
<span>Short, scannable, mobile-readable copy</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="docs-viz-caption">The table below lists what's different. This is what it looks like at the pixel.</p>
|
||||
</div>
|
||||
|
||||
## Why register matters
|
||||
|
||||
Every design task belongs to one of two worlds:
|
||||
|
||||
- **Brand** is where design IS the product. Marketing sites, landing pages, portfolios, long-form content, campaign surfaces. Distinctiveness is the bar. Fonts, motion, density, and color all push toward "this looks like nothing else in the category."
|
||||
- **Product** is where design SERVES the product. App UI, admin, dashboards, tools. Earned familiarity is the bar. Fluent users of Linear, Figma, Notion, Raycast, or Stripe should trust the output on sight.
|
||||
|
||||
If you ask the same AI to design a dashboard and a campaign page without naming which world, you'll get the average of the two. Brand surfaces will feel too careful. Product surfaces will feel too precious. Register is how Impeccable avoids that.
|
||||
|
||||
Impeccable tracks register as a single field in `PRODUCT.md`:
|
||||
|
||||
```markdown
|
||||
## Register
|
||||
|
||||
product
|
||||
```
|
||||
|
||||
That is it: a bare value, `brand` or `product`. Every command that does register-sensitive work (`typeset`, `animate`, `colorize`, `layout`, `bolder`, `quieter`, `delight`) loads a different reference file based on what it finds here.
|
||||
|
||||
## How the two worlds diverge
|
||||
|
||||
This is not an exhaustive list, the full divergence lives in the `brand.md` and `product.md` reference files, but the shape of the difference:
|
||||
|
||||
| Dimension | Brand | Product |
|
||||
|---|---|---|
|
||||
| **Type lanes** | Editorial-magazine, luxury, brutalist, consumer-warm, tech-minimal, all available. Swing. | Tighter set: neutral sans + optional mono, sized for dense reading, fluid type reserved for marketing surfaces. |
|
||||
| **Motion** | Choreographed entrances, scroll-driven sequences, decorative moments earn their place. | Restrained. State changes only. Animation serves feedback, not atmosphere. |
|
||||
| **Color** | Full palette, Committed, or Drenched are all on the table. | Restrained by default. Accents carry meaning; color is not decoration. |
|
||||
| **Density** | Whatever the narrative wants. Generous whitespace or packed rule-divided columns both valid. | Comfortable to dense. Every pixel earns its place. |
|
||||
| **References** | Real-world, from the right lane. *Klim specimen pages* or *Broadsheet masthead*, not "modern SaaS". | Category best-tool. *Linear*, *Figma*, *Notion*, *Raycast*, *Stripe*. |
|
||||
|
||||
The same command, `/impeccable typeset`, pulls from different fonts in the two worlds. The same command, `/impeccable animate`, picks different motion vocabularies. The same command, `/impeccable layout`, assumes different density defaults. You do not re-learn the command: you answer the register question once, and the command adapts.
|
||||
|
||||
## Step 1. Decide or inherit
|
||||
|
||||
If you haven't run `/impeccable teach` yet, run it now. The first question is about register:
|
||||
|
||||
```
|
||||
/impeccable teach
|
||||
```
|
||||
|
||||
Teach scans your codebase first and forms a hypothesis: routes like `/`, `/pricing`, `/blog`, hero sections, scroll-driven content point toward brand. Routes like `/app`, `/dashboard`, `/settings`, forms and tables point toward product. It leads with the hypothesis rather than starting cold:
|
||||
|
||||
> From the codebase, this looks like a product surface, does that match your intent, or should we treat it differently?
|
||||
|
||||
If the project genuinely spans both (a product with a big marketing landing), teach asks which register describes the **primary** surface. Register is per-project, not per-page, but you can override it per task when needed.
|
||||
|
||||
## Step 2. Verify the register landed
|
||||
|
||||
Open `PRODUCT.md` and look for the `## Register` section. It should carry a bare value, not prose:
|
||||
|
||||
```markdown
|
||||
## Register
|
||||
|
||||
brand
|
||||
```
|
||||
|
||||
If the section is missing (you're on an older `PRODUCT.md` from pre-v3.0), re-run `/impeccable teach`. It will detect the gap and add the field without re-interviewing you on everything else.
|
||||
|
||||
## Step 3. Override per task when you need to
|
||||
|
||||
Most of the time, register is set once and forgotten. But a product project might occasionally need a single brand surface (a launch landing, an investor one-pager) without flipping the whole project.
|
||||
|
||||
You have two options:
|
||||
|
||||
- **Name it in the brief.** "`/impeccable craft a launch landing for v2, brand register for this one page.`" The skill honors the override for that task only.
|
||||
- **Set a per-surface register.** If the override is lasting, add a short note in `PRODUCT.md` under an explicit section: `## Register overrides: /launch is brand.` Commands that read PRODUCT.md will respect it.
|
||||
|
||||
## What to try next
|
||||
|
||||
- Run a command that is register-sensitive and watch the divergence: `/impeccable typeset the pricing page` on a product project vs. a brand project will pick different type families, different scale ratios, and different pairings.
|
||||
- Pair with [getting started](/tutorials/getting-started) if you haven't installed Impeccable yet.
|
||||
- Reach for `/impeccable document` after teach to capture the visual side (colors, components) into DESIGN.md.
|
||||
|
||||
## Common issues
|
||||
|
||||
- **Register keeps slipping the wrong way.** If you set `product` but commands keep producing brand-feeling output, check that `PRODUCT.md` is at the project root and the `## Register` section has a bare value (no prose, no explanation, just the word). Commands can only read what is there.
|
||||
- **The hypothesis teach formed is wrong.** Disagree in the answer. Teach is asking, not telling.
|
||||
- **A project is genuinely 50/50.** Pick the primary surface, then use per-task overrides for the minority one. Trying to average the two in PRODUCT.md produces worse output than committing to one.
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
title: Critique with the visual overlay
|
||||
tagline: "Use /impeccable critique plus the browser overlay to review a live page with ground truth."
|
||||
order: 4
|
||||
description: "Run a full design critique that combines LLM assessment, the automated detector, and a live browser overlay so you can see exactly which elements trigger which anti-patterns on the page you're looking at."
|
||||
---
|
||||
|
||||
## What you'll build
|
||||
|
||||
You will run a complete design critique against a live page in your browser, with every flagged anti-pattern highlighted directly on the element that caused it. No screenshots, no guesswork, no paragraph of findings you have to map back to the code.
|
||||
|
||||
Total time: about ten minutes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Impeccable installed in your project (see [getting started](/tutorials/getting-started) if you have not).
|
||||
- A harness with browser automation available (Claude Code with the Chrome extension, or similar).
|
||||
- A page you want to critique, either local (`localhost:3000/pricing`) or deployed.
|
||||
|
||||
## Step 1. Run /impeccable critique
|
||||
|
||||
From your harness, run:
|
||||
|
||||
```
|
||||
/impeccable critique the pricing page at localhost:3000/pricing
|
||||
```
|
||||
|
||||
The skill kicks off two independent assessments in parallel. They run in separate sub-agents so one does not bias the other.
|
||||
|
||||
### What the LLM assessment does
|
||||
|
||||
The first assessment reads your source code and, if browser automation is available, opens the live page in a new tab. It walks the full impeccable skill DO/DON'T catalog and scores the page against Nielsen's 10 heuristics, the 8-item cognitive load checklist, and the brand fit from your `PRODUCT.md`.
|
||||
|
||||
It labels the tab it opens with `[LLM]` in the title so you can tell which one is which.
|
||||
|
||||
### What the automated detector does
|
||||
|
||||
The second assessment runs `npx impeccable detect` against the page. This is deterministic: around thirty specific pattern checks that fire or do not fire. Gradient text, purple palettes, side-tab borders, nested cards, line length problems, low contrast, tiny body text, and the rest. The [full catalog](/anti-patterns) lists every rule and which layer (CLI, browser, or LLM-only) catches it.
|
||||
|
||||
You get back a JSON list of every finding with its element selector, the rule that fired, and a short description.
|
||||
|
||||
## Step 2. Open the visual overlay
|
||||
|
||||
Impeccable ships with a visual mode that highlights every detected anti-pattern directly on the page. Here is what it looks like running on a deliberately-bad synthwave landing page:
|
||||
|
||||
<div class="tutorial-embed">
|
||||
<div class="tutorial-embed-header">
|
||||
<span class="tutorial-embed-dot red"></span>
|
||||
<span class="tutorial-embed-dot yellow"></span>
|
||||
<span class="tutorial-embed-dot green"></span>
|
||||
<span class="tutorial-embed-title">Live detection overlay</span>
|
||||
</div>
|
||||
<iframe src="/antipattern-examples/visual-mode-demo.html" class="tutorial-embed-iframe" loading="lazy" title="Impeccable visual overlay running on a demo page"></iframe>
|
||||
</div>
|
||||
|
||||
Every outlined element has a floating label naming the rule that fired. Hover an outline to see the full finding. This is exactly what you will see on your own page.
|
||||
|
||||
You have two ways to open it:
|
||||
|
||||
1. **[Chrome extension](https://chromewebstore.google.com/detail/impeccable/bdkgmiklpdmaojlpflclinlofgjfpabf)**: one-click activation on any page. Click the Impeccable icon in the toolbar and every anti-pattern gets highlighted instantly.
|
||||
2. **Inside `/impeccable critique`**: the skill opens a browser tab labeled `[Human]` with the detector active during the browser portion of the assessment. You do not need to do anything extra.
|
||||
|
||||
For this tutorial, the easiest option is the Chrome extension. Install it, navigate to your pricing page, and click the Impeccable icon. You will see the overlay appear immediately on the live page.
|
||||
|
||||
## Step 3. Merge the two assessments
|
||||
|
||||
Back in your harness, `/impeccable critique` has finished and produced a combined report. It looks something like:
|
||||
|
||||
```
|
||||
AI slop verdict: FAIL
|
||||
Detected tells: gradient-text (2), ai-color-palette (1),
|
||||
nested-cards (1), side-tab (3)
|
||||
|
||||
Heuristic scores (avg 2.8/4):
|
||||
Visibility of status: 3 (good)
|
||||
Match between system and real world: 2 (partial)
|
||||
Consistency and standards: 2 (partial)
|
||||
...
|
||||
|
||||
Cognitive load: 3/8 failures (moderate)
|
||||
Visible options at primary decision: 6 (flag)
|
||||
Decision points stacked at top: yes (flag)
|
||||
Progressive disclosure: absent on advanced pricing toggles
|
||||
|
||||
What's working:
|
||||
- Clear price hierarchy
|
||||
- Strong headline
|
||||
|
||||
Priority issues:
|
||||
1. Hero uses gradient text on the main price
|
||||
Why: AI tell, reduces contrast, hurts scannability
|
||||
Fix: solid ink color at one weight heavier
|
||||
2. Feature comparison table has 4 nested card levels
|
||||
Why: visual noise, unclear hierarchy
|
||||
Fix: flatten to a table with zebra striping
|
||||
|
||||
Questions to answer:
|
||||
- Is the free tier a real product or a funnel?
|
||||
- What does a user feel when they land here from an ad vs from search?
|
||||
```
|
||||
|
||||
## Step 4. Fix the findings
|
||||
|
||||
The report gives you a priority list. You can work through them one at a time, ask the model to fix them all at once, or anything in between. What matters is using the overlay to verify:
|
||||
|
||||
1. Keep the overlay open in one tab.
|
||||
2. Make fixes in code (or ask the model to fix everything).
|
||||
3. Reload. The overlay re-scans and resolved findings disappear.
|
||||
|
||||
This feedback loop is the reason the overlay matters. You see fixes land in real time, and you never ship a "fix" that did not actually satisfy the rule.
|
||||
|
||||
## Step 5. Re-run when you are done
|
||||
|
||||
After you have worked through the priority list, run `/impeccable critique` again. The goal is a clean AI slop verdict and at least a 3.5 average on the heuristics. Cognitive load should be below 2 failures.
|
||||
|
||||
If something still fires, fix it or write a suppression comment explaining why the rule does not apply in your context (the detector respects a small set of opt-out pragmas, but use them sparingly).
|
||||
|
||||
## What to try next
|
||||
|
||||
- [Iterate on the critique findings with Live Mode](/tutorials/iterate-live). Pick the element critique flagged, drop a comment, get three redirections hot-swapped in place, and write the accepted one back to source.
|
||||
- `/impeccable audit the same page` to catch the implementation issues critique does not cover (accessibility, performance, theming).
|
||||
- `/impeccable polish` if the critique report is clean and you want the last-mile refinement pass.
|
||||
- `/impeccable distill` if critique flagged "too busy" or "cognitive load". Distill removes what should not be there.
|
||||
|
||||
## Common issues
|
||||
|
||||
- **The overlay shows no findings but critique says there are problems**. The detector catches deterministic patterns. Critique catches judgment calls. They are complementary, not redundant.
|
||||
- **The LLM assessment and the detector disagree**. That is normal. The LLM is subjective. The detector is deterministic. When they disagree, look at both and make a call.
|
||||
- **The overlay breaks the page layout**. Rare, but some CSS can interact with the injected overlay styles. Use the [Chrome extension](https://chromewebstore.google.com/detail/impeccable/bdkgmiklpdmaojlpflclinlofgjfpabf) for the most reliable experience, or run `npx impeccable detect` from the CLI and apply findings manually.
|
||||
@@ -0,0 +1,106 @@
|
||||
---
|
||||
title: Getting started
|
||||
tagline: "From zero to your first polish pass in five minutes."
|
||||
order: 1
|
||||
description: "Install Impeccable, run /impeccable teach once to establish project context, and run /impeccable polish on something that already exists. The fastest path to seeing what Impeccable changes about AI-generated design."
|
||||
---
|
||||
|
||||
## What you'll build
|
||||
|
||||
You will end this tutorial with Impeccable installed in your project, a `PRODUCT.md` plus `DESIGN.md` pair that captures your brand, audience, and visual system, and one hand-polished page that went through a polish pass. Total time: about ten minutes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- An AI coding harness: Claude Code, Cursor, Gemini CLI, Codex CLI, or any of the other supported tools.
|
||||
- A project with at least one HTML or component file you want to improve. A fresh scaffolded landing page works fine.
|
||||
|
||||
## How Impeccable works
|
||||
|
||||
Impeccable installs as a single agent skill called `impeccable`. You access all 23 sub-commands through it:
|
||||
|
||||
```
|
||||
/impeccable <command> <target>
|
||||
```
|
||||
|
||||
For example: `/impeccable polish the pricing page`, or `/impeccable audit the checkout`. Type `/impeccable` alone to see the full list.
|
||||
|
||||
If you use a command often, pin it with `/impeccable pin <command>` to create a standalone shortcut (for example, `/impeccable pin audit` gives you `/audit` directly).
|
||||
|
||||
## Step 1. Install
|
||||
|
||||
From the root of your project, run:
|
||||
|
||||
```
|
||||
npx skills add pbakaus/impeccable
|
||||
```
|
||||
|
||||
This auto-detects your harness and writes the skill files to the right location (e.g., `.claude/skills/`, `.cursor/skills/`). Reload your harness and type `/`. You should see `/impeccable` in the autocomplete. Type it and the skill's argument hint will show all available commands.
|
||||
|
||||
## Step 2. Teach Impeccable about your project
|
||||
|
||||
This is the most important step. Design without context produces generic output. The `/impeccable teach` command runs a short discovery interview and writes a `PRODUCT.md` file at the root of your project.
|
||||
|
||||
Run:
|
||||
|
||||
```
|
||||
/impeccable teach
|
||||
```
|
||||
|
||||
The first question is about **register**: is this a brand surface (marketing site, landing page, portfolio, where design IS the product) or a product surface (app UI, dashboard, tools, where design SERVES the product)? Register shapes every downstream default, from type lanes to motion energy. See [brand vs product](/tutorials/brand-vs-product) for how the two diverge. Teach will form a hypothesis from your codebase and ask you to confirm, rather than starting cold.
|
||||
|
||||
Then a handful of shorter questions:
|
||||
|
||||
- **Who is this product for?** Be specific. Not "users" but "solo founders evaluating a new tool on their phone between meetings".
|
||||
- **What is the brand voice in three words?** Pick real words. "Warm and mechanical and opinionated" is better than "modern and clean".
|
||||
- **Any visual references?** Named brands, products, or printed objects, not adjectives. "Klim Type Foundry specimen pages", not "technical and clean".
|
||||
- **Anti-references?** Things the product should explicitly not look like, equally named.
|
||||
|
||||
Answer in your own words. The skill writes `PRODUCT.md` with the answers. Every future command run reads it automatically.
|
||||
|
||||
Open `PRODUCT.md` and read what it wrote. Edit anything that does not feel right. The file is yours.
|
||||
|
||||
## Step 2.5. Capture the visual system
|
||||
|
||||
At the end of `/impeccable teach`, the skill offers to run `/impeccable document` for you. Say yes. It scans your tokens (CSS custom properties, Tailwind config, CSS-in-JS themes), extracts colors and typography, asks one grouped question for the parts that need creative input (a Creative North Star, descriptive color names), and writes a `DESIGN.md` that follows the [Google Stitch DESIGN.md format](https://stitch.withgoogle.com/docs/design-md/format/).
|
||||
|
||||
On a fresh project with no tokens yet, document runs in seed mode: five quick questions about color strategy, type direction, and motion energy, and writes a scaffold you can refresh once there is code.
|
||||
|
||||
`PRODUCT.md` carries strategy (who, what, why). `DESIGN.md` carries visuals (colors, typography, components). Every command reads both before generating.
|
||||
|
||||
## Step 3. Polish something
|
||||
|
||||
Pick a page that already exists. An about page, a settings screen, a pricing table, anything. Run:
|
||||
|
||||
```
|
||||
/impeccable polish the pricing page
|
||||
```
|
||||
|
||||
The skill will walk through alignment, spacing, typography, color, interaction states, transitions, and copy. It makes targeted fixes, not a rewrite. Expect a handful of small diffs that together lift the page from "done" to "done well".
|
||||
|
||||
A typical polish pass looks like:
|
||||
|
||||
```
|
||||
Visual alignment: fixed 3 off-grid elements
|
||||
Typography: tightened h1 kerning, fixed widow on feature list
|
||||
Color: replaced one hardcoded hex with --color-accent token
|
||||
Interaction: added missing hover state on FAQ items
|
||||
Motion: softened modal entrance to 220ms ease-out-quart
|
||||
Copy: removed stray 'Lorem' placeholder
|
||||
```
|
||||
|
||||
Review the diff. If something does not feel right, ask the model to explain the change. If it still does not feel right, revert it. Impeccable is opinionated but not infallible.
|
||||
|
||||
## What to try next
|
||||
|
||||
- [Iterate visually with Live Mode](/tutorials/iterate-live) opens a browser picker on your dev server, generates three production-quality variants per element, and writes the accepted one back to source.
|
||||
- `/impeccable critique the landing page` runs a full design review with scoring, persona tests, and automated detection. It is the best way to find what to fix next.
|
||||
- `/impeccable audit the checkout` runs accessibility, performance, theming, responsive, and anti-pattern checks against the implementation. Useful before shipping.
|
||||
- `/impeccable craft a pricing page for enterprise customers` runs the full shape-then-build flow on a brand new feature.
|
||||
- **Pin your favorites.** If you reach for one command constantly, `/impeccable pin audit` makes `/audit` work as a standalone shortcut without reversing the consolidation.
|
||||
- `/impeccable redo this hero section` works too. Any description after `/impeccable` applies the design principles to the task.
|
||||
|
||||
## Common issues
|
||||
|
||||
- **The skill says "no design context found"**. You skipped step 2. Run `/impeccable teach` first.
|
||||
- **Commands do not appear in the harness**. Reload the harness after installing. If they still do not appear, check that the installer wrote files into the expected location (`.claude/skills/`, `.cursor/skills/`, etc.) and that your harness is picking up that directory.
|
||||
- **The polish pass rewrote something you liked**. Say so. Revert the change, tell the model which specific edit to undo, and continue from there.
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: Iterate on UI with Live Mode
|
||||
tagline: "Pick an element, generate three variants, accept one. Canvas-like iteration without leaving your code."
|
||||
order: 2
|
||||
description: "Use /impeccable live to visually iterate on a real element in your dev server: pick, annotate, generate three variants, accept the one you want, and have it written back to source."
|
||||
---
|
||||
|
||||
## What you'll build
|
||||
|
||||
You will use `/impeccable live` on your dev server to iterate on a single piece of UI (a hero, a card, a section) and end with one of three AI-generated variants written back to source as real code. You'll see the canvas-style picking, annotation, and three-up cycling flow.
|
||||
|
||||
Total time: about ten minutes. Most of that is picking what to iterate on.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Impeccable installed (see [getting started](/tutorials/getting-started) if you have not). Run `/impeccable teach` first if you haven't yet: variants lean on `PRODUCT.md` and `DESIGN.md` for brand fit.
|
||||
- A running dev server with HMR (Vite, Next.js, SvelteKit, Astro, Nuxt, Bun) OR a static HTML file open in a browser.
|
||||
- A page with at least one piece of UI you'd like to iterate on. A newsletter card, a hero, a pricing tier, something small enough to hold in your head.
|
||||
|
||||
## Step 1. Start live mode
|
||||
|
||||
From your harness, run:
|
||||
|
||||
```
|
||||
/impeccable live
|
||||
```
|
||||
|
||||
The skill starts a small local helper server on port 8400 and injects a `<script>` tag into your dev entry file that loads the picker. If your project has a strict Content Security Policy, the first run detects it and offers a one-time, dev-only patch for `script-src` and `connect-src`. Accept the patch: it is guarded by `NODE_ENV === "development"` and you can revert any time.
|
||||
|
||||
Open your dev server URL (not port 8400, that's the helper server, not the app). You'll see a dark pill at the bottom of the page with **Pick** highlighted.
|
||||
|
||||
## Step 2. Pick an element
|
||||
|
||||
<div class="docs-viz-step">
|
||||
<div class="docs-viz-picker-row">
|
||||
<div class="docs-viz-picker-target">
|
||||
<span class="docs-viz-picker-pin">1</span>
|
||||
Newsletter signup
|
||||
<span class="docs-viz-picker-note">more playful</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Click the element you want to iterate on. A picker outline appears around it, and a light context bar pops up next to the selection with a command chip on the left and a freeform text field.
|
||||
|
||||
A few things you can do before pressing Go:
|
||||
|
||||
- **Click the command chip** (default is `impeccable`, the freeform action). Pick a specific action like `bolder`, `delight`, `layout`, or `typeset` to constrain the variants along one dimension.
|
||||
- **Type in the freeform field.** "More playful." "Less SaaS." "Feel like a newsletter from a magazine."
|
||||
- **Drop a comment pin** by clicking anywhere on the picked element. The pin's position is load-bearing: a comment near the title is about the title, not the whole element.
|
||||
- **Draw a stroke** by dragging across the element. Closed loop = "this part matters." Arrow = direction. Cross = "delete this." The skill reads strokes by shape, not by pixel content.
|
||||
|
||||
When the brief feels clear, hit **Go**.
|
||||
|
||||
## Step 3. Cycle through the three variants
|
||||
|
||||
<div class="docs-viz-step">
|
||||
<div class="docs-viz-variants">
|
||||
<div class="docs-viz-variant docs-viz-variant--v1">
|
||||
<span class="docs-viz-variant-badge">1 / 3</span>
|
||||
<span class="docs-viz-variant-kicker">No. 04</span>
|
||||
<p class="docs-viz-variant-title">Letters, <em>occasionally</em>.</p>
|
||||
<span class="docs-viz-variant-btn">Send me one</span>
|
||||
</div>
|
||||
<div class="docs-viz-variant docs-viz-variant--v2 is-active">
|
||||
<span class="docs-viz-variant-badge">2 / 3</span>
|
||||
<span class="docs-viz-variant-kicker">Dispatch</span>
|
||||
<p class="docs-viz-variant-title">Design notes, <br>every other<br>Thursday.</p>
|
||||
<span class="docs-viz-variant-btn">Join →</span>
|
||||
</div>
|
||||
<div class="docs-viz-variant docs-viz-variant--v3">
|
||||
<span class="docs-viz-variant-badge">3 / 3</span>
|
||||
<span class="docs-viz-variant-kicker">Field Notes</span>
|
||||
<p class="docs-viz-variant-title">A monthly letter, for people who still read email.</p>
|
||||
<span class="docs-viz-variant-btn">Receive ✺</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
You'll see a spinner ("Generating variants...") and within a few seconds, three variants hot-swap into the page in place. Not a preview, the actual rendered DOM on your actual dev server with your actual context.
|
||||
|
||||
Use the arrow keys (or the prev / next buttons on the context bar) to cycle through them. A counter at the top right shows `1 / 3`, `2 / 3`, `3 / 3`.
|
||||
|
||||
The three variants are designed to be **genuinely different**, not three riffs on one idea. Freeform variants anchor to three different design archetypes (broadsheet masthead, oversized-glyph poster, catalog-style spec rows, and so on). Action-specific variants vary along the dimension the action names: `colorize` gives you three hue families, `animate` gives you three motion vocabularies, `layout` gives you three structural arrangements.
|
||||
|
||||
If two variants feel like they rhyme, that is the skill's "squint test" failure mode. You can tell the picker "try again, all three felt too similar" and get a fresh set.
|
||||
|
||||
## Step 4. Accept one
|
||||
|
||||
<div class="docs-viz-step" style="text-align:center">
|
||||
<span class="docs-viz-accept-pill">Variant 2 written to source</span>
|
||||
</div>
|
||||
|
||||
When you find the one you like, click **Accept** on the context bar (or press Enter). Three things happen:
|
||||
|
||||
1. The picked element is replaced with the accepted variant on the page.
|
||||
2. The variant is written back to source: the same file your picker was injected into, or the component source if live detected a generated file during step 1.
|
||||
3. If the accept touched CSS, the relevant rules are consolidated into your project's real stylesheet, not left inline.
|
||||
|
||||
Discard all three (press Escape) and the original stays. No trace, no commented-out leftovers.
|
||||
|
||||
## Step 5. Stop live mode
|
||||
|
||||
When you are done iterating, stop the helper:
|
||||
|
||||
- Say **"stop live mode"** in your harness chat, or
|
||||
- Click the **×** on the picker pill, or
|
||||
- Close the browser tab: the helper detects the dropped connection after eight seconds and exits cleanly.
|
||||
|
||||
The stop also strips the `<script>` tag from your dev entry and stops the helper server on port 8400.
|
||||
|
||||
## What to try next
|
||||
|
||||
- Run `/impeccable live` on a different page after a `/impeccable polish` pass to A/B the polished version against two more directions.
|
||||
- Pair with [critique with the overlay](/tutorials/critique-with-overlay): run critique first, fix priority issues, then use live to explore redirections on the element critique flagged.
|
||||
- Reach for `/impeccable craft` when you want the shape-then-build flow (a new feature end-to-end, not a single element).
|
||||
|
||||
## Common issues
|
||||
|
||||
- **The picker never appears on the page.** Either the helper did not start (look for errors in the terminal) or CSP is blocking the inject. Re-run `/impeccable live` and let it re-check CSP. If you declined the patch on first run, delete the `cspChecked` line in `.impeccable/live/config.json` and re-run.
|
||||
- **"element lives in a generated file"** on Go. Live detected that the picked element is in a compiled output, not a source file. It routes the accept through a fallback path so the variant still lands in true source. Follow the hint; don't force-accept into the generated file.
|
||||
- **Variants don't feel brand-aligned.** Check that `PRODUCT.md` and `DESIGN.md` exist at the project root. Without them, live leans toward generic defaults. Run `/impeccable teach` and `/impeccable document` first.
|
||||
- **The helper port is in use.** Another live session left its server running. `npx impeccable live stop` releases the port.
|
||||
Reference in New Issue
Block a user