Generates side-by-side HTML prototypes of radically different design approaches for pages, components, or features to compare visual directions and interaction models before converging.
npx claudepluginhub tmchow/tmc-marketplace --plugin iterative-engineeringThis skill uses the workspace's default tool permissions.
Generate a single self-contained HTML file presenting distinct design variations (scaled to scope — see Step 2) with per-variation interactive controls, a rating/feedback system, and structured export. The goal is divergent thinking: explore fundamentally different approaches to a design problem before converging on a direction. "Different" means different on the right axis — usually different ...
Verifies tests pass on completed feature branch, presents options to merge locally, create GitHub PR, keep as-is or discard; executes choice and cleans up worktree.
Guides root cause investigation for bugs, test failures, unexpected behavior, performance issues, and build failures before proposing fixes.
Writes implementation plans from specs for multi-step tasks, mapping files and breaking into TDD bite-sized steps before coding.
Generate a single self-contained HTML file presenting distinct design variations (scaled to scope — see Step 2) with per-variation interactive controls, a rating/feedback system, and structured export. The goal is divergent thinking: explore fundamentally different approaches to a design problem before converging on a direction. "Different" means different on the right axis — usually different interaction models, not different visual themes.
All artifacts for an exploration live in a dated topic directory:
docs/design-explorations/YYYY-MM-DD-<topic>/
v1.html ← first round
v2.html ← refined round
v3.html ← further refinement
docs/design-directions/
YYYY-MM-DD-<topic>-design-direction.md ← written at conclude
Your very first action must be detection — before any Q&A, scoping questions, or even acknowledging the request. Do NOT skip to Step 1 without completing the checks below.
If the user's message contains structured feedback (ratings, reference to a previous exploration file), this is an iteration round. Extract the Source: path from the feedback, then read the metadata from that HTML file (see "Reading prior metadata" in Step 3). This gives you the families, variations, and round number. Proceed to Step 2 with both the feedback and the metadata as context.
Before responding to the user, check what's in docs/design-explorations/. If any existing exploration looks relevant to the user's request, tell them you found it and ask whether to iterate or start fresh. If iterating, read the previous round's metadata (see Step 3). Proceed to Step 2 — skip Step 1 entirely. If nothing relevant exists, proceed to Step 1.
Input can range from a single sentence ("explore designs for a notification system") to a full PRD. The goal of this step is to gather enough context that the approach-based divergence planning in Step 2 produces meaningfully different directions — not random ones.
This step only runs for fresh explorations (no feedback input, no existing exploration to iterate on). If Step 0 found a previous round to iterate on, skip this step — the metadata provides the context.
Ask 0-2 scoping questions based on how much ambiguity exists. When a PRD or detailed requirements already exist (e.g., from iterative:brainstorming), the problem space is already mapped — determine the divergence axis from the existing context and proceed to Step 2. The PRD informs the exploration but doesn't constrain the creative surface; the whole point is to discover visual and interaction possibilities the requirements alone can't express.
When input is lighter (a sentence or brief description), component prompts tend to describe the full problem; larger scopes tend to leave more genuinely open. The right questions inform the exploration — the wrong ones constrain it. The test: does knowing the answer change which approaches you'd explore, or does it just eliminate options the user should see? If it eliminates options, don't ask — let the exploration show them.
When input covers multiple distinct UI surfaces (e.g., a PRD describing a dashboard, an upload flow, a settings page, and an image grid), identify the surfaces and ask the user what to explore. Present options including exploring everything (full scope) as a first-class choice, plus focused options for individual surfaces or natural groupings. Frame it as "I see these surfaces — want to explore all of them, or focus on a subset?" — not "pick exactly one." Keep it to a single question.
When input is already narrow (a single component, one screen, one flow), skip this — there's nothing to scope.
The divergence axis determines WHAT varies between families. This is the most important decision — getting it wrong produces explorations that are visually impressive but practically useless.
Interaction divergence (DEFAULT) — Families explore different ways the thing WORKS. Different behavior, flow, information architecture, progressive disclosure, state handling. All variations share a clean, professional visual treatment — a realistic neutral UI that looks like it belongs in a real product. The user is comparing interaction models, not color palettes.
Visual divergence — Families explore different ways the thing LOOKS. Same functional structure (or a simple reference structure), different aesthetics, typography, spatial composition, atmosphere. Useful for establishing visual identity when there IS no existing design language.
Both — Families differ in both visual identity AND interaction model. Only appropriate when the entire page or app is open — no existing design system, no existing interaction patterns, full greenfield.
How to determine the axis:
| Signal | Axis |
|---|---|
| "explore different ways to [do X]" | Interaction |
| Component or feature scope | Interaction |
| Mentions an existing app, screen, or design system | Interaction |
| Has a clear functional problem to solve | Interaction |
| "explore visual styles for...", "what should it look like" | Visual |
| Landing page, marketing site, brand identity | Visual |
| Full page, no existing app, no functional constraints | Both |
When in doubt, default to interaction. Wild visual divergence on a functional problem (like a price input rendered as a neon cyberpunk terminal) is rarely useful. Interaction divergence is almost always what people need — they want to see different UX approaches, rendered professionally, so they can make a decision about how the thing should work.
Orthogonal to the divergence axis — this determines whether visual choices are locked to an existing system or open.
Within an existing app — Visual language is locked. Axis is always interaction.
Greenfield — No existing app or design system. The divergence axis determines how much visual freedom each variation gets.
The variation count scales with the design space — how many meaningfully different approaches exist for the problem. Don't default to 6 every time; don't inflate to 12 when the scope doesn't warrant it.
| Scope | Round 1 | Round 2+ (refinement) | Families |
|---|---|---|---|
| Component (toggle, input, card, single widget) | 4-6 | 4 | 2 × 2, or 2 × 3 |
| Feature / section (notification panel, pricing area, settings) | 6-8 | 6 | 3 × 2, or 3 × 3 |
| Full page (dashboard, landing page, onboarding) | 8-9 | 6-8 | 3 × 3 |
| Full app / multi-page flow | 9-12 | 8-9 | 3-4 × 3 |
Rules:
When planning Round 2+ from user feedback, use these principles to translate ratings, notes, and control adjustments into a concrete plan for the next round. These aren't rigid rules — the agents are smart enough to make good judgment calls given the right framing.
Reading the feedback signal
Each rating tier tells you something directional:
User notes are design requirements
When notes say things like "I'd like the model to be selectable" or "needs a way to add reference images" — those aren't suggestions, they're requirements for the next round. Fold them into the variation briefs for agents. A note on a loved variation ("love this but needs a dimensions input") becomes a requirement in every variation of that family's next iteration.
Control adjustments carry forward
When the exported feedback shows a user moved a control from its default (e.g., sidebar width 240→300px, density compact→spacious), use those adjusted values as the new defaults in the next round's variation briefs. The user already told you what they prefer — start there.
The exploration-convergence balance
Each round should feel like it's narrowing AND discovering. A round that only refines what worked feels like diminishing returns. A round that ignores feedback feels like it wasn't listening.
Keep at least one family slot for a genuinely new approach the user hasn't seen — even in Round 3+. The new approach should be informed by what worked (if the user loved a sidebar layout, the new approach might also use a sidebar — but with a fundamentally different interaction model). This prevents the exploration from collapsing too early while still feeling responsive to feedback.
Direction for Next Round
When the user fills in the "Direction for Next Round" section of the export, that's the highest-signal input — it overrides tier-based inference. If the direction says "focus on A1 and make it production-ready," that's a refinement round, not an exploration round. If it says "I liked A1 but want to see completely different aesthetics," that's a visual-axis pivot. Plan accordingly.
When the direction is empty ([No direction provided]), fall back to the tier-based planning above.
Worked example
Suppose Round 1 explored an image generation tool with three families:
Round 2 plan:
Before deciding families, identify the specific design question the exploration is answering — then brainstorm different answers to it.
The axis from Step 1 (interaction vs visual) determines the visual treatment: interaction-axis variations share a neutral professional style; visual-axis variations get full creative freedom. But within the chosen axis, the specific question is what makes the exploration focused and useful. "Explore different ways a price input works" is too broad — "explore different mental models for how a user sets a sale price" is specific enough to produce meaningfully different families.
Interaction axis (default): Each approach is a different answer to the design question — articulable as "What if [specific concept]?" The concept should evoke a UX pattern, mental model, or interaction philosophy — not a visual aesthetic.
Visual axis: Each approach is a different way the thing LOOKS — articulable as "What if it felt like [aesthetic / brand / product]?" Full creative divergence on typography, color, spatial composition.
Both axes: Approaches differ in both how it works AND how it looks. The concept evokes a complete product mental model.
Process:
Brainstorm 4-6 approaches. Frame each as a question appropriate to the axis:
Interaction-axis examples:
Visual-axis examples:
Both-axes examples:
Push past obvious references. The first approaches that come to mind are usually the most familiar — Notion, Linear, Slack, Shopify. These are fine as one data point but they're not exploration. Draw from outside the usual tech product vocabulary: print design, architecture, game UI, industrial controls, analog tools, other industries entirely. The goal is to surface approaches the user hasn't already considered.
Select 2-3 approaches that are most divergent from each other. Two approaches are divergent if they imply different answers to fundamental questions: What's visible first? How does the user interact? Where does complexity live? What's the primary flow?
Articulate what makes each approach different before assigning families. Don't just name the concept — state the concrete implications: what's prominent, what's hidden, how the user moves through the content, what the interaction prioritizes.
CRITICAL for interaction axis: Approaches must differ in BEHAVIOR, not aesthetics. "Nordic Ledger" and "Neon Terminal" sound different but might have identical interaction patterns — different paint on the same UX. "Side-by-side comparison" and "progressive disclosure wizard" ARE different — fundamentally different interaction models regardless of visual treatment. When the axis is interaction, name the UX pattern, not the aesthetic.
Scale to scope:
Each family (approach) receives:
LETTER + NUMBER — Letter = family, Number = member (A1, A2, B1, B2, C1, C2, C3)Commit to a clear direction for each family before writing HTML. The divergence axis determines what to decide.
Interaction axis (default) — behavioral + structural divergence:
Visual axis — aesthetic divergence:
Both axes — full divergence:
Components — scale the thinking regardless of axis:
Each variation gets 4-8 controls that let the user explore design decisions without generating a whole new variant. Controls modify CSS custom properties on the variation's iframe.
The litmus test: if someone across the room can't tell the control changed something, it's too subtle. Each control should represent a decision a designer would credibly debate. Switching between options should produce a visibly different result.
Start with what makes this variation unique. The most valuable controls expose the decisions specific to THIS variation's structure and interaction model. Two variations with different interaction models should have mostly different controls.
| Structure element | Controls |
|---|---|
| Sidebar | Width (range), Position (left/right), Collapse toggle |
| Card grid | Columns (2/3/4), Gap size, Card style (bordered/shadow/flat) |
| Content area | Max width (narrow/medium/wide/full) |
| Hero section | Height (range), Alignment (left/center) |
| Table/list | Row density, Stripe toggle, Border style |
Full-page additions (optional, only for full-page scope): For full pages, you may add 1-2 global controls like spacing density or content width if they meaningfully reshape the layout. For components, skip these entirely; they're noise at component scale and eat the control budget. | Borders | Style (none/subtle/visible), Radius (range) |
Control data model schema:
// Range control — value + unit are set directly on the CSS var
{
id: 'sidebar-width', // unique within variation
label: 'Sidebar Width', // human-readable
type: 'range', // range | select | toggle
min: 180, max: 320, step: 10,
options: null,
value: 240, // current value (REQUIRED — never null/undefined)
defaultValue: 240, // reset target
unit: 'px', // appended to value when setting CSS var
cssVar: '--sidebar-width' // CSS custom property this modifies
}
// Select — single property (e.g. accent color):
{
id: 'accent',
label: 'Accent Color',
type: 'select',
min: null, max: null, step: null,
options: ['coral', 'teal', 'indigo', 'amber'],
cssValues: { coral: '#e07a5f', teal: '#4a9e8f', indigo: '#5c6bc0', amber: '#d4a853' },
value: 'teal',
defaultValue: 'teal',
unit: '',
cssVar: '--accent' // single var: --accent: #4a9e8f
}
// Select — MULTI-VAR (e.g. mood changes bg + text + borders together):
{
id: 'mood',
label: 'Mood',
type: 'select',
min: null, max: null, step: null,
options: ['light', 'dark', 'midnight'],
cssValues: {
light: { '--bg': '#faf9f7', '--text': '#2d2a26', '--text-dim': '#8a8580', '--border': '#e5e0d8' },
dark: { '--bg': '#1e1e2a', '--text': '#e0ddd8', '--text-dim': '#8a8580', '--border': '#333340' },
midnight: { '--bg': '#0d0d14', '--text': '#c8c4be', '--text-dim': '#6a6660', '--border': '#1e1e2a' }
},
value: 'light',
defaultValue: 'light',
unit: '',
cssVar: null // multi-var: no single var, cssValues objects set all vars
}
// Toggle — cssValues maps true/false to CSS values:
{
id: 'show-dividers',
label: 'Show Dividers',
type: 'toggle',
min: null, max: null, step: null,
options: null,
cssValues: { true: '1px', false: '0px' },
value: true,
defaultValue: true,
unit: '',
cssVar: '--divider-width'
}
Key rules for controls:
id is REQUIRED — unique within the variation. Without it, the control renders but clicking/dragging does nothing. (The template auto-generates from label as a safety net, but don't rely on this.)value and defaultValue must ALWAYS be set (never null/undefined)value is numeric, unit is appended → --gap: 24px. Exception: never use unit: '%' for percentage-scale ranges — use unitless values (e.g., 0-100 or 0-1) and let the CSS handle the math (calc(var(--opacity) / 100) or calc(var(--opacity) * 1%)). The % unit in CSS var output causes calc() failures.cssValues mapping options → CSS values. Without it, the CSS var gets a label string like --bg: warm which is uselesscssValues mapping true/false → CSS values. Without it, defaults to 1/0cssValues value instead of a string. Set cssVar: null. See the "mood" example above.cssVar must be used in the variation. The HTML must reference it via Tailwind arbitrary values (e.g., bg-[var(--bg)], rounded-[var(--radius)]) or the CSS must use it. If a control defines --card-radius but the HTML uses rounded-xl, the control does nothing. The assembly script validates this and prints warnings.var() for controlled properties. Hover, active, and focus states must reference CSS vars, not hardcoded values. If --accent is #BB6BD9, don't write :hover { color: #BB6BD9 } — write :hover { color: var(--accent) }. Use color-mix() for derived colors: color-mix(in srgb, var(--accent) 10%, transparent).[style*="..."] attribute selectors for CSS variable detection. Attribute selectors are fragile for detecting CSS custom property values and should not be used.Generate a single self-contained HTML file (~3000-5000 lines total) using Tailwind CSS Play CDN + Alpine.js CDN + Google Fonts. This step uses parallel html-prototyper agents to generate variation content, keeping context windows small and variation quality high.
Exploration directory: docs/design-explorations/YYYY-MM-DD-<topic>/
Before creating files, check if the directory already exists. If it does:
User provided feedback from a previous round (pasted export with ratings/direction) → this is an iteration. The feedback's Source: line gives the HTML path. Extract its metadata with the same sed command from "Reading prior metadata" below to get the families array and variations array. Create v{N+1}.html where N is the round value from the metadata.
No feedback provided, but directory has existing files → ask the user:
docs/design-explorations/YYYY-MM-DD-<topic>/ with v1.html. Would you like to continue iterating (creates v2.html) or start fresh?"vN.html. Extract the metadata from the latest existing round to avoid repeating previous designs (see "Reading prior metadata" below).YYYY-MM-DD-<topic>-2/. This preserves the original exploration.Directory doesn't exist → create it and generate v1.html.
Round detection:
v*.html files: ls docs/design-explorations/YYYY-MM-DD-<topic>/v*.html 2>/dev/null"round": N)Reading prior metadata (continue without feedback):
When the user chooses to continue in an existing directory but hasn't provided feedback, extract the metadata from the latest round's HTML to learn what was already explored. Use sed to pull just the JSON block — do NOT read the full file:
sed -n '/<script type="application\/json" id="exploration-metadata">/,/<\/script>/p' "{exploration_dir}/v{latest}.html" | sed '1d;$d'
This gives you the families array (each family's approach concept) and the variations array (each entry's layoutType, aesthetic, familyName, name, and description). Use this to:
families[].approach field captures the "What if it worked like...?" concept behind each family"previousVariations" summary in the new round's metadata so the chain is traceableInclude the prior family approaches and variation summary in each agent prompt as a "do not repeat" constraint:
Previous round explored these approaches (do NOT recreate these):
- Family A "Editorial Manifesto": What if it worked like a long-form magazine article? → Sidebar + Cards layout, Clean Light aesthetic
- Family B "Interactive Product Stage": What if the product demo was the hero? → Stacked Full Width layout, Dark Dramatic aesthetic
Generate something with a fundamentally different approach.
The file is too large for a single agent to generate well — quality degrades across multiple variations in one context. Split the work:
You (the orchestrator, Opus) handle:
_metadata.json (the only file the orchestrator creates directly)html-prototyper agents with complete promptsassemble.py which copies the template, injects all content, and produces the final HTMLhtml-prototyper agents (Sonnet, parallel, background) handle:
_var-{ID}.html) in one turnThe shell template (references/shell-template.html) is a complete gallery page with three placeholders: __METADATA_JSON__, __VARIATIONS_ARRAY__, and __VARIATION_TEMPLATES__. Each variation's HTML is a complete page rendered inside an <iframe srcdoc>. The assembly script copies the template, wraps each _var-{ID}.html file in a <template id="tpl-{id}"> element, and fills all placeholders automatically — the orchestrator never reads it. Do NOT read any files in references/ — all essential rules are in this document, and assemble.py handles the template. Reading plugin reference files triggers avoidable permission prompts.
For each planned variation, spawn an html-prototyper agent in the background with write permissions. Launch all agents in a single message so they run in parallel.
Critical — permissions: The agent frontmatter declares permissionMode: acceptEdits, but this does NOT propagate automatically on all platforms. You MUST explicitly grant write/file permissions when spawning. Platform examples:
subagent_type: "iterative-engineering:html-prototyper", mode: "bypassPermissions", and run_in_background: true.spawn_agent with write permissions enabled. The agent only needs the Write tool.Waiting for agents — MANDATORY PATTERN:
After spawning all agents, you MUST wait for each one using your platform's blocking agent-output mechanism. Do NOT use sleep, ls, or any bash polling.
Claude Code example:
# In a single message, call TaskOutput for each background agent:
TaskOutput(task_id=<agent_1_id>, block=true, timeout=300000)
TaskOutput(task_id=<agent_2_id>, block=true, timeout=300000)
... one per agent, all in parallel
Codex: Use wait to block until each spawned agent completes, then close_agent to release it. Call wait for each agent before proceeding to assembly.
Other platforms: Use whatever your platform provides to block until a background agent completes. The key requirement is: do NOT proceed to assembly until every agent has finished writing its file.
NEVER use sleep N && ls to check if files exist. This is the single most common orchestrator mistake. It wastes tokens, adds latency, triggers permission prompts, and can proceed before agents finish writing.
Prompt structure for each agent:
The agent has the design-prototyping skill preloaded, which contains the complete file format, control schema, styling rules, and pre-output checklist. The orchestrator prompt only needs variation-specific content. Keep it lean.
Write
{exploration_dir}/_var-{ID}.html. Follow the design-prototyping loaded in your context. CRITICAL: The metadata block MUST use exactlyid="variation-meta"— this ID is machine-parsed by the assembly script.
Then include ONLY:
"event": true — this tells the agent the control needs a JS event listener, not just a CSS var. The agent knows the schema from its preloaded skill; you just specify WHICH controls this variation gets and their parameters.min-h-screen flex items-center justify-center p-8 on <body>."Do NOT repeat the file format, control schema, styling rules, or checklist in the prompt. The agent already has these from the design-prototyping skill. Repeating them wastes tokens and increases context pressure.
The goal: a self-contained prompt under ~1000 words. The agent generates content and writes one file.
The orchestrator assembles via the standalone assemble.py script — it does NOT read variation file contents into its own context. This is critical for scaling to many variations without the orchestrator itself hitting context limits.
Write the metadata JSON to {exploration_dir}/_metadata.json (the orchestrator generates this — it's small)
Run the assembly script — a single bash command. The {skill_base} path is the "Base directory for this skill" shown when the skill loads. Run the command directly (don't verify the path first — that triggers permission prompts).
python3 "{skill_base}/references/assemble.py" "{exploration_dir}" {round} "{skill_base}/references/shell-template.html" && open "{exploration_dir}/v{round}.html"
The script handles everything:
v{round}.html_var-{ID}.html exists and contains a valid variation-meta JSON block</template> close tags (balanced nesting is safe)<template id="tpl-{id}"> element_var-*.html, _metadata.json)If the script reports missing files (e.g. "B1: missing or invalid variation-meta"), do NOT try to fix this by reading existing files and generating the missing ones. That approach reads variation content into the orchestrator's context and defeats the whole architecture. Instead:
rm -f {exploration_dir}/_var-{ID}.htmlIf the script reports validation errors (e.g. "orphaned </template> close tags"), delete the variation's output and re-spawn with a note to ensure every <template> open tag has a matching close tag.
The orchestrator's context only holds the conversation, the metadata JSON (small), and one bash command. It never reads the variation files.
Include a <script type="application/json" id="exploration-metadata"> block in the HTML <head>:
{
"project": "Dashboard",
"topic": "dashboard",
"round": 2,
"date": "2026-02-18",
"previousRound": "v1.html",
"sourceDirectory": "docs/design-explorations/2026-02-18-dashboard",
"families": [
{ "letter": "A", "name": "Horizontal Flow", "approach": "What if it worked like a social media feed — infinite scroll, cards, algorithmic ordering?" },
{ "letter": "B", "name": "Command Center", "approach": "What if it worked like a Bloomberg terminal — dense, data-forward, keyboard-driven?" }
],
"previousVariations": [
{ "family": "A", "familyName": "Sidebar Classic", "layoutType": "Sidebar + Cards", "aesthetic": "Clean Light" },
{ "family": "B", "familyName": "Bold Editorial", "layoutType": "Stacked Full Width", "aesthetic": "Dark Dramatic" }
],
"variations": [
{
"id": "A1",
"family": "A",
"familyName": "Horizontal Flow",
"name": "Nordic Mist",
"layoutType": "Top Nav + Masonry",
"aesthetic": "Muted Scandinavian",
"description": "Horizontal navigation with masonry content grid in cool muted tones."
}
]
}
The families array captures the conceptual approach behind each family — the "What if it worked like...?" framing from Step 2. This is included in the feedback export so the next round's agent understands what was tried and can iterate meaningfully. The previousRound field maintains the iteration chain. The previousVariations field (included when continuing without feedback) records what was explored in earlier rounds so agents can avoid repeating the same directions.
The export modal (built into the shell template) produces a markdown document optimized for LLM consumption. Per variation it includes: the family approach concept ("What if it worked like...?"), layout/aesthetic labels, the variation description, user notes, and control adjustments showing direction of change (default → adjusted value). Grouped by rating tier (Loved/Mixed/Low/Skip/Not reviewed). Designed to be pasted back into the agent to trigger the next round. The format spec is documented in references/export-formats.md (for human reference — do not read at runtime).
These files exist for human maintenance and for assemble.py to consume. The orchestrator must NOT read them — doing so triggers avoidable permission prompts. All rules the orchestrator needs are inlined in this document.
references/shell-template.html — Gallery shell template. Consumed by assemble.py, never by the orchestrator.references/html-architecture.md — Architecture spec for maintainers. Essential rules are inlined in this skill file.references/export-formats.md — Export format spec for maintainers. The export modal is built into the template.The user finalizes from the gallery by clicking "Ship It" on their chosen variation, then pastes the direction output into the conversation. The skill handles everything from there.
The gallery has two actions:
When the user clicks "Ship It", the gallery generates a ## Design Direction block containing the chosen variation's family approach, description, and adjusted design specs (absolute values). The user adds notes and copies it to paste into the conversation.
## Design DirectionThe skill detects the header and runs the conclude sequence:
Read metadata — extract the Source: path from the pasted text. Read the metadata from the HTML file using sed (same as Step 0/3). This gives full context: families, approaches, all variations, round count.
Write direction doc — create docs/design-directions/YYYY-MM-DD-<topic>-design-direction.md using the template below. Combine the pasted direction data with metadata context.
PRD integration — if a PRD exists, add a reference line (**Design Direction:** [path]). If no PRD, the direction doc stands alone.
Handoff — depends on how the skill was invoked:
Invoked from iterative:brainstorming: Write the direction doc, then exit. Do NOT present handoff options — iterative:brainstorming owns the workflow and will resume its own flow with the updated context (direction doc now exists, PRD references it).
Invoked standalone: Write the direction doc, then present an interactive choice:
iterative:brainstorming — define requirements around the chosen direction (when no PRD exists)# Design Direction: [Topic]
**Date:** YYYY-MM-DD
**Rounds:** N
**Gallery:** vN.html
## Chosen Direction
### [Variation code] "[Name]" — [Layout Type / Aesthetic]
**Approach:** [Family approach concept — "What if it worked like...?"]
[What works about this direction. Key design decisions — interaction model,
layout structure, typography, color direction, etc. Include adjusted design specs
if the user changed controls from defaults. Include any notes the user added.]
## Design Parameters
<!-- Cross-cutting decisions worth carrying forward.
Only include if the exploration surfaced clear preferences.
Skip this section entirely if there are none. -->
## Context
<!-- Include when standalone (no PRD). Skip when a PRD provides the context. -->
[What prompted this exploration. The problem being solved. Who it's for.]
"event": true and have JS listeners in the variationid field — control renders but clicks do nothing (template auto-fixes this but don't rely on it); (2) cssVar: '--card-radius' defined but HTML uses rounded-3xl instead of rounded-[var(--card-radius)] — the var is set but nothing reads it; (3) unit: '%' on a range control breaks calc() in CSS (use unitless values for percentage scales); (4) hover/active states use hardcoded colors instead of var(--accent) — the default state changes but hover doesn't; (5) cssValues written as an array instead of an object — cssValues: ['0.75rem', '1rem'] MUST be cssValues: { compact: '0.75rem', comfortable: '1rem' } keyed by option labels (the template auto-fixes this but don't rely on it). Controls are applied via iframe.contentDocument.documentElement.style.setProperty(). The assembly script warns about orphaned CSS vars.setProperty(). For visual controls, all styling must flow through var() references. For behavioral controls that need DOM manipulation (sorting, filtering, showing/hiding sections), mark them "event": true and add a control-change event listener in the variation's JS. See the design-prototyping skill for the pattern.<link> in <head>. Each variation is a complete page inside an iframe and loads its own fonts.exploration-metadata JSON block for agent consumption.references/ during skill execution. The orchestrator has everything it needs in this document, and assemble.py handles the template. Reading plugin files triggers permission prompts that interrupt the user.html-prototyper agent is pre-configured with maxTurns: 1 to prevent multi-turn exploration. Include size guidance (HTML page 250-600 lines depending on scope). Critically, the orchestrator must NOT read variation file contents into its own context — use the file-based assembly pattern (bash/python to replace template placeholders with file contents). If the orchestrator reads all 7 variation files, it will hit context limits during assembly.margin-top: 24px; padding: 16px; border-radius: 12px; background: var(--bg); as custom CSS, it should be mt-6 p-4 rounded-xl bg-[var(--bg)] in a Tailwind class string. Custom CSS is only for property definitions, keyframes, transitions, and things Tailwind genuinely can't express. Use Tailwind utility classes in the HTML and keep <style> blocks compact.</template> in variation HTML — The assembly script wraps each file in a <template> element. Orphaned (unbalanced) </template> close tags break the wrapper. Balanced <template> nesting is safe (e.g., Alpine.js <template x-for>, <template x-if>) — the HTML parser closes the nearest open <template>, not the outer wrapper. The assembly script validates this: it strips <script> blocks (where </template> in string literals is inert), counts opens vs closes, and only errors if closes > opens.variation-meta block — Every HTML file must contain a <script type="application/json" id="variation-meta"> block in <head> with valid JSON. The assembly script extracts this to build the variations array. If the block is missing or contains invalid JSON, assembly fails.:root — Variations are isolated in iframes. Define custom properties on :root, not on .v-a1. Class-scoped properties won't be reached by setProperty() on documentElement.:root * { transition: ... }) for smooth control changes. Without it, control adjustments appear as jarring instant changes.rm -f _var-*.html _metadata.json after assembly.cssValues (object format) when one control needs to change multiple properties together.ls, find) before running commands. Run commands directly.sleep N && ls to check if agents finished. Use your platform's blocking mechanism to wait for each agent (Claude Code: TaskOutput(task_id=<id>, block=true, timeout=300000) for each agent in a single message; Codex: wait + close_agent for each spawned agent). This is mandatory, not a suggestion. sleep && ls wastes minutes of wall time, burns tokens on repeated bash calls, and can proceed to assembly before an agent finishes writing.