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.htmlprototypes plus source (.jsx/.css/data.js). - A
PRD.mdand/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 epics1. 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):
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:
{
"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":
| Section | Must specify |
|---|---|
| Route & Data | Server load list, visibility / 404 rule, what's server-derived |
| Layout | ASCII desktop sketch with px/fr grid columns + mobile collapse rule |
| Component Tree | Named root → children (with optional/variant branches) + modals |
| Per-element tables | element · spec (size/copy/dimension) · RBAC/state |
| Tables / lists | Exact columns, filters, sort, pagination, empty state, row actions — via <DataTable>, never a hand-rolled <table> |
| Modals | Per modal: field · type · validation · default · copy |
| RBAC matrix | Every gated control × each role, incl. hard rules (e.g. "operator cannot set progress %"). Gated controls show a lock hint, not a hidden button |
| Mutations → audit | Each action → its log verb; actions return success (no redirect) → modal closes + list refreshes (revalidatePath + router.refresh()) |
| Style mapping | Each 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 |
| States | Empty · loading · error · lock (per-role) · mobile · variant-specific |
| Acceptance Criteria | Each 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:planregistered 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'sVisual refsheader.
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:flowexecutes them — pre-screen worktree-unsafe epics (shadcn-add, new deps, colliding migrations) and run those in-repo.- The
mockup-to-epicsskill (.claude/skills/mockup-to-epics/) is the canonical reference for this pipeline and is auto-loaded when you drop a design bundle.
See Also
- First Epic Walkthrough — the spec → implement → qa → pr pipeline an enriched epic feeds into.
- Custom Agents — author subagents for the parallel source-reading step.