Skip to content

Mockup → UI-Ready Epics

This guide walks through turning a mockup HTML handoff into UI-ready, build-grade epics — epics so detailed a build agent can implement each screen pixel-aligned without ever opening the mockup.

A standard /athena:plan epic describes intent ("build the case list"). A mockup handoff already contains the answers — exact fields, validation, layout, copy, states, RBAC branches. The job here is to capture those answers in the epics so the build agent doesn't re-guess and drift from the design.

When to Use

Reach for this pipeline when someone drops a design bundle on you — typically a Claude-Design / HTML handoff containing:

  • A README.md ("handoff from Claude Design") naming the primary file and intended fidelity.
  • A project/ folder of .html prototypes plus source (.jsx / .css / data.js).
  • A PRD.md and/or a domain-knowledge doc.

Trigger phrases: "implement this mockup", "make the epics align to the HTML", "the epics look too simple / like a recipe".

The Pipeline

read handoff → run + screenshot → read source in full → inventory codebase → write epics

1. Read the handoff contract first

Read the bundle README.md — it names the primary file the user had open and the intended fidelity. Then read any PRD.md and domain-knowledge doc: these are the SSOT for rules (RBAC, status enums, delete policy, alert thresholds, vocabulary).

When sources conflict, the domain doc + the latest user decision win over the prototype.

2. Run it and "play" it (visual ground-truth)

The source is authoritative for function; screenshots are authoritative for layout / visual hierarchy / interaction. Capture both.

  • A self-contained single-file offline HTML loads via file://.
  • A multi-file prototype needs python3 -m http.server.

Use the screenshot helper (Playwright + Chromium ship with next-app):

bash
node scripts/mockup/shot.cjs <abs-path-to-html> <out-dir> [tour.json]

Capture every screen × each role (switch via demo-login personas or a tweaks panel), key modals, and mobile (390px). Persist the shots into the repo (e.g. docs/_handoff/screenshots/) so epics can reference them durably.

A tour.json drives the capture — click into modals, switch roles, and change viewport between shots:

json
{
  "steps": [
    { "name": "01-dashboard", "viewport": [1440, 900] },
    { "name": "02-case-list", "clickText": "案件管理" },
    { "name": "03-new-case-modal", "clickText": "新增案件" },
    { "name": "04-case-detail", "clickSelector": "tr[data-case-id='C-001']" },
    { "name": "05-dashboard-mobile", "clickText": "首頁", "viewport": [390, 844] }
  ]
}

If the bundle README says "don't screenshot", that's its default — the user asking for shots overrides it.

3. Read each screen's source IN FULL

For each screen's source file, read every line (not a summary). Extract:

  • Exact field names + types
  • Validation rules (e.g. "weights must sum to 100%", "note required")
  • Conditional / RBAC-gated rendering
  • Copy strings (keep the original language)
  • Layout dimensions (grid columns, widths, row heights, breakpoints)
  • Empty / loading / error / lock states
  • Every mutation + what it logs

Parallelize with subagents

When there are many screens, fan out — one subagent per 1–2 screens, each returning a structured inventory. This is the slowest step done serially and the easiest to parallelize.

4. Inventory the codebase + surface conflicts

List what already exists (schema, auth/RBAC, routes, reusable components, design tokens) so epics say "reuse <DataTable> / <Dialog> / audit_log" instead of rebuilding.

Identify conflicts that need a human decision — role model, login method, scope — and surface them via AskUserQuestion before writing epics. Resolving "is the mockup's operator role the same as our editor?" up front prevents an entire batch of mis-scoped epics.

5. Write epics from the template

Use docs/epics/_templates/ui-spec-epic.md. Run /athena:plan to register the epic list + dependency DAG first, then enrich each epic to the depth below.

What a UI-Ready Epic Must Contain

Every UI epic MUST carry all of the following — anything missing means it's still a "recipe":

SectionMust specify
Route & DataServer load list, visibility / 404 rule, what's server-derived
LayoutASCII desktop sketch with px/fr grid columns + mobile collapse rule
Component TreeNamed root → children (with optional/variant branches) + modals
Per-element tableselement · spec (size/copy/dimension) · RBAC/state
Tables / listsExact columns, filters, sort, pagination, empty state, row actions — via <DataTable>, never a hand-rolled <table>
ModalsPer modal: field · type · validation · default · copy
RBAC matrixEvery gated control × each role, incl. hard rules (e.g. "operator cannot set progress %"). Gated controls show a lock hint, not a hidden button
Mutations → auditEach action → its log verb; actions return success (no redirect) → modal closes + list refreshes (revalidatePath + router.refresh())
Style mappingEach prototype primitive + design token mapped to a real target (Card<Card>, Modal<Dialog>/<Sheet>, ProgressBar<Progress>, var(--brand)bg-primary). Recreate the visual output — do not copy the prototype's inline-style structure
StatesEmpty · loading · error · lock (per-role) · mobile · variant-specific
Acceptance CriteriaEach tied to a specific UI element + behavior + copy, plus pnpm typecheck + pnpm test + pnpm build green

Build a UI-foundation epic FIRST

The shared primitives (design tokens, shared components, missing shadcn parts like progress / textarea / date-picker, mobile nav) gate every screen. Make it the first epic in the entity phase.

The Quality Bar

Before declaring an epic "UI-ready", self-check:

  • Could a build agent implement the screen pixel-aligned without opening the mockup?
  • Is every modal's validation explicit? Every list's columns / filters / sort / pagination?
  • Is every RBAC branch + its lock-hint copy specified?
  • Does the style-mapping name a real target component for each primitive?

If any answer is "no", it's still a recipe — keep enriching.

Worktree Caveat

Not all epics are /athena:flow worktree-safe

Epics that run npx shadcn add, add new dependencies, or add colliding migrations are not safe to run in an isolated worktree — they mutate shared, non-mergeable state. Pre-screen for these (the UI-foundation epic is the usual culprit) and run them in-repo, not via a /athena:flow worktree.

Keep the design bundle committed in-repo so /athena:flow worktree agents can read the source + screenshots at build time.

Worked Example — 瑞成工程專案管理系統

docs/_handoff/ handoff

The docs/_handoff/ handoff (a Claude-Design bundle for an engineering project-management system) ran through this exact pipeline:

  • /athena:plan registered 17 epics, E282–E298.
  • Each was enriched roughly 10× against the mockup source — e.g. E291 grew 55 → 307 lines once its fields, validation, RBAC matrix, and style mapping were filled in.
  • Screenshots live in docs/_handoff/screenshots/ (01-dashboard.png, 03-cases.png, 04-case-detail.png, 07-wizard.png, role/mobile variants, …) and are referenced from each epic's Visual refs header.

The 10× growth is the signal that the epics moved from intent to answers.

Integration with athena

  • /athena:plan (mockup mode) produces the epic list + dependency DAG; this pipeline defines their depth. Run plan to register epics, then enrich each with the template.
  • /athena:flow executes them — pre-screen worktree-unsafe epics (shadcn-add, new deps, colliding migrations) and run those in-repo.
  • The mockup-to-epics skill (.claude/skills/mockup-to-epics/) is the canonical reference for this pipeline and is auto-loaded when you drop a design bundle.

See Also

Released under the MIT License.