mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-17 16:46:31 +03:00
The public repo keeps the OSS promise surface: skill, CLI, extension, tests, and the provider build. The site, labs, concept/composition catalogs, image pipeline, Cloudflare functions, and authoring guide move to pbakaus/impeccable-site. concept-seed tests run against a synthetic fixture catalog; the plugin icon and skill categories moved in-repo; build validation narrows to README prose and non-site counts; release notes read from a sibling impeccable-site checkout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
470 lines
28 KiB
HTML
470 lines
28 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>/impeccable shape | Impeccable</title>
|
||
<meta name="description" content="Think before you build. Produce a design brief through discovery, not guesswork.">
|
||
<meta name="theme-color" content="#fafafa">
|
||
<link rel="canonical" href="https://impeccable.style/docs/shape">
|
||
<link rel="icon" type="image/svg+xml" href="../favicon.svg">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,600;1,400&family=Instrument+Sans:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="../css/sub-pages.css">
|
||
|
||
</head>
|
||
<body class="sub-page skills-layout-page">
|
||
<a href="#main" class="skip-link">Skip to content</a>
|
||
<!-- site-header v1 -->
|
||
<header class="site-header" data-site-header>
|
||
<a href="/" class="site-header-brand" aria-label="Impeccable home">
|
||
<svg class="site-header-brand-logo" viewBox="0 0 32 32" aria-hidden="true"><rect width="32" height="32" rx="6" fill="#1a1a1a"/><text x="16" y="24" font-family="system-ui, -apple-system, sans-serif" font-size="22" font-weight="500" fill="#f5f3ef" text-anchor="middle">/</text></svg>
|
||
<span class="site-header-brand-name">Impeccable</span>
|
||
</a>
|
||
<div class="site-header-right">
|
||
<nav class="site-header-nav" aria-label="Primary">
|
||
<a href="/" data-nav="home">Home</a>
|
||
<a href="/designing" data-nav="designing">Designing</a>
|
||
<a href="/docs" data-nav="docs" aria-current="page">Docs</a>
|
||
<a href="/slop" data-nav="slop">Slop</a>
|
||
<a href="/live-mode" data-nav="live">Live</a>
|
||
</nav>
|
||
<a href="https://github.com/pbakaus/impeccable" class="site-header-github" target="_blank" rel="noopener" aria-label="Impeccable on GitHub, 21k stars">
|
||
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
|
||
<span class="site-header-github-label">21k</span>
|
||
<svg class="site-header-github-star" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2l2.76 6.36L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.24-.91L12 2z"/></svg>
|
||
</a>
|
||
</div>
|
||
</header>
|
||
<main id="main">
|
||
|
||
<div class="skills-layout">
|
||
|
||
<aside class="skills-sidebar" aria-label="Documentation">
|
||
<button class="skills-sidebar-toggle" type="button" aria-expanded="false" aria-controls="skills-sidebar-inner">
|
||
<span class="skills-sidebar-toggle-label">/shape</span>
|
||
<svg class="skills-sidebar-toggle-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
|
||
</button>
|
||
<div class="skills-sidebar-inner" id="skills-sidebar-inner">
|
||
<p class="skills-sidebar-label">Docs</p>
|
||
|
||
<div class="skills-sidebar-group" data-category="tutorials">
|
||
<p class="skills-sidebar-group-title">Tutorials</p>
|
||
<ul class="skills-sidebar-list">
|
||
<li><a href="/tutorials/getting-started">Getting started</a></li>
|
||
<li><a href="/tutorials/iterate-live">Iterate on UI with Live Mode</a></li>
|
||
<li><a href="/tutorials/brand-vs-product">Brand vs product, pick a register</a></li>
|
||
<li><a href="/tutorials/critique-with-overlay">Critique with the visual overlay</a></li>
|
||
</ul>
|
||
</div>
|
||
<hr class="skills-sidebar-divider">
|
||
|
||
<div class="skills-sidebar-group" data-category="create">
|
||
<p class="skills-sidebar-group-title">Create</p>
|
||
<ul class="skills-sidebar-list">
|
||
<li><a href="/docs/impeccable">/impeccable</a></li>
|
||
<li><a href="/docs/craft">craft</a></li>
|
||
<li><a href="/docs/shape" aria-current="page">shape</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="skills-sidebar-group" data-category="evaluate">
|
||
<p class="skills-sidebar-group-title">Evaluate</p>
|
||
<ul class="skills-sidebar-list">
|
||
<li><a href="/docs/audit">audit</a></li>
|
||
<li><a href="/docs/critique">critique</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="skills-sidebar-group" data-category="refine">
|
||
<p class="skills-sidebar-group-title">Refine</p>
|
||
<ul class="skills-sidebar-list">
|
||
<li><a href="/docs/animate">animate</a></li>
|
||
<li><a href="/docs/bolder">bolder</a></li>
|
||
<li><a href="/docs/colorize">colorize</a></li>
|
||
<li><a href="/docs/delight">delight</a></li>
|
||
<li><a href="/docs/layout">layout</a></li>
|
||
<li><a href="/docs/overdrive">overdrive</a></li>
|
||
<li><a href="/docs/quieter">quieter</a></li>
|
||
<li><a href="/docs/typeset">typeset</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="skills-sidebar-group" data-category="simplify">
|
||
<p class="skills-sidebar-group-title">Simplify</p>
|
||
<ul class="skills-sidebar-list">
|
||
<li><a href="/docs/adapt">adapt</a></li>
|
||
<li><a href="/docs/clarify">clarify</a></li>
|
||
<li><a href="/docs/distill">distill</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="skills-sidebar-group" data-category="harden">
|
||
<p class="skills-sidebar-group-title">Harden</p>
|
||
<ul class="skills-sidebar-list">
|
||
<li><a href="/docs/harden">harden</a></li>
|
||
<li><a href="/docs/onboard">onboard</a></li>
|
||
<li><a href="/docs/optimize">optimize</a></li>
|
||
<li><a href="/docs/polish">polish</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="skills-sidebar-group" data-category="system">
|
||
<p class="skills-sidebar-group-title">System</p>
|
||
<ul class="skills-sidebar-list">
|
||
<li><a href="/docs/document">document</a></li>
|
||
<li><a href="/docs/extract">extract</a></li>
|
||
<li><a href="/docs/live">live</a></li>
|
||
<li><a href="/docs/teach">teach</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
</div>
|
||
</aside>
|
||
<div class="skills-main">
|
||
|
||
<article class="skill-detail">
|
||
<div class="skill-detail-hero">
|
||
<header class="skill-detail-header">
|
||
<p class="skill-detail-eyebrow"><a href="/docs">Docs</a> / Create</p>
|
||
<h1 class="skill-detail-title"><span class="skill-detail-title-namespace"><span class="skill-detail-title-slash">/</span>impeccable</span>shape</h1>
|
||
<p class="skill-detail-tagline">Think before you build. Produce a design brief through discovery, not guesswork.</p>
|
||
|
||
<div class="skill-meta-strip">
|
||
<span class="skill-meta-chip skill-meta-category" data-category="create">Create</span>
|
||
<span class="skill-meta-chip">User-invocable</span>
|
||
<span class="skill-meta-chip skill-meta-args">[feature to shape]</span>
|
||
</div>
|
||
</header>
|
||
|
||
</div>
|
||
|
||
<section class="skill-detail-editorial prose">
|
||
<div class="docs-viz-hero">
|
||
<div class="docs-viz-file">
|
||
<div class="docs-viz-file-header">
|
||
<span class="docs-viz-file-name">brief.md</span>
|
||
<span class="docs-viz-file-status">Output of /impeccable shape</span>
|
||
</div>
|
||
<div class="docs-viz-file-body">
|
||
<div class="docs-viz-file-row">
|
||
<span class="docs-viz-file-k">Purpose</span>
|
||
<span class="docs-viz-file-v">Let committed subscribers change what they get without losing them to unsubscribe.</span>
|
||
</div>
|
||
<div class="docs-viz-file-row">
|
||
<span class="docs-viz-file-k">User</span>
|
||
<span class="docs-viz-file-v">Rushed, on mobile, mid-meeting. Reading fast, low patience.</span>
|
||
</div>
|
||
<div class="docs-viz-file-row">
|
||
<span class="docs-viz-file-k">Content</span>
|
||
<span class="docs-viz-file-v">4 digest types, 2 cadences, one opt-out-all at the bottom.</span>
|
||
</div>
|
||
<div class="docs-viz-file-row">
|
||
<span class="docs-viz-file-k">Feeling</span>
|
||
<span class="docs-viz-file-v">Calm, trustworthy, no dark patterns.</span>
|
||
</div>
|
||
<div class="docs-viz-file-row">
|
||
<span class="docs-viz-file-k">Constraints</span>
|
||
<span class="docs-viz-file-v">Mobile-first. WCAG AA contrast. One column, no modals.</span>
|
||
</div>
|
||
</div>
|
||
<div class="docs-viz-file-footer">Hand it to <code>/impeccable</code>, <code>/impeccable craft</code>, or any implementation flow.</div>
|
||
</div>
|
||
<p class="docs-viz-caption">A shape brief is a compass, not a spec. It captures intent, not UI. Implementation skills read it before writing a line of code.</p>
|
||
</div>
|
||
|
||
<h2 id="when-to-use-it">When to use it</h2>
|
||
<p><code>/impeccable shape</code> is where a feature starts. Before anyone writes code, before anyone argues about the hero treatment, before anyone picks a font. Use it to force a discovery conversation about purpose, users, content, and constraints, then capture the answers as a design brief the implementation skills can lean on.</p>
|
||
<p>Reach for it whenever a feature is about to start, a ticket is vague, or you catch yourself writing JSX to figure out what the product should be.</p>
|
||
<h2 id="how-it-works">How it works</h2>
|
||
<p>Most AI-generated UIs fail not because of bad code, but because of skipped thinking. The model jumps to "here is a card grid" without asking "what is the user trying to accomplish". <code>/impeccable shape</code> inverts that order.</p>
|
||
<p>The skill runs a structured discovery interview in conversation. It will not write code during this phase. The questions cover:</p>
|
||
<ul>
|
||
<li><strong>Purpose and context</strong>: what the feature is for, who uses it, what state of mind they are in</li>
|
||
<li><strong>Content and data</strong>: what is displayed, realistic ranges, edge cases, what is dynamic</li>
|
||
<li><strong>Design goals</strong>: the single most important thing, the intended feeling, reference examples</li>
|
||
<li><strong>Constraints</strong>: technical, content, accessibility, localization</li>
|
||
</ul>
|
||
<p>You answer naturally. The skill asks follow-ups, not a form. At the end it produces a design brief: a structured artifact you can hand to <code>/impeccable</code> or any other implementation skill.</p>
|
||
<p>Note: if you want the full flow (discovery interview, then straight into building), use <code>/impeccable craft</code> instead. It runs <code>/impeccable shape</code> internally, then continues into implementation with visual iteration. <code>/impeccable shape</code> standalone is for when you want just the brief, so you can take it to whatever implementation approach you prefer.</p>
|
||
<h2 id="try-it">Try it</h2>
|
||
<div class="code-block-wrap"><pre class="code-block"><code>/impeccable shape a daily digest email preferences page</code></pre><button class="code-block-copy" type="button" data-copy="/impeccable shape a daily digest email preferences page" aria-label="Copy to clipboard"></button></div>
|
||
<p>Expect a 5 to 10 question conversation. The skill asks things like "who is the person opening this, and are they already committed or still curious" and "what happens when the user has unsubscribed from everything, do we hide the feature or show something". You answer, and a brief materializes.</p>
|
||
<p>From there you can hand the brief to <code>/impeccable</code>, <code>/impeccable polish</code>, or any other skill. Or just use it as a reference while you build by hand.</p>
|
||
<h2 id="pitfalls">Pitfalls</h2>
|
||
<ul>
|
||
<li><strong>Skipping it because it feels slow.</strong> The interview is maybe 5 minutes. The rewrites you avoid are measured in hours.</li>
|
||
<li><strong>Treating the brief as a spec.</strong> It is a compass, not a checklist. It captures intent, not UI.</li>
|
||
<li><strong>Answering with "standard" or "normal".</strong> Specificity is the whole point. If a user is "rushed, on mobile, between meetings", say so. That changes everything downstream.</li>
|
||
</ul>
|
||
|
||
</section>
|
||
|
||
|
||
|
||
<section class="skill-source-card">
|
||
<header class="skill-source-card-header">
|
||
<span class="skill-source-card-label">reference/shape.md</span>
|
||
<span class="skill-source-card-subtitle">Loaded when the impeccable skill routes to this command.</span>
|
||
</header>
|
||
<div class="skill-source-card-body prose">
|
||
<p>Shape the UX and UI for a feature before any code is written. This command produces a <strong>design brief</strong>: a structured artifact that guides implementation through discovery, not guesswork.</p>
|
||
<p><strong>Scope</strong>: Design planning only. This command does NOT write code. It produces the thinking that makes code good.</p>
|
||
<p><strong>Output</strong>: A design brief that can be handed off to /impeccable craft, or directly to /impeccable for freeform implementation. When visual direction probes are used, the images are supporting artifacts, not the primary output.</p>
|
||
<h2 id="philosophy">Philosophy</h2>
|
||
<p>Most AI-generated UIs fail not because of bad code, but because of skipped thinking. They jump to "here's a card grid" without asking "what is the user trying to accomplish?" This command inverts that: understand deeply first, so implementation is precise.</p>
|
||
<h2 id="phase-1-discovery-interview">Phase 1: Discovery Interview</h2>
|
||
<p><strong>Do NOT write any code or make any design decisions during this phase.</strong> Your only job is to understand the feature deeply enough to make excellent design decisions later.</p>
|
||
<p>This is a required interaction, not optional guidance. Ask these questions in conversation, adapting based on answers. Don't dump them all at once; have a natural dialogue. STOP and call the AskUserQuestion tool to clarify.</p>
|
||
<h3 id="interview-cadence">Interview cadence</h3>
|
||
<p>Discovery must include at least one user-answer round unless PRODUCT.md, DESIGN.md, or an already-confirmed brief directly answers the needed design inputs. With a sparse prompt, do <strong>not</strong> synthesize a complete brief for confirmation on the first response.</p>
|
||
<ul>
|
||
<li>Use the harness's structured question tool when one exists. Otherwise, ask directly in chat and stop.</li>
|
||
<li>Ask <strong>2-3 questions per round</strong>, then wait for answers.</li>
|
||
<li>Treat PRODUCT.md and DESIGN.md as anchors; they reduce repeated questions but do <strong>not</strong> replace shape for craft. Shape is task-specific.</li>
|
||
<li>Round 1 should clarify purpose, audience/context, and success or emotional outcome.</li>
|
||
<li>Round 2 should clarify content/data/states and scope/fidelity.</li>
|
||
<li>Round 3 should clarify visual direction, constraints, and anti-goals when still unresolved.</li>
|
||
</ul>
|
||
<h3 id="purpose-context">Purpose & Context</h3>
|
||
<ul>
|
||
<li>What is this feature for? What problem does it solve?</li>
|
||
<li>Who specifically will use it? (Not "users"; be specific: role, context, frequency)</li>
|
||
<li>What does success look like? How will you know this feature is working?</li>
|
||
<li>What's the user's state of mind when they reach this feature? (Rushed? Exploring? Anxious? Focused?)</li>
|
||
</ul>
|
||
<h3 id="content-data">Content & Data</h3>
|
||
<ul>
|
||
<li>What content or data does this feature display or collect?</li>
|
||
<li>What are the realistic ranges? (Minimum, typical, maximum, e.g., 0 items, 5 items, 500 items)</li>
|
||
<li>What are the edge cases? (Empty state, error state, first-time use, power user)</li>
|
||
<li>Is any content dynamic? What changes and how often?</li>
|
||
</ul>
|
||
<h3 id="design-direction">Design Direction</h3>
|
||
<p>Force a visual decision on three fronts. Skip anything PRODUCT.md or DESIGN.md already answers; ask only what's missing.</p>
|
||
<ul>
|
||
<li><strong>Color strategy for this surface.</strong> Pick one: Restrained / Committed / Full palette / Drenched. Can override the project default if the surface earns it (e.g. a drenched hero inside an otherwise Restrained product).</li>
|
||
<li><strong>Theme via scene sentence.</strong> Write one sentence of physical context for this surface — who uses it, where, under what ambient light, in what mood. The sentence forces dark vs light. If it doesn't, add detail until it does.</li>
|
||
<li><strong>Two or three named anchor references.</strong> Specific products, brands, objects — not adjectives like "modern" or "clean."</li>
|
||
</ul>
|
||
<h3 id="scope">Scope</h3>
|
||
<p>Always ask. Sketch quality and shipped quality are different outputs; don't guess between them.</p>
|
||
<ul>
|
||
<li><strong>Fidelity.</strong> Sketch / mid-fi / high-fi / production-ready?</li>
|
||
<li><strong>Breadth.</strong> One screen / a flow / a whole surface?</li>
|
||
<li><strong>Interactivity.</strong> Static visual / interactive prototype / shipped-quality component?</li>
|
||
<li><strong>Time intent.</strong> Quick exploration, or polish until it ships?</li>
|
||
</ul>
|
||
<p>Scope answers are task-scoped. Don't write them to PRODUCT.md or DESIGN.md — carry them through the design brief only.</p>
|
||
<h3 id="constraints">Constraints</h3>
|
||
<ul>
|
||
<li>Are there technical constraints? (Framework, performance budget, browser support)</li>
|
||
<li>Are there content constraints? (Localization, dynamic text length, user-generated content)</li>
|
||
<li>Mobile/responsive requirements?</li>
|
||
<li>Accessibility requirements beyond WCAG AA?</li>
|
||
</ul>
|
||
<h3 id="anti-goals">Anti-Goals</h3>
|
||
<ul>
|
||
<li>What should this NOT be? What would be a wrong direction?</li>
|
||
<li>What's the biggest risk of getting this wrong?</li>
|
||
</ul>
|
||
<h2 id="phase-15-visual-direction-probe-capability-gated">Phase 1.5: Visual Direction Probe (Capability-Gated)</h2>
|
||
<p>After the discovery interview, generate a small set of visual direction probes <strong>before</strong> writing the final brief when all of these are true:</p>
|
||
<ul>
|
||
<li>The work is <strong>net-new</strong> or directionally ambiguous enough that visual exploration will clarify the brief.</li>
|
||
<li>The requested fidelity is <strong>mid-fi, high-fi, or production-ready</strong>. Skip for sketch-only planning.</li>
|
||
<li>The current harness has <strong>built-in image generation capability</strong> (for example, Codex with a native image tool). Do <strong>not</strong> ask the user to set up external APIs, shell scripts, or one-off tooling just to do this.</li>
|
||
</ul>
|
||
<p>When those conditions are met, this step is mandatory for Codex and any harness with built-in image generation. Use native image generation; in Codex, use the built-in <code>image_gen</code> tool via the imagegen skill. If image generation is unavailable, do not ask the user to install APIs or tooling. State in one line that the image step is skipped because the harness lacks native image generation, then proceed.</p>
|
||
<p>Use probes to explore visual lanes, not to replace the brief.</p>
|
||
<p>Do not skip probes because the final UI will be semantic, editable, code-native, responsive, or accessible. Those are implementation requirements, not reasons to avoid visual exploration.</p>
|
||
<h3 id="what-to-generate">What to generate</h3>
|
||
<p>Generate <strong>2 to 4</strong> distinct direction probes based on the discovery answers, especially:</p>
|
||
<ul>
|
||
<li>Color strategy</li>
|
||
<li>Theme scene sentence</li>
|
||
<li>Named anchor references</li>
|
||
<li>Scope and fidelity</li>
|
||
</ul>
|
||
<p>The probes should differ in primary visual direction (hierarchy, topology, density, typographic voice, or color strategy), not just palette tweaks.</p>
|
||
<h3 id="how-to-use-the-probes">How to use the probes</h3>
|
||
<ul>
|
||
<li>Treat them as <strong>direction tests</strong>, not final designs.</li>
|
||
<li>Use them to pressure-test whether the brief is pointing at the right lane.</li>
|
||
<li>Ask the user which direction feels closest, what feels off, and what should carry forward.</li>
|
||
<li>If the probes reveal a mismatch, revise the brief inputs before finalizing the brief.</li>
|
||
</ul>
|
||
<h3 id="important-limits">Important limits</h3>
|
||
<ul>
|
||
<li>Do <strong>not</strong> skip discovery because image generation is available.</li>
|
||
<li>Do <strong>not</strong> treat generated imagery as final UX specification, final copy, or final accessibility behavior.</li>
|
||
<li>Do <strong>not</strong> use this step for minor refinements of existing work. It's for shaping a new surface or clarifying a big directional choice.</li>
|
||
</ul>
|
||
<p>If image generation is unavailable, or the task doesn't benefit from it, skip this phase only with a one-line reason and proceed directly to the design brief.</p>
|
||
<h2 id="phase-2-design-brief">Phase 2: Design Brief</h2>
|
||
<p>After the interview and any required probes, synthesize everything into a structured design brief. Present it to the user for explicit confirmation before considering this command complete. Stop after asking for confirmation; do not proceed to craft or implementation in the same response unless the user has already approved the brief.</p>
|
||
<h3 id="brief-structure">Brief Structure</h3>
|
||
<p><strong>1. Feature Summary</strong> (2-3 sentences)
|
||
What this is, who it's for, what it needs to accomplish.</p>
|
||
<p><strong>2. Primary User Action</strong>
|
||
The single most important thing a user should do or understand here.</p>
|
||
<p><strong>3. Design Direction</strong>
|
||
Color strategy (Restrained / Committed / Full palette / Drenched) + the theme scene sentence + 2–3 named anchor references. Reference PRODUCT.md and DESIGN.md where they already answer, and note any per-surface overrides.</p>
|
||
<p>If you ran the Visual Direction Probe step, name which probe direction won and what changed in the brief because of it.</p>
|
||
<p><strong>4. Scope</strong>
|
||
Fidelity, breadth, interactivity, and time intent from the Scope section of the interview. Task-scoped — these don't persist beyond the brief.</p>
|
||
<p><strong>5. Layout Strategy</strong>
|
||
High-level spatial approach: what gets emphasis, what's secondary, how information flows. Describe the visual hierarchy and rhythm, not specific CSS.</p>
|
||
<p><strong>6. Key States</strong>
|
||
List every state the feature needs: default, empty, loading, error, success, edge cases. For each, note what the user needs to see and feel.</p>
|
||
<p><strong>7. Interaction Model</strong>
|
||
How users interact with this feature. What happens on click, hover, scroll? What feedback do they get? What's the flow from entry to completion?</p>
|
||
<p><strong>8. Content Requirements</strong>
|
||
What copy, labels, empty state messages, error messages, and microcopy are needed. Note any dynamic content and its realistic ranges.</p>
|
||
<p><strong>9. Recommended References</strong>
|
||
Based on the brief, list which impeccable reference files would be most valuable during implementation (e.g., spatial-design.md for complex layouts, motion-design.md for animated features, interaction-design.md for form-heavy features).</p>
|
||
<p><strong>10. Open Questions</strong>
|
||
Anything unresolved that the implementer should resolve during build.</p>
|
||
<hr>
|
||
<p>STOP and call the AskUserQuestion tool to clarify. Ask for explicit confirmation of the brief before finishing. If the user disagrees with any part, revisit the relevant discovery questions. A shape run is incomplete until the brief is confirmed.</p>
|
||
<p>Once confirmed, the brief is complete. The user can now hand it to /impeccable, or use it to guide any other implementation approach. (If the user wants the full discovery-then-build flow in one step, they should use /impeccable craft instead, which runs this command internally.)</p>
|
||
|
||
</div>
|
||
</section>
|
||
|
||
|
||
</article>
|
||
|
||
</div>
|
||
</div>
|
||
</main>
|
||
<script>
|
||
// Copy buttons on rendered code blocks
|
||
document.addEventListener('click', (e) => {
|
||
const btn = e.target.closest('[data-copy]');
|
||
if (!btn) return;
|
||
const text = btn.getAttribute('data-copy');
|
||
if (!text) return;
|
||
navigator.clipboard.writeText(text).then(() => {
|
||
btn.classList.add('is-copied');
|
||
setTimeout(() => btn.classList.remove('is-copied'), 1500);
|
||
}).catch(() => {});
|
||
});
|
||
|
||
// Mobile sidebar toggle (shown on narrow viewports, hidden on desktop).
|
||
document.addEventListener('click', (e) => {
|
||
const toggle = e.target.closest('.skills-sidebar-toggle');
|
||
if (!toggle) return;
|
||
const expanded = toggle.getAttribute('aria-expanded') === 'true';
|
||
toggle.setAttribute('aria-expanded', String(!expanded));
|
||
});
|
||
|
||
// Before/after split-compare: drag on touch, hover OR drag on mouse.
|
||
// Pointer events attach to the padded .split-comparison wrapper so
|
||
// there is a ~20px invisible buffer around the visible box. The
|
||
// divider only snaps back when the pointer leaves that outer buffer.
|
||
(function initSplitCompare() {
|
||
const wrappers = document.querySelectorAll('.split-comparison');
|
||
if (wrappers.length === 0) return;
|
||
const hasHover = matchMedia('(hover: hover)').matches;
|
||
const DEFAULT_POSITION = 50;
|
||
|
||
for (const wrapper of wrappers) {
|
||
const container = wrapper.querySelector('.split-container');
|
||
const splitAfter = wrapper.querySelector('.split-after');
|
||
const splitDivider = wrapper.querySelector('.split-divider');
|
||
if (!container || !splitAfter || !splitDivider) continue;
|
||
|
||
const tanAngle = Math.tan(10 * Math.PI / 180);
|
||
let skewOffset = 8;
|
||
const recalcSkew = () => {
|
||
const r = container.getBoundingClientRect();
|
||
if (r.width > 0 && r.height > 0) {
|
||
skewOffset = 50 * r.height * tanAngle / r.width;
|
||
}
|
||
};
|
||
recalcSkew();
|
||
window.addEventListener('resize', recalcSkew, { passive: true });
|
||
|
||
let targetX = DEFAULT_POSITION;
|
||
let currentX = DEFAULT_POSITION;
|
||
let rafId = null;
|
||
|
||
const paint = (pct) => {
|
||
const x = Math.max(-skewOffset, Math.min(100 + skewOffset, pct));
|
||
splitAfter.style.clipPath =
|
||
`polygon(${x + skewOffset}% 0%, 100% 0%, 100% 100%, ${x - skewOffset}% 100%)`;
|
||
splitDivider.style.left = `${x}%`;
|
||
};
|
||
|
||
const step = () => {
|
||
currentX += (targetX - currentX) * 0.2;
|
||
if (Math.abs(targetX - currentX) < 0.1) {
|
||
currentX = targetX;
|
||
rafId = null;
|
||
} else {
|
||
rafId = requestAnimationFrame(step);
|
||
}
|
||
paint(currentX);
|
||
};
|
||
|
||
const setTarget = (pct) => {
|
||
targetX = pct;
|
||
if (rafId === null) rafId = requestAnimationFrame(step);
|
||
};
|
||
|
||
paint(DEFAULT_POSITION);
|
||
|
||
// Percentage is always relative to the VISIBLE .split-container,
|
||
// not the padded .split-comparison wrapper. The pointer event
|
||
// target is the wrapper but the clip-path math uses the inner box.
|
||
const pctFromClientX = (clientX) => {
|
||
const rect = container.getBoundingClientRect();
|
||
return ((clientX - rect.left) / rect.width) * 100;
|
||
};
|
||
|
||
let hovering = false;
|
||
let dragging = false;
|
||
|
||
wrapper.addEventListener('pointerenter', (e) => {
|
||
if (hasHover && e.pointerType === 'mouse') {
|
||
hovering = true;
|
||
}
|
||
});
|
||
|
||
wrapper.addEventListener('pointerdown', (e) => {
|
||
dragging = true;
|
||
wrapper.setPointerCapture(e.pointerId);
|
||
setTarget(pctFromClientX(e.clientX));
|
||
});
|
||
|
||
wrapper.addEventListener('pointermove', (e) => {
|
||
if (dragging || hovering) {
|
||
setTarget(pctFromClientX(e.clientX));
|
||
}
|
||
});
|
||
|
||
const endDrag = (e) => {
|
||
if (dragging) {
|
||
dragging = false;
|
||
try { wrapper.releasePointerCapture(e.pointerId); } catch {}
|
||
}
|
||
};
|
||
|
||
wrapper.addEventListener('pointerup', endDrag);
|
||
wrapper.addEventListener('pointercancel', endDrag);
|
||
|
||
wrapper.addEventListener('pointerleave', (e) => {
|
||
endDrag(e);
|
||
if (hovering) {
|
||
hovering = false;
|
||
setTarget(DEFAULT_POSITION);
|
||
}
|
||
});
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|