Designer Frontend Contract
designer-frontend-contract/
Freeze an approved mockup into a reference, port it 1:1 on any stack, and verify every page, state and breakpoint with screenshot diffs before merge.

The tech-agnostic contract between designer and frontend dev, and the gate that mechanically enforces it.
Why use it
- "Matches the design" asserted from a screenshot glance, while a whole page region is missing.
- The build quietly re-styles the mockup, and the drift is only noticed after launch.
- HTTP 200 and a green CI badge say nothing about whether the UI is actually right.
What it does
- Designer side: freeze the approved mockup into a canonical oracle: manifest, baseline renders, a region/element inventory, token parity, a visual acceptance contract.
- Frontend side: port the oracle 1:1 (transcribe, never redesign) and self-gate census → DOM → pixel before handoff.
- Verifier side: independently screenshot every page × access state × pinned breakpoint against the frozen baseline; census FIRST, then pixel diff, then interaction hit-testing.
- Report-only verification: findings route to the dev (drift) or the designer (a legitimate design change).
Benefits
- Ship what was actually designed. Fidelity becomes an enforced gate, not an assumption.
- Catch the missing region the pixel diff would have waved through.
- No more launch-day drift: every page, state and breakpoint is checked before merge.
- Any stack. Dev server, template language and tokens all come from your project config.
Install
Download this skill and copy the designer-frontend-contract folder to .claude/skills/designer-frontend-contract/ in your project, or to ~/.claude/skills/designer-frontend-contract/ to use it in every project. Claude Code finds it on its own; you can also call it with /designer-frontend-contract.
Part of the Web Dev Design Pipeline bundle. To get the whole set as a Claude Code plugin: /plugin marketplace add endorphin-ai/hasbrains-agent-kit, then /plugin install web-dev@hasbrains-agent-kit.
Source: endorphin-ai/hasbrains-agent-kit. License: MIT.
Files (18)
Files
---
id: frontend-port
title: CONSUMER — consume the acceptance contract, port the oracle 1:1, self-gate census→DOM→pixel
summary: The frontend dev's playbook — read the six binding inputs from the design spec + oracle-manifest.json, verify token parity on the project's single styling source, transcribe the oracle in two passes (static 1:1, then interactivity without DOM change), self-gate every component AND assembled page/state with census→DOM→pixel until census 100% + under threshold, report evidence, write back the docs/frontend/ KB + deviations ledger. What the frontend owes the designer, made mechanical.
tags: [contract/consumer, contract/port, contract/self-gate]
aliases: [port the oracle, consume the contract, two-pass port, visual regression port, port rule]
load_when: Building or fixing a page that has a frozen oracle + a visual acceptance contract.
links: [[contract-and-communication]], [[region-census]], [[fidelity-checks]], [[designer-handoff]]
---
<!-- Related notes: [[contract-and-communication]] · [[region-census]] · [[fidelity-checks]] -->
TASKLANG
TYPE WORKFLOW
IDENTITY "Frontend Port Playbook (consumer side of the contract)"
> The consumer side: how the frontend dev builds to the frozen baseline and PROVES the
> match before handing off. PORT, don't re-derive — authoring a page fresh from memory
> is what drops whole regions. Order: consume → parity → PASS A → PASS B → gate →
> assemble → re-gate → report + KB write-back. Stack facts (template language, binding
> whitelist, token source, settle signal) resolve from `{config.frontend_runtime}`.
---
## Steps
0. **CONSUME the contract first.** From the design spec + `docs/design/oracle-manifest.json`,
read and record the SIX binding inputs:
1. the **canonical oracle file** (resolved via the manifest — never pick among candidates),
2. the **baseline renders** dir,
3. the **region/element inventory** (`docs/design/<page>-inventory.md`),
4. the **pinned breakpoint widths**,
5. the **pixel-diff threshold** per breakpoint (+ named exclusions),
6. the **PORT RULE** (the template-language binding whitelist).
If ANY is missing → `[CONTRACT-GAP]`: ask the designer / the orchestrator
([[contract-and-communication]] §4). Do not guess a threshold, invent styling, or pick
an oracle yourself.
1. **VERIFY TOKEN PARITY before porting.** The oracle and the build must render from the
project's ONE declared token source per `{config.frontend_runtime}` (e.g. CSS custom
properties in `:root`, a utility-framework config, a CSS-in-JS theme — read the
declaration, never assume which kind). Render one ported region and confirm a token
(e.g. `var(--cta)`) resolves to the SAME computed value the oracle shows. If a token is undefined or diverges, fix the token source FIRST —
porting onto a divergent token source guarantees a failed diff everywhere. Load the SAME
fonts (`@font-face` + `font-display`) the frozen oracle self-hosts. Copy the oracle's
literal styles verbatim; reference token NAMES, never raw values where a token exists;
never introduce a second styling source.
2. **PASS A — static 1:1 port (no logic).** Open the canonical oracle and TRANSCRIBE it
element-by-element into the project's template language (typically a near-superset of
HTML — copy the markup, then apply only the mechanical escaping/attribute mapping the
language requires, e.g. JSX's `class`→`className`):
- Preserve **every tag, style, class, attribute** exactly; same DOM tree, same order,
same `data-test` hooks.
- **No** dynamic values, **no** event bindings, **no** component extraction, **no**
cleanup, **no** "simplify".
- **NEVER** redesign, swap classes, collapse/merge containers, reorder regions, or
substitute markup-changing components.
- Gate PASS A at the static level before adding logic (cheap to diff, easy to localize).
3. **PASS B — interactivity without touching layout.** Layer behavior onto the frozen
markup WITHOUT changing the rendered DOM/CSS: inject ONLY the stack's dynamic bindings
per the PORT RULE whitelist — dynamic values/interpolation, event/controller bindings,
iteration for repeated regions, conditionals for stateful regions (examples per stack in
`{config.frontend_runtime}`: LiveView `{@assigns}` + `phx-*`; Hotwire instance vars +
Turbo/Stimulus `data-*`; React props + handlers). Extract reusable components ONLY where
the extraction emits the IDENTICAL markup it replaced — extraction is a refactor of
source, not of output. Gating-aware components take entitlement/locked state IN as
props/attrs — they never read session state or call the authz layer themselves. Every
data-bearing component renders loaded/loading/empty/error + any locked branch the spec
defines.
4. **SELF-GATE per component/page — census FIRST, then DOM, then pixel.** Loop until green:
1. **Completeness census** ([[region-census]]): every inventory region + interactive
element PRESENT in the build, in order, none extra — ticked off by `data-test` hook.
A whole missing region is a BLOCKING defect. Census must be 100% before spending a
DOM or pixel diff. (Same census the verifier runs — pass it here first.)
2. **DOM diff:** compare the built tag tree + per-node class/style lists against the
oracle. Catches dropped attrs, tag swaps, reordered/missing nodes, missing hooks —
failures a pixel diff can miss or mislocate. Any structural delta = fail; fix.
3. **Pixel diff per pinned breakpoint:** screenshot built page vs baseline render
(agent-browser, or Playwright `toHaveScreenshot()` / pixelmatch / odiff with
`maxDiffPixelRatio` = the contract threshold). Feed the diff regions back, fix the
cause (usually a parity gap or a stray class), re-render, re-diff.
4. **Loop** until census 100% + DOM match + every breakpoint under threshold. Never
advance with an open miss — drift compounds. Contract-EXCLUDED regions are masked and
recorded as WAIVED diffs with reasons — never silently widen the threshold.
5. **RE-RUN the gate on ASSEMBLED pages.** A component passing in isolation can drift once
composed into the real page (layout context, wrapper classes, live/pushed content).
After pages are wired, re-run census→DOM→pixel on each FULL page in EACH access state
the project defines (including any locked/paywall variant and populated dashboards), at
all pinned breakpoints. The match must hold end-to-end.
6. **PROVE the interactions.** Before reporting done, drive a REAL browser (the `agent-browser`
CLI, Playwright, or a browser MCP): for each built page × each reachable access state, CLICK every control (links,
buttons, menu open + items, form submit, toggles, modal open/close) AND hit-test real
clickability (`elementFromPoint` at the control's centre resolves to the control, not an
overlay); walk the full UI-reachable entity lifecycle (create → read → edit → delete
where the entity supports it). Never report done with an unclickable, obscured, or dead
control — a feature is EXERCISED, not loaded.
7. **REPORT the evidence + WRITE BACK the KB.** Hand back per page per breakpoint: census
result, DOM-check pass, final pixel-diff %, waived diffs + reasons, interaction-proof
matrix — evidence screenshots to `.ai_log/`, paths + key fields to the run's handoff state (never inlined blobs).
Then update `docs/frontend/`: one atomized file per new/changed reusable component
(path, prop/slot contract, variants, states, `data-test` hooks, where used), the
page→component map, and the **deviations ledger** in `design-system-in-use.md` — every
departure from the design library recorded and raised to the designer, never silently
shipped ([[contract-and-communication]] §4). A page with a census miss, over threshold,
or an unexplained DOM delta is NOT done — it is a build defect, not a redesign
opportunity.
## The fidelity loop (measurable 1:1)
consume the contract + manifest → verify ONE token source → PASS A (static transcription) →
PASS B (interactivity, DOM unchanged) → census→DOM→pixel per component (loop) → assemble →
re-gate full pages × states × breakpoints → prove interactions → report evidence + KB
write-back + deviations ledger.