Commit Graph
604 Commits
Author SHA1 Message Date
VinaywhoandClaude Opus 4.7 4f66eb9c08 feat: add Qoder harness support (closes #76)
Qoder ships an Agent Skills system at .qoder/skills/{name}/SKILL.md with
slash-command invocation, mapping cleanly onto the existing transformer
pipeline. Adds Qoder as a 13th first-class harness:

- PROVIDER_PLACEHOLDERS entry in scripts/lib/utils.js (model, config_file,
  ask_instruction, command_prefix) mirroring the Pi/Rovo Dev shape.
- PROVIDERS entry in scripts/lib/transformers/providers.js with
  configDir=.qoder and the OpenCode/Claude Code frontmatter field set
  (user-invocable, argument-hint, license, compatibility, metadata,
  allowed-tools), since Qoder docs explicitly support those.
- transformQoder named export in scripts/lib/transformers/index.js for
  test-spy parity (kept per CLAUDE.md guidance, even though build.js uses
  PROVIDERS directly).
- .qoder added to PROVIDER_DIRS in bin/commands/skills.mjs so the CLI
  detects existing Qoder installs.
- HARNESSES.md updated: official docs row, frontmatter support column,
  directory structure row, and "Last verified" date bumped.
- DEVELOP.md reference link added.
- .github/ISSUE_TEMPLATE/feature_request.md and PULL_REQUEST_TEMPLATE.md
  extended with Qoder in the provider checklists.
- Built .qoder/skills/impeccable/ tree committed (per CLAUDE.md harness
  output dirs are tracked so npx skills can read them at install time).

The dynamic providers.test.js loop picks up Qoder automatically; all
non-prefix Qoder cases pass. The pre-existing Windows-only prefix-test
flake affects every provider equally and is out of scope for this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 15:16:12 +05:30
Paul Bakaus 5f5e2b013d Release impeccable skill v3.0.4 2026-04-28 00:16:30 -07:00
Paul Bakaus 54f6ccf6f0 codex in auto-review became way too autonomous - significantly harden craft/shape flows 2026-04-27 23:41:23 -07:00
Paul BakausandGitHub 62ce35ac8e Merge pull request #116 from pbakaus/feat/live-modal-host-friendliness
feat(live): make picker chrome modal-host friendly (Radix, Headless UI, vaul)
2026-04-27 16:39:39 -07:00
Paul BakausandClaude Opus 4.7 630e586b01 feat(live): make picker chrome modal-host friendly (Radix, Headless UI, vaul)
Closes #113.

Picker chrome could become unclickable inside Radix Dialog portals, and
clicking it dismissed the host dialog. Three orthogonal issues surfaced
during manual verification:

1. Modal-aware chrome
   - Add `defangOutsideHandlers` and apply it to bar, picker, params
     panel, annotation overlay, global bar, and design panel host.
   - Sets `pointer-events: auto !important` on interactive chrome so
     Radix's `body { pointer-events: none }` modal scroll-lock can't
     silence our UI.
   - Stops `pointerdown` / `mousedown` / `focusin` propagation at the
     chrome boundary so DismissableLayer / FocusScope outside-handlers
     never fire for clicks that land on us.

2. detectPageTheme: misread transparent body as black
   - `getComputedStyle(body).backgroundColor` returns `rgba(0,0,0,0)`
     when no bg is set; the prior regex captured (0,0,0) and ignored
     alpha, calling every default-bg page "dark."
   - Honor alpha, walk body → html, fall back to
     `prefers-color-scheme` only when both are transparent.

3. Exit X invisible on host pages with `button { padding: ... }`
   - Every other chrome button sets padding inline; exitBtn didn't.
     Host resets like `button { padding: 0.5rem 1rem }` (in the new
     fixture, common in the wild) inflated the 24x24 button into 56x40
     and pushed the SVG into a non-rendering region — DevTools showed
     the right styles, the X just didn't paint.
   - Pin `padding: 0` + `box-sizing: border-box`, match the toggle
     icon spec (14 / stroke 1.5 / textDim → text on hover).

4. Toast no longer obscures the global bar
   - Position the toast above globalBarEl's actual rect instead of a
     fixed bottom: 16px that overlapped the bar's bottom: 14px.

Test coverage: new `vite8-react-radix-dialog` fixture exercises the
full pick → Go → cycle → Accept loop with `@radix-ui/react-dialog`
+ `Portal` + `Overlay` + `Content`. Without the fix, clicking Go
dismisses the dialog and unmounts the picked element. All 20 live
e2e fixtures pass; all 180 unit tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 16:22:00 -07:00
Paul BakausandGitHub 39bec7c08c Merge pull request #115 from pbakaus/feat/harden-jsdom-border-radius
feat(detector): harden border-radius reads against jsdom CSS regressions
2026-04-27 14:55:12 -07:00
Paul BakausandGitHub e3d488e123 Merge pull request #101 from voidborne-d/fix/windows-detect-path-drive-letter
fix: use fileURLToPath for Windows path resolution
2026-04-27 14:49:13 -07:00
Paul BakausandClaude Opus 4.7 668263843f test: wire windows-path-fix into bun test script + rebase notes
- Added tests/windows-path-fix.test.js to package.json's test script so
  the regression suite actually runs in CI; without this the file lived
  on disk but no command picked it up. Verified with bun run test:
  170 bun tests / 3 files, all green.
- Rebased onto current main. The PR's second hunk (live-mode browser
  script load) no longer applies because that code path was extracted
  into source/skills/impeccable/scripts/live-*.mjs during the live-mode
  rewrite. The remaining puppeteer site at line 2700 still had the bug
  and now uses fileURLToPath, matching the PR's intent.
- The added test file's mix of ESM imports + require/__dirname runs
  cleanly under Bun's test runner; left as-is to preserve the PR's
  authorship.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:46:58 -07:00
voidborne-dandPaul Bakaus 94b315ef63 fix: use fileURLToPath for Windows path resolution (#95)
On Windows, `new URL(import.meta.url).pathname` returns `/C:/...`
(with a leading slash). Passing that to `path.resolve()` or
`path.join()` causes Node to prepend the drive letter again, producing
doubled paths like `C:\C:\Users\...\detect-antipatterns-browser.js`.

Replace both occurrences (puppeteer scan at ~L2690 and live detect at
~L3506) with `fileURLToPath(import.meta.url)` from `node:url`, which
correctly strips the leading slash on Windows while remaining a no-op
on POSIX.

Add regression tests verifying the source no longer uses the raw
`.pathname` accessor for local path construction and that
`fileURLToPath` handles both Windows and POSIX file URLs correctly.

Closes #95
2026-04-27 14:44:25 -07:00
Paul BakausandClaude Opus 4.7 28875097b0 fix(detector): preserve percent-radius signal when width is missing
parseRadiusToPx("50%", 0) used to return 0, and resolveBorderRadiusPx's
"if (fromComputed !== null) return fromComputed" guard short-circuited
with that 0 before ever consulting longhand / inline / stylesheet
fallbacks. Callers that gate on `> 0` (border-accent-on-rounded and
isCardLike's hasRadius) silently lost findings the old
parseFloat(style.borderRadius) === 50 heuristic happened to keep.

In jsdom this is reachable any time style.width resolves to "auto" or
an empty string — parseFloat yields NaN, the `|| 0` fallback turns it
into 0, and any percent radius collapses to nothing. Real-world cards
with `width: 100%` hit this on every load.

Fix: when widthPx is 0 / missing, return the raw percentage number
instead. The percent-to-px conversion only makes sense with a width
reference; without one, the value still serves as a positive presence
signal for boolean checks. The icon-tile circle exclusion is
unaffected because that rule already gates on `siblingWidth >= 32`.

Caught by Cursor Bugbot on PR #115.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:33:54 -07:00
Paul BakausandClaude Opus 4.7 65bbd6cb5f feat(detector): harden border-radius reads against jsdom CSS regressions
Adds resolveBorderRadiusPx(el, style, widthPx, win), a helper that walks
computed style → longhand → inline DOM → raw style attribute → matching
stylesheet rules to recover a pixel value, converting % to px when
needed.

Three jsdom adapter sites now use it: checkElementBorders (via a new
optional resolvedRadius param threaded from detectHtml), the icon-tile
sibling check in checkElementIconTile, and isCardLike's hasRadius gate.
Browser DOM adapters hit the fast path on the first line since real
getComputedStyle resolves both shorthand and percentages.

Background: from jsdom 29.0.2 onward, getComputedStyle(el).borderRadius
returns "" for the shorthand and "0" for longhand reads when the rule
used the shorthand. checkIconTile relied on parseFloat(borderRadius) >=
width/2 to exclude circular avatars; that comparison broke and circles
got false-flagged as icon-tile-stack. jsdom 29.1.0 has a separate
parser crash on <h*> + linear-gradient inline style which keeps the
pin at exactly 29.0.0 for now, but landing the helper means we can
move forward as soon as the gradient crash is fixed upstream without
touching detector code again.

The change is also strictly more correct than the old parseFloat
approach: percentage values now convert to actual pixel sizes, so
checkIconTile no longer relies on parseFloat("50%") == 50 happening
to satisfy `>= width/2` only for elements <= 100px wide.

bun run test passes (174/174); bun run build:browser and
bun run build:extension regenerated to mirror the helper into
bundled artifacts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:09:49 -07:00
17fe31baa9 chore: bump in-range deps; pin jsdom to 29.0.0
- @ai-sdk/anthropic 3.0.69 → 3.0.71
- @anthropic-ai/claude-agent-sdk 0.2.110 → 0.2.119
- ai 6.0.162 → 6.0.168
- playwright 1.58.2 → 1.59.1
- wrangler 4.75.0 → 4.85.0
- puppeteer 24.39.1 → 24.42.0 (optional)
- marked range floor bumped to 16.4.2 (already installed)

jsdom is intentionally pinned to exact 29.0.0. From 29.0.2 onward,
getComputedStyle(el).borderRadius returns "" (empty string) instead
of "50%" for percentage values that the engine can't resolve to px
without layout. checkIconTile relies on parseFloat(borderRadius) ≥
width/2 to exclude circular avatars; with the empty string, all
circles get re-flagged as icon-tile-stack. Real browsers resolve
the percentage so the public-site overlay and Chrome extension are
unaffected — only the Node/jsdom path used by `npx impeccable detect`
on HTML files breaks. Hardening the detector to read raw stylesheet
rules as a fallback is a follow-up; pinning is the safe move today.

Skipped: marked 16 → 18 (major bump, unrelated to this work).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:59:06 -07:00
427128e073 chore: reconcile bun.lock with @anthropic-ai/sdk ^0.91.1
package.json was updated to ^0.91.1 in d26ccac (live-mode E2E LLM
agent), but the lockfile was not committed alongside. The next
bun install bumped @anthropic-ai/sdk from 0.81.0 to 0.91.1 to match
the declared range. The nested resolution under
@anthropic-ai/claude-agent-sdk stays at 0.81.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:59:06 -07:00
70a9246401 fix(plugin): slim Claude Code install (291MB→770KB) + fix skills path
- Marketplace source moved from "./" to "./plugin", a thin generated
  subtree containing only the plugin manifest and the impeccable skill.
  Per-version plugin cache shrinks ~378× (~770 KB instead of ~291 MB),
  and the lockfile is no longer included in the source path so the
  cache extraction never runs bun install. (#107)
- skills field in plugin.json now ends with a trailing slash to match
  the documented schema (code.claude.com/docs/en/plugins-reference,
  every directory example uses ./path/). Three reporters converged on
  this fix because Claude Code's plugin loader skips command
  registration on some setups when the slash is missing. (#86)
- Anti-patterns maintenance agent moved out of .claude/agents/ into
  CLAUDE.md / AGENTS.md as concise inline guidance, since it is
  repo-internal dev workflow, not user-facing. The plugin was also
  the only place this agent was exposed to install users.
- Skills version bumped to 3.0.2 so existing users pick up the new
  install path on next /plugin update.
- Top-level harness directories (.claude/skills/, .cursor/skills/, ...)
  intentionally stay where they are; npx skills add reads them
  directly from the GitHub repo and that path is unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:59:06 -07:00
Paul BakausandGitHub 8548003cc1 Merge pull request #111 from vivshaw/main
Rename all references to `Neon Mirai` -> `Neo Mirai`, to match case study site's actual content
2026-04-27 11:07:48 -07:00
vivshaw 579006cda5 fix: add missing trailing-slash redirect for /cases/neon-mirai/ 2026-04-26 19:30:09 -04:00
vivshaw ceb0ef8f67 chore: rename all references Neon Mirai -> Neo Mirai to match site title 2026-04-26 19:10:46 -04:00
Paul BakausandClaude Opus 4.7 25e6c820aa chore(site): bump GitHub star count to 22k
Live count is 21,826 stars; rounding up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 01:35:37 -07:00
Paul BakausandClaude Opus 4.7 6e96f62803 fix(live): readable freeform input on dark bar + tools/live-loop.mjs
The configure row's text input filled its background with translucent
magenta (BP.accentSoft) on focus. Composited against the dark bar surface
this produced a murky purple where the browser's default placeholder
gray washed out — flagged in a real session as "godawful styling, gray
text on dark magenta really hurts my eyes". Fix: focus state shows an
accent-colored border only, no fill; placeholder color is set explicitly
to BP.textDim via a one-shot stylesheet so it reads in both themes.

tests/live-e2e/agent.mjs: runAgentLoop's wrapTarget now accepts either a
static {classes,tag,elementId} (test fixture mode) OR a function that
derives the target from each generate event (real-use mode where the
picked element is unknown ahead of time).

tools/live-loop.mjs: standalone runner that attaches the LLM agent to a
running live-server. Used as a test-harness shortcut for validating live
mode out of band; in production the user's coding agent (Claude Code,
Cursor, etc.) plays this role directly via the live skill spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 01:35:32 -07:00
Paul Bakaus 74f16d6310 Add Neon Mirai showcase 2026-04-25 01:23:51 -07:00
Paul BakausandClaude Opus 4.7 d26ccac1be feat(test): pluggable LLM agent for live-mode E2E suite
tests/live-e2e/agents/llm-agent.mjs: a Claude-backed VariantAgent that
implements the same one-method interface as the fake agent
(generateVariants(event, context) → { scopedCss, variants[] }). Default
model claude-haiku-4-5; override via IMPECCABLE_E2E_LLM_MODEL.

Prompt caching is on — the system prompt (instructions + the live-mode
spec from reference/live.md) is the cacheable prefix. First call writes
~10K tokens to cache; subsequent fixtures pay only the cache-read rate.
JSON output is validated for shape (scopedCss, variants[N].innerHtml),
with light error messages on parse failure.

tests/live-e2e.test.mjs: read IMPECCABLE_E2E_AGENT (fake|llm). When 'llm',
construct the LLM agent and skip the case cleanly if ANTHROPIC_API_KEY is
unset. Param-manifest assertions are gated to fake mode (LLM may emit
zero-param "fixed point" variants per the live.md spec). The accepted-h1
class assertion now allows hero-title as one of multiple classes so an
LLM agent that adds classes alongside the original still passes.

Test timeouts widen for LLM mode: 25s first-pass on conditional-render
fixtures (vs 5s for fake), 60s on direct waits (vs 30s). Without these,
the LLM's 3-8s generate latency races the orchestration's state-loss
recovery window.

tests/live-e2e/ui.mjs: clickGo retries up to 3× on stability failures.
Required because conditional-render fixtures (modal/tabs) animate the bar
mid-transition when preActions trigger framework HMR; a single click can
land during a re-render and Playwright's stability gate times out.

Pass rate on a typical sweep: 18/19 in LLM mode, 19/19 in fake mode.
The modal fixture's intrinsic state-loss flake (Fast Refresh resetting
useState(open) when source changes) is amplified by LLM latency and may
need a re-run; documented in CLAUDE.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 01:06:06 -07:00
Paul BakausandClaude Opus 4.7 4310352423 fix(live): variant observer detects wrappers added as descendants
startVariantObserver's "dominated" check only matched when the variant
wrapper was added directly as a mutation's addedNode. SvelteKit (and any
framework whose HMR replaces a whole subtree on edit) adds the wrapper as
a descendant of an added <main> or similar — the observer ignored those
mutations and the session stayed in GENERATING forever even with all 3
variants present in the DOM.

Surfaced by the LLM-agent E2E run on vite8-sveltekit. The fake-agent path
masked the issue because its splice timing happened before Vite's reload
finalized; the slower LLM call shifted timing into the failure window.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 01:05:28 -07:00
Paul BakausandClaude Opus 4.7 89ffd73d4b improve(polish): make polish a true superset of retired /normalize
Aligning to the design system is now non-optional, drift gets named by
root cause (missing token / one-off / conceptual), and a new Information
Architecture & Flow dimension covers the user-flow shape that polish
previously left to chance. Folds the missing pieces from the deprecated
normalize skill into the v3.0.1 changelog bullet rather than a new bump.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 00:56:35 -07:00
Paul BakausandClaude Opus 4.7 4fa02bf573 docs: add live-mode E2E test instructions to CLAUDE.md and AGENTS.md
Documents `bun run test:live-e2e`, the IMPECCABLE_E2E_ONLY scope env var,
the IMPECCABLE_E2E_DEBUG diagnostic flag, the one-time
`npx playwright install chromium` setup, and why the suite is kept off
the default `bun run test` path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:44:14 -07:00
Paul BakausandClaude Opus 4.7 7baf77a457 chore: bump impeccable skill to v3.0.1
User-facing changes shipped in this patch:
- Live mode runs in strict-CSP apps (auto-patches meta CSP, reverts on stop)
- Live mode survives conditional-render content (modal/tab/collapsible)
- Live mode no longer breaks JSX projects (carbonize stash + accept rewrite)
- SvelteKit hydration race fixed
- Headless Chromium WebGL fallback fixed

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:39:49 -07:00
Paul BakausandClaude Opus 4.7 c3e18fe664 fix(live): four bugs surfaced by E2E suite + CSP meta auto-patch
CSP meta-tag auto-patch (live-inject.mjs)
  When the user's HTML carries <meta http-equiv="Content-Security-Policy">,
  the cross-origin load of /live.js and the SSE/POST stream back to
  localhost:PORT are both blocked. Insert: append http://localhost:PORT to
  script-src and connect-src, plus blob: to img-src (the shader overlay),
  stash the original content value as a base64 data-impeccable-csp-original
  attribute. Remove: decode the marker and restore the original verbatim.
  Header-based CSP (Next/Nuxt/SvelteKit configs) intentionally untouched —
  those flow through the existing detect-csp.mjs reference path.

JSX-aware accept (live-accept.mjs)
  - Carbonize stash now emits style={{ display: 'contents' }} for JSX targets
    instead of style="display: contents" (HTML form). React 19 was throwing
    "Failed to set indexed property [0] on CSSStyleDeclaration" on the
    string form because it iterated chars onto the style object.
  - extractCss now matches </style> anywhere on a line, not just at line
    start. Previously a JSX template-literal close like `}</style> would
    leak the backtick + brace into the carbonize stash, breaking JSX.
  - Carbonize stash wraps the CSS body in {` … `} for JSX targets so curly
    braces in CSS rules don't get parsed as JSX expressions.

Conditional-render UX (live-browser.js)
  - Drop the 2s-then-window.location.reload() fallback in the SSE 'done'
    handler. That reload was masking a real failure mode: when the picked
    element lives inside conditional render (closed modal, hidden tab,
    other-route), Fast Refresh remounts the parent and state resets, so
    the variants land in source but never reach the DOM. Reload also reset
    state to default, leaving the user stuck.
  - Replace with a 6s contextual toast: "Variants ready. If the picked
    element isn't visible, retrace the path that revealed it — they'll
    appear automatically." The MutationObserver stays armed and
    auto-transitions to CYCLING once the variants finally mount.
  - Pick-time heads-up: when the picked element is inside [role="dialog"],
    [data-state="open"], a multi-tab tabpanel, or an aria-expanded
    collapsible, fire a brief upfront toast so the user knows what to
    expect if state resets during generation.

Hydration race (live-browser.js)
  - SvelteKit (and any framework that hydrates after HTML parse) was
    failing post-Vite-page-reload because init() ran resumeSession()
    before the variant wrapper hydrated into the DOM. The OLD reload
    fallback masked this by triggering a second reload whose hydration
    benefited from warm cache. Without that, fix it properly: install a
    scout MutationObserver in init() that retries resumeSession() once
    [data-impeccable-variants] lands in the DOM.

Shader overlay (live-browser.js)
  - WebGL fallback in showShaderOverlay used Object.assign(img.style,
    canvas.style, …), which throws on modern Chromium because
    CSSStyleDeclaration's indexed properties are not writable. Use
    cssText to copy positioning instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:37:45 -07:00
Paul BakausandClaude Opus 4.7 c8de59d81e test(live): add full-cycle E2E framework-fixture suite with pluggable agent
19 fixtures (11 styling/build variants + 4 conditional-render scenarios + 4
meta-frameworks) drive the entire user flow end-to-end: handshake, pick,
configure, Go, cycle, accept, carbonize cleanup. Each fixture installs real
deps, boots the framework dev server, and runs Playwright Chromium against a
deterministic fake agent that produces realistic variants (colocated style
with @scope rules, full data-impeccable-params manifests covering range +
steps + toggle, JSX/HTML/Svelte syntax-aware rendering).

The agent is pluggable via a one-method interface — generateVariants(event) —
so a future LLM-backed agent slots in by implementing the same shape. The
orchestrator handles wrap, file write, accept, and carbonize cleanup
deterministically regardless of which agent is plugged in.

Schema extensions (tests/framework-fixtures/README.md): runtime block adds
preActions / reloadProbe / pickSelector / scheme / ignoreHTTPSErrors so
fixtures can drive conditional UI (modal, tab, route) before pick and verify
the carbonized variant survives a reload.

Static fixture suite filtered to skip dirs without fixture.json so empty
scaffold dirs no longer break discovery. Total: 178 static checks, 19 E2E
full cycles, ~107s wall clock for the E2E suite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:37:04 -07:00
Paul Bakaus d29a690797 Fix Neon Mirai active navigation 2026-04-24 23:18:23 -07:00
Paul Bakaus d340f075e8 Improve Neon Mirai manifesto artwork 2026-04-24 23:10:34 -07:00
Paul Bakaus 7de610c620 Add Neon Mirai conference example 2026-04-24 17:22:59 -07:00
Paul BakausandClaude Opus 4.7 25353448e2 fix(site): restore docs-viz-caption top margin squashed by .prose p
The .prose p rule (specificity 0,1,1) was overriding .docs-viz-caption's
intended margin-top, leaving 0px between the caption and the cards/file/
report above it on every docs page that uses the hero block.

Bump specificity with .docs-viz-hero .docs-viz-caption and set
margin: 16px 0 0 so the caption sits 16px below the visual and lets the
hero's 24px padding alone control the bottom gap. Symmetric inside the
cream box.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 15:45:59 -07:00
Paul BakausandClaude Opus 4.7 346ce25952 docs(site): add image gen bullet and Live Mode alpha tag to v3.0 changelog
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:21:01 -07:00
Paul BakausandClaude Opus 4.7 f5e82162c1 fix(site): strip dev-only live.js inject tags from production HTML
public/index.html and public/privacy.html had stale
`<script src="http://localhost:8400/live.js">` scaffolding from a
local /impeccable live session. On impeccable.style (Cloudflare) this
fired Chrome's private-network-access prompt on every page load. The
inject is dev-only; normally stripped by live-server.mjs stop, but
these two slipped through.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 18:21:26 -07:00
Paul BakausandGitHub 6816558d7a Merge pull request #109 from pbakaus/3.0
v3.0: single /impeccable skill, Live Mode, /designing orientation, visualize-first
2026-04-23 18:08:34 -07:00
Paul BakausandClaude Opus 4.7 0760cdf3e9 fix(skill): update stale SKILL.md font-tag reference in typography.md
typography.md pointed at SKILL.md's `<font_selection_procedure>` and
`<reflex_fonts_to_reject>` XML tags, which were removed in the v3
consolidation and moved into brand.md as the "Font selection procedure"
and "Reflex-reject list" sections. Agents loading typography.md via the
craft flow were chasing content that no longer existed. Now points at
brand.md with correct section names.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 18:03:57 -07:00
Paul BakausandClaude Opus 4.7 a42d21856c fix(skill): resolve cursor bot findings on colorize + critique
colorize.md: the brand-register paragraph claimed "a dominant color can own
the page" and "accent rate stays ≤10%" in the same breath. SKILL.md scopes
the ≤10% rule to Restrained only; Committed / Full palette / Drenched
exceed it on purpose, and brand.md explicitly encourages those strategies.
Rewritten to defer to the color-strategy ladder.

critique.md: two cross-references still pointed at "Step 4" / "Step 5"
after those headers were renamed to "Ask the User" / "Recommended Actions".
Swapped the references to the new names so the flow is self-consistent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 17:06:09 -07:00
Paul BakausandClaude Opus 4.7 5613891aa6 docs(typography): absorb tactical additions from typecraft-guide-skill
Merged ten tactical items from ehmo/typecraft-guide-skill into the typography
reference at the upstream author's request: dark-mode weight/tracking/leading
compensation, font-display: optional vs swap, preload-critical-weight-only,
variable fonts for 3+ weights, clamp() max-to-min ratio bound, container/
font-size coupling to preserve measure, text-wrap: balance / pretty,
font-optical-sizing: auto, quantified ALL-CAPS tracking (5-12%), and the
paragraph-rhythm rule (space OR indent, never both).

Skipped: platform-specific tables (iOS/Android/print), confidence markers,
severity-graded report format, academic sources, and the punctuation
subsection (em-dash prescription conflicts with the project copy rule).

Attribution lives in NOTICE.md, not inside the skill content.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:56:29 -07:00
Paul BakausandClaude Opus 4.7 e0ab3a73b7 feat(live + site): preserve variant attr on accept, designing-page redesigns
Runtime fix in live-browser.js: the 2s static-server fallback in handleAccept
now swaps the outer wrapper with the `[data-impeccable-variant="N"]` div itself
(+ display:contents), matching what live-accept.mjs writes to disk. Scope rules
anchored on the variant attribute keep matching on the non-HMR path, so the
accepted design no longer flashes unstyled until reload. Propagated to all
harness script copies.

/designing:
- §03 Polish redesigned as drenched magenta masthead: commands live in the band,
  three title/description columns beneath on cream.
- §04 Maintain redesigned as architectural poster diptych: extract + document
  vizzes become the hero element, caption below.
- §05 Interop section removed.
- §05 (was §06) "Pick a register" renamed to "Brand, or product." with a
  two-lane hairline-divided layout and an auto-selected framing in the sub.

Live mode status: BETA → ALPHA across the periodic table, magazine spread,
and docs callout, reflecting real-world-testing readiness.

Skill bootstrap: removed the `<post-update-cleanup>` block from source/SKILL.md
(the source repo is the origin; running cleanup-deprecated here would touch
legitimate source). CLAUDE.md and AGENTS.md now document the skip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:44:46 -07:00
Paul BakausandClaude Opus 4.7 37f79cd013 feat(site): foreground visualize-first workflow on /designing + Case carousel
/designing §01 is reframed around the words → pictures → code arc.
The phase sub covers teach, shape, and craft in one breath; the body
splits into two labeled micro-steps ("teach · in words" and
"shape + craft · in pictures") so the new image-gen spread reads as
step 2 of the same flow instead of a separate topic. Generated plates
from GPT Image 2 sit as an editorial two-up beside their brand and
hi-fi captions. Also fixes a long-standing font-size mismatch where
<code> inside .designing-phase-sub fell back to the browser's default
monospace.

Homepage: inserts a new "Visualize, then build" slot at position 02 of
The Case carousel, compact two-plate visual, shifts the remaining
eight slots to 03-09.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 13:32:32 -07:00
Paul Bakaus df72ca2a58 docs(impeccable): clarify live mode param expectations for freeform
Section 7 no longer reads as default-zero: composition-sized targets,
freeform bias toward 1–2 dials on non-tiny surfaces, hard cap of four.
Cross-link freeform to §7 in the action loader; sync all harness copies.

Made-with: Cursor
2026-04-23 13:28:35 -07:00
Paul BakausandClaude Opus 4.7 5316809139 feat(site): merge /anti-patterns and /visual-mode into /slop
Top nav was at six items and growing. The anti-patterns catalog and the
visual-mode overlay demo were always two views of the same subject (the
rule set and seeing it caught in place), so collapsing them into one page
reduces nav weight and puts the catalog + live demo next to each other.

Four sections in one scroll: See it (iframe demo), Try it live (specimen
gallery), The catalog (full rule list), Run it yourself (invocation
methods). Sidebar TOC nests the catalog sections under "The catalog" for
deep linking. 301s from the old URLs preserve external links.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 13:13:56 -07:00
Paul BakausandClaude Opus 4.7 c160ffc38d feat(live): v2 sidecar upgrade + preserve per-project config on build
Unify the design-system panel's data shape around DESIGN.md frontmatter
as the primary source of truth; the sidecar carries only what Stitch's
frontmatter schema can't (extensions + live component HTML + narrative).
Also fix a long-standing build bug that destroyed per-project config.

Shape changes:
- Server /design-system.json now returns { parsed, sidecar, hasMd,
  hasSidecar, mdNewerThanJson, parseError?, sidecarError? }. No more
  mode switching; both layers ship when present and the panel merges.
- Panel consolidates renderSidecarVisual + renderParsedMdVisual into a
  single renderDesignVisual that merges frontmatter primitives with
  sidecar extensions.colorMeta / typographyMeta. Helpers for color,
  typography, radii model-building. Parsed-md narrative synthesis
  survives as a fallback when no sidecar.
- DESIGN.json rewritten at schemaVersion 2: extensions.{colorMeta,
  typographyMeta, shadows, motion, breakpoints} + components (with
  refersTo pointing back to frontmatter component keys) + narrative.
  Token primitives no longer duplicated in the sidecar.

Build fix:
- scripts/build.js:634 wiped .claude/skills/ (and every other harness
  dir) on each rebuild, then recopied from dist. After commit b0feed0
  unbundled per-project config.json from dist, the sync destroyed the
  user's live-mode config on every build without replacing it.
- Added stashPerProjectArtifacts / restorePerProjectArtifacts in
  scripts/lib/utils.js. Hoisted PER_PROJECT_SCRIPT_ARTIFACTS to a
  module-level export so build.js and readSourceFiles share one
  source of truth. Build now preserves config.json across the sync.

Verified in browser: panel renders 10 colors, 9 typography roles, 3
shadows, 6 grouped components, 9 rules, 25 do/don't items, all merged
correctly from frontmatter + v2 sidecar with zero console errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 12:09:55 -07:00
Paul BakausandClaude Opus 4.7 a5cd7bf859 refine(skill): harden critique against skipping sub-agents and [Human] overlay
Two loopholes in the critique procedure let the model shortcut past its own rigor: "SHOULD delegate" with a broad "if sub-agents are not available" escape, and "Browser visualization (when available)" framing that made the [Human] detector-overlay tab read as optional color. Both get rationalized away under context pressure even though the isolation is what makes the combined score honest and the overlay is the user-facing deliverable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 11:02:39 -07:00
Paul BakausandClaude Opus 4.7 e1cfba0f25 feat(design): align DESIGN.md with Stitch's frontmatter spec
Adopt the Stitch google-labs-code/design.md format's two-layer shape:
YAML frontmatter carries machine-readable tokens, prose body covers the
six canonical sections. The sidecar DESIGN.json now extends frontmatter
rather than duplicating it.

- document.md: new frontmatter section, Step 2b staging, sidecar scoped
  to extensions, Do's/Don'ts now cite PRODUCT.md anti-references by name,
  OKLCH vs hex presented as project posture not mandate.
- design-parser.mjs: tiny YAML-subset reader, exposes model.frontmatter,
  schemaVersion bumped to 2, prose-scraping fallback intact.
- live-browser.js: "basic view" CTA copy reflects frontmatter-first model.
- DESIGN.md: add frontmatter with 10 colors, 9 type roles, 7 components;
  OKLCH values direct per The OKLCH-Only Rule.
- tests/design-parser.test.mjs: coverage for no-frontmatter, Stitch-shape,
  missing-terminator, comment handling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:30:00 -07:00
Paul BakausandClaude Opus 4.7 a95212aa87 feat(site): Designing orientation page with compass loop
New /designing page: the missing "how do I actually use this tool?" story,
organized around a four-phase core loop. Start, iterate, polish, maintain.
Text-dominant editorial sections, cards are rare, spacing pulls from
DESIGN.md's scale only.

Hero runs as a single editorial spread: title and lede on the left,
a compass loop on the right. The compass is a thin ink circle with
cardinal phase labels at N/E/S/W, clockwise arrow glyphs at 45°
transit points, a slow orbiting accent dot, and an italic impeccable
wordmark in the middle. Collapses to vertical stack below 880px.

Phase sections below the hero are full width. Each opens with a
numbered eyebrow, italic Cormorant title (spine), and a 60ch sub.
Appendix sections (register cross-link, DESIGN.md interop, what to
avoid, CTA) use a quieter title tier in roman to separate spine from
supporting material. All separators are 1px mist hairline, no 2px
black rules; rhythm comes from variable padding and margins.

Adds /live-mode hero-frame polish, new top-nav entry (Home · Designing
· Docs · Anti-Patterns · Live · Overlay), footer link, and the server
route for /designing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:13:15 -07:00
Paul BakausandClaude Opus 4.7 b0feed06c9 feat(live): config globs + drift-heal warning for multi-page projects
Config drift was a real tripwire for projects with static generators: new
HTML files get added, never make it into config.files, silently skip
injection. Two additions.

config.files entries now accept glob patterns (**, *, ?) expanded via
fs.globSync in live-inject. Multi-page projects can write
["public/**/*.html"] once and never maintain the list again. New optional
exclude field filters out matched files (email templates, demo fixtures).
HARD_EXCLUDES of node_modules and .git are enforced regardless of user
config so vendor trees can never receive a tracking script.

live.mjs now runs a drift scan after inject: walks common page-source
roots (public/, src/, app/, pages/) and reports HTML files not covered
by the resolved inject targets. Respects user excludes so intentional
omissions aren't flagged. Output JSON carries configDrift: { orphans,
orphanCount, hint } or null. live.md documents the agent flow for
surfacing drift to users without auto-mutating the config.

Unbundle config.json from the distributable skill: it's a per-project
artifact, not skill code. readSourceFiles now skips any PER_PROJECT_ARTIFACTS
during source scan so build output to .claude/ .cursor/ etc never ships
one project's inject targets to another's install. The per-harness
copies stay gitignored via the existing **/skills/impeccable/scripts/config.json
rule; each consuming project writes its own on first /impeccable live.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:12:56 -07:00
Paul BakausandClaude Opus 4.7 6846a135ce refine(live): skip screenshot upload when no annotations present
Without comments or strokes the screenshot is pure visual anchoring,
biasing the model toward the existing rendering and fighting the
three-distinct-directions brief. Local blob still drives the shader
overlay; upload and screenshotPath are gated on annotation presence.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:19:00 -07:00
Paul BakausandClaude Opus 4.7 d60de0fb97 refine(site): restructure "Get Started" around the skill first
Step 1 is now skill-only (the outdated "powers visual mode" claim
and the global CLI install are gone). Chrome extension stays at
step 3, the CLI moves to a new optional step 4 with a link to npm,
and "Stay updated" shifts to step 5. Step 2 collapses its three
numbered sub-steps into a compact command/caption table so the
"Use it" panel matches step 1's height instead of towering over it.

Also: keep code chips and the npm link on one line each (nowrap)
so the caption wraps only on natural prose.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:38:33 -07:00
Paul BakausandClaude Opus 4.7 2658baa461 refine(site): adapt "The Case" to mobile as horizontal pill strip
Vertical 8-tab list ate ~430px of viewport on mobile; panel content
sat far below the fold. At ≤900px, the tab list becomes a sticky
horizontal scrollable pill strip (47px tall) under the header, with
edge-fade mask, pill-shaped buttons, ink-filled active state, and
the active pill auto-centered as rotation advances or users tap.
Desktop layout unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:21:37 -07:00
Paul BakausandClaude Opus 4.7 3ffc485a8d refine(site): "The Case" crossfade + content cleanup, pattern-tabs scroll
- why-panel tab swap is a proper opacity+transform crossfade (display:grid
  stack area) instead of display:none jump; 650/800ms ease-out.
- tab progress indicator animates linearly (timer, not eased).
- Panel 01: dropped redundant "Every command reads this…" footer; moved the
  commands meta into the visual as a right-side sidebar aside PRODUCT.md.
- Panel 02: "Browse the full catalog →" moved under the Gallery of Shame;
  pattern category tabs are now always a single-row horizontal scroll with
  JS-tracked edge-fade mask and chevron affordances; click centers the
  selected tab inside the strip (never scrolls the page).
- Panel 04: "register" → "mode" in body, labels, meta for plain-language.
- Panel 05: removed redundant "Works in Claude Code…" meta.
- Panel 06: removed "Spec-compliant. Interoperable. Not a proprietary
  sidecar." meta.
- .language-content grid gap reduced from --spacing-lg to --spacing-sm so
  the commands palette sits closer to the section lead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 18:47:33 -07:00