From e0ab3a73b7f6aa2f3ad931cc8f379edd98981038 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Thu, 23 Apr 2026 16:44:46 -0700 Subject: [PATCH] feat(live + site): preserve variant attr on accept, designing-page redesigns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 `` 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) --- .agents/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- .claude/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- .cursor/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- .gemini/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- .github/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- .kiro/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- .opencode/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- .pi/skills/impeccable/SKILL.md | 16 - .pi/skills/impeccable/scripts/live-browser.js | 8 +- .rovodev/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- .trae-cn/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- .trae/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- AGENTS.md | 4 + CLAUDE.md | 6 + content/site/skills/live.md | 5 + public/css/docs-visuals.css | 482 ++++++++++-------- public/designing/index.html | 158 +++--- public/index.html | 2 +- public/js/components/framework-viz.js | 8 +- public/js/components/glass-terminal.js | 10 +- public/js/data.js | 4 +- public/live-mode/index.html | 3 +- scripts/build-sub-pages.js | 165 +++--- source/skills/impeccable/SKILL.md | 16 - .../skills/impeccable/scripts/live-browser.js | 8 +- 35 files changed, 524 insertions(+), 611 deletions(-) diff --git a/.agents/skills/impeccable/SKILL.md b/.agents/skills/impeccable/SKILL.md index 873292cfd..576199435 100644 --- a/.agents/skills/impeccable/SKILL.md +++ b/.agents/skills/impeccable/SKILL.md @@ -5,22 +5,6 @@ description: Use when the user wants to design, redesign, shape, critique, audit Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands ($audit, $polish, $critique, etc.) are now accessed through $impeccable (e.g., `$impeccable audit`). I'll clean up the old standalone skill files. Use `$impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .agents/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.agents/skills/impeccable/scripts/live-browser.js b/.agents/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.agents/skills/impeccable/scripts/live-browser.js +++ b/.agents/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/.claude/skills/impeccable/SKILL.md b/.claude/skills/impeccable/SKILL.md index e2e7930e8..5978f72de 100644 --- a/.claude/skills/impeccable/SKILL.md +++ b/.claude/skills/impeccable/SKILL.md @@ -11,22 +11,6 @@ allowed-tools: Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands (/audit, /polish, /critique, etc.) are now accessed through /impeccable (e.g., `/impeccable audit`). I'll clean up the old standalone skill files. Use `/impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .claude/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.claude/skills/impeccable/scripts/live-browser.js b/.claude/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.claude/skills/impeccable/scripts/live-browser.js +++ b/.claude/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/.cursor/skills/impeccable/SKILL.md b/.cursor/skills/impeccable/SKILL.md index 7834b5bb1..9f579cd95 100644 --- a/.cursor/skills/impeccable/SKILL.md +++ b/.cursor/skills/impeccable/SKILL.md @@ -7,22 +7,6 @@ license: Apache 2.0. Based on Anthropic's frontend-design skill. See NOTICE.md f Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands (/audit, /polish, /critique, etc.) are now accessed through /impeccable (e.g., `/impeccable audit`). I'll clean up the old standalone skill files. Use `/impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .cursor/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.cursor/skills/impeccable/scripts/live-browser.js b/.cursor/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.cursor/skills/impeccable/scripts/live-browser.js +++ b/.cursor/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/.gemini/skills/impeccable/SKILL.md b/.gemini/skills/impeccable/SKILL.md index bb93640ab..49c8c81eb 100644 --- a/.gemini/skills/impeccable/SKILL.md +++ b/.gemini/skills/impeccable/SKILL.md @@ -6,22 +6,6 @@ version: 3.0.0 Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands (/audit, /polish, /critique, etc.) are now accessed through /impeccable (e.g., `/impeccable audit`). I'll clean up the old standalone skill files. Use `/impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .gemini/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.gemini/skills/impeccable/scripts/live-browser.js b/.gemini/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.gemini/skills/impeccable/scripts/live-browser.js +++ b/.gemini/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/.github/skills/impeccable/SKILL.md b/.github/skills/impeccable/SKILL.md index 30ef89843..47754c347 100644 --- a/.github/skills/impeccable/SKILL.md +++ b/.github/skills/impeccable/SKILL.md @@ -9,22 +9,6 @@ license: Apache 2.0. Based on Anthropic's frontend-design skill. See NOTICE.md f Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands (/audit, /polish, /critique, etc.) are now accessed through /impeccable (e.g., `/impeccable audit`). I'll clean up the old standalone skill files. Use `/impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .github/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.github/skills/impeccable/scripts/live-browser.js b/.github/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.github/skills/impeccable/scripts/live-browser.js +++ b/.github/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/.kiro/skills/impeccable/SKILL.md b/.kiro/skills/impeccable/SKILL.md index c3dc00364..05c07fba1 100644 --- a/.kiro/skills/impeccable/SKILL.md +++ b/.kiro/skills/impeccable/SKILL.md @@ -7,22 +7,6 @@ license: Apache 2.0. Based on Anthropic's frontend-design skill. See NOTICE.md f Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands (/audit, /polish, /critique, etc.) are now accessed through /impeccable (e.g., `/impeccable audit`). I'll clean up the old standalone skill files. Use `/impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .kiro/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.kiro/skills/impeccable/scripts/live-browser.js b/.kiro/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.kiro/skills/impeccable/scripts/live-browser.js +++ b/.kiro/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/.opencode/skills/impeccable/SKILL.md b/.opencode/skills/impeccable/SKILL.md index e186eca85..e9b79285d 100644 --- a/.opencode/skills/impeccable/SKILL.md +++ b/.opencode/skills/impeccable/SKILL.md @@ -11,22 +11,6 @@ allowed-tools: Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands (/audit, /polish, /critique, etc.) are now accessed through /impeccable (e.g., `/impeccable audit`). I'll clean up the old standalone skill files. Use `/impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .opencode/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.opencode/skills/impeccable/scripts/live-browser.js b/.opencode/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.opencode/skills/impeccable/scripts/live-browser.js +++ b/.opencode/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/.pi/skills/impeccable/SKILL.md b/.pi/skills/impeccable/SKILL.md index e1d5b859e..0553686db 100644 --- a/.pi/skills/impeccable/SKILL.md +++ b/.pi/skills/impeccable/SKILL.md @@ -9,22 +9,6 @@ allowed-tools: Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands (/audit, /polish, /critique, etc.) are now accessed through /impeccable (e.g., `/impeccable audit`). I'll clean up the old standalone skill files. Use `/impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .pi/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.pi/skills/impeccable/scripts/live-browser.js b/.pi/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.pi/skills/impeccable/scripts/live-browser.js +++ b/.pi/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/.rovodev/skills/impeccable/SKILL.md b/.rovodev/skills/impeccable/SKILL.md index 12d459937..3e21cada6 100644 --- a/.rovodev/skills/impeccable/SKILL.md +++ b/.rovodev/skills/impeccable/SKILL.md @@ -11,22 +11,6 @@ allowed-tools: Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands (/audit, /polish, /critique, etc.) are now accessed through /impeccable (e.g., `/impeccable audit`). I'll clean up the old standalone skill files. Use `/impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .rovodev/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.rovodev/skills/impeccable/scripts/live-browser.js b/.rovodev/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.rovodev/skills/impeccable/scripts/live-browser.js +++ b/.rovodev/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/.trae-cn/skills/impeccable/SKILL.md b/.trae-cn/skills/impeccable/SKILL.md index 5682fbe4b..f471d8537 100644 --- a/.trae-cn/skills/impeccable/SKILL.md +++ b/.trae-cn/skills/impeccable/SKILL.md @@ -9,22 +9,6 @@ license: Apache 2.0. Based on Anthropic's frontend-design skill. See NOTICE.md f Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands (/audit, /polish, /critique, etc.) are now accessed through /impeccable (e.g., `/impeccable audit`). I'll clean up the old standalone skill files. Use `/impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .trae-cn/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.trae-cn/skills/impeccable/scripts/live-browser.js b/.trae-cn/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.trae-cn/skills/impeccable/scripts/live-browser.js +++ b/.trae-cn/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/.trae/skills/impeccable/SKILL.md b/.trae/skills/impeccable/SKILL.md index a097b0a41..9b5d10abd 100644 --- a/.trae/skills/impeccable/SKILL.md +++ b/.trae/skills/impeccable/SKILL.md @@ -9,22 +9,6 @@ license: Apache 2.0. Based on Anthropic's frontend-design skill. See NOTICE.md f Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands (/audit, /polish, /critique, etc.) are now accessed through /impeccable (e.g., `/impeccable audit`). I'll clean up the old standalone skill files. Use `/impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node .trae/skills/impeccable/scripts/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/.trae/skills/impeccable/scripts/live-browser.js b/.trae/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/.trae/skills/impeccable/scripts/live-browser.js +++ b/.trae/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); } diff --git a/AGENTS.md b/AGENTS.md index 954bc3df1..8bc23b79d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,9 @@ # Repository Guidelines +## Skill bootstrap: skip the post-update-cleanup step + +If you load the Impeccable skill from `.agents/skills/impeccable/SKILL.md` (or any sibling harness directory under this repo), it begins with a `` block that runs `scripts/cleanup-deprecated.mjs` and then self-deletes. **Do not run it here, and do not delete the block.** This repo is the source of truth for the skill; cleanup-deprecated assumes a consumer project and would touch legitimate source files. The block is regenerated from `source/skills/impeccable/SKILL.md` on every `bun run build`, so any deletion churns back. Skip it silently and proceed with the task. + ## Project Structure & Module Organization `source/` is the source of truth. Author skills in `source/skills/impeccable/` and keep provider output in `dist/` generated, not hand-edited. Build logic lives in `scripts/`, with provider configs in `scripts/lib/transformers/`. Runtime detection code ships from `src/`. The website lives in `public/`, local API/dev serving lives in `server/`, and regression coverage lives in `tests/` with fixtures under `tests/fixtures/`. diff --git a/CLAUDE.md b/CLAUDE.md index f5ce038ef..23e40722e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,5 +1,11 @@ # Project Instructions for Claude +## Skill bootstrap: skip the post-update-cleanup step + +The `` block at the top of `.claude/skills/impeccable/SKILL.md` runs `scripts/cleanup-deprecated.mjs` and then self-deletes. **Do not run it in this repo, and do not delete the block.** This repo is the source of truth for the Impeccable skill; the cleanup script scans for "leftover" skill files to remove and its judgment doesn't fit a repo where the skill lives in `source/`. The block is also regenerated from `source/skills/impeccable/SKILL.md` on every `bun run build`, so any deletion churns back on the next build. Skip the step silently and proceed. + +Same rule for AGENTS.md and every other harness-specific instruction file: treat post-update-cleanup as a no-op in this repo. + ## Architecture (v3.0+) There is **one** user-invocable skill, `impeccable`, with **23 commands** underneath it. Users type `/impeccable polish`, `/impeccable audit`, etc. The skill is defined in `source/skills/impeccable/`: diff --git a/content/site/skills/live.md b/content/site/skills/live.md index 99cacf47d..ae2969609 100644 --- a/content/site/skills/live.md +++ b/content/site/skills/live.md @@ -7,6 +7,11 @@ tagline: "Iterate on UI in the browser. Pick an element, drop a comment, get thr See it in action, with the animated demo, at /live-mode. This page is the reference for what your AI harness reads when the command runs. +
+ + Status: alpha. Live Mode works end-to-end and is ready to try, but it still needs more testing against real-world repos and framework configs. Expect rough edges on uncommon setups, and please report what breaks. +
+
diff --git a/public/css/docs-visuals.css b/public/css/docs-visuals.css index 65af36bec..531516a92 100644 --- a/public/css/docs-visuals.css +++ b/public/css/docs-visuals.css @@ -1319,6 +1319,24 @@ max-width: 56ch; } +.live-mode-page-alpha-note { + font-family: var(--font-body); + font-size: 0.9375rem; + line-height: 1.55; + color: var(--color-ash); + margin: 0; + max-width: 56ch; + padding: 10px 14px; + border-left: 2px solid var(--color-accent); + background: color-mix(in oklab, var(--color-accent) 6%, transparent); + border-radius: 0 4px 4px 0; +} + +.live-mode-page-alpha-note strong { + color: var(--color-ink); + font-weight: 600; +} + .live-mode-start { display: flex; align-items: center; @@ -2411,47 +2429,87 @@ PHASE 3 — Polish (3-column editorial, no cards) ============================================ */ +/* Polish section — drenched magenta masthead band over a three-column + title/description grid. Commands live in the band so the grid stays + focused on the editorial titles. */ .designing-polish { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: clamp(1.5rem, 3vw, 2.5rem); + display: block; } -@media (max-width: 720px) { - .designing-polish { - grid-template-columns: 1fr; - gap: var(--spacing-lg, 32px); - } +.designing-polish-band { + background: var(--color-accent); + padding: 20px 28px; + display: grid; + grid-template-columns: auto 1fr auto; + gap: 24px; + align-items: baseline; + color: oklch(98% 0 0); +} + +.designing-polish-band-label { + font-family: var(--font-mono); + font-size: 0.6875rem; + font-weight: 600; + letter-spacing: 0.22em; + text-transform: uppercase; + opacity: 0.85; +} + +.designing-polish-band-cmds { + display: flex; + font-family: var(--font-mono); + font-size: 0.8125rem; + font-weight: 500; + letter-spacing: 0.05em; +} + +.designing-polish-band-cmds a { + display: inline-block; + padding: 4px 16px; + color: inherit; + text-decoration: none; + border-right: 1px solid color-mix(in oklch, currentColor 32%, transparent); +} + +.designing-polish-band-cmds a:first-child { padding-left: 0; } +.designing-polish-band-cmds a:last-child { border-right: 0; padding-right: 0; } + +.designing-polish-band-cmds a:hover { + text-decoration: underline; + text-underline-offset: 3px; +} + +.designing-polish-band-meta { + font-family: var(--font-mono); + font-size: 0.625rem; + letter-spacing: 0.2em; + text-transform: uppercase; + opacity: 0.75; +} + +.designing-polish-grid { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 28px; + padding: 28px; + background: var(--color-cream); + border-left: 1px solid var(--color-mist); + border-right: 1px solid var(--color-mist); + border-bottom: 1px solid var(--color-mist); } .designing-polish-col { display: flex; flex-direction: column; - gap: var(--spacing-sm, 16px); - padding-top: var(--spacing-sm, 16px); - border-top: 1px solid var(--color-ink); + gap: 10px; } -.designing-polish-cmd { - font-family: var(--font-mono); - font-size: 0.75rem; - color: var(--color-accent); -} - -.designing-polish-cmd a { - color: inherit; - text-decoration: underline; - text-underline-offset: 3px; - text-decoration-thickness: 1px; -} - -.designing-polish-cmd a:hover { text-decoration-thickness: 2px; } - .designing-polish-name { font-family: var(--font-display); font-style: italic; + font-weight: 400; font-size: 1.5rem; - line-height: 1.1; + line-height: 1.15; color: var(--color-ink); margin: 0; } @@ -2459,51 +2517,80 @@ .designing-polish-desc { font-family: var(--font-body); font-size: 0.9375rem; - line-height: 1.7; + line-height: 1.6; color: var(--color-charcoal); margin: 0; } +@media (max-width: 720px) { + .designing-polish-grid { + grid-template-columns: 1fr; + } + .designing-polish-band { + grid-template-columns: 1fr; + gap: 10px; + } +} + /* ============================================ PHASE 4 — Maintain (two editorial columns + one hero viz each) ============================================ */ +/* Maintain section — architectural poster diptych. Each tile presents the + domain visualization as the hero (stage) with a quiet caption beneath + (command link, italic title, short description). */ .designing-maintain { display: grid; grid-template-columns: 1fr 1fr; - gap: clamp(1.5rem, 3vw, 2.5rem); + gap: clamp(1.5rem, 3vw, 2rem); } -@media (max-width: 720px) { - .designing-maintain { - grid-template-columns: 1fr; - gap: var(--spacing-xl, 48px); - } -} - -.designing-maintain-col { +.designing-maintain-tile { + margin: 0; display: flex; flex-direction: column; - gap: var(--spacing-sm, 16px); + gap: 18px; + min-width: 0; +} + +.designing-maintain-stage { + aspect-ratio: 5 / 3; + background: var(--color-cream); + border: 1px solid var(--color-mist); + display: grid; + place-items: center; + padding: 28px; + overflow: hidden; +} + +.designing-maintain-caption { + display: flex; + flex-direction: column; + gap: 6px; } .designing-maintain-label { font-family: var(--font-mono); - font-size: 0.75rem; + font-size: 0.6875rem; + font-weight: 600; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--color-accent); } .designing-maintain-label a { - color: var(--color-accent); - text-decoration: underline; - text-underline-offset: 3px; - text-decoration-thickness: 1px; + color: inherit; + text-decoration: none; } -.designing-maintain-label a:hover { text-decoration-thickness: 2px; } +.designing-maintain-label a:hover { + color: var(--color-accent-hover); +} .designing-maintain-name { font-family: var(--font-display); font-style: italic; + font-weight: 400; font-size: 1.5rem; line-height: 1.15; color: var(--color-ink); @@ -2512,159 +2599,191 @@ .designing-maintain-desc { font-family: var(--font-body); - font-size: 0.9375rem; - line-height: 1.7; + font-size: 0.875rem; + line-height: 1.55; color: var(--color-charcoal); - margin: 0 0 var(--spacing-md, 24px) 0; + margin: 0; + max-width: 42ch; } -/* Extract consolidation viz — inline, no card */ +/* Extract consolidation viz — cloud of pills converging on a single primitive */ .designing-extract-viz { - display: grid; - grid-template-columns: 1fr auto 1fr; - gap: 14px; + display: flex; align-items: center; + gap: 20px; + flex-wrap: nowrap; + justify-content: center; + width: 100%; } .designing-extract-before { display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 4px; -} - -.designing-extract-btn { - padding: 6px 4px; - background: var(--color-paper); - border: 1px solid var(--color-mist); - border-radius: 3px; - font-family: var(--font-body); - font-size: 9px; - text-align: center; - color: var(--color-charcoal); -} - -.designing-extract-btn:nth-child(1) { background: oklch(97% 0.01 20); } -.designing-extract-btn:nth-child(3) { background: oklch(97% 0.01 220); color: oklch(40% 0.06 220); } -.designing-extract-btn:nth-child(4) { border-radius: 0; } -.designing-extract-btn:nth-child(6) { border-radius: 999px; } - -.designing-extract-arrow { - color: var(--color-accent); - font-size: 16px; -} - -.designing-extract-after { - padding: 10px; - background: var(--color-ink); - color: var(--color-paper); - font-family: var(--font-body); - font-size: 11px; - font-weight: 500; - letter-spacing: 0.06em; - text-transform: uppercase; - border-radius: 4px; - text-align: center; - min-height: 42px; - display: flex; - align-items: center; + grid-template-columns: repeat(2, auto); + gap: 6px; justify-content: center; } -/* DESIGN.md inline preview */ -.designing-designmd-preview { - padding: 10px 14px; - background: var(--color-cream); - border-radius: 6px; - font-family: var(--font-mono); +.designing-extract-btn { + display: inline-block; + padding: 5px 12px; + background: var(--color-paper); + border: 1px solid var(--color-mist); + font-family: var(--font-body); font-size: 0.75rem; - line-height: 1.85; - color: var(--color-ink); + color: var(--color-ash); + opacity: 0.75; +} + +.designing-extract-arrow { + font-family: var(--font-display); + font-style: italic; + font-size: 2.5rem; + line-height: 1; + color: var(--color-accent); +} + +.designing-extract-after { + display: inline-block; + padding: 10px 22px; + background: var(--color-ink); + color: var(--color-paper); + font-family: var(--font-body); + font-size: 1rem; + font-weight: 500; + letter-spacing: 0.04em; +} + +/* DESIGN.md index — enlarged list of numbered sections */ +.designing-designmd-preview { + display: flex; + flex-direction: column; + gap: 8px; + width: 100%; + max-width: 280px; } .designing-designmd-preview-line { - display: flex; - gap: 10px; - align-items: baseline; + display: grid; + grid-template-columns: 32px 1fr; + gap: 14px; + padding-bottom: 6px; + border-bottom: 1px solid var(--color-mist); + font-family: var(--font-body); + font-size: 0.9375rem; + color: var(--color-ink); } +.designing-designmd-preview-line:last-child { border-bottom: 0; } + .designing-designmd-preview-num { - color: var(--color-ash); - min-width: 18px; + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--color-accent); +} + +@media (max-width: 720px) { + .designing-maintain { + grid-template-columns: 1fr; + gap: var(--spacing-xl, 48px); + } + .designing-extract-viz { flex-wrap: wrap; } } /* ============================================ APPENDIX: Register (cross-link, quieter aside) ============================================ */ -.designing-register { - display: grid; - grid-template-columns: 1fr 1.6fr; - gap: clamp(1.5rem, 4vw, 2.5rem); - align-items: center; -} - -@media (max-width: 640px) { - .designing-register { - grid-template-columns: 1fr; - } -} - -.designing-register-preview { +/* Two-lane explainer — brand vs product as twin columns divided by a + hairline, each with its own mock to make the vocabulary visible. */ +.designing-lanes { display: grid; grid-template-columns: 1fr 1fr; - gap: 8px; + gap: 0; + margin-bottom: var(--spacing-lg, 32px); } -.designing-register-mini { - padding: 14px 12px; - border-radius: 6px; +.designing-lane { + padding: 0 clamp(18px, 3vw, 32px); display: flex; flex-direction: column; - gap: 4px; - min-height: 88px; - justify-content: center; + gap: 14px; + border-left: 1px solid var(--color-mist); } -.designing-register-mini--brand { +.designing-lane:first-child { + padding-left: 0; + border-left: 0; +} + +.designing-lane-kind { + font-family: var(--font-mono); + font-size: 0.6875rem; + font-weight: 600; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--color-accent); +} + +.designing-lane-rule { + margin: 0; + font-family: var(--font-body); + font-size: 0.9375rem; + line-height: 1.55; + color: var(--color-charcoal); + max-width: 38ch; +} + +.designing-lane-mock { + padding: 28px 20px; + display: flex; + flex-direction: column; + gap: 6px; + justify-content: center; + min-height: 116px; + border: 1px solid var(--color-mist); +} + +.designing-lane-mock--brand { background: oklch(96% 0.02 30); } -.designing-register-mini--brand .designing-register-mini-label { +.designing-lane-mock--brand .designing-lane-mock-label { font-family: var(--font-mono); - font-size: 8px; + font-size: 9px; letter-spacing: 0.18em; text-transform: uppercase; color: oklch(40% 0.12 30); } -.designing-register-mini--brand .designing-register-mini-title { +.designing-lane-mock--brand .designing-lane-mock-title { font-family: var(--font-display); font-style: italic; - font-size: 14px; + font-size: 22px; color: oklch(20% 0.1 30); line-height: 1.1; } -.designing-register-mini--product { +.designing-lane-mock--product { background: var(--color-cream); } -.designing-register-mini--product .designing-register-mini-label { +.designing-lane-mock--product .designing-lane-mock-label { font-family: var(--font-body); - font-size: 9px; + font-size: 10px; font-weight: 600; color: var(--color-ash); + letter-spacing: 0.04em; } -.designing-register-mini--product .designing-register-mini-title { +.designing-lane-mock--product .designing-lane-mock-title { font-family: var(--font-body); font-weight: 600; - font-size: 13px; + font-size: 15px; color: var(--color-ink); - line-height: 1.2; + line-height: 1.25; } -.designing-register-link { +.designing-lane-link { font-family: var(--font-body); font-size: 0.875rem; font-weight: 600; @@ -2673,93 +2792,26 @@ text-underline-offset: 3px; text-decoration-thickness: 1px; display: inline-block; - margin-top: var(--spacing-md, 24px); - margin-bottom: var(--spacing-sm, 16px); } -.designing-register-link:hover { +.designing-lane-link:hover { text-decoration-thickness: 2px; } -/* ============================================ - APPENDIX: Interop (minimal inline diagram) - ============================================ */ - -.designing-interop { - display: grid; - grid-template-columns: 1fr auto 1fr; - gap: 16px 24px; - align-items: center; - justify-items: center; - font-family: var(--font-body); - font-size: 0.9375rem; - color: var(--color-ink); - padding: 32px 16px; - border: 1px solid var(--color-mist); - border-radius: 8px; - background: var(--color-cream); -} - @media (max-width: 640px) { - .designing-interop { + .designing-lanes { grid-template-columns: 1fr; - padding: 24px 16px; + gap: var(--spacing-md, 24px); + } + .designing-lane { + padding: var(--spacing-md, 24px) 0 0 0; + border-left: 0; + border-top: 1px solid var(--color-mist); + } + .designing-lane:first-child { + padding-top: 0; + border-top: 0; } -} - -.designing-interop-side { - display: flex; - flex-direction: column; - gap: 6px; - align-items: center; - text-align: center; -} - -.designing-interop-side-label { - font-family: var(--font-mono); - font-size: 0.625rem; - letter-spacing: 0.16em; - text-transform: uppercase; - color: var(--color-ash); -} - -.designing-interop-side-list { - display: flex; - flex-direction: column; - gap: 4px; - font-family: var(--font-body); - font-size: 0.9375rem; - color: var(--color-ink); -} - -.designing-interop-node { - padding: 8px 16px; - background: var(--color-paper); - border: 1px solid var(--color-mist); - border-radius: 6px; - white-space: nowrap; -} - -.designing-interop-node--center { - background: var(--color-ink); - color: var(--color-paper); - border-color: transparent; - font-family: var(--font-mono); - font-size: 0.875rem; - padding: 12px 20px; -} - -.designing-interop-arrow { - display: flex; - align-items: center; - justify-content: center; - color: var(--color-accent); - font-size: 18px; - line-height: 1; -} - -@media (max-width: 640px) { - .designing-interop-arrow { transform: rotate(90deg); } } /* ============================================ diff --git a/public/designing/index.html b/public/designing/index.html index 5194e18c2..3c0a39ecb 100644 --- a/public/designing/index.html +++ b/public/designing/index.html @@ -275,20 +275,28 @@
-
- /impeccable audit -

Score it.

-

Five dimensions scored 0 to 4: accessibility, performance, theming, responsive, anti-patterns. Findings tagged P0 to P3.

+
+ Pre-ship +
+ audit + clarify + harden +
+ 03 · 04
-
- /impeccable clarify -

Rewrite the copy.

-

Labels, error messages, empty-state prose, microcopy. Tuned to the audience from PRODUCT.md.

-
-
- /impeccable harden -

Stress-test reality.

-

60-character names, German product titles, prices in the billions, 500s, offline. Production data is messy.

+
+
+

Score it.

+

Five dimensions scored 0 to 4: accessibility, performance, theming, responsive, anti-patterns. Findings tagged P0 to P3.

+
+
+

Rewrite the copy.

+

Labels, error messages, empty-state prose, microcopy. Tuned to the audience from PRODUCT.md.

+
+
+

Stress-test reality.

+

60-character names, German product titles, prices in the billions, 500s, offline. Production data is messy.

+
@@ -303,90 +311,76 @@
-
- /impeccable extract -

Consolidate drift.

-

Find patterns used three or more times with the same intent. Propose tokens and primitives. Migrate call sites in the same pass.

- -
+
- Before any of this -

Pick a register.

-

Brand and product surfaces have different defaults. Impeccable tracks this in PRODUCT.md as a single field, so commands like typeset, animate, and colorize adapt their vocabulary to match.

+ Two lanes +

Brand, or product.

+

Two defaults with different vocabularies. Impeccable picks the lane from your task cue and PRODUCT.md before every command, so typeset, animate, colorize, and friends adjust their output to match. You rarely need to set it by hand.

-
- -
- -
-
- Interop -

Your system travels.

-

DESIGN.md follows the format Google Stitch publishes. Not a lock-in. When you outgrow Impeccable or want a second opinion from another tool, the file comes with you.

-
- -
-
+ Read the brand-vs-product tutorial →
diff --git a/public/index.html b/public/index.html index ddd827708..2bbc4b709 100644 --- a/public/index.html +++ b/public/index.html @@ -554,7 +554,7 @@
04 -

Live Mode BETA

+

Live Mode ALPHA

Pick any element in the browser. Drop a comment or a stroke. Hit Go. Three production-quality variants swap in via your framework's HMR. Accept the one you want and it writes back to source.

diff --git a/public/js/components/framework-viz.js b/public/js/components/framework-viz.js index 1caf03d55..bde86bac2 100644 --- a/public/js/components/framework-viz.js +++ b/public/js/components/framework-viz.js @@ -4,7 +4,7 @@ * Hover tooltips show description and relationships inline. */ -import { commandCategories, commandRelationships, betaCommands } from '../data.js'; +import { commandCategories, commandRelationships, alphaCommands } from '../data.js'; const categoryColors = { create: { bg: 'var(--cat-create-bg)', border: 'var(--cat-create-border)', text: 'var(--cat-create-text)' }, @@ -298,8 +298,8 @@ export class PeriodicTable { } el.appendChild(name); - // Beta badge - if (betaCommands.includes(cmd)) { + // Alpha badge + if (alphaCommands.includes(cmd)) { const badge = document.createElement('div'); badge.style.cssText = ` position: absolute; @@ -312,7 +312,7 @@ export class PeriodicTable { opacity: 0.45; text-transform: uppercase; `; - badge.textContent = 'β'; + badge.textContent = 'α'; el.appendChild(badge); } diff --git a/public/js/components/glass-terminal.js b/public/js/components/glass-terminal.js index cd1673482..71f79f357 100644 --- a/public/js/components/glass-terminal.js +++ b/public/js/components/glass-terminal.js @@ -1,6 +1,6 @@ import { renderCommandDemo, initCommandDemo } from "../demo-renderer.js"; import { initSplitCompare } from "../effects/split-compare.js"; -import { commandProcessSteps, commandCategories, commandRelationships, betaCommands } from "../data.js"; +import { commandProcessSteps, commandCategories, commandRelationships, alphaCommands } from "../data.js"; // Track current split instance and command for cleanup let currentSplitInstance = null; @@ -134,14 +134,14 @@ function renderDesktopLayout(container, commands) { const fisheyeHTML = filteredCommands.map((cmd, i) => { const cat = commandCategories[cmd.id] || 'other'; - const isBeta = betaCommands.includes(cmd.id); + const isAlpha = alphaCommands.includes(cmd.id); // The root skill is shown as "/impeccable", everything else is a sub-command // displayed without a slash (invocation is /impeccable ) const isRoot = cmd.id === 'impeccable'; const label = isRoot ? `/impeccable` : cmd.id; - return ``; + return ``; }).join(''); container.innerHTML = ` @@ -166,7 +166,7 @@ function renderDesktopLayout(container, commands) { function renderSpread(cmd, index, isActive) { const cat = commandCategories[cmd.id] || 'other'; - const isBeta = betaCommands.includes(cmd.id); + const isAlpha = alphaCommands.includes(cmd.id); const relationship = commandRelationships[cmd.id]; // Build relationship flow let flowHTML = ''; @@ -213,7 +213,7 @@ function renderSpread(cmd, index, isActive) {
${categoryLabels[cat] || cat} -

${nameHTML}${isBeta ? 'BETA' : ''}

+

${nameHTML}${isAlpha ? 'ALPHA' : ''}

${cmd.tagline || cmd.description}

${flowHTML}
diff --git a/public/js/data.js b/public/js/data.js index 25e61a855..16a0ab53f 100644 --- a/public/js/data.js +++ b/public/js/data.js @@ -12,8 +12,8 @@ export const readyCommands = [ 'layout' // First command to be fully completed ]; -// Commands marked as beta — shown with a badge in the UI -export const betaCommands = [ +// Commands marked as alpha — shown with a badge in the UI +export const alphaCommands = [ 'live' ]; diff --git a/public/live-mode/index.html b/public/live-mode/index.html index 2668afe19..1a76f9ded 100644 --- a/public/live-mode/index.html +++ b/public/live-mode/index.html @@ -46,9 +46,10 @@
-

New in v3.0 Beta

+

New in v3.0 Alpha

Live Mode

Pick any element in the browser. Drop a comment or a stroke. Three production-quality variants swap in via your framework's HMR. Accept the one you want and it writes back to source.

+

Why alpha: Live Mode works end-to-end and is ready to try, but it still needs more testing against real-world repos and framework configs. Expect rough edges on uncommon setups, and please report what breaks.

$ /impeccable live diff --git a/scripts/build-sub-pages.js b/scripts/build-sub-pages.js index d714512d3..96d1b914e 100644 --- a/scripts/build-sub-pages.js +++ b/scripts/build-sub-pages.js @@ -263,7 +263,7 @@ function renderSkillsOverviewMain(skillsByCategory, allSkills) { const tagline = skill.editorial?.frontmatter?.tagline || skill.description; const shortTagline = tagline.length > 140 ? tagline.slice(0, 137) + '...' : tagline; const rel = COMMAND_RELATIONSHIPS[skill.id] || {}; - const isBeta = skill.id === 'live'; + const isAlpha = skill.id === 'live'; let metaHtml = ''; if (rel.pairs) { @@ -281,7 +281,7 @@ function renderSkillsOverviewMain(skillsByCategory, allSkills) { return `
- /impeccable ${escapeHtml(skill.id)}${isBeta ? ' BETA' : ''} + /impeccable ${escapeHtml(skill.id)}${isAlpha ? ' ALPHA' : ''}

${escapeHtml(shortTagline)}

@@ -805,9 +805,10 @@ function renderLiveModeMain() { return `
-

New in v3.0 Beta

+

New in v3.0 Alpha

Live Mode

Pick any element in the browser. Drop a comment or a stroke. Three production-quality variants swap in via your framework's HMR. Accept the one you want and it writes back to source.

+

Why alpha: Live Mode works end-to-end and is ready to try, but it still needs more testing against real-world repos and framework configs. Expect rough edges on uncommon setups, and please report what breaks.

$ /impeccable live @@ -1143,20 +1144,28 @@ function renderDesigningMain() {
-
- /impeccable audit -

Score it.

-

Five dimensions scored 0 to 4: accessibility, performance, theming, responsive, anti-patterns. Findings tagged P0 to P3.

+
+ Pre-ship +
+ audit + clarify + harden +
+ 03 · 04
-
- /impeccable clarify -

Rewrite the copy.

-

Labels, error messages, empty-state prose, microcopy. Tuned to the audience from PRODUCT.md.

-
-
- /impeccable harden -

Stress-test reality.

-

60-character names, German product titles, prices in the billions, 500s, offline. Production data is messy.

+
+
+

Score it.

+

Five dimensions scored 0 to 4: accessibility, performance, theming, responsive, anti-patterns. Findings tagged P0 to P3.

+
+
+

Rewrite the copy.

+

Labels, error messages, empty-state prose, microcopy. Tuned to the audience from PRODUCT.md.

+
+
+

Stress-test reality.

+

60-character names, German product titles, prices in the billions, 500s, offline. Production data is messy.

+
@@ -1171,90 +1180,76 @@ function renderDesigningMain() {
-
- /impeccable extract -

Consolidate drift.

-

Find patterns used three or more times with the same intent. Propose tokens and primitives. Migrate call sites in the same pass.

-
-
+
- Before any of this -

Pick a register.

-

Brand and product surfaces have different defaults. Impeccable tracks this in PRODUCT.md as a single field, so commands like typeset, animate, and colorize adapt their vocabulary to match.

+ Two lanes +

Brand, or product.

+

Two defaults with different vocabularies. Impeccable picks the lane from your task cue and PRODUCT.md before every command, so typeset, animate, colorize, and friends adjust their output to match. You rarely need to set it by hand.

-
- -
- -
-
- Interop -

Your system travels.

-

DESIGN.md follows the format Google Stitch publishes. Not a lock-in. When you outgrow Impeccable or want a second opinion from another tool, the file comes with you.

-
- -
-
+ Read the brand-vs-product tutorial →
diff --git a/source/skills/impeccable/SKILL.md b/source/skills/impeccable/SKILL.md index 7d11094c6..3e30929bd 100644 --- a/source/skills/impeccable/SKILL.md +++ b/source/skills/impeccable/SKILL.md @@ -10,22 +10,6 @@ license: Apache 2.0. Based on Anthropic's frontend-design skill. See NOTICE.md f Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. - -BEFORE doing any design work, run this one-time maintenance step. Tell the user: - -> **Impeccable 3.0 consolidation.** All standalone commands ({{command_prefix}}audit, {{command_prefix}}polish, {{command_prefix}}critique, etc.) are now accessed through {{command_prefix}}impeccable (e.g., `{{command_prefix}}impeccable audit`). I'll clean up the old standalone skill files. Use `{{command_prefix}}impeccable pin ` to restore shortcuts for commands you use often. - -Then run: - -```bash -node {{scripts_path}}/cleanup-deprecated.mjs -``` - -If the script removed files, briefly confirm what was cleaned up. If it found nothing, skip any output and move on. - -After running the script, delete this entire section (from `` through `` inclusive) from THIS file so it does not run again until the next update. Save the file. - - ## Setup (non-optional) Two steps before any design work. Both are required. Skipping either produces generic output that ignores the project. diff --git a/source/skills/impeccable/scripts/live-browser.js b/source/skills/impeccable/scripts/live-browser.js index 8b1839211..65e779628 100644 --- a/source/skills/impeccable/scripts/live-browser.js +++ b/source/skills/impeccable/scripts/live-browser.js @@ -2818,14 +2818,18 @@ void main() { // Static-server / no-HMR fallback: if the wrapper is still around 2s after // the cleanup above, swap it out manually. By now React has either moved - // on or the app isn't React at all. + // on or the app isn't React at all. Preserve the `data-impeccable-variant="N"` + // div (with display:contents) so @scope rules anchored to the variant + // attribute keep matching until reload replaces it with the carbonize block. setTimeout(function() { const wrapper = document.querySelector('[data-impeccable-variants="' + acceptedSessionId + '"]'); if (!wrapper) return; const accepted = wrapper.querySelector('[data-impeccable-variant="' + acceptedVariant + '"]'); if (accepted && accepted.firstElementChild) { const parent = wrapper.parentElement; - if (parent) parent.replaceChild(accepted.firstElementChild.cloneNode(true), wrapper); + if (!parent) return; + accepted.style.display = 'contents'; + parent.replaceChild(accepted, wrapper); } }, 2000); }