---
name: build-wireframe
description: "Use when the user wants to build a wireframe, annotated mockup, click-through prototype demo, presales walkthrough, or any HTML artifact with callout/leader lines pointing into a UI design — even if they don't say 'wireframe'. Also use when extending an existing wireframe HTML (new screens, callouts, demo flows). Triggers on 'wireframe', 'annotated mockup', 'click-through', 'callouts', 'legend lines', 'leader lines', 'tabs to switch screens/states', 'presales artifact'. This skill encodes hard-won fixes (label clipping, sticky-tabbar overlap, demo state races) so don't re-derive from scratch."
---

# Build wireframe

You are building a **single self-contained HTML file** that renders multiple annotated wireframe states accessible via tab navigation, plus optionally interactive click-through demos. Every wireframe state has callouts ("legend lines") in the side gutters explaining its key components.

This artifact format is for **concept verification, annotated walkthroughs, and prototype design discussions** — visual fidelity, no real backend, no real interactivity beyond the click-through demos. The deliverable opens directly in any modern browser; no build step.

## When to load each reference

The full rule set and the iteration history are in references — load on demand:

- **`references/legend-lines.md`** — the 7 visual rules for callouts, with the "why" behind each. Read this when adding callouts to a new state or when a leader is rendering wrong.
- **`references/demo-walkthroughs.md`** — the per-step callouts pattern with `dynamicCallouts` state and cleanup-on-unmount. Read this when building or modifying a click-through demo.
- **`references/gotchas.md`** — the iteration history. Read this when something doesn't render right despite following the rules — often it's a known race or layout trap.

The baseline template at **`assets/baseline-template.html`** is your starting point. It contains all the boilerplate (React + Tailwind + Babel CDN, primitives, StateShell, Tabs, Callouts, App with hash routing, one example state). **Always start from this template** — don't write the boilerplate from scratch.

## Architecture in one breath

```
single index.html
├── React + Tailwind + Babel + Lucide via CDN (no build step)
├── Inter font from Google Fonts
├── Stage = 1920×1080 16:9 div, scaled to fit viewport via transform: scale()
├── 320px symmetric gutters (where callout labels live)
├── Tab strip at the top (NOT sticky — it would cover top callouts)
├── State components, each rendered inside StateShell
├── Each state has its own _CALLOUTS array (id + side + anchor + label)
├── Callouts overlay reads view.callouts (or App.dynamicCallouts for demo views)
└── Hash routing (#s1, #demo-inbound, etc.) so views are linkable
```

## Three view types

| Type | Has callouts? | Has internal state? | Example |
|---|---|---|---|
| **Static state** | Yes — array on `view.callouts` | No | Home screen, Live ops dashboard |
| **Interactive demo** | Yes — per-step array via `dynamicCallouts` | Yes — `useState` for current step | Inbound walkthrough |
| **Flow diagram** | No — the layout itself is the explanation | No | Agent flow, Supervisor flow |

## The 7 visual rules for callouts

These rules are non-negotiable. Read `references/legend-lines.md` for examples and the math behind each one.

1. **Anchor on the section's edge facing its label.** Right-side label → dot on the element's right edge. Left-side label → left edge. Don't put the dot in the centre or the far edge.
2. **Leader is mostly a single straight run.** One horizontal or vertical segment from anchor to label. No diagonals through the wireframe.
3. **Bend only in the gutter, never over UI.** When the label sits at a different y from the anchor, the leader bends 16px inside the gutter — not over the wireframe stage.
4. **Comprehensive over minimal.** Aim for 5–8 callouts per main-shell state, covering each chrome column AND each section of the main-content area. Drop a callout only if the leader genuinely cannot avoid crossing other UI.
5. **Collision-avoidance push direction is fixed.** Top/bottom labels push right (later labels move x+). Left/right labels push down (later labels move y+).
6. **Overlay states annotate the overlay, not the underlying shell.** Modal / sheet / banner states draw callouts targeting overlay anchors. The dimmed shell underneath is context, not content.
7. **Closest path wins — for both `side` and `anchor`.** Pick the side whose gutter is NEAREST the anchor element. Then anchor on the element's edge facing that gutter. A banner at the top of the wireframe gets `side: "top"`, NEVER `"bottom"`. A toast in the top-right corner gets `side: "top"` (or `"right"`). For row-spanning components (a row of cards, a footer strip, a multi-column row), the dot lands on the outer ROW's edge — humans read that as "this row of components", not "this single column".

## Stage geometry (memorize these numbers)

| Knob | Value | Why |
|---|---|---|
| Stage design size | 1920 × 1080 | 16:9, kiosk-shaped, wide enough for 3-column shells |
| Outer max-width | 2400px | Lets stage hit 1:1 on wide monitors |
| Stage maxWidth | 1920px | Caps scale at 1.0 |
| Gutter | 320 px each side | Label width 230 + offset 60 + slack 30 |
| Top/bottom callout offset | 60 px | Breathing room above/below stage |
| Tab-bar clearance | mt-32 (128 px) | Top callouts must clear tab bar — see gotchas |
| Label width | 230 px | Fits ~2 lines of body copy |
| Label height (estimated) | ~32 px | Two-line labels grow upward from `bottom: …` |

Don't change these without good reason. The numbers are interlocked: `gutter ≥ label_width + offset` is a hard constraint, and the tab-bar clearance is what separates "labels are visible" from "labels are clipped above viewport".

## Workflow

### Adding a static state

1. Build the state component as a JSX function returning `<StateShell>...</StateShell>`. Reuse `Topbar`, `Sidebar`, `LeftCaseList`, `RightRail` shared components where they apply.
2. For each element you want to annotate, give it `id="a-something"` (descriptive prefix, kebab-case). For elements that should be highlighted with a 0-size dot, use a `<span id="a-..." className="absolute ..." data-callout-anchor="" />` inside the parent. The span's position determines where the dot lands.
3. Define `<NewState>_CALLOUTS = [{id, side, anchor, label}, ...]` next to the state. Apply rules 1–7. Aim for 5–8 entries on a main-shell state.
4. Register in `VIEWS`: `"key": {label: "User-facing tab label", group: "agent" | "sup" | "demo", render: NewState, callouts: NewState_CALLOUTS}`.
5. Add the key to the right group's tab list.
6. **Verify in the browser.** Use Playwright (or any browser) to measure: no clipping (label fits in viewport), no overlap with the tab bar, leader lines hit visible elements. See `references/gotchas.md` for the exact measurement queries.

### Adding an interactive demo

Read `references/demo-walkthroughs.md` first. Key pattern: the demo holds a `step` state, defines a `D{N}_STEP_CALLOUTS` array indexed by step, pushes the active step's slice via `useEffect` keyed on `[step, setCallouts]` with a **cleanup that nulls** `setCallouts(null)` on unmount. The cleanup is critical — without it you get stale callouts on tab switches.

### Fixing wrong callout placement

Symptom → first thing to check:
- **Label clipped at viewport edge** → gutter too narrow OR the outer container has `overflow: hidden` clipping the label box. Bump gutter to ≥ label_width + offset + 30.
- **Top label hidden behind tab bar** → tab bar is `sticky` (don't do that) OR top padding above stage is < tab_bar_height + ~50. Add `mt-32` to the stage wrapper.
- **Leader cuts across UI** → wrong `side` (you picked the far gutter) or wrong `anchor` (dot landed inside the element instead of on its edge). Apply rule 7.
- **Dot at zero-length leader** (label flush against wireframe edge) → element is at the wireframe edge AND `anchor` is on the same edge. Flip `anchor` to the opposite edge so the leader has visible travel, OR move the anchor to the outer row wrapper.
- **Leader points at the wrong row** when a section spans multiple columns → anchor span is inside ONE cell instead of the outer row. Add `relative` to the outer row wrapper and host the span there.

## When NOT to add a callout

- Pure flow views (the layout itself is the explanation).
- A second callout pointing at the same `id` as another callout in the same view (one is enough — duplicate IDs produce two leaders into the same dot).
- An element whose function is obvious from its on-screen label (a search box that says "Search…" doesn't need annotation).

## Output format

The deliverable is `index.html` in a directory you can recommend (e.g. `pocs/wireframe/index.html`). Open with `open index.html` or via a local HTTP server (`npx http-server -p 8767 -c-1`) — http-server is required if your demo or asset paths use `file://`-incompatible features.

Always alongside the HTML: write a short `README.md` that lists the views, hash routes, and which deck slides / spec docs each view derives from. This is the index a future contributor reads first.

## When the user says "iterate" or shows a screenshot of broken callouts

Don't redesign. The 7 rules + the gotchas catalog cover ~95% of issues. Read `references/gotchas.md`, identify the failure mode, apply the fix. If the user is on the first iteration of a new project, start from `assets/baseline-template.html` — copy it to their target path and extend.
