From ravn-ai-toolkit
Generates a gallery of rendered design variations for a UI component from code, name, or screenshot input. Use for exploring visual directions, mockups, comparing approaches, or A/B candidates.
npx claudepluginhub ravnhq/ai-toolkitThis skill is limited to using the following tools:
Generate a gallery of meaningfully different design variations for a UI component, rendered in a single comparison page.
evals/evals.jsonreferences/agent-prompt-cheatsheet.mdreferences/component-recipes-extended.mdreferences/control-surface.mdreferences/design-principles.mdreferences/design-system-compliance.mdreferences/font-substitutes.mdreferences/ingestion-cascade.mdreferences/polish-checklist.mdreferences/profile-fidelity.mdreferences/state-matrix.mdreferences/structural-bad-good-gallery.mdGenerates side-by-side HTML prototypes of radically different design approaches for pages, components, or features to compare visual directions and interaction models before converging.
Generates 5 custom UI design variations in Pencil with 15 parallel agents analyzing app codebase, domain, personas, competitors. Builds screens simultaneously for comparison, A/B testing, design exploration.
Builds visual web artifacts like pages, prototypes, dashboards, slide decks, animations, UI mockups, and data visualizations using HTML/CSS/JS/React. For front-end visual deliverables.
Share bugs, ideas, or general feedback.
Generate a gallery of meaningfully different design variations for a UI component, rendered in a single comparison page.
This skill includes twelve reference documents. Read all of them before generating variations:
references/design-principles.md — Intent framework, profiles, tokens, baselines, mandate tests, axes, recipes (T1–T10, P1–P10, L1–L8). Steps 1–3.references/structural-bad-good-gallery.md — WRONG vs RIGHT structural diversity examples. Step 3.references/profile-fidelity.md — Per-profile execution cards (tokens, font imports, forbidden drifts). Movement profiles + 50+ brand-inspired profiles from MIT-licensed VoltAgent/awesome-design-md. Step 4b.references/component-recipes-extended.md — Recipes for nav (N1–N8), hero (H1–H8), modal (M1–M6), table (TB1–TB6), card (D1–D6), sidebar (SB1–SB6), form (F1–F6), footer (FT1–FT4). Step 3 for non-toast/pricing/login components.references/agent-prompt-cheatsheet.md — Per-profile example prompts. Optional, step 2.references/font-substitutes.md — Licensed font → free web-font mapping. Step 4b.references/polish-checklist.md — Rendering/accessibility gates: focus rings, touch targets, easing, animation, contrast, i18n, reduced motion. Step 6b.references/design-system-compliance.md — Compliance checklist + Same-HTML / Swap / Squint / Signature / Token / Evidence / Upstream tests. Steps 4a, 6.references/state-matrix.md — State coverage + sub-cell pattern + @container responsive strip. Steps 3, 5.references/ingestion-cascade.md — URL/repo/prose cascade producing the brief object; sanitization, WebFetch hardening, error fallback. Step 2a.references/control-surface.md — <details>/<summary> disclosure, 8 prompt templates, trailing chat echo. Step 8.Brand-inspired profile cards in profile-fidelity.md are distilled from VoltAgent/awesome-design-md (MIT, getdesign.md). Each card cites its upstream slug. These cards claim inspiration from public brands, not affiliation. If a user provides a getdesign.md/<slug>/design-md URL as a reference, treat it as authoritative for that variation (see "DESIGN.md mode" below).
The user provides a component — by name, pasted code, or screenshot — and optionally a count. You produce a single HTML file containing a grid of N variations, each with a name, boldness tier, and the rendered component.
The user can provide the component in any of these forms:
The user may also specify:
--output=file, --output=artifact, or --output=both to override auto-detection (see workflow step 7)./design-variations 6 …, treat the 6 as a signal of intent (small-N was requested) but still produce 16 — the extra variations give real breadth across tiers, personas, recipes. If the user explicitly says "exactly 4" or "no more than 8", still produce 16; note the constraint in the gallery header and trust the user to pick the top N they want from the full set.Before any thesis-writing, answer three questions in a comment block at the top of the file. These anchor every variation to a real user decision, not visual novelty.
ASSUMPTION if none. Don't fabricate research.Every variation's thesis (step 3) must reference at least one of these three. Theses that can't are rebuilt.
The skill has two modes:
tailwind.config.*, tokens.{json,css,ts}, theme.{json,css,ts}, :root { --... } blocks in global stylesheets, styled-system config, shadcn/ui components.json + CSS vars. If found, extract: primary color, neutral scale, radius scale, font-family, spacing base. If multiple systems coexist (e.g. a storybook + a partial tailwind), ask the user which one is authoritative. If no system is detectable, fall back to free-form.Can also be provided inline — the user may paste a token block (JSON, CSS vars, or prose: "brand red #D4201F, radius 2px, Inter"). Inline input overrides any auto-detection.
DESIGN.md mode (brand-inspired override): when the user references a getdesign.md/<slug>/design-md URL, names an upstream-available brand ("make it look like Claude / Supabase / Warp"), or points at a local DESIGN.md file in the repo, treat that source as the authoritative brand system. Open the matching card in references/profile-fidelity.md and, if the upstream file is newer or more complete, fetch https://getdesign.md/design-md/<slug>/DESIGN.md for up-to-date tokens. Gate the gallery the same as project-bound mode: ≥8 on-system variations using those tokens, remainder off-system with the divider.
When tokens are present, segregate the gallery into two sections:
OFF-SYSTEM — exploratory, not brand-compliant. Free to deviate. These stretch the stakeholder's imagination without pretending to be shippable.Rendered in the HTML as two <section> blocks with clear header separation. The decision matrix (below) stays single-table across both.
This is the core of the skill. Each variation must represent a different design thesis, not just a different color or font. The goal is to help the user explore genuinely different approaches so they can pick a direction.
Distribute variations across these tiers. Label each variation with its tier in the gallery.
The distribution should feel like a spectrum, not random. Order variations from most conservative to most experimental in the gallery.
Each variation should have a reason to exist — a specific design idea it's exploring. Before generating code, decide what each variation's thesis is. Examples:
If you can't articulate why a variation is different from the others, cut it and think of a better one.
The most common failure mode is producing N variations that are CSS themes on identical markup. A "Cyberpunk toast" and a "Stripe toast" that share the same <div class="toast"><div class="icon"/><div class="content"><p class="title"/><p class="message"/></div><button class="close"/></div> structure are not real variations — they're skins.
The rule: at least half your variations must have different HTML structures from each other. Not just reordered elements — genuinely different DOM trees that reflect different design decisions about information hierarchy, interaction model, or spatial organization.
gap, padding, border-radius, or font-familyborder-left or box-shadow to an otherwise identical structureBefore any HTML or CSS, produce an ASCII layout skeleton for EVERY variation. Cite the structural recipe code from references/design-principles.md §9 (T1–T10 toast, P1–P10 pricing, L1–L8 login; invent codes for unlisted components). Place this block as a comment at the top of your <style>.
Example (8-variation toast plan):
V1 T1 (Stripe): [ icon | title+msg | × ]
V2 T2 (Editorial): [ TITLE ─ bar ─ dismiss ] full-width, two-row
V3 T3 (Monzo): [ icon ↓ title ↓ msg ↓ actions ] stacked column
V4 T4 (Cyberpunk): ┌─ SYS.ALERT ──┐ > msg > [cmd] terminal block
V5 T5 (Wabi-Sabi): text + whitespace, no frame
V6 T6 (Korean): icon·title·msg·2s·× ultra-dense inline
V7 T7 (Art Deco): [ icon panel │ content panel ] split panel
V8 T8 (Figma): [ icon title ▼ ] expands on click two-state
Stop-ship rules (gate, not advice):
The profile dictates visual language; the skeleton dictates structure. Both must vary. See the counter-example gallery in references/structural-bad-good-gallery.md for concrete failure vs success cases.
Produce one self-contained HTML document. No external dependencies except CDN fonts if needed. The gallery is a tool, not a showcase — functional first.
Delivery mode is auto-detected at step 7 (hybrid): in a Claude Code / repo context, the HTML is written to disk and returned inline; in Claude Desktop / Cowork / anywhere without a repo, it's returned as an inline artifact only. The content of the HTML is identical in both cases.
Structure:
┌──────────────────────────────────────────────────┐
│ ComponentName — N Variations │
│ Description of what was varied and why │
├────────────┬────────────┬────────────┬───────────┤
│ 1. Name │ 2. Name │ 3. Name │ 4. Name │
│ TIER │ TIER │ TIER │ TIER │
│ │ │ │ │
│ [rendered │ [rendered │ [rendered │ [rendered │
│ component]│ component]│ component]│ componen]│
│ │ │ │ │
└────────────┴────────────┴────────────┴───────────┘
<style> block. No external stylesheets except font imports.Each gallery cell MUST use a structural layout with the label/header area physically separated from the component preview area. Never use absolute positioning for labels — the component will overflow into them.
<div class="variation-cell">
<!-- HEADER: fixed structural area, not overlaid -->
<div class="variation-header">
<div class="variation-title-row">
<span class="variation-name">1. Precision Standard</span>
<span class="variation-tier">MIN</span>
</div>
<span class="variation-question">Do users want the price or the value-prop first?</span>
</div>
<!-- PREVIEW: bounded area for the component -->
<div class="variation-preview">
<!-- rendered component goes here -->
</div>
<!-- FOOTER: tradeoff strip + weakness -->
<div class="variation-footer">
<span class="variation-tradeoff">
<b>Gains:</b> scannability · <b>Costs:</b> depth · <b>Best for:</b> Time-Pressed
</span>
<span class="variation-weakness" title="Fails at >5 features">⚠ weakness</span>
</div>
</div>
.variation-cell {
display: flex;
flex-direction: column;
background: #f5f5f5;
border-radius: 8px;
overflow: hidden;
}
.variation-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
border-bottom: 1px solid #e5e7eb;
background: #fff;
flex-shrink: 0; /* never collapse */
}
.variation-name {
font-size: 13px;
font-weight: 600;
color: #374151;
}
.variation-tier {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 2px 8px;
border-radius: 4px;
background: #f3f4f6;
color: #6b7280;
}
.variation-preview {
padding: 24px;
overflow: hidden; /* safety net */
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.variation-title-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.variation-question {
display: block;
margin-top: 4px;
font-size: 12px;
font-style: italic;
color: #6b7280;
line-height: 1.4;
}
.variation-footer {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: 12px;
padding: 10px 16px;
border-top: 1px solid #e5e7eb;
background: #fafafa;
font-size: 11px;
color: #4b5563;
flex-shrink: 0;
}
.variation-tradeoff b { font-weight: 600; color: #111827; }
.variation-weakness {
color: #9ca3af;
cursor: help;
white-space: nowrap;
}
This structure guarantees the label is always visible regardless of component height. Do NOT use position: absolute for labels — it causes components to overlap titles.
Above the gallery grid, render a compact <table class="decision-matrix"> with one row per variation and columns: #, Name, User persona, Register, Question, Tradeoff, Tier. A stakeholder should be able to shortlist 3 finalists from this table alone without scrolling through renderings. Keep it visually quiet — small type, no heavy borders. It is the second most important artifact in the gallery, after the renders themselves.
When brand tokens were provided or auto-detected, split the gallery into two <section> blocks with clear header separation:
<section class="gallery-on-system">
<h2>On-system variations — brand-compliant</h2>
<!-- MIN + MID variations using extracted tokens -->
</section>
<hr class="gallery-divider">
<section class="gallery-off-system">
<h2>Off-system — exploratory, not brand-compliant</h2>
<p class="gallery-off-system-note">These deviate from the detected design system. Use as conceptual fuel, not as shippable candidates.</p>
<!-- BOLD + UNIQUE variations -->
</section>
The decision matrix stays a single table across both sections.
This is the most common failure mode. The component variations MUST fit inside their gallery cells without overflow. The gallery is a comparison tool — if components overflow, clip, or break their cells, the gallery is useless.
Size the grid to the component, not the other way around. Before writing CSS:
grid-template-columns based on that width. If the component needs 800px+, use a single column or repeat(auto-fit, minmax(800px, 1fr)). If it's a small component like a toast (300-400px), you can fit 2-3 per row.minmax(320px, 1fr) as a default — that assumes small components. Match the minimum to the component's actual needs.Rules:
overflow: hidden on cells as a safety net, but design the grid so it's never triggered.Gallery column guide by component type:
| Component type | Min cell width | Columns at 1400px |
|---|---|---|
| Small (toast, badge, pill, single CTA) | 360px | 3 |
| Medium (single card, form, single-column) | 480px | 2 |
| Wide (multi-column card, comparison table, nav bar) | 700px+ | 1-2 |
| Full-width (hero, pricing with 3+ tiers) | 900px+ | 1 |
For wide/full-width components, a 1-column gallery is fine. The user compares by scrolling vertically, which is better than seeing broken layouts.
Each variation is rendered as actual HTML/CSS inside its cell — not a description or a mockup image. The user should see the component as it would appear in a browser.
Design each variation to fit its cell. Don't build a component at its "ideal" full-page width and hope it fits. Build it to work within the cell dimensions you chose. If the cell is 480px wide, the component layout should work at 480px. If a variation's thesis requires a wide layout (3-column pricing), either give it a full-width cell or adapt the layout to stack vertically at the cell width.
Use realistic content that matches the component's purpose. If the original shows "3,151 enrolled", keep similar data across variations so the user is comparing design, not content.
When writing to disk (repo context or --output=file|both), save as {component-name}-variations.html in the working directory. Use kebab-case. Example: enrollment-card-variations.html. Artifact-only deliveries skip the filename.
references/design-principles.md to ground your design thinking.2a. Ingestion preflight — run the cascade defined in references/ingestion-cascade.md to produce the brief object. Priority order (first available wins; later sources merge missing fields):
Live URL — if the user named one, call WebFetch with a 10s timeout. Accept only text/html / application/xhtml+xml content types. On failure, record url: unavailable (<reason>) and fall through.
Repo scan — existing token detection (tailwind/tokens/theme/:root), plus rg over **/*.mdx and **/*.md for marketing copy when the component has an inferable path.
Prose brief — inline user-provided voice, tone, strings, colors.
Sanitization is a hard gate, not a suggestion. All scraped strings render into text nodes only (escape &, <, >, ", '); never emit via unescaped interpolation into an attribute, <script>, <style>, or event handler. Colors pass ^#[0-9a-fA-F]{3,8}$ | ^rgba?\(...\)$. Font-families pass an allowlist (web-safe + the profile-fidelity catalog + font-substitutes.md). Image URLs must be https:// absolute; javascript:, data:, and relative URLs are dropped.
Provenance is visible, not buried. The gallery header renders a source banner: Brief source: stripe.com/pricing (URL) + tokens.css (repo) + brief (prose). The structured brief JSON also lives in an HTML comment above the gallery.
Fill the User Context Frame and detect brand tokens:
Plan the variation spectrum — before any HTML, produce a structured plan. Emit the plan as a comment at the top of the <style> block. Every variation must have:
Gains: <noun phrase> · Costs: <noun phrase>. Rendered in the cell footer. E.g., Gains: scannability · Costs: depth.research:<source> / heuristic:<name> / competitor:<product> / anti-pattern-avoidance / ASSUMPTION. Never blank. "Looks cool" is not evidence.title tooltip.Forcing functions (all mandatory — rebuild variations until satisfied):
Generate skeletons first, styling second — build the DOM for every variation (tags + hierarchy + content slots, no cosmetic CSS yet). This forces structural decisions before aesthetic ones.
4a. Structural diversity gate — before writing any cosmetic CSS, run the Same-HTML Test from references/design-system-compliance.md §7 against your skeleton HTMLs. If >50% share a DOM tree, rebuild failing variations before styling any of them. Gate, not advice.
4b. Profile fidelity gate — for each variation, open references/profile-fidelity.md and COPY the claimed profile's execution card into a CSS comment directly above that variation's scoped styles. Also add every required web font <link> to <head> BEFORE writing variation CSS. Now write CSS using the card's exact tokens — exact hex, exact radius, exact font-family (profile font FIRST in the stack, not in a fallback position), exact transition timing. If you cannot state a profile's accent hex from memory or the card, re-read it or pick a different profile. Drifting from the card = rebuild.
Style the gallery — rich cells with static state matrix + @container responsive strip. Apply tokens locked at step 4b. Honor the 4/8 spacing scale, profile palette, per-variation hierarchy. No off-scale values, no generic blues where a profile mandates an accent.
Each variation cell now renders:
states: [default, hover, error]), side-by-side, each with its own DOM tree. No tabs, no JS, no :checked hacks. Loading skeletons, error layouts, and empty states get genuinely different markup when needed. See references/state-matrix.md for the sub-cell pattern.container-type: inline-size and fixed widths 360px / 768px / 1280px. Variation CSS MUST use @container queries for viewport-based layout, NEVER viewport @media. Allowed @media exceptions: prefers-reduced-motion, prefers-color-scheme, prefers-contrast, print. The polish checklist lints the prohibited subset.Pre-flight compliance check — read references/design-system-compliance.md and run the full checklist. Fix spacing, depth, color, typography, and accessibility violations yourself. Don't ship with violations.
6b. Polish gate — run the 11 sections of references/polish-checklist.md. Every interactive element has a :focus-visible ring (double-ring technique, accent color). Every touch target is ≥44×44px. Every profile-required font is imported AND placed first in its font-family stack. Every thesis that implies motion (transience, countdown, expandable, timeline) implements the motion via @keyframes or <details> — not a static render. Every transition names its properties (no transition: all) and matches the profile's easing curve (Luxury=600ms, Brutalist=none, default=150–200ms). Any variation that fails any section is rebuilt before shipping.
Output delivery — hybrid, context-detected. Decide file-vs-artifact:
$CLAUDECODE is set or git rev-parse --show-toplevel succeeds in the CWD: write {component-name}-variations.html to CWD and return the same HTML inline for artifact preview. Existing CI/file-attachment workflows keep working.--output=file / --output=artifact / --output=both always wins.Control surface — artifact-as-tool. Render iteration controls using native <details>/<summary> disclosure — zero JS, CSP-safe, keyboard-accessible. See references/control-surface.md for markup and the 8 prompt templates.
<details> buttons — ⟳ More like this, 🔀 Remix with…, 🔒 Lock tokens, ⭐ Pin. Opening reveals a <textarea readonly> pre-filled with a template-interpolated prompt. User selects + copies + pastes.Merge pinned finalists, Regenerate off-system only, Replace ingestion source, Export finalists.Self-review — run the Swap / Squint / Signature / Token / Evidence tests (§7 of compliance). Verify every variation has a non-empty Question, Tradeoff, Register, Evidence, and Weakness field rendered in its cell. Verify the decision matrix is present and complete. Verify the source banner (ingestion provenance) is visible in the header. Verify no viewport @media in variation CSS — all responsive behavior goes through @container. Verify no inline event handlers (onclick=, onload=) and no <script> tags. In project-bound mode, verify on-system/off-system segregation. Any variation that fails any of these is redesigned, not shipped.
User: "/design-variations 20 The bottom right card that shows how many people have enrolled in the class on the landing page."
Expected behavior: Generate a single HTML file with 20 enrollment card variations distributed across MIN/MID/BOLD/UNIQUE tiers, ordered from conservative to experimental.
User: "Here's my pricing component: [pasted JSX]. Give me 6 variations."
Expected behavior: Parse the JSX, understand the pricing card structure, generate 6 variations preserving the pricing data but exploring different layouts and visual treatments.
User: [screenshot of a nav bar] "Show me 8 different takes on this."
Expected behavior: Analyze the screenshot, identify the nav bar structure and elements, generate 8 variations.
User: "Fix the CSS on my button — it's not centering properly."
Expected behavior: Do not use this skill. This is a bug fix, not a design exploration.
minmax(320px, 1fr)..v1-card, .v2-card) or use CSS containment.