Top-level .gitignore excludes dist/ broadly, which silently dropped the
multipage-with-generator fixture's files/dist/*.html from the previous
commit. The fixture tests need those files on disk to copy into the
tmp repo and assert is-generated behavior — without them, the test
suite fails on a fresh clone.
Added a negation pattern that re-includes tests/framework-fixtures/**/dist/
paths. The real dist/ output directories elsewhere in the repo remain
ignored.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a full annotation pipeline to /impeccable live. On Go, the browser
captures the selected element as a PNG (with annotations composed in),
uploads it to the live helper, and sends the generate event with the
screenshot path so the agent reads user intent visually instead of from
HTML alone.
Annotation tools (while an element is picked):
- Click inside the outline to drop a magenta comment pin with a text input
- Drag to paint a magenta SVG stroke (5 px click-vs-drag threshold)
- Click a pin to edit; double-click to delete; drag a pin to reposition
- Click a stroke to delete it (wider invisible hit path)
- Clear chip top-right wipes everything; hidden when no annotations
Capture pipeline:
- modern-screenshot vendored as an IIFE (scripts/modern-screenshot.umd.js)
and lazy-loaded from the live helper
- Font fix: cross-origin @font-face rules are fetched and fonts are inlined
as base64 data URIs before being handed to modern-screenshot via
font.cssText, since SVGs rasterized via canvas can't fetch external
resources (fix for "Impeccable" rendering bold-serif and items wrapping
wrong in the capture)
- Annotations are temporarily attached to the live element (not only the
clone) so computed styles resolve during the embed pass
- Session screenshots live in .impeccable-live/annotations/session-*/ in
the project root (gitignored) so the agent's Read tool doesn't trip a
per-path permission prompt
Loading shader (activates during GENERATING):
- WebGL overlay rendering the captured PNG as a halftone — cells with
luma-driven dot radius, rendered on paper-cream underneath a magenta
roller that sweeps top-to-bottom with a 3.4s cycle and clean overshoot
- Fixed asymmetric bandAt() using one-sided smoothsteps (previous reversed
smoothstep was undefined on d>0, giving "trail=1 everywhere below")
- Graceful <img> fallback when WebGL is unavailable; prefers-reduced-motion
freezes the band at t=0
Server:
- POST /annotation endpoint (raw image/png body, token + eventId query),
session-scoped tmpdir cleaned up on shutdown
- GET /modern-screenshot.js serves the vendored UMD with aggressive caching
- Optional screenshotPath / comments / strokes fields on generate events
- Fixed pre-existing /source crash on ENOENT (writeHead called twice)
Agent side:
- reference/live.md step 0 tells the agent to Read the screenshot first,
with four rules for interpreting annotations: comments are position-
anchored and scoped to the sub-element under their {x,y}; strokes are
gestures (loop=focus, arrow=direction, cross=delete); comments and
strokes are independent unless adjacent; don't silently guess on
ambiguous strokes
Also:
- Generating bar no longer claims "Generating 1 of 3..." (variants arrive
atomically) — now says "Generating N variants..."
- tests/live-server.test.mjs fixed to read the PID file from project root,
matching the server; adds coverage for the new endpoints and validator
fields
- .impeccable-live/ added to .gitignore
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This repo is the canonical example of impeccable — users who install the
skill should be able to look at how a real project uses PRODUCT.md and
(later) DESIGN.md. Ungitignored both files.
Also rewrote PRODUCT.md itself to match the new schema from teach.md
(# Product → Users / Product Purpose / Brand Personality / Anti-references
/ Design Principles / Accessibility), dropping the legacy "Design Context"
wrapper and the Aesthetic Direction section that belongs in DESIGN.md.
.impeccable.md stays gitignored as legacy (the loader auto-migrates it).
DESIGN.md for this project is pending — to be generated with
/impeccable document once we run it on our own codebase.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pioneers a two-file convention for project context:
- PRODUCT.md (strategic): users, brand, principles — answers who/what/why
- DESIGN.md (visual): follows Google's Stitch DESIGN.md spec — answers how-it-looks
Both files live at the repo root. Filename matching is case-insensitive.
DESIGN.md wins on visual conflicts, PRODUCT.md wins on strategic/voice.
Legacy .impeccable.md is auto-migrated to PRODUCT.md on first read by the
new shared loader. This is silent and one-shot — the rename is permanent.
What changed:
- New scripts/load-context.mjs: shared context loader used by every command
that needs project context. Reads both files, handles legacy migration.
- New reference/document.md: /impeccable document command that generates
DESIGN.md by auto-extracting tokens (colors, typography, spacing, radii,
shadows, components) from CSS/Tailwind/theme files, then asking the user
to confirm descriptive language for atmosphere and color character.
Follows Google's Stitch DESIGN.md format for tool compatibility.
- SKILL.md Context Gathering Protocol updated to load both files and
nudge the user to run /impeccable document when DESIGN.md is missing.
- reference/teach.md rewritten to split discovery cleanly: strategic
questions go to PRODUCT.md, visual/design-system work is delegated to
/impeccable document (skipped on empty projects).
- reference/live.md consumes {product, design, productPath, designPath,
migrated} from the loader instead of a single context blob.
- scripts/live.mjs uses the shared loader instead of inline file reading.
- Command count updated 22 → 23 (new: document). Metadata, router table,
command menu, periodic table viz, and homepage data all updated.
- .gitignore adds PRODUCT.md + DESIGN.md (repo-local, not shared).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
First live run: agent auto-detects framework and writes a small config.json
(file, insertBefore/insertAfter anchor, comment syntax). Every subsequent
run: live-inject.mjs handles insert/remove deterministically, no LLM needed.
The config lives at {scripts_path}/config.json and is gitignored — it's a
per-project cache that wipes on skill update and regenerates on next use.
- New live-inject.mjs: --port (insert), --remove, --check modes
- Idempotent insert: re-running with a different port replaces cleanly
- Reference doc: one-time detection step, then instant insert/remove
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
os.tmpdir() returns /var/folders/.../T/ on macOS, not /tmp/. The skill
reference was telling the agent to cat /tmp/impeccable-live.json which
didn't exist. Moving the PID file to the project root makes it
predictable across platforms and project-scoped (multiple projects can
run independent live sessions).
Changed in: live-server.mjs, live-poll.mjs, live.md reference.
Added .impeccable-live.json to .gitignore.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
npm subprocesses can regenerate a stray package-lock.json (last time
this happened, it was reverted in 3ca60a8). Add it to .gitignore so it
stops showing up as untracked.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Biggest change in a while. Users previously had 18 standalone skill
entries cluttering their /menu; now they have one entry (/impeccable)
that routes to 20 specialized commands via argument dispatch. The pin
mechanism (/impeccable pin audit) restores standalone shortcuts on
demand for commands users hit all the time.
## Architecture
- Single /impeccable skill with command router section in SKILL.md
- 20 commands served via reference files under source/skills/impeccable/reference/
- /impeccable pin <command> creates a lightweight redirect shim so users
who prefer /audit, /polish, etc. can still have them
- Context gathering (teach) auto-runs on first use
- command-metadata.json is the single source of truth for command
descriptions, argument hints, and relationships
## Site rewrite
- Docs URL: /skills renamed to /docs (with /skills permanent redirects)
- Homepage hero frames Impeccable as "one skill with 20 commands"
- "Get Started" split into 50/50 install + how-to-use with editorial
numbered steps, /impeccable shown as the home command with three modes
- New /docs overview: home command hero card + dense category rows
matching the old cheatsheet density, with leads-to/pairs-with/
combines-with relationship metadata served from a shared source
- Cheatsheet merged into /docs, /cheatsheet redirects
- Magazine spread and mobile cards show /impeccable as a stacked
namespace label above the command name at full display size
- Periodic table updated with craft/teach/extract as first-class cells
- Skill detail pages generate from reference files, with an editorial
wrapper per command for tagline + body
- Tutorials and anti-patterns pages updated to use /impeccable <cmd>
## Build system
- Dead code removed (scripts/lib/transformers/shared.js)
- Build log wording fixed ("1 skill" not "1 skills (1 user-invocable)")
- generateApiData fallback branch removed (throws loudly if metadata
missing instead of silently degrading)
- Commands API includes editorial tagline alongside the long description;
UI surfaces prefer tagline for human display, description for auto-
trigger keyword matching
## Gitignore
- Added .claude/scheduled_tasks.lock, .claude/settings.local.json to
ignore list (local Claude Code state that should not be tracked).
- Harness skill directories (.claude/skills/, .agents/skills/, etc.)
remain tracked by design: npx skills reads them from this repo at
install time and they enable clean submodule use.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 'In the wild' section at the bottom of /anti-patterns was
mischaracterizing synthetic fixtures as real examples and was buried
deep in a taxonomy of detection rules. The specimens belong somewhere
that frames them as what they actually are: live pages you can click
into to experience Visual Mode. Split them off into a new top-level
page that also finally gives Visual Mode first-class treatment.
- New /visual-mode page, top-level nav item, single-column layout (no
sidebar). Structure:
1. Editorial header with an "Live detection overlay" eyebrow.
2. Live iframe embed of visual-mode-demo.html inside mac-window
chrome, same preview component the homepage uses.
3. "Three ways to run it" section with three method cards:
- /critique runs the overlay inside its browser pass
- `npx impeccable live` starts a standalone overlay server
- Chrome extension, marked coming soon, with a cream bg
4. "Try it live" gallery of the 11 synthetic specimens as
clickable cards. Each links to /antipattern-examples/{id}.html
where the detector script is already injected so the reader
lands on a live overlay.
- scripts/build-sub-pages.js: new renderVisualModeMain(); visualMode
added to outDirs; generator loop writes /visual-mode/index.html.
- server/index.js: new /visual-mode route serving the generated file.
- Top nav on every page gains 'Visual Mode' between Anti-Patterns
and the GitHub pill. Updated the partial + all 4 hand-authored
HTML pages.
- .gitignore adds public/visual-mode/.
- /anti-patterns: 'In the wild' section and its TOC entry removed.
Replaced with a one-line pointer at the end of the lede: "Want to
see them live on real pages? Try Visual Mode." GALLERY_ITEMS stays
in the catalog file (now used by /visual-mode only).
- public/css/sub-pages.css: new .visual-mode-page-body + .visual-mode-*
classes. Ports the mac-window chrome (dots + mono title) from
main.css, adds three-card method grid, and reuses the existing
.gallery-card styles for the specimen list.
Clean up a few em-dashes in the catalog (block comments + one visible
visual example) so the build-time validator stays clean.
Server restart required to pick up the new /visual-mode route.
Ships the first new sub-page section. Every user-invocable skill now has
its own page at /skills/{id}, with the canonical SKILL.md body rendered
via marked. The index at /skills lists all 21 skills grouped by category.
Editorial wrappers are opt-in: if content/site/skills/{id}.md exists, it
renders above the canonical body (with a "The skill itself" divider).
All 21 pages currently ship with the auto-rendered body only; hand-written
wrappers land in the next few commits.
- scripts/lib/sub-pages-data.js: builds the data model. Reuses
readSourceFiles() from lib/utils.js for skill content; parses the
ANTIPATTERNS array out of src/detect-antipatterns.mjs; reads optional
editorial wrappers from content/site/skills/*.md; validates that every
user-invocable skill has a category entry (build fails loudly if not).
- scripts/build-sub-pages.js: orchestrator. Writes generated HTML into
public/skills/*.html (gitignored). Called from both scripts/build.js
(before buildStaticSite) and server/index.js (at module load) so dev
and prod share the same generation code path.
- scripts/lib/render-page.js: new assetDepth parameter so generated
pages one level deep under public/ use relative paths (../favicon.svg,
../css/sub-pages.css) that Bun's HTML loader can resolve on disk.
- scripts/build.js: pass generated files into Bun.build entrypoints;
post-process to flatten build/public/* → build/* (Bun preserves the
public/ prefix when entrypoints span multiple depths).
- server/index.js: generateSubPages() runs at module load; new routes
/skills, /skills/:id, /anti-patterns, /tutorials, /tutorials/:slug
serve the pre-generated files via Bun.file().
- public/css/sub-pages.css: adds sub-page layout shell, skills index
grouped-list styling, skill detail header/meta chips/divider, collapsed
<details> reference sections, and a .prose block for rendered markdown
with editorial typography, code blocks, and inline code.
Verified: bun run build produces 26 HTML files (4 hand-authored + 22
generated), all flat under build/. Dev server returns 200 on /skills,
/skills/polish, /skills/impeccable, /skills/critique. Tests pass.
- Restructure install section into a split primary card with the
recommended path on the left and other install methods on the right
- Drop the prefix toggle UI; bundle name is now baked into data-bundle
- Balance the Stay updated step as paired Substack iframe + X follow card
with matching height, border, and treatment
- Pair Changelog and FAQ side-by-side on desktop with a centered divider
and shared border-top; section nav highlights both when in view
- Tone down the Visual Mode demo by removing side-tab borders, stacked
card icons, and tiny body text so the overlay reads cleanly
- Refine the Chrome extension callout: drop the pill badge, use an
editorial eyebrow above the title, enlarge the thumbnail
- Exclude private evals/ directory from version control
Adds a Manifest V3 Chrome extension that injects the detector when
DevTools opens, with a dedicated panel for browsing findings, a toolbar
popup for quick scan/toggle, and per-rule settings synced via
chrome.storage. Categorizes anti-patterns into AI slop vs quality
issues with visual differentiation (sparkle prefix, panel grouping).
Overlay labels are polished with flush positioning, cycling for
multi-finding elements, and synchronized hover darkening.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename bin/impeccable.mjs to bin/impeccable (npm rejects .mjs in bin)
- Shebang: #!/usr/bin/env node (works without Bun)
- Add README.npm.md with CLI-focused docs, swapped in during publish
- Build browser script to source/ dir so URL scanning works in npm pkg
- Include browser script in files field
- Move website-only deps (archiver, motion, playwright) to devDependencies
- jsdom as dependency, puppeteer as optionalDependency
- Bump version to 2.0.1 across package.json, plugin.json, marketplace.json
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove Tailwind CSS and related dependencies (tailwindcss, @tailwindcss/cli, bun-plugin-tailwind)
- Remove unused dependencies (lenis, @paper-design/shaders, three)
- Convert @theme variables to CSS custom properties in :root
- Add minimal CSS reset for browser consistency
- Update server to serve /css/* and /js/* routes directly
- Fix conflicting CSS rules that broke commands section layout
- Delete bunfig.toml (no longer needed without Tailwind plugin)
The site now uses native CSS imports via Bun's built-in bundler,
eliminating the need for separate Tailwind compilation step.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bun's native CSS bundler doesn't support Tailwind v4's @theme directive.
Solution:
1. Run Tailwind CLI first to compile main.css → styles.css
2. Reference styles.css in HTML
3. Bun HTML bundler then bundles everything together
Build output:
- JS: 82 KB (minified, bundled)
- CSS: 63 KB (minified, includes all custom styles)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use HTML as entrypoint for Bun.build() instead of separate JS/CSS builds
- Leverage bun-plugin-tailwind for automatic Tailwind CSS processing
- Output bundled site to ./build/ directory
- Update vercel.json outputDirectory to build
- Clean up obsolete build artifacts and gitignore entries
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Bundle all frontend JS with Bun.build() (82KB minified)
- Dependencies (motion, lenis, three) are now bundled instead of CDN
- Remove import map from index.html (no longer needed)
- Output to public/dist/app.bundle.js with source map
- Add public/dist/ to .gitignore (generated during build)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add missing /api/patterns.js endpoint (was causing 404)
- Fix Tailwind CSS: compile with @tailwindcss/cli instead of Bun virtual module
- Update API handlers to use standard Vercel function export format
- Configure vercel.json with proper Bun runtime (runtime: "bun@1")
- Add @tailwindcss/cli to devDependencies
- Add generated styles.css to .gitignore
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>