Commit Graph
224 Commits
Author SHA1 Message Date
Paul BakausandClaude Opus 4.6 af2d6e1194 Support PRODUCT.md + DESIGN.md as canonical context files
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>
2026-04-13 18:14:13 -07:00
Paul BakausandClaude Opus 4.6 8030bc226a Add live-inject.mjs: per-project config for instant script tag management
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>
2026-04-13 16:44:26 -07:00
Paul BakausandClaude Opus 4.6 5fee3148be Fix section-nav using wrong positions for nested sections
The changelog and FAQ sections are inside a positioned .changelog-faq-row
wrapper, so their offsetTop was 0 (relative to parent) instead of their
actual document position. This broke current-section detection and caused
both pills to appear permanently active. Use getBoundingClientRect()
instead, which returns correct absolute positions regardless of nesting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:14:51 -07:00
Paul BakausandClaude Opus 4.6 830fe8e5fc Instant accept/discard for live mode, SSE heartbeats, background server startup
Accept and discard in live variant mode are now handled by a deterministic
script (live-accept.mjs) that runs inside the poller before returning to
the agent. The browser updates the DOM instantly on click (fire-and-forget)
so the user is never blocked waiting for LLM-driven file cleanup.

Key changes:
- New live-accept.mjs: deterministic accept/discard file operations
- Poller auto-runs accept script for accept/discard events (_acceptResult)
- Browser handleAccept() now commits DOM change instantly, no SAVING state
- CSS+HTML colocated in one write (style tag inside variant wrapper)
- SSE heartbeat every 30s prevents silent connection drops
- Poll timeout increased from 2min to 10min
- EventSource onopen resets retry counter for reliable reconnection
- Server --background flag for clean single-command startup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:06:03 -07:00
Paul BakausandClaude Opus 4.6 4092ee5f22 Move PID file to project root (.impeccable-live.json)
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>
2026-04-13 12:32:42 -07:00
Paul BakausandClaude Opus 4.6 0a1e5614e9 Add global floating bar with detect/pick toggles
Compact floating pill at the bottom center of the viewport, always
visible during live mode. Matches the action bar's light, translucent
aesthetic with brand-tinted active states.

Controls:
- "Impeccable" brand mark (capitalized, brand magenta)
- Detect toggle: eye icon, loads anti-pattern scanner in extension mode,
  waits for impeccable-ready before first scan, shows issue count badge
  inside the button. Toggle off removes overlays.
- Pick toggle: crosshair icon, enables/disables element picker. Active
  by default. When pick is active, detect overlays get pointer-events:
  none so the picker sees through them.
- Exit button: sends exit event and tears down all UI.

Detect + pick coexistence fixes:
- Picker highlight z-index raised above detect overlays (100001 vs 99999)
  so the selection outline and element path are always visible.
- Removed layout-property transitions (top/left/width/height) from the
  highlight to avoid triggering the anti-pattern detector and to give
  instant cursor tracking.
- First-click-on-detect fix: script loads async, scan command is queued
  until the impeccable-ready postMessage arrives.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:35:48 -07:00
Paul BakausandClaude Opus 4.6 52b050bb7e Fix 5 bugs from real-world live mode testing
1. Skill reference: poll should run as background task with no timeout.
   Changed "blocking poll loop" to "background task, no timeout" so the
   agent keeps the main conversation free for other work.

2. Resume restores selectedAction from localStorage: the bar was showing
   "Freeform" after page reload even when the user picked "Bolder". Also
   improved selectedElement targeting to prefer the visible variant's
   content over the wrapper parent.

3. Discard no longer shows "Applying variant...": accept shows the
   saving→confirmed flow, but discard now dismisses immediately and
   cleans up the DOM. Different intent, different UX.

4. Picker works after discard: cleanup() now removes the variant wrapper
   from the live DOM and restores the original element. Previously the
   stale wrapper with data-impeccable-variant attributes confused the
   picker's isPickable/own checks.

5. Stop live mode: added "Stopping Live Mode" section to the skill
   reference. The user can say "stop live mode" in the conversation, and
   the agent proceeds to cleanup (remove script tag, stop server).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:04:31 -07:00
Paul BakausandClaude Opus 4.6 bb94dadda0 Add live variant mode: element picker, action panel, poll/reply bridge (22 commands)
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>
2026-04-12 17:13:53 -07:00
Paul BakausandClaude Opus 4.6 e58cbc432f Split /onboard back out as its own command (21 commands total)
Pre-3.0, onboard was folded into /harden when we were trying to reduce
namespace pollution. In the single-skill model that tradeoff is gone,
so the weakest of the old merges is the first to undo.

Harden and onboard live in different mental modes. Harden is defensive
(edge cases, i18n, overflow, errors). Onboard is activation (first-run
flows, empty states as CTAs, progressive disclosure). A user thinking
"design the onboarding flow" was never going to type /impeccable harden.

Changes:
- New reference file at source/skills/impeccable/reference/onboard.md,
  restored from the pre-merge version in git history rather than the
  condensed 33-line summary that was in harden.md.
- Removed the "Onboarding & First-Run Experience" section from
  source/skills/impeccable/reference/harden.md.
- Updated harden description/editorial/process-steps to drop onboarding
  keywords; split commandProcessSteps so harden stays focused on
  production resilience and onboard gets its own phases.
- Registered onboard in: SKILL.md description + command menu + router
  table, command-metadata.json, IMPECCABLE_SUB_COMMANDS, pin.mjs
  VALID_COMMANDS, SKILL_CATEGORIES, COMMAND_RELATIONSHIPS, data.js
  commandCategories + commandProcessSteps + commandRelationships,
  framework-viz commandSymbols + commandNumbers.
- Reused the existing content/site/skills/onboard.md editorial wrapper
  (it was orphaned by the merge but never deleted), updating it to use
  /impeccable onboard.
- Bumped all user-facing count references 20 -> 21: public/index.html,
  CLAUDE.md, README.md, NOTICE.md, plugin.json, marketplace.json,
  sitemap.xml, build-sub-pages.js.
- Harness dir audit.md and critique.md changes are the
  {{available_commands}} placeholder expanding to include onboard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:21:45 -07:00
Paul BakausandClaude Opus 4.6 2c10cfb664 Trim v3.0 changelog to user-facing changes only
Remove "Rewritten docs site" (internal site polish, not a shipped
feature) and "Teach runs automatically on first use" (not new; that
behavior already existed pre-3.0). What's left is the consolidation
and the pin mechanism, which are the two user-facing changes in 3.0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 17:29:03 -07:00
Paul BakausandClaude Opus 4.6 2233d82f3a Bump skills to 3.0, remove prefixed bundle, redesign install section
- Bump skills plugin version 2.1.1 -> 3.0.0 (plugin.json, marketplace.json,
  harness SKILL.md files). CLI and Chrome extension unchanged.
- Remove prefixed universal zip bundle and all related code:
  factory.js prefix/outputSuffix options, zip.js variant pass, utils.js
  prefixSkillReferences, the "universal-prefixed" entry in
  download-providers.js, and the matching test suite in utils.test.js.
- Redesign Get Started step 1 "Install the skill and CLI": two terminal
  rows (npx skills + npm i -g impeccable) with paired notes, drop the
  Recommended badge.
- Collapse "Other install methods" back into a <details> element so the
  primary install path is the first thing users see.
- Simplify step 3 to "Add the Chrome extension": remove the CLI tool
  block (now in step 1), use standard .btn .btn-primary for the CTA so
  it matches other primary buttons (square corners, accent slide-up
  hover), and lay out the preview screenshot next to the button instead
  of stacked so the screenshot no longer dominates vertical space.
- CLAUDE.md: rewrite with v3.0 architecture, the "no em dash also means
  no --" rule, the harness-dirs-are-tracked gotcha, the named-export
  test-spy warning, and the evals inline-skill.ts sync note.
- AGENTS.md, DEVELOP.md: drop prefixed variant references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 20:28:07 -07:00
Paul BakausandClaude Opus 4.6 b0f44f83c6 Consolidate 18 skills into 1 /impeccable skill with 20 commands
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>
2026-04-10 19:45:17 -07:00
Paul BakausandClaude Opus 4.6 7d29aaca1b Deprecate /gallery page, redirect to /visual-mode#try-it-live
The gallery page had broken styling and missing images. The visual
mode page already has the same specimen gallery in a better layout.

- Removed public/gallery.html and its build entry point
- Updated homepage links to point to /visual-mode#try-it-live
- Added 301 redirect from /gallery to /visual-mode#try-it-live
- Added id="try-it-live" anchor to the visual-mode gallery section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 12:35:37 -07:00
Paul BakausandClaude Opus 4.6 2af435d2a5 Update GitHub star count from 17k to 18k
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:42:44 -07:00
Paul BakausandClaude Opus 4.6 697541f77e Skip broken npx skills update, use direct download as primary path
npx skills update has a known upstream bug (vercel-labs/skills#775)
where it can't find the lock file. Instead of trying it first and
falling back, always use our direct download which is reliable.

Also:
- Site now recommends `npx impeccable skills update` everywhere
  instead of `npx skills update`
- Direct download path now re-applies prefix after updating
- Runs cleanup after download to strip deprecated stubs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:22:44 -07:00
Paul BakausandClaude Opus 4.6 68ae6235ce Cap install step body width, restructure FAQ update entry
- Add max-width: 56ch to install-step-body so long descriptions
  don't run edge to edge
- Rewrite FAQ update answer as a scannable list instead of dense
  paragraphs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:41:07 -07:00
Paul BakausandClaude Opus 4.6 f30475cdf4 Remove deprecated source stubs, update FAQ and install copy, add CLI cleanup
- Delete source/skills/ directories for deprecated skills (arrange,
  normalize, onboard, extract, frontend-design, teach-impeccable).
  The cleanup script handles migration; stubs are no longer needed.
- Add "npx skills update" command to the Stay Updated install section
- Rewrite FAQ update answer: lead with npx skills update, add
  troubleshooting for failed updates (re-install + run /impeccable)
- Run cleanup script in `npx impeccable skills update` before
  delegating to npx skills update, preventing failures from
  deprecated entries in skills-lock.json
- Run cleanup script after `npx impeccable skills install` to remove
  leftover files from previous versions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:34:38 -07:00
Paul BakausandClaude Opus 4.6 8c480843e7 Bump to v2.1.0: changelog, self-deleting cleanup for deprecated skills
- 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>
2026-04-09 20:47:24 -07:00
Paul BakausandClaude Opus 4.6 faa7453db7 Consolidate skills from 21 to 18: rename, merge, and fold
- Rename /arrange to /layout for clarity
- Merge /normalize into /polish (design system discovery + cleanup phases)
- Merge /onboard into /harden (onboarding, empty states, progressive disclosure)
- Fold /extract into /impeccable extract sub-mode (reference file, sidebar link)
- Update all counts, cross-references, data files, demos, and metadata
- Remove System category (now empty)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:39:02 -07:00
Paul BakausandClaude Opus 4.6 e79873621b Add scroll-margin-top to prose headings so anchors clear the sticky header
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:53:36 -07:00
Paul BakausandClaude Opus 4.6 2a554bd4ef Remove parenthetical from shape flow description that was rendering in UI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:44:07 -07:00
Paul BakausandClaude Opus 4.6 a024195ddb Fix website copy: shape/craft relationship, install sections, tutorial accuracy
- Clarify that /impeccable craft runs /shape internally (not the other way around)
- Add three-mode documentation (freeform/craft/teach) to /impeccable page with anchor links
- Add sidebar sub-links for /impeccable craft and /impeccable teach
- Fix hallucinated npx impeccable live description in tutorial and visual-mode page
- Remove nonsensical "Do not skip the independent part" from critique tutorial
- Make Step 4 less prescriptive (users can fix all at once or one-by-one)
- Improve CLI and browser extension install copy with specific features and use cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:39:45 -07:00
Paul BakausandClaude Opus 4.6 0e4cc16620 Update Chrome extension from 'coming soon' to published
Extension is now live on the Chrome Web Store. Replace all
coming-soon placeholders with install links on the homepage,
visual-mode page, and overlay tutorial.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 08:59:26 -07:00
Paul BakausandClaude Opus 4.6 b0c78cacda Scope sub-page .visual-mode-preview styles so they don't leak to homepage
The /visual-mode sub-page rules added in 27d1b13 duplicated
.visual-mode-preview (and its header/dot/title children) in
sub-pages.css with a max-width + margin: 0 auto. Because sub-pages.css
loads after main.css on index.html, those styles won on the homepage
too. Auto margins on a grid item disable justify-self: stretch, so the
preview collapsed to the iframe's 300px intrinsic width instead of
filling its 3fr cell in .visual-mode-demo.

Scope the rules to .visual-mode-page so they only apply on the sub-page
and the homepage falls back to main.css's .visual-mode-preview rule.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:57:43 -07:00
Paul BakausandClaude Opus 4.6 f1d4131964 Split rename + creation-workflow bullets in v2.0 changelog
Call out the frontend-design to impeccable rename on its own (and the
/teach-impeccable to /impeccable teach move), and reframe the /shape
bullet to cover both /shape and /impeccable craft as the new ways to
create with Impeccable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:50:09 -07:00
Paul BakausandClaude Opus 4.6 c8b3d9d33a Tighten data-driven rewrite bullet in v2.0 changelog
Drop the metric-heavy framing and lead with the user-facing wins
(font/color diversity, design quality, Codex support) plus a brief
nod to the eval framework and anti-attractor technique.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:47:05 -07:00
Paul Bakaus 17cdcc1335 Drop Apache 2.0 bullet from v2.0 changelog
Impeccable has always been Apache 2.0; the back-and-forth on licensing
was internal to the v2.0 PR and is not a user-facing change.
2026-04-08 13:34:02 -07:00
Paul Bakaus 04f284a651 Polish v2.0 changelog entry
Tightened the v2.0 changelog on the homepage. Same information density,
fewer words, no em dashes, and dropped what does not concern users.

- Skill rewrite bullet: same numbers, shorter framing.
- Detection engine bullet: dropped the 'hard-to-hit cases that slip
  past regex-only scanners' flourish at the end.
- CLI bullet: collapsed parenthetical clauses into short phrases.
- Chrome extension bullet: replaced the em dash with a colon.
- /critique bullet: tightened.
- /shape bullet: replaced the em dash with a period break.
- "Rebuilt site and docs" renamed to "New docs site" and trimmed to
  just what users experience (top-level sections, skill pages,
  tutorials, rule cards). Dropped the 'mobile experience overhauled'
  line — implementation detail, not a user-facing feature.
- Licensing bullet: renamed to 'Apache 2.0 throughout'.
2026-04-08 13:33:42 -07:00
Paul Bakaus 1bd08ebad9 Scope sidebar min-height fix to desktop only
The min-height: calc(100vh - var(--site-header-height)) added earlier
so the sticky sidebar's border-right divider reaches the bottom of
the viewport on desktop was applying on mobile too. On mobile the
sidebar is static (not sticky) and collapses behind a toggle, so the
min-height reserved a full viewport of empty space above the main
content whenever the menu was collapsed. The result: opening
/anti-patterns on mobile showed just the 'Sections' dropdown in the
first screen, then a blank viewport, then the rules below the fold.

Wrap the min-height rule in a min-width: 921px media query so it only
applies on desktop, matching the breakpoint that switches the layout
to the two-column grid.
2026-04-08 13:31:23 -07:00
Paul BakausandClaude Opus 4.6 2a38fad925 Refresh OG image with Chrome extension product shot
Replaces the brand-only card with a split layout: wordmark left,
floating Chrome extension detection panel right. Generator now counts
user-invocable, non-deprecated skills from source/skills/ (v2.0 unified
structure) instead of the removed source/commands/ directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:17:52 -07:00
Paul Bakaus 27d1b13bc2 New /visual-mode top-level page, pull gallery out of /anti-patterns
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.
2026-04-08 13:04:23 -07:00
Paul Bakaus ebe07cbae5 Merge gallery into /anti-patterns, hide rule ids
Two fixes from the review.

1. Rule id chip hidden. The internal slugs (e.g. 'border-accent-on-rounded')
   are not useful to readers, only to detector code. Drop the
   .rule-card-id element from the card head entirely. The DOM id on
   the article stays so rules can still be anchor-linked.

2. Merge /gallery into /anti-patterns and drop 'Gallery' from the nav.
   'Gallery' in the top nav reads as 'things built with impeccable'
   when it is actually a curated collection of AI-generated UI in the
   wild — the complement to the rule catalog above.

   - Add GALLERY_ITEMS to content/site/anti-patterns-catalog.js
     (11 entries, same ids and copy as the old gallery.html)
   - Render a new 'In the wild' section at the bottom of
     /anti-patterns with a card grid of the 11 specimens, each linking
     to its standalone live example under /antipattern-examples/{id}.html
   - New .gallery-card CSS: square thumbnail, italic display title,
     charcoal body, hover lifts the card and tints the title accent
   - Add an 'In the wild' entry to the anti-patterns TOC sidebar so
     readers can jump to it
   - Drop the 'Gallery' link from the top-level nav in the shared
     header partial and the 4 hand-authored HTML pages. The old
     /gallery route still serves its page directly (for bookmarked
     links), but the nav no longer advertises it and the gallery page
     itself now marks Anti-Patterns as the active nav item.
2026-04-08 12:48:24 -07:00
Paul Bakaus c384e6b568 Anti-patterns page polish: visuals for LLM rules, wider grid, compact legend, sidebar divider fix
Six fixes from the first-pass review.

1. Visuals for all 13 LLM-only rules. The catalog now ships a preview
   snippet for every card: Syne-style display, monospace-as-technical,
   dark-mode-default, everything-in-cards (nested), identical card
   grids (literal 3x2), hero metric layout (big number + gradient +
   supporting stats), glassmorphism (backdrop-filter on a gradient),
   sparkline decoration, generic drop shadows (three rounded squares),
   modal reflex (backdrop + centered dialog), every-button-primary,
   redundant-headers, mobile-amputation. Every rule card now has the
   same ~160px preview treatment.

2. Lede font normalized to match skill detail pages. .sub-page-lede
   dropped from clamp(1.0625, 1.6vw, 1.25rem) to clamp(1, 1.4vw, 1.125rem)
   so the paragraph under the anti-patterns title is the same size as
   the tagline on every other /skills page.

3. "How to read this" legend collapsed into a <details> disclosure.
   Summary is a single compact row with the title + chevron, padding
   14px vertical. Body appears when opened, same content as before.
   Chevron rotates on open.

4. Visual example height bumped 140px -> 160px for more breathing
   room with the complex snippets.

5. Wider grid on the anti-patterns page. .anti-patterns-content no
   longer has a 820px max-width; only the header (720px max) and
   legend (720px max) are capped. The rule card grid fills the full
   main column width on wide viewports, so 38 cards stop wasting
   horizontal space.

6. Sidebar divider extends to the bottom of the viewport. Add
   min-height: calc(100vh - var(--site-header-height)) to .skills-sidebar
   so the sticky column fills the full viewport vertically regardless
   of content height, and the border-right reaches the footer.
2026-04-08 12:38:12 -07:00
Paul Bakaus 0d87b5afb5 Overhaul /anti-patterns with visuals, detection layers, and LLM rules
Three additions to the anti-patterns catalog page, all sourced from a
new content/site/anti-patterns-catalog.js file so the user's parallel
edits to src/detect-antipatterns.mjs don't conflict with display metadata.

1. Detection layer badge per rule. Three layers:
     cli     - static analysis or jsdom. Runs from `npx impeccable detect`
               on files, no browser required. 23 of 25 current rules.
     browser - needs real browser layout (getBoundingClientRect).
               Runs via the browser extension or Puppeteer, not the
               plain CLI. Only 2 rules: cramped-padding and line-length,
               as documented in tests/detect-antipatterns-browser.test.mjs.
     llm     - no deterministic detector. Flagged by /critique's LLM
               review pass. 13 rules live only in the skill's DON'T list.
   Each card renders a mono pill with the layer label, color-coded per
   layer (neutral mist for CLI, blue tint for browser, amber tint for LLM).
   The How-to-read legend grows a dl explaining what each layer means.

2. Inline visual example per detected rule. All 25 detection rules get
   a ~140px tall preview area at the top of the card showing the bad
   pattern as live HTML (cream background, self-contained inline styles).
   Visuals for side-tab, gradient-text, dark-glow, nested-cards, and the
   rest let you see what the detector is actually flagging. LLM-only
   rules ship without visuals for now; their card bodies take the full
   card height.

3. LLM-only rules merged into the sections. Parsed out from
   source/skills/impeccable/SKILL.md DON'T lines that the detector
   doesn't cover: Syne, monospace-as-technical, dark-mode-default,
   everything-in-cards, identical-card-grids, hero-metric-layout,
   glassmorphism, sparkline-decoration, generic-drop-shadows,
   modal-reflex, every-button-primary, redundant-headers,
   mobile-amputation. Each renders like a detection rule card but
   shows the 'LLM only' layer badge and has no rule id chip. They
   slot into the same section groups as detected rules (Interaction
   and Responsive sections added to the section order so these get
   real headings).

- scripts/lib/sub-pages-data.js: imports the catalog, enriches
  detected rules with { layer, visual }, appends LLM_ONLY_RULES with
  layer: 'llm'. Re-exports LAYER_LABELS and LAYER_DESCRIPTIONS for
  the generator.
- scripts/build-sub-pages.js: renderRuleCard adds the visual block
  and the layer badge; LLM rules drop the rule id chip since their id
  is just an internal slug. groupRulesBySection now extends the
  primary order with whatever extra sections rules reference.
- public/css/sub-pages.css: .rule-card now has a .rule-card-visual
  preview area on top with border-bottom, body section below. New
  .rule-card-layer pill styling per layer. Layer legend dl using a
  2-column grid for badge -> description.

Dev server serves 38 total cards (25 detected + 13 LLM) across 8
sections: Visual Details, Typography, Color & Contrast, Layout & Space,
Motion, Interaction, Responsive, General quality.
2026-04-08 12:05:12 -07:00
Paul BakausandClaude Opus 4.6 a2a8627e94 Update v2.0 changelog + hero teaser with branch-to-date work
Expands the v2.0 entry from 5 flat bullets to 9 grouped highlights
and surfaces the additions the existing entry missed: the data-driven
skill rewrite (validated against the internal eval framework with
concrete per-niche metrics), the Chrome DevTools extension, the
rebuilt site and docs, /critique's persona sub-agents, Rovo Dev
support, and Apache 2.0 unification. Each item leads with a bold
label so the list stays scannable despite the length.

Hero version link tightened to signal the three most visible pieces
of the release (detection engine, Chrome extension, data-driven
skill) instead of just the detector.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:02:11 -07:00
Paul Bakaus 484967e23f Drop background fill on active sidebar item
The accent-dim background fill on active items was too loud. Keep
only the border-left accent, ink color, and bold weight. Hover tint
on other items still works as a subtle interactivity hint.
2026-04-08 11:55:03 -07:00
Paul Bakaus 0d22c28733 Make the active sidebar state actually visible on desktop
The previous attempt put the active-state border at margin-left: -14px
so it would sit in the layout gutter while keeping the link text
aligned with the header logo. Problem: .skills-sidebar uses
overflow-y: auto, and per CSS spec that coerces overflow-x from
visible to auto too, which clips any content outside the column. The
border was being painted and then clipped, so the user saw nothing.

Rework:
- Border now sits inside the normal flow. padding: 4px 0 4px 12px
  with a 2px border-left means link text is 14px inset from the column
  edge. Group titles pick up the same 14px padding-left so the two
  align vertically.
- Add a subtle accent-dim background on the active item (not just the
  border) so the cell reads as highlighted, not just marked.
- Add a hover background tint so items feel interactive.
- Remove the duplicate .skills-sidebar-list a[aria-current] block that
  was left over from the previous rewrite.

Trade-off: links are now 14px to the right of where the header logo
sits (before, they aligned). Worth it: the active state is now clearly
visible on both desktop and mobile.
2026-04-08 11:53:43 -07:00
Paul Bakaus 648eb036ea Mobile collapsible sidebar + more breathing room on active state
Three docs sidebar improvements.

1. Collapsible mobile menu. The sidebar on narrow viewports used to
   dump 21 skill links and 2 tutorial links inline above the content,
   forcing a long scroll past the nav. Add a toggle button at the top
   of the sidebar that shows the current page label (e.g. "/overdrive"
   or "Getting started") plus a chevron, and collapses the menu behind
   it on mobile. Click the button to open/close. On desktop (>=920px)
   the toggle is hidden and the menu shows unconditionally as before.
   Pure aria-expanded state driven by a small delegated click handler
   in render-page.js.

2. Active-state breathing room. The left-border accent on the current
   sidebar item used to sit 2px from the text, which felt cramped. Pull
   the border 14px to the left via margin-left and push the text 12px
   to the right via padding-left. The net result: the accent bar sits
   in the layout gutter, the text keeps its alignment with the brand
   logo in the header, and there's now 12px of comfortable space
   between the border and the text.

3. Active state visibility. The same change makes the accent bar more
   visible on desktop, since it no longer hugs the text. 'aria-current'
   was already being set correctly on /skills/* and /tutorials/* pages;
   the bar just looked too subtle at 2px of clearance.
2026-04-08 11:47:47 -07:00
Paul Bakaus 26436a657a Put Before, caption, After on a single row
The demo's Before/After labels and the descriptive caption were on two
separate rows below the card. Merge them into one row: Before pinned
left, caption centered in the middle, After pinned right.

- Move the caption <p> inside .split-labels between the two label spans.
  If a skill has no caption, emit an empty <span> placeholder so the
  grid still has three cells and Before/After sit at the edges.
- Switch .split-labels from flex space-between to a 3-column grid
  (auto minmax(0,1fr) auto) with baseline alignment. Before is
  justify-self: start, After is justify-self: end, caption is
  justify-self: center.
- Reset the caption's typography inside the grid (default body font,
  not mono; text-transform: none; letter-spacing: 0) since it inherits
  the label row's monospace caps by default.
2026-04-08 11:40:36 -07:00
Paul Bakaus db4d533228 Move demo eyebrow inside .split-comparison for card-edge alignment
The eyebrow ('Drag or hover to compare') was a sibling of
.split-comparison, sitting at the left edge of the outer .skill-demo
section. Because .split-comparison has 32px padding, the visible card
inside sat 32px to the right of the eyebrow, creating a visible
indentation mismatch. Move the eyebrow inside .split-comparison so it
inherits the same 32px offset and aligns with the card's left edge
(same as how .split-labels and .skill-demo-caption already align).

Note: the HTML order inside .split-comparison is now eyebrow -> container
-> labels -> caption, which matches the homepage's before/after demo
flow (card -> BEFORE/AFTER -> descriptive caption).
2026-04-08 11:38:32 -07:00
Paul Bakaus 282987ad7b Let the editorial hero break out wider than the body text column
Two problems with the previous hero pass:

1. The whole .skill-detail was capped at 720px, so the hero grid got
   squeezed into that same width. The demo column tried to hold its
   fixed 360px height but lost width, forcing the split-container into
   a portrait aspect ratio with no room for the intended 500x360
   landscape layout.

2. The grid used grid-template-columns: minmax(0, 1fr) auto, which
   meant the demo column was sized to its content (max 564px) but
   competed with the text column for the shared 720px. The demo got
   cramped instead of floating as a proper hero module.

Fix: drop the max-width from .skill-detail itself. Apply it per body
section (.skill-detail-hero, .skill-detail-editorial, .skill-source-card,
.skill-references) so each one keeps its readable 720px cap by default
but the hero can override it. At >=1280px viewport, .skill-detail-hero--has-demo
switches to a grid with a FIXED 564px demo column (guaranteeing the
split-container holds its 500x360 landscape) and a minmax(0,1fr) text
column, capped at max-width: 1200px. The editorial body below still
renders at 720px for line length.

Below 1280px the hero stacks as before (header then demo) within the
720px body column, same layout as a minute ago.
2026-04-08 11:32:57 -07:00
Paul Bakaus b3a23e651e Editorial hero: demo floats top-right on wide viewports
Two visual fixes to the skill detail demo block.

1. Remove the 24px padding from .split-content. This padding was the
   'persistent indentation' visible in the screenshot: it created a
   white band between the container border and demo content that had
   its own card background. The overdrive demo (which fills the
   container via absolute canvases and 100% divs) lost some of its
   bleed to the padding; the polish-style demos (small centered cards)
   don't need it because .split-content already uses flex centering.

2. Restructure the skill detail header into a .skill-detail-hero
   wrapper that holds both the header text and the demo block.
   - At >=1100px viewport: switch to a grid (minmax(0,1fr) auto),
     text column on the left, demo on the right, align-items:center
     so the eyebrow/title/tagline center with the demo vertically.
     The demo floats as an editorial hero element alongside the title.
   - Below 1100px: stack (demo under the header) with clamp-based
     spacing between them. Same visual as before, just now inside the
     hero wrapper.
   - skill-detail-hero--has-demo class so skills without a demo
     (/shape) keep the single-column layout with no grid quirks.
2026-04-08 11:30:09 -07:00
Paul Bakaus b0c829a20e Move demo caption inside .split-comparison, tighten its style
Caption was sitting with a ~56px gap below the labels (32px container
padding-bottom + 24px caption margin-top). Move the <p> inside
.split-comparison so the padding wraps the caption too, not separates
it from the labels. Drop caption margin-top from 24px to 12px and tone
the color down from charcoal to ash + 0.8125rem to match the rest of
the supporting-text rhythm on these pages.
2026-04-08 11:22:20 -07:00
Paul BakausandClaude Opus 4.6 f04dc113c0 Rephrase consulting section from "us" to "me"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 11:22:01 -07:00
Paul Bakaus 13ade4a7e2 Bigger, truly invisible buffer around demo
Two issues with the previous buffer pass:

1. The buffer was too small (20px) to feel forgiving.
2. The visible box had a cream background while the buffer area showed
   the paper page background, creating a 2% contrast inset that read
   as a card-inside-a-card border.

Bump the buffer to 32px per side (64px total) so the demo stops at
500px visible with 564px max-width. Change .split-container background
from cream to paper so it blends into the page and the buffer area is
genuinely invisible. The demo box is now defined by its 1px mist border
and 12px radius alone; individual demos still provide their own
background colors on top via the inline before/after HTML.
2026-04-08 11:15:15 -07:00
Paul Bakaus 71f46ef20f Add invisible hover buffer around the before/after demo
Ported the homepage's padding-margin trick: .split-comparison now has
20px of padding around the visible box, with a matching negative
top/bottom margin so the padding does not affect layout flow. The
pointer event listeners move from .split-container to .split-comparison
so the hover tracking engages inside the buffer and only resets when
the mouse leaves the full padded area. Percentage math still reads
.split-container.getBoundingClientRect() so the divider position stays
aligned with the visible box.

This matches how the landing-page split demo feels: graze the edge
and the divider holds; leave the box entirely and it eases back.
2026-04-08 11:09:05 -07:00
Paul Bakaus ac710d5ec1 Fix before/after demo layout, labels, and interaction
Four issues reported on /skills/overdrive (and every other skill demo):

1. The demo block was centered inside the content column, looking odd
   against the otherwise left-aligned page. Drop 'margin: 0 auto' from
   both .split-comparison and .split-container, and remove the nested
   max-width so the whole demo left-aligns at 500px max-width with no
   centering.

2. The BEFORE and AFTER labels were stretching beyond the demo box
   because .split-comparison (560px) was wider than .split-container
   (500px) and .split-labels was using justify-content: space-between
   across the wider parent. Collapse the two max-widths to a single
   500px cap so the labels now sit flush with the container edges.

3. The label row was sitting way below the demo (16px margin-top plus
   the height-stretched container). Tighten margin-top to 10px.

4. The inline split-compare handler only supported click-and-drag. The
   homepage effect also tracks hover on devices with hover:hover, so
   the mouse sweeps the divider and leaving the box eases it back to
   the default. Port that behavior: matchMedia('(hover: hover)') to
   detect, pointerenter/leave to toggle a hovering flag, pointerdown/up
   for drag, and a tiny lerp on requestAnimationFrame so the return to
   center feels smooth. Eyebrow text now reads 'Drag or hover to
   compare' to signal both modes.

Also drop text-align: center on .skill-demo-eyebrow and .skill-demo-caption
for the same left-align consistency.
2026-04-08 11:04:35 -07:00
Paul Bakaus 0ff20b1ba2 Drop italic cursive from tutorial detail titles
The tutorial h1 used font-style: italic + weight 500, which read as
cursive and sat oddly next to the non-italic h1 on /skills, /anti-patterns,
and skill detail pages. Align it with the shared .sub-page-title
treatment: display serif at weight 400, no italic, clamp(2.5rem, 6vw,
4.5rem). The italic style stays on subsection headings (skill category
titles, anti-pattern section titles) where it still reads as a label,
not a page title.
2026-04-08 10:57:55 -07:00
Paul Bakaus 7d7f77d2ba Before/after split demos on skill pages + sidebar reorder
Two changes bundled:

1. Before/after split demos on every skill detail page.
   - loadCommandDemos() in sub-pages-data.js: dynamically imports each
     module in public/js/demos/commands (the same files the homepage
     uses), returning a { skillId: { id, caption, before, after } } map.
     Falls back to a warn-and-continue if a demo file can't be loaded
     so one bad demo doesn't break the whole generator.
   - buildSubPageData becomes async; caller in build-sub-pages.js
     awaits it.
   - Each skill object gets a .demo field (may be null for /shape).
   - renderSkillDemo() produces the .split-comparison markup matching
     the homepage: .split-container with .split-before + .split-after
     + .split-divider, plus Before/After labels and the caption. The
     block sits between the detail header and the editorial wrapper
     so readers see the visual before reading any prose.
   - sub-pages.css ports the core .split-* layout from main.css (the
     .slop-* and .impeccable-* helpers are homepage-specific and not
     copied). Height is 360px to match the docs column.
   - render-page.js grows a lightweight inline split-compare init
     script (60 lines of vanilla JS) that handles drag and the skewed
     clip-path without depending on the homepage's full lerp/ResizeObserver
     module. Runs only on pages that actually have .split-container.

2. Sidebar reorder: Tutorials first, then skills.
   Walk-throughs are the on-ramp; they belong at the top of the sidebar
   where a new visitor will find them. Add <hr class="skills-sidebar-divider">
   between the Tutorials group and the first skill category so the two
   sections read as distinct.

Verified: /skills/polish, /skills/bolder, /skills/critique all render
the demo block. /skills/shape correctly has none. Sidebar on any /skills
or /tutorials page shows Tutorials first, then a thin mist divider,
then Create / Evaluate / Refine / Simplify / Harden / System skill
categories.
2026-04-08 10:54:18 -07:00
Paul Bakaus eb130c4af9 Copy buttons on code blocks + merge Skills and Tutorials under Docs
Two small-to-medium improvements bundled together.

1. Copy buttons on every rendered code block.
   - render-markdown.js: wrap each fenced code block in a .code-block-wrap
     container and emit a <button class="code-block-copy" data-copy="...">
     alongside it. Button text is set via CSS ::before content so the
     'Copy' / 'Copied' label is a single toggle class (.is-copied).
   - render-page.js: 12-line inline script at the end of the body wires
     a delegated click handler that calls navigator.clipboard.writeText
     and flips .is-copied for 1.5s.
   - sub-pages.css: button styles matching the dark terminal palette,
     hidden until you hover the code block, accent-colored success state.

2. Merge Skills and Tutorials under a single Docs nav item.
   - Rename the Skills nav link to 'Docs' in every header (partial +
     4 hand-authored pages). Drop the separate Tutorials nav item; it
     now lives inside Docs. Anti-patterns stays as its own top-level.
   - scripts/build-sub-pages.js: replace renderSkillsSidebar and
     renderTutorialsSidebar with a unified renderDocsSidebar that shows
     every skill category followed by a Tutorials group. Takes a
     current descriptor of shape { kind: 'skill'|'tutorial', id|slug }
     so both skill detail and tutorial detail pages can mark the active
     row. activeNav on every /skills/* and /tutorials/* page is now
     'docs'; the shared site header's data-nav matches.

Verified: /skills/polish and /tutorials/getting-started both render
with the unified Docs sidebar (all 21 skills grouped by category +
both tutorials as a final group). The Docs nav item is aria-current
on both. Copy buttons appear on every fenced code block and toggle
to 'Copied' when clicked.
2026-04-08 10:50:23 -07:00