Commit Graph
119 Commits
Author SHA1 Message Date
Paul BakausandClaude Opus 4.6 e4d1d96926 Auto-generate argument hint with all commands grouped by category
The static "[command] [target]" hint didn't help users discover available
commands. The build now reads command-metadata.json and groups commands
by category (from SKILL_CATEGORIES) with middle-dot separators for
natural line-breaking in the prompt bar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:22:09 -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 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 f957fcad20 Fix: quote YAML scalars that contain colon-space in frontmatter
generateYamlFrontmatter only re-quoted values starting with `[` or `{`,
but parseFrontmatter strips surrounding quotes on input. Descriptions
containing `: ` (e.g. "Also handles: critique...") round-tripped into
unquoted plain scalars that YAML parsers reject. Added a yamlNeedsQuoting
check covering colon-space, space-hash, YAML indicator chars, reserved
keywords, and number-like strings, plus regression tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:09:55 -07:00
Paul BakausandClaude Opus 4.6 00d485659a Fix false positives: bg-black opacity modifiers and background-image contrast
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>
2026-04-10 12:57:06 -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 7670d1325a Show actual skills version, not CLI version; normalize version for hash
- 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>
2026-04-10 11:18:06 -07:00
Paul BakausandClaude Opus 4.6 c2b72b9d44 Fix: factory transformer was not copying skill scripts to dist
The refactored factory.js transformer dropped script file support that
existed in the old shared.js version. Scripts were read from source
but never written to dist/, so npx skills installed skills without the
cleanup-deprecated.mjs script, causing errors on first load.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:43:50 -07:00
Paul BakausandClaude Opus 4.6 22b7adf56f Strip deprecated skill stubs from local harness dirs after build sync
The build still generates deprecated stubs in dist/ (so the cleanup
script can redirect users), but now removes them from the repo's own
harness directories so they don't clutter the local skill list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:19:53 -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 0567d1954d Fix scroll anchors for /impeccable craft and /impeccable teach
Use h3 headings with custom IDs instead of inline spans so the browser
scrolls to the right position. Added {#id} syntax support to the
markdown heading renderer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:48:22 -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 eeee5bc0aa Copy antipattern examples and browser detector to build output
These self-contained HTML files and the detector script were served
by the dev server from public/ but never made it into the Cloudflare
Pages build directory, causing 404s on the deployed site.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 08:20:01 -07:00
Paul BakausandClaude Opus 4.6 3769057e79 Use SAMEORIGIN globally instead of per-path X-Frame-Options override
Cloudflare Pages merges headers from all matching rules rather than
overriding, so the path-specific SAMEORIGIN conflicted with the global
DENY. Switch the global rule to SAMEORIGIN since the site only frames
its own antipattern example pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 08:11:34 -07:00
Paul BakausandClaude Opus 4.6 e284ef882b Fix visual-mode iframe blocked by X-Frame-Options: DENY
The global _headers rule set DENY for all paths, preventing the
/visual-mode/ page from embedding /antipattern-examples/ in an iframe.
Add a path-specific SAMEORIGIN override for /antipattern-examples/*.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 08:08:04 -07:00
Paul BakausandClaude Opus 4.6 b30b1ab1a3 Scope chunk + asset naming by [dir] to avoid collisions on older Bun
The Bun shipped with Cloudflare Pages doesn't dedupe shared CSS chunks
across HTML entrypoints — each entry tries to emit its own copy. With
chunk: '[name]-[hash].[ext]', three sub-pages all named index.html
(skills/, tutorials/, anti-patterns/) plus shared CSS content end up
producing chunks with identical name+hash and the build aborts on
'Multiple files share the same output path'.

Including [dir] in the chunk and asset templates scopes each chunk to
its entry's source directory, so the per-entry copies land in unique
paths even when dedupe is off. Local Bun (1.3.x) still emits a single
shared chunk because [dir] is only used when there are multiple chunk
candidates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 14:21:11 -07:00
Paul BakausandClaude Opus 4.6 8f05b9bfa5 Force [hash] in Bun chunk naming so older Bun versions don't collide
Cloudflare Pages ships an older Bun than the one used locally. That
version emits shared CSS chunks via the default 'chunk-[hash]' naming
template, but the [hash] token isn't always populated when the chunk
is shared across multiple HTML entrypoints — every sub-page that
imports sub-pages.css ends up wanting the same './chunk-' filename
and the build aborts with 'Multiple files share the same output path'.

Pin the chunk and asset naming explicitly so [hash] is always present
regardless of Bun version.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 14:17:38 -07:00
Paul BakausandClaude Opus 4.6 adcca35b03 Surface Bun build error details in build.js error handler
When Bun.build aggregates resolution failures, the thrown error keeps the
real causes on error.errors (an array). The previous handler only printed
error.message and error.stack, both of which are generic / undefined for
this kind of failure, so CI logs read as 'Bundle failed / undefined' with
no clue what was unresolved. Walk error.errors first so the actual file +
import that failed shows up in CI output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 14:01:09 -07:00
Paul BakausandClaude Opus 4.6 a6a58f712c Fix CI: relative img path in /visual-mode + sandbox flags for Puppeteer
Two unrelated breakages were stacking on the v2.0 PR:

1. The static site build crashed because the generated /visual-mode page
   referenced images via root-absolute paths (/antipattern-images/*.png).
   Bun's HTML loader resolves <img src> at build time relative to the
   source HTML file and treats a leading slash as filesystem-absolute, so
   it could not find the images. Use a relative path so Bun bundles and
   hashes them the same way the homepage already does.

2. The Puppeteer-backed fixture tests crashed in GitHub Actions because
   the Ubuntu runners block unprivileged user namespaces, so Chrome's
   sandbox cannot initialize. Pass --no-sandbox / --disable-setuid-sandbox
   only when process.env.CI is set, so local users keep the hardened
   default launch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:57:41 -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 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 BakausandClaude Opus 4.6 0728eaadea Allow XML-block prose form in SKILL.md DON'T parser
Recognize "DO NOT" / "DO" lines (with optional colon) inside <rules>
and <absolute_bans> blocks, and make skillGuideline substring matching
case-insensitive so the validator handles the new XML-structured
SKILL.md without rejecting the refactored prose.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 11:38:26 -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 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 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
Paul Bakaus a89f7f5040 Polish pass on editorial wrappers and skill detail layout
Feedback round from first review of the skill pages. Six concrete fixes:

1. Contain the auto-rendered SKILL.md in a distinct card.
   The "skill itself" section was flowing straight into the editorial
   wrapper above, making the two blocks read as one long mixed
   document. Wrap the canonical body in .skill-source-card: white
   paper background, mist border, rounded, with a small "SKILL.md"
   badge header and an italic subtitle. Drop the old full-width
   divider treatment; the card does the visual separation work.

2. Rewrite the /impeccable "do not fight the opinion" pitfall.
   The old text said "fighting the opinion usually produces worse
   output", which discouraged informed pushback. Replace with language
   that explicitly encourages users with real reasons (brand guideline,
   accessibility, user research) to push back; the skill raises the
   floor, not overrules your judgment when you have evidence.

3. Move /onboard from create to refine.
   Onboarding is refinement of empty states and first-run experiences,
   not greenfield creation. Fixed in:
   - scripts/lib/sub-pages-data.js SKILL_CATEGORIES
   - public/js/data.js commandCategories
   Both locations now list onboard under 'refine'.

4. De-dupe overdrive and animate.
   - overdrive: "how it works" listed 7 techniques as bullets and then
     "try it" listed 5 concrete examples using the same 7 techniques.
     Collapse "how it works" into a tight paragraph and make "try it"
     a specific scenario instead of a laundry list.
   - animate: pitfalls repeated the "no layout properties" rule that
     was already stated in "how it works". Drop the duplicate.

5. Remove outdated tutorial guidance.
   getting-started.md said "Cursor needs Nightly channel plus Agent
   Skills in Settings. Gemini CLI needs the preview version." Neither
   is true anymore. Replace with a generic pointer to check the
   harness's own skill docs.

6. Embed the live visual overlay in critique-with-overlay tutorial.
   The tutorial now renders the same demo iframe the homepage uses
   (/antipattern-examples/visual-mode-demo.html) inside step 2, with
   a mac-window chrome frame that mirrors the homepage preview. New
   .tutorial-embed CSS in sub-pages.css defines the header with
   traffic-light dots + mono title, the iframe body (520px tall),
   and an optional caption. The user now sees the overlay in action
   before being asked to run it locally.
2026-04-08 10:26:01 -07:00
Paul Bakaus 500fe448cd Generate /tutorials index + 2 walk-throughs
Third and final new section. Adds the tutorials browser with two
hand-written walk-throughs: "Getting started" and "Critique with the
visual overlay". Same docs-browser shell as skills and anti-patterns.

- content/site/tutorials/getting-started.md
  Five-minute install, teach, and first polish pass. Covers npx skills
  add, answering the teach interview honestly, and running /polish on
  an existing page. Includes common issues and what to try next.

- content/site/tutorials/critique-with-overlay.md
  Ten-minute walk-through of the full /critique workflow with the
  browser overlay. Covers the two-assessment model (LLM + detector),
  the three ways to open the overlay (extension, inside critique, or
  standalone via `npx impeccable live`), the fix-reload-verify loop,
  and how to interpret merged reports.

- scripts/build-sub-pages.js
  - renderTutorialsSidebar(): tutorial list with current-item marking
  - renderTutorialsIndexMain(): card grid with mono order numbers,
    italic display titles, taglines, arrow affordances
  - renderTutorialDetail(): breadcrumb eyebrow, italic display title,
    plain tagline, rendered markdown body inside .prose
  - Wire both into the main generator loop.
  - sub-pages-data.js already reads content/site/tutorials/*.md and
    sorts by frontmatter.order, so no data-layer change was needed.

- public/css/sub-pages.css
  - .tutorial-card grid (number, body, arrow) with hover border
    darken + arrow slide. Mono order numbers, italic display titles.
  - .tutorial-detail header with italic display title and plain sans
    tagline (matching the visual rhythm of skill detail pages without
    the mono command style since tutorials are prose, not commands).
2026-04-08 10:18:04 -07:00
Paul Bakaus e49a4b4a02 Generate /anti-patterns index page
Add the anti-patterns browser. Single page, same docs-browser shell as
the skills section, but the sidebar is a table of contents instead of
a navigation list.

- scripts/build-sub-pages.js
  - groupRulesBySection(): bucket the 25 detection rules by skill
    section (Visual Details, Typography, Color & Contrast, Layout &
    Space, Motion) plus a 'General quality' bucket for the 7 rules
    without a skillSection cross-reference. Each bucket sorts slop
    rules first, then quality rules alphabetically.
  - renderAntiPatternsSidebar(): TOC with anchor links to each
    section, per-section rule count on the right, reusing the
    .skills-sidebar styles with anti-patterns-specific tweaks for
    the two-column item layout.
  - renderRuleCard(): rule id + category badge + name + description
    + optional 'See in /impeccable' link that jumps to the right
    anchor on the skill detail page.
  - renderAntiPatternsMain(): editorial header ('25 detection rules')
    + 'How to read this' legend callout + six sections each with a
    grid of rule cards.
  - Wire the new page into the main generator loop.

- public/css/sub-pages.css
  - .rule-card grid (auto-fill minmax 320px) with header row, mono
    rule id, pill category badge, bold name, body description,
    arrow skill link at the bottom.
  - .rule-card-category variants: slop uses accent-dim background
    with accent text, quality uses mist background with charcoal text.
  - Section headers with baseline-aligned title and right-aligned
    rule count, matching the rhythm of the /skills overview.
  - Anti-patterns sidebar count styling (tabular-nums, ash).

Verified: /anti-patterns returns 200 with 25 rule cards rendered across
all six section anchors.
2026-04-08 10:14:18 -07:00
Paul Bakaus 9b1b709bab Align sidebar to header logo, bump sidebar font, rework detail title
Three tightening passes based on visual feedback.

- Sidebar alignment. The skills layout now uses the same horizontal
  padding clamp as the site header, so the sidebar column's left edge
  sits under the brand logo above. Sidebar items drop their 10px left
  padding and sit flush with the column edge; the 2px active-item
  accent lives in a -2px margin so it hangs in the layout gutter
  without pushing text right. Drop the max-width constraint so the
  docs shell extends wall-to-wall on wide screens like a real docs site.

- Sidebar font. The command list was 0.8125rem which read too small
  next to the sidebar group titles. Bump to 0.875rem and tighten the
  vertical rhythm (4px vs 3px padding, group title margin-bottom 6px).

- Skill detail title. The title was set in mono at ~3rem and the
  tagline in italic display, which inverted the visual weight (the
  tagline felt heavier than the title). Rework to match the landing
  page's .spread-command-name palette styling:
    - Title: display serif, clamp(3rem, 5.5vw, 5rem), line-height 0.95
    - Leading '/' split into <span class="skill-detail-title-slash">
      and colored with --color-accent at weight 300 so it reads as a
      quiet prefix glyph
    - Tagline: body sans at 1-1.125rem, no italics, max-width 60ch
2026-04-08 09:56:40 -07:00
Paul Bakaus 80d7502737 Extend docs-browser shell to detail pages, tighten sidebar, ban em dashes
Builds on the /skills overview landing. Every skill detail page now lives
inside the same sticky-sidebar shell, with the active skill marked via
aria-current and pulled out of the list with a 2px accent border.

- scripts/build-sub-pages.js: detail pages now wrap the .skill-detail
  body in wrapInDocsLayout() and pass currentSkillId into the sidebar
  renderer so the active row is marked
- public/css/sub-pages.css sidebar pass:
  - Narrow from 260px to 200px (was way too wide for the content)
  - Drop the redundant "Skills" label at the top (it was visually
    competing with the category titles); keep the node for a11y via
    visually-hidden styling
  - Group titles shrink to 0.625rem mono uppercase in --color-ash so
    they read as quiet signposts, not headings
  - Tighten item line-height to 1.5 and vertical padding to 3px
  - Replace the box-shadow inset accent with a border-left accent on
    the active item, leaving it visually pulled left
  - Simplify .skill-detail sizing so it works inside .skills-main
    without its own max-width / padding
- Ban em dashes in user-facing copy everywhere:
  - Rewrite 9 copy lines in index.html, 2 title tags in gallery.html,
    inline category descriptions, the /skills overview lede + how-to,
    two skills-generator comments, one aria-label, and the page titles
    for Skills and skill detail pages
  - New validateNoEmDashes step in scripts/build.js scans content/site,
    public/*.html, and the sub-page generator sources. Build fails on
    any — or &mdash; in user-facing copy. Uses commas, colons, periods,
    or parentheses instead

Build green: all 26 HTML entrypoints bundle cleanly, all four hand-authored
pages retain the shared site header, anti-pattern rules still match
SKILL.md, zero em dashes.
2026-04-08 09:45:13 -07:00
Paul Bakaus 88d647a555 Restructure /skills overview as a docs-browser layout
The old /skills was one long scrollable list. Replace it with a proper
app-shell layout: sticky left sidebar with every skill grouped by
category, main column on the right with an orientation piece (intro
+ 'how to pick one' callout + category sections with chip lists).

- scripts/build-sub-pages.js
  - renderSkillsSidebar(): the sticky left rail used across the /skills
    section. Takes an optional currentSkillId so we can mark the active
    skill with aria-current when detail pages adopt the same shell in a
    later commit
  - renderSkillsOverviewMain(): the right column. Editorial header,
    'how to pick one' callout that inlines 5 hot-link skill references,
    then one block per category (title, count, description, chip row
    of all skills in that category)
  - wrapInDocsLayout(): tiny helper that pastes the sidebar and main
    into a .skills-layout grid

- public/css/sub-pages.css
  - Copy .skip-link a11y styles over from main.css so the 'Skip to
    content' link is properly hidden until keyboard focus (was showing
    unstyled at the top-left of every generated page)
  - Add .skills-layout grid shell (260px sidebar + flex main column,
    max-width 1400px, clamp-based horizontal padding)
  - Add sticky .skills-sidebar with its own scroll-y overflow and a
    thin scrollbar; group titles + mono link list; aria-current styling
    with a 2px left accent bar
  - Add .skills-overview-howto callout, category sections with chip
    rows, and mobile collapse (sidebar becomes an inline block above
    the main column at <=920px)
  - Introduce --site-header-height and --skills-sidebar-width tokens

No detail page layout changes in this commit — those still use the
single-column .skill-detail shell.
2026-04-08 09:24:54 -07:00
Paul Bakaus 7847daffff Generate /skills index + 21 auto-rendered skill detail pages
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.
2026-04-08 09:16:19 -07:00
Paul Bakaus c598a63498 Add shared site header across all pages
Every hand-authored HTML page now carries the same sticky top nav:
Home / Skills / Anti-Patterns / Tutorials / Gallery / GitHub. The three
future sections (skills, anti-patterns, tutorials) will land behind
these links in subsequent commits.

- Add <header class="site-header"> with a <!-- site-header v1 --> marker
  to index, cheatsheet, gallery, privacy
- Each page links public/css/sub-pages.css so it picks up the shared
  header styling (sticky, backdrop blur, accent-underlined current item)
- Gallery: drop the inline .site-header/.header-brand/.header-nav
  definitions that predate the shared component (class names conflicted)
- Cheatsheet: restructure the page title into .cheatsheet-page-header
  so it doesn't collide with the new <header class="site-header">; move
  the page container max-width/padding off <body> onto .cheatsheet-page-header,
  main, and footer so the shared sticky header spans the full viewport
- Privacy: full styling refresh using sub-pages.css tokens + a small
  inline block for the page body typography
- Add a validateSiteHeader step to scripts/build.js that fails the build
  if any of the four pages drops the marker
- Add /privacy route to server/index.js so extensionless URLs work

All four built pages pass the marker check; dev server serves all four
with 200 and the shared header.
2026-04-08 08:09:41 -07:00
Paul Bakaus 54b687d16f Add sub-page render pipeline foundation
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.
2026-04-08 08:01:34 -07:00
Paul Bakaus 038d281247 Drop Tailwind CLI from the build
Tailwind was wired into the build but the project didn't actually use it:
no @tailwind/@theme/@apply directives in source CSS, no utility classes
in any HTML or JS, no tailwindcss dependency in package.json, and no
HTML page linked to the compiled styles.css output.

Bun's HTML loader already handles main.css's @import chain transparently
in both `bun run dev` and `bun run build`. Removing the Tailwind step:

- Deletes buildTailwindCSS() from scripts/build.js (and the now-unused
  execSync import)
- Removes public/css/styles.css (dead compiled output that nothing read)
- Updates CLAUDE.md to drop the "must rebuild Tailwind after CSS edits"
  instruction

Verified: `bun run build` produces the same 104 KB CSS chunk linked from
index.html via Bun's HTML loader. No more rebuild step after CSS edits.
2026-04-07 19:52:27 -07:00
Paul BakausandClaude Opus 4.6 e1032b7285 Add icon-tile-stack rule and cross-validate engine against skill
A new icon-tile-stack detection (the canonical AI feature-card with a
small rounded-square icon container above a heading), backed by a
two-column TDD fixture, plus a single-source-of-truth design that ties
the engine to the impeccable skill so they can no longer drift silently.

Detection
- New icon-tile-stack rule (slop): heading's previousElementSibling is
  a 32–128px rounded-square element with a non-transparent background
  or border, contains an svg/icon-i child, and sits above (not next to)
  the heading. Excludes round avatars, wide thumbnails, side-by-side
  layouts, tiny icons, and hero images.
- Two-column fixture convention: a single icon-tile-stack.html with a
  flag column (4 cases) and pass column (6 cases), with snippet-text
  matching used by the fixture test.

Single source of truth
- Each ANTIPATTERNS entry can now declare skillSection + skillGuideline.
  18 of 25 rules carry these fields; the build's new
  validateAntipatternRules() in scripts/build.js fails if any declared
  skillGuideline isn't found verbatim in the right SKILL.md section.
- scripts/build-extension.js now includes the description field in
  extension/detector/antipatterns.json (it was previously dropped).
- The existing count validator was promoted from warn to error so
  command count drift fails the build the same way detection drift does.

Impeccable skill DON'Ts
- Added 4 new top-level DON'Ts that target real default AI behavior:
  single-font, flat-type-hierarchy, all-caps-body, line-length.
- Cut 7 new DON'Ts I had drafted (tight-leading, tiny-text, wide-tracking,
  justified-text, low-contrast, cramped-padding, skipped-heading) because
  they teach things every model already knows from CSS/a11y basics. The
  detector still catches all of them.

Stale count cleanup
- 22 commands → 21 across 17 references in HTML, README, NOTICE, AGENTS,
  plugin.json, marketplace.json (left over from the validate skill removal).
- Dropped the hand-coded "212 design guidelines" marketing copy on the
  homepage, which never mapped to any real count.

Sub-agent
- New private .claude/agents/anti-patterns.md captures the full TDD
  recipe, schema, plug-in points, jsdom constraints, and pre-commit
  checklist so future sessions can add rules end-to-end without
  re-investigating the wiring.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:58:13 -07:00
Paul BakausandClaude Opus 4.6 13b2f763d9 Polish Chrome extension for Web Store submission
Refactors the extension for on-demand injection (no static content_scripts
entry — content script and detector are loaded only when the user actively
opens the Impeccable panel, sidebar pane, or popup). Adds a new "Auto-scan"
preference (default: scan when the Impeccable panel opens, opt-in: scan
when DevTools opens) plus configurable line length (strict/lax) and
highlight blur on/off settings. Adds an Elements panel sidebar that shows
findings for the currently selected element.

Includes substantial overlay UX work: page-pixel-perfect spotlight mask
via clip-path, refined hover/dim states, instant transitions for snappier
feel, copy buttons for findings, hover-from-panel highlighting, and a
brand-aware exception list so the font check no longer flags Roboto on
Google's own properties.

Robustness fixes for the MV3 service worker lifecycle: heartbeat keepalive
plus auto-reconnecting ports across panel/sidebar/devtools so transient
SW restarts don't break the panel UI, and immediate teardown on DevTools
close (replacing an unreliable setTimeout-based defer that didn't survive
SW termination).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 21:06:09 -07:00
Paul BakausandClaude Opus 4.6 e961d56252 Add Chrome DevTools extension for anti-pattern detection
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>
2026-04-06 15:18:36 -07:00