Claude
Skills
Sign in
Back

design-prototyping

Included with Lifetime
$97 forever

The craft of building design exploration prototypes. Covers file structure, control wiring, styling conventions, and output validation. Preloaded into the html-prototyper agent. Not intended for direct invocation.

Design

What this skill does


# Design Prototyping

How to build a single self-contained design exploration variation file.

## File Format

Every variation is a single HTML file with embedded metadata. The file is a complete page rendered inside an iframe in the gallery shell.

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.tailwindcss.com"></script>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <!-- Google Fonts <link> for specified fonts -->
  <script type="application/json" id="variation-meta">
  {
    "id": "A1",
    "family": "A",
    "familyName": "...",
    "name": "...",
    "layoutType": "...",
    "aesthetic": "...",
    "description": "...",
    "controls": [ /* control objects — see Control Schema below */ ]
  }
  </script>
  <style>
    :root {
      /* All theme values as CSS custom properties */
    }
    :root * {
      transition: color 0.3s ease, background-color 0.3s ease,
                  border-color 0.3s ease, padding 0.3s ease,
                  gap 0.3s ease, font-size 0.3s ease,
                  border-radius 0.3s ease, box-shadow 0.3s ease,
                  max-width 0.3s ease, width 0.3s ease;
    }
  </style>
</head>
<body>
  <!-- Variation content -->
</body>
</html>
```

### Metadata Block

The `<script type="application/json" id="variation-meta">` block in `<head>` contains valid JSON with:

| Field | Type | Description |
|---|---|---|
| `id` | string | Variation code, e.g. `"A1"`, `"B2"` |
| `family` | string | Family letter, e.g. `"A"` |
| `familyName` | string | Human-readable family name |
| `name` | string | Memorable variation name |
| `layoutType` | string | Layout description, e.g. `"Sidebar + Cards"` |
| `aesthetic` | string | Aesthetic description, e.g. `"Clean Light"` |
| `description` | string | One-line description of the variation |
| `controls` | array | 4-6 control objects (see schema below) |

Populate all fields from the variation brief provided in the prompt.

## Styling Rules

- **Tailwind-first.** Utility classes for layout, spacing, colors, typography, borders, shadows. Custom CSS in `<style>` only for: `:root` property definitions, `@keyframes`, transitions, scrollbar styling.
- **CSS custom properties on `:root`.** All theme values: colors, fonts, spacing, radii. Unprefixed names: `--bg`, `--text`, `--accent`. Never `--shell-*`. Reference via Tailwind arbitrary values: `bg-[var(--bg)]`, `text-[var(--text)]`, `rounded-[var(--radius)]`.
- **Self-contained.** No external images. Use CSS gradients, inline SVG, Unicode.
- **Realistic content only.** Never lorem ipsum. Use the data from the prompt.
- **Motion.** Hover transitions on interactive elements. At least one entrance animation with staggered delays. JavaScript is allowed for interactive demonstrations (accordions, toggles, wizards).
- **Component scope.** For components (not full pages), center content in the viewport: `min-h-screen flex items-center justify-center p-8` on `<body>`.
- **Viewport containment.** The outermost container element must use `overflow-hidden` (or `overflow-auto` if scrolling is intentional). This prevents content from breaking out of the iframe bounds. Apply to the root layout wrapper, not `<body>`.
- **Transition CSS required.** The `:root * { transition: ... }` rule (shown in file format above) must be included for smooth control changes.

## Control Schema

Controls are **JSON metadata only**. Define them in the `controls` array inside the variation-meta block. A separate gallery shell reads this JSON and renders the control UI (sliders, dropdowns, toggles) outside the iframe.

**Do NOT build any control panel, settings panel, or configuration UI into the variation HTML.** The variation contains only the design content. All control rendering and interaction is handled by the shell.

Include 4-6 controls in the `controls` array.

### Two types of controls

**CSS controls** (default) — The shell sets a CSS custom property on `:root` via `style.setProperty()`. The HTML references it via `var()`. This is automatic — no JS needed in the variation. Use for visual parameters: colors, spacing, radii, opacity, font sizes, layout widths.

**Event controls** — For behavioral parameters that CSS can't express (sort order, filter thresholds, data grouping, expansion mode). The shell sets the CSS var AND dispatches a `CustomEvent` on the iframe's `document`. The variation includes a JS listener that reads the value and updates the DOM.

To make a control an event control, add `"event": true` to the control JSON. The shell dispatches `control-change` events with `{ detail: { id, value } }` for all controls, but only event controls need a listener.

Event controls still need a `cssVar` (it can be a dummy like `"--sort-order"`) so the shell has something to set. The actual work happens in your listener.

### Range

Value + unit are set directly on the CSS var.

```json
{
  "id": "sidebar-width",
  "label": "Sidebar Width",
  "type": "range",
  "min": 180, "max": 320, "step": 10,
  "options": null,
  "value": 240,
  "defaultValue": 240,
  "unit": "px",
  "cssVar": "--sidebar-width"
}
```

### Select (single CSS var)

Maps option labels to CSS values via `cssValues`.

```json
{
  "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"
}
```

### Select (multi-var)

When one control changes multiple CSS properties, use an object as the `cssValues` value and set `cssVar: null`.

```json
{
  "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
}
```

### Toggle

Maps `true`/`false` to CSS values. Without `cssValues`, defaults to `"1"`/`"0"`.

```json
{
  "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"
}
```

### Event Control Pattern

When a control needs to drive behavior (not just CSS), mark it with `"event": true` and add a listener in the variation's `<script>`:

```json
{
  "id": "sort-order",
  "label": "Sort By",
  "type": "select",
  "options": ["status", "last-active", "name"],
  "cssValues": { "status": "status", "last-active": "last-active", "name": "name" },
  "value": "status",
  "defaultValue": "status",
  "unit": "",
  "cssVar": "--sort-order",
  "event": true
}
```

```html
<script>
  document.addEventListener('control-change', (e) => {
    const { id, value } = e.detail;
    if (id === 'sort-order') {
      sortAgents(value);  // your function that re-sorts the DOM
    }
  });

  // Also handle initial state — controls-ready fires once after all
  // CSS vars are set on first iframe load
  document.addEventListener('controls-ready', () => {
    const sort = getComputedStyle(document.documentElement)
      .getPropertyValue('--sort-order').trim();
    if (sort) sortAgents(sort);
  });
</script>
```

The `controls-ready` event fires once after all controls are applied on iframe load. Use it to read initial CSS var values and set up initial stat

Related in Design