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>
Tests:
- tests/live-wrap.test.mjs (26 tests): unit tests for buildSearchQueries,
findElement, findClosingLine, detectCommentSyntax (20 pure function
tests) + integration tests for the full wrapCli on HTML and JSX
fixtures with temp dirs (6 tests covering wrapping, ID/class lookup,
error handling, content preservation).
- tests/live-server.test.mjs (15 tests): integration tests that start a
real server on port 8499, then test /health, /live.js, /detect.js,
/poll (timeout + auth), /events POST (validation + auth), browser→agent
event flow (POST event → poll receives it), agent→browser SSE flow
(POST reply → SSE stream delivers it), /source (read, path traversal
rejection, auth, 404).
Also:
- Added auto-execute guards to live-wrap.mjs and live-poll.mjs so they
work when run directly with `node live-wrap.mjs ...` (needed for both
skill instructions and integration tests).
- Exported buildSearchQueries, findElement, findClosingLine,
detectCommentSyntax from live-wrap.mjs for unit testing.
- Updated package.json test script to include the new test files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two architectural changes that make the live variant mode self-contained:
1. SSE replaces WebSocket: the server now uses Server-Sent Events for
server→browser push and regular fetch POST for browser→server
events. This eliminates the ws npm dependency entirely. The live
server is now zero-dependency pure Node.js (http, crypto, fs, net).
Browser: EventSource replaces WebSocket. sendEvent() uses fetch POST.
Server: GET /events returns SSE stream, POST /events receives browser
events. All other endpoints (poll, source, health, stop) unchanged.
2. Scripts moved to source/skills/impeccable/scripts/: live-server.mjs,
live-poll.mjs, live-wrap.mjs, live-browser.js are now part of the
skill itself. Users who install the skill via npx skills get the live
mode without needing npm install impeccable separately.
The skill reference uses {{scripts_path}}/live-server.mjs etc.
The CLI (bin/cli.js) delegates to the skill scripts as a convenience.
Removed ws from package.json dependencies.
The old src/live/ files remain as the development copy. The build system
syncs source/skills/ to all harness dirs (11 providers).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New feature: /impeccable live starts an interactive visual iteration server.
Users select elements in the browser, pick a design action (bolder, quieter,
etc.), and the agent generates HTML+CSS variants written directly to source.
The dev server's HMR hot-swaps them in, and MutationObserver progressively
reveals each variant in a cycler UI as it arrives.
Architecture:
- src/live/server.mjs: HTTP + WebSocket server with session token auth,
long-poll /poll endpoint for the agent, WebSocket for the browser
- src/live/poll.mjs: CLI client (npx impeccable poll / poll --reply)
- src/live/browser.js: element picker with keyboard nav (arrows=siblings,
shift+arrows=parent/child), action panel (12 commands, freeform input,
variant count), variant cycler with progressive reveal via MutationObserver
- src/live/protocol.mjs: shared message types and event validation
- source/skills/impeccable/reference/live.md: agent loop instructions
(inject script, poll loop, generate variants, accept/discard, cleanup)
CLI changes:
- bin/cli.js: added "poll" top-level command
- src/detect-antipatterns.mjs: liveCli() now delegates to src/live/server.mjs
- package.json: added ws dependency
Registered /impeccable live as command #22 across all standard locations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two detector bugs that produced false positives on sites like uselinkshot.com:
1. The bg-black regex matched Tailwind opacity modifiers (bg-black/3,
hover:bg-black/5) because / is a word boundary. Added negative lookahead.
2. resolveBackground ignored url() background-images, walking past them to
the body's white bg. White text on a dark hero image was flagged as
1.0:1 white-on-white. Now bails on url() images like it does for gradients.
Also: extension build auto-generates dist/extension.zip, version bumps for
CLI (2.1.7) and extension (1.0.1).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When .claude/skills is a symlink to .agents/skills, updating both
providers wrote to the same directory twice -- the last write
(.agents) always won, making .claude content identical to .agents.
The up-to-date check also always failed because it compared
provider-specific bundle content against the wrong provider's files.
Fix: use realpathSync to detect shared directories and process each
unique real path only once with its matching bundle provider. Respects
the user's symlink setup for non-impeccable skills.
Tested: first run updates 18 skills, second run reports "up to date".
CLI bumped to v2.1.6.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Build system now injects skills version (from plugin.json) into
every SKILL.md frontmatter as a version field
- CLI reads the version from the local impeccable SKILL.md and
displays it in check/update output
- Hash comparison normalizes the version field (so a version bump
alone doesn't trigger a full re-download)
- Removed misleading CLI version display from skills commands
CLI bumped to v2.1.5.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Skills installed via npx skills add resolve {{scripts_path}} to
.agents/skills/... while our bundle resolves it per-provider
(.claude/skills/..., .cursor/skills/..., etc). Without normalizing,
identical content always shows as different.
Also compare only one provider instead of all (they have the same
content, just different path prefixes).
CLI bumped to v2.1.4.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The hash comparison was comparing the entire local skills directory
(which includes user's custom skills) against the bundle (which only
has impeccable skills). Now only compares skills that exist in the
bundle, so custom skills don't cause a false mismatch.
CLI bumped to v2.1.3.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CLI changes (bumped to v2.1.2, skills stay at v2.1.1):
- `npx impeccable skills check` compares local skill files against
the latest bundle and reports whether updates are available
- `npx impeccable skills update` now downloads the bundle first,
compares hashes, and skips with "up to date" if nothing changed
- Removed the local-modifications warning (was confusing for users
who installed via npx skills add)
Versioning:
- CLI (package.json), skills (plugin.json/marketplace.json), and
Chrome extension (manifest.json) are now versioned independently
- CLAUDE.md updated to document when to bump each
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bundled as source/skills/impeccable/scripts/cleanup-deprecated.mjs,
runs via the self-deleting <post-update-cleanup> section in the skill.
The script:
- Finds all harness skill dirs (.claude, .cursor, .agents, etc.)
- Deletes deprecated skill directories (arrange, normalize, onboard,
extract, frontend-design, teach-impeccable) and i-prefixed variants
- Verifies each file contains "impeccable" before deleting to avoid
touching unrelated user skills with the same name
- Handles both symlinks and regular directories
- Removes matching entries from skills-lock.json (only if source is
pbakaus/impeccable)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Version bump across package.json, plugin.json, marketplace.json
- Changelog entry for v2.1 in index.html
- Hero version link updated
- Added <post-update-cleanup> section to impeccable SKILL.md that
detects and removes leftover files from renamed/merged skills
(arrange, normalize, onboard, extract, frontend-design,
teach-impeccable). Verifies files contain "impeccable" before
deleting to avoid touching unrelated user skills. Self-deletes
after first run so it only executes once per update.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bundles recent CLI/detector work that landed on v2.0 since 2.0.6:
side-tab border detection on oklch/oklab/lch/lab and CSS variables,
emoji-only handling in contrast/icon-tile rules, asymmetric
font-size-aware cramped-padding rule, full anti-pattern names in
overlay labels, and the CI sandbox flags for Puppeteer fixture tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Groundwork for new /skills, /anti-patterns, /tutorials sections.
No user-visible changes yet — this is pure plumbing.
- Split main.css into tokens.css (design tokens + reset, ~100 lines) and
main.css (everything else, imports tokens.css). Lets sub-pages import
only tokens without pulling in the landing-page component CSS.
- Add marked as a dependency.
- Add scripts/lib/render-markdown.js: marked wrapper with a custom link
resolver (skill slugs, reference/*.md anchors, external rel=noopener),
stable heading slugger, and terminal-style code blocks.
- Add scripts/lib/render-page.js: page shell wrapper that injects the
shared site header partial with aria-current marking.
- Add content/site/partials/header.html: shared site header with nav
(Home / Skills / Anti-Patterns / Tutorials / Gallery / GitHub).
- Add public/css/sub-pages.css: shared styles for generated pages, with
.site-header styling (sticky, backdrop blur, accent-underlined active
nav item) and mobile collapse.
Build still produces the same 104 KB landing-page CSS chunk; tests pass.
The quality detection rules (line-length, cramped-padding, tight-leading,
tiny-text, justified-text, all-caps-body, wide-tracking, skipped-heading)
were originally added as browser-only and wired only into the overlay
loop. The CLI's jsdom path silently skipped all of them.
Two of the eight rules genuinely need real browser layout
(line-length reads rect.width for chars-per-line; cramped-padding reads
rect.width/height to filter small badges). The other six only need
computed CSS values and pure DOM walks — they can run in jsdom too.
Refactor
- Extract a pure checkQuality(opts) from checkElementQualityDOM, taking
pre-resolved lineHeightPx and letterSpacingPx so each adapter handles
its own unit resolution.
- Add resolveFontSizePx(el, win) — walks the parent chain to compute
effective font-size in pixels, handling px / rem / em / % through
inheritance. Browsers do this automatically in getComputedStyle, but
jsdom returns "0.875rem" verbatim, which broke naive parseFloat math.
- Add resolveLengthPx(value, fontSizePx) — generic CSS length → px
helper used for line-height and letter-spacing in the Node adapter.
- Extract checkPageQualityFromDoc(doc) and add a Node call site so
skipped-heading fires from the CLI too.
- Add checkElementQuality(el, style, tag, window) Node adapter and wire
it into detectHtml's element loop.
Tests
- New tests/detect-antipatterns-browser.test.mjs — Puppeteer-backed
runner that spins up a temporary static server (port 8765, mirrors
the dev server's /fixtures/* and /js/* routes) and uses detectUrl()
to load fixtures in headless Chrome. Asserts the two browser-only
rules (cramped-padding, line-length) that need real layout.
- New tests/fixtures/antipatterns/cramped-padding.html — focused
side-by-side fixture for the cramped-padding rule. Pass column
includes a faithful replica of .detection-cmd from the homepage
(the disputed "small inline pill" case the user is deciding what
to do with). Test asserts 3 findings: 2 from the obvious flag
column + 1 from the disputed pill.
- New tests/fixtures/antipatterns/quality.html — merged side-by-side
replacement for the orphaned quality-should-flag/pass.html files.
Covers all 7 typography-quality rules. The 6 jsdom-compatible rules
are asserted in the jsdom test; line-length stays in the Puppeteer
test.
- Delete the orphaned quality-should-flag.html / quality-should-pass.html.
- Wire the new browser test into bun run test (~2.6s overhead).
Coverage win: the CLI now catches tight-leading, tiny-text,
justified-text, all-caps-body, wide-tracking, and skipped-heading on
real projects, where it previously missed all six.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Merges the impeccable-detect CLI repo (pbakaus/impeccable-cli@831a6cc)
into this repo. The BSL-1.1 license that motivated the split is gone;
everything is now Apache 2.0.
- Add bin/, src/, detection tests and fixtures from CLI repo
- Merge package.json: name → "impeccable", add bin/exports/files fields
- Internal refs now read from local src/ instead of node_modules/
- Update SPDX headers, NOTICE.md, CLAUDE.md, FAQ, npm README
- Add prepack/postpack scripts for CLI-focused README on npm
- Remove terminal license labels (no longer needed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The CLI and detection engine now live in pbakaus/impeccable-detect
(published as 'impeccable' on npm, BSL-1.1). This repo is purely
Apache 2.0: skills, prompts, website, and build system.
- Remove bin/ (CLI moved to CLI repo)
- Remove README.npm.md (moved to CLI repo)
- Remove @impeccable/detect dependency, add impeccable dependency
- Set package.json to private (no longer published to npm)
- Update all references from @impeccable/detect to impeccable
- Update CLAUDE.md, NOTICE.md, FAQ, and changelog
- Rebuild all provider skill distributions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace local detection engine dependency with @impeccable/detect (BSL-1.1
licensed, github:pbakaus/impeccable-detect). The main CLI now delegates
both `detect` and `live` commands to the external package.
Update critique skill to use `npx @impeccable/detect live` instead of
python3 http.server for serving the browser detection overlay.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New `impeccable skills` CLI with three subcommands:
- `skills help`: fetches and displays all 20 commands from the API
- `skills install`: delegates to `npx skills add pbakaus/impeccable`
- `skills update`: tries `npx skills update` first; if skills aren't
managed by the skills CLI, downloads the universal bundle from
impeccable.style and overwrites provider folders directly, with
git-based modification detection and confirmation prompt
Also fixes npm metadata: homepage -> impeccable.style, license -> Apache-2.0
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>
Usage: npx impeccable detect [file-or-dir-or-url...]
Subcommand structure designed for future expansion. The detect
subcommand delegates to the existing detection engine with all
its modes (jsdom, regex, Puppeteer).
- bin/impeccable.mjs: CLI entry point with bun shebang
- package.json: bin field added
- Export detectCli (main) from detection script
- Updated help text to show impeccable detect usage
- Updated CLAUDE.md and README.md with CLI docs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detection improvements:
- Remove SAFE_TAGS from glow check (buttons/links with glows are valid)
- Add gradient color parsing (parseGradientColors) for AI palette
detection on gradient backgrounds including buttons
- Detect cyan neon text on dark backgrounds as AI palette
- Resolve gradient backgrounds as dark for glow detection
- Fix pure-black false positive on semi-transparent overlays (a >= 0.9)
- Skip low-contrast/gray-on-color when background is a gradient
- Fix "Only font:" double-colon in browser labels
Test performance:
- Split jsdom fixture tests to Node's test runner (bun + jsdom hangs
after ~13 instances due to resource leak)
- bun test for unit/regex/CLI tests (94 tests, 4s)
- node --test for jsdom fixtures (15 tests, 1.3s)
- Total: 109 tests in ~5s (was 280s+)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Major cleanup:
- detectUrl() now injects the browser script via page.evaluate() and
calls window.impeccableScan() instead of reimplementing all detection
logic inline. Removes ~80 lines of triple-duplicated code.
- Removed dead isPureBlackOrWhite function.
- CLI reduced from 1286 to 1212 lines.
New: Puppeteer-powered browser parity tests (detect-antipatterns-browser.test.js):
- Starts a local HTTP server for fixtures
- Loads fixture pages in headless Chrome
- Runs the browser detection script via impeccableScan()
- Verifies findings match expectations for all fixture categories:
borders, colors, layout, typography, partials
8 new browser tests catch desync between CLI and browser script
(like the WeakSet iteration bugs we hit earlier).
puppeteer added as devDependency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New in v1.5.0:
- 3 new skills: /typeset, /arrange, /overdrive (beta)
- Shared Context Gathering Protocol with .impeccable.md
- teach-impeccable writes provider-agnostic context
- Deep linking to commands (#cmd-overdrive etc.)
- JS-powered demo infrastructure with live laser signature
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Added OpenCode provider support
- Added Pi provider support
- Recategorized /onboard as an enhancement command
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cloudflare Pages build environment doesn't have the zip CLI tool,
causing zip bundle creation to fail silently. Switched to the archiver
npm package for cross-platform zip generation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace Vercel serverless functions with Cloudflare Pages static
rewrites and lightweight download functions. Pre-generate all API
JSON data at build time for zero-invocation static serving. Also
fix stale simplify→distill rename in framework-viz periodic table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Combined all post-v1.0 changelog entries into single v1.1.0
- Updated version to 1.1.0 in package.json, plugin.json, marketplace.json
- Added GitHub icon link to hero top-right
- Added README.txt to universal ZIP (macOS hides dotfile-only folders)
- Added versioning instructions to CLAUDE.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All commands are now skills with user-invokable: true. Source lives in
source/skills/{name}/SKILL.md. Added VS Code Copilot (.agents/skills/)
and Google Antigravity (.agent/skills/) transformers. All 6 providers
output to skills directories only — no more commands/prompts dirs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add scripts/generate-og-image.js that renders the OG image with Playwright
using the actual site fonts (Cormorant Garamond, Instrument Sans, Space
Grotesk) and dynamically counts skills/commands from source/. Switch from
PNG to JPEG (512 KB → 25 KB). Run with `bun run og-image`.
Co-Authored-By: Claude Opus 4.6 <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>
- 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>
- Replace subway map with periodic table of commands
- Info panel shows command details on hover
- Click element to jump to command in Commands section
- URL hash updates as you scroll between sections
- Direct linking to sections works
- Fix spacing issues in solution section
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major changes:
- Consolidate 8 design skills into single frontend-design skill with 7 reference files
- Add source/patterns.md as single source of truth for patterns/antipatterns
- Patterns are merged into skill during build, served via API for website
- Website now dynamically renders both "What TO Do" and "What NOT to Do" sections
- Update build system to handle directory-based skills with references
- Add /api/patterns endpoint to server
- Refactor website with new Antidote section layout
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>