Design Handoff skill for Codex
Specs engineers can build without a meeting. Codex turns a design into a spec an engineer can build from without follow-up questions. Every element is mapped to an existing component or flagged as new, spacing references tokens, a state matrix covers hover, focus, disabled, loading, error and empty, and responsive, motion, accessibility and content-length rules are written down. The spec ends with acceptance criteria a reviewer can tick.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- design-handoff Installs to ~/.agents/skills/design-handoff/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install design-handoff The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project design-handoff Installs to .agents/skills/design-handoff/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/design-handoff.zipunzip -o design-handoff.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) design-handoff PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
104-line POSIX script. No sudo, no telemetry. Read install.sh
Use it in Codex
Start a prompt with $design-handoff, or pick it from /skills.
You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.
What Codex reads before loading it
Prepares design-to-engineering handoff specs that leave nothing to guess - token-referenced measurements and redlines, a full component state matrix, responsive rules per breakpoint, interaction and motion specs, accessibility notes (roles, focus order, labels), content limits and truncation, asset exports, and acceptance criteria. Works from Figma Dev Mode, screenshots or an existing build. Use when handing a design to developers, writing a UI spec or redline document, or when implemented screens keep drifting from the design.
Use it when
- A design is ready and engineers need a complete spec
- Built screens keep drifting from the approved design
- Mockups show only the default state and nobody has specified the rest
- You need acceptance criteria to review a UI implementation
Use something else when
- You are writing the code from a Figma file yourself: use figma-to-code
- You need to create or restructure the token system: use design-tokens
How to check the result
An engineer can implement every element and state from the spec without asking a question, and the finished build passes each written acceptance criterion at every breakpoint.
The mistake it prevents
Handing off only the default state, so loading, error, disabled and long-content cases get improvised during implementation.
A handoff is complete when an engineer who was not in any design meeting can build the screen, every state included, without asking a question, and a reviewer can check the result against written acceptance criteria. Values reference tokens, never raw pixels pulled off a mockup.
Inputs to gather first
- The design source: Figma file and frame links (Dev Mode, variables), exported PNGs, or a prototype. Note the file version or date.
- The codebase’s design system: tokens file, component library, Storybook
(
rg -l "createTheme|@theme|tokens\.json|style-dictionary" .,ls src/components). ReadAGENTS.mdfor naming and where specs live. - The flow the screens belong to, and which states the designer drew.
If the design uses values that are not tokens (a 13px gap, an off-palette gray), list them as questions rather than inventing new tokens.
Workflow
- Map every element to an existing component or mark it as new.
- Specify layout and spacing in tokens; redline only what is not obvious.
- Fill the state matrix for every interactive and data-driven element.
- Write responsive rules at each breakpoint.
- Specify interactions, motion, accessibility and content rules.
- Export assets; list them with formats.
- Write acceptance criteria; review with the designer; file open questions.
1. Component mapping
| Element | Component | Variant / props | New? |
|---|---|---|---|
| Plan cards | `Card` | `variant="outlined"`, selected state | No |
| Seat stepper | - | - | New: `QuantityStepper` |
| Price | `Text` | `size="2xl" weight="semibold"` | No |
New components get their own section with anatomy (named parts), props and states. Prefer extending an existing component over a near-duplicate.
2. Layout and redlines
Write layout as rules, not coordinates:
Page: max-width `--container-lg` (1120px), centred, side padding `--space-6`.
Plan grid: 3 columns >= 1024px, gap `--space-6`; cards equal height; stack below 768px.
Card: padding `--space-6`; title -> price `--space-2`; price -> features `--space-5`.
Primary button: full card width, pinned to card bottom (cards align their buttons).
Redline (annotated measurements) only where a rule would be ambiguous: optical offsets, overlaps, non-grid alignment. If you produce a visual redline, generate an HTML overlay on the real screenshot so it stays editable:
<div style="position:relative;width:1440px">
<img src="plan-select.png" width="1440">
<div style="position:absolute;left:160px;top:312px;width:24px;height:1px;background:#e5004c"></div>
<span style="position:absolute;left:162px;top:296px;font:600 11px system-ui;color:#e5004c">space-6 / 24</span>
</div>
3. State matrix
Every interactive or data-driven element gets one row per state. Missing states are the main source of improvised UI.
| Element | Default | Hover | Focus-visible | Active | Disabled | Loading | Error | Empty | Selected |
|---|---|---|---|---|---|---|---|---|---|
| Plan card | outlined | border --border-strong | 2px ring --focus | - | n/a | skeleton | - | - | border --accent, check icon, aria-checked="true" |
| Continue button | primary | primary-hover | ring | pressed | when no plan, with helper text | spinner, label kept, aria-busy | - | - | - |
| Seat stepper | value 1 | - | ring on input | - | at min/max bounds per side | - | “Max 500 seats” below | - | - |
Also specify page-level states: first load, slow load (over 1 s), API error, no
permission, and partial data. Wording goes through $ui-copy-states.
4. Responsive rules
| Breakpoint | Change |
|---|---|
| < 640 | Cards stack; sticky bottom bar holds total + Continue; comparison table becomes accordion |
| 640-1023 | 2-column grid; third card wraps full width |
| >= 1024 | 3 columns; comparison table visible |
Text never truncates on prices or plan names; feature lists clamp at 6 with "Show all".
Use the breakpoints the codebase already defines.
5. Interaction and motion
- Selecting a card selects its radio; arrow keys move between cards (radiogroup).
- Seat stepper: typing allowed; clamps on blur; long-press repeats every 100 ms.
- Total price updates without layout shift; number crossfade 150 ms `--ease-out`.
- Reduced motion: no crossfade, instant update.
6. Accessibility
- Roles and names: plan cards are a
radiogrouplabelled “Choose a plan”; icon buttons havearia-label. - Focus order follows visual order; after “Continue” errors, focus moves to the first invalid field.
- Contrast pairs referenced by token and checked (
$color-contrast-accessibility). - Targets at least 24x24 CSS px (44 on touch layouts).
- Headings: one
h1, logicalh2per section.
7. Content rules
| Field | Max length | Overflow | Localisation |
|---|---|---|---|
| Plan name | 24 chars | never truncate; wrap | allow +35% length (German, Finnish) |
| Feature item | 60 chars | wrap to 2 lines | - |
| Price | - | currency from locale; Intl.NumberFormat | RTL mirrors layout, not numbers |
8. Assets
List each asset with format and source: SVG for icons and illustrations (optimised,
currentColor where it should inherit), AVIF/WebP plus fallback for photos with sizes
for srcset, and fonts already in the system. In Figma Dev Mode, export from the
asset’s frame, not a screenshot crop.
Acceptance criteria
Write checkable statements, not “matches the design”:
- [ ] At 1440, 1024, 768, 375 widths the layout matches the responsive table.
- [ ] All values come from tokens; no new hard-coded colors or spacing (grep clean).
- [ ] Each state in the matrix is reachable in Storybook or by a documented step.
- [ ] Keyboard: tab reaches every control in order; arrows move within plan cards.
- [ ] Screen reader announces "Team, radio button, 2 of 3, selected".
- [ ] Visual diff against approved screenshots under 1% per viewport (if tooling exists).
Gotchas
- Figma auto layout and CSS differ: Figma “space between” with one child, absolute children, and text box heights (line-height trimming) do not map 1:1. Spec intent.
- Mockups show perfect data. Specify the 0, 1, many and very long cases explicitly.
- Designers draw hover but rarely focus-visible, disabled-with-reason, or loading. The state matrix catches this; ask instead of inventing.
- Pixel values measured from a 2x export are double. Check the export scale.
- A spec that duplicates the token values (hex codes beside token names) goes stale; refer to token names, and link the token file.
Verification
- Walk the spec as the implementer: for every element, can you write the code without a question? Each “it depends” becomes an open question.
- Grep the design for values without a token and confirm each is listed.
- After implementation, compare screenshots at each breakpoint and tick acceptance criteria one by one.
Output template
# Handoff: <feature> (<design link>, version <date>)
Owner: <designer> Engineer: <name> Status: draft | ready | in build
## Scope and flow
## Component mapping
## Layout
## State matrix
## Responsive
## Interaction and motion
## Accessibility
## Content rules
## Assets
## Acceptance criteria
## Open questions
| # | Question | For | Blocking? |
Related: implementing from Figma directly with $figma-to-code; adding missing tokens
with $design-tokens.
What the zip contains
SKILL.md plus the interface file below. Nothing runs on install.
agents/openai.yaml
Gives the Codex app a display name, a one-line description and a starter prompt for this skill.
interface:
display_name: "Design Handoff"
short_description: "Specs engineers can build without a meeting"
default_prompt: "$design-handoff Write a developer handoff spec for this plan selection screen from Figma" About this skill
Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.