learn-ai-design-with-phoebe / Designer session 9 of 10
Learn AI Design with Phoebe · Designer track · Session 9 of 10

Handoff to code

This is the hardest session in the designer track, and the one that decides whether any of the previous eight mattered. Everything you have built - the direction, the tokens, the imagery rights, the words - leaks in exactly one place: the gap between the mock you approved and the screen a user loads. Tonight you write a spec an engineer can build from without asking you a single question, you learn precisely how AI reaches your design system at handoff time and where each route is gated, and then you review the built result the only way that counts: by measuring the thing in a browser.

🔴 Designer track Product · brand · design-adjacent builders Design to build 45 min
0-2 · Where the design leaks 2-18 · The spec + the AI routes 18-42 · Build-along: spec, then verify 42-45 · Q&A
Part 1 · the artifact that survives you

A spec an engineer can build from 7 min live

The test of a handoff is not whether it looks thorough. It is whether an engineer who has never spoken to you can build the screen correctly and know when they are done. That means the spec names token names rather than hex values, so a colour change later does not silently detach; component and variant names from the real system, not descriptions of appearance; spacing in scale steps, not measured pixels; every state enumerated - empty, loading, partial, error, offline and both string extremes; interaction and focus behaviour, including keyboard order; responsive rules stated as breakpoint intent rather than pixel-perfect mocks at three widths; and accessibility written as acceptance criteria - contrast pairs, target sizes, reading order, focus visibility. The first four are usually there. The last four are what go missing, and they are the ones that come back as bugs.

USUALLY IN THE HANDOFF USUALLY MISSING - FILE AS DEFECTS Token names, never hex values colour.surface.raised, not the sampled colour Every state enumerated empty, loading, partial, error, offline Component and variant names Button/secondary, Card/summary - the real names Interaction and focus behaviour keyboard order, focus ring, escape, hover Spacing in scale steps space-3, not "about 24 pixels here" Accessibility as criteria contrast pairs, target size, reading order Responsive rules by intent what reflows and why, not three exact mocks String extremes longest and shortest plausible text, drawn A spec is done when an engineer can build it and know when they are finished without asking you. The right column is not extra polish. It is the half of the spec that becomes next quarter's bugs.
🔍 Click to zoom - spec anatomy, with the four sections most often missing marked
LiveWhy token names beat hex values, every time4 min▶

A hex value in a handoff note is a fact about today. A token name is an instruction about forever. The difference shows up six months later when the surface colour changes: everything referencing colour.surface.raised moves, and everything that was sampled by eye and typed in by hand stays behind. Those hand-typed values are invisible in a screenshot and invisible in a Figma inspection - the only way to find them is to look at the code or ask.

  • Same for spacing. "24px" is a measurement. "space-3" is a decision that stays consistent when the scale is retuned.
  • Same for type. "20px semibold" is a description. "text.title.m" is the third rung of the 1.25 scale from b6 and cannot drift off it.
  • Same for components. "the grey button" is an appearance. "Button/secondary" is a contract, and if the design needs something the variant cannot do, that is a system conversation rather than a one-off override.

The habit to build: when you cannot name a token for something you drew, you have either found a genuine gap in the system or drawn something off-system. Both are worth knowing before an engineer discovers it for you.

Self-studyTwo handoff notes for the same card4 min read▶

Same Cadence shared-summary card. The first note describes how it looks. The second one can be built and accepted.

Describes appearance - every line invites a question

"Summary card with a light plum background and rounded corners, roughly 24px of padding. Title in a slightly larger semibold, then the AI note in small grey underneath, then the body. Share button bottom right in the brand colour. Should look good on mobile too."

Names tokens, components, states and acceptance criteria

"Component: Card/summary. Surface colour.surface.raised, radius radius-m, padding space-4 all sides, internal stack gap space-3. Title: text.title.m, colour.text.primary, 2 lines max then ellipsis. Disclosure line: text.body.s, colour.text.secondary, sits ABOVE the body in both DOM and visual order. Body: text.body.m, colour.text.primary. Action: Button/primary, label "Share summary", 44x44 minimum hit target, sits after the body in reading order. States required: empty (no summaries), loading (skeleton, no spinner), partial (transcript still processing - show what exists plus the low-confidence banner), error (send failed - message plus retry), offline (read-only, Share disabled with reason). String extremes: title at 4 and at 90 characters, both drawn. Responsive intent: below the medium breakpoint the action becomes full-width and moves below the body, and the disclosure line stays above the body. Acceptance criteria: every text and background pair passes WCAG 2.2 SC 1.4.3 at its computed size and weight; the button boundary passes SC 1.4.11 at 3:1; every interactive target meets SC 2.5.8 at 24x24 CSS px minimum; focus is visible on every interactive element; tab order is title, disclosure, body links, Share."

The second note is four times longer and roughly forty times cheaper, because every line in it is either buildable or checkable. Notice that nothing in it is a picture. A mock shows one state at one width - the spec is what covers the other fifteen.

Part 2 · the routes, and what gates them

How AI actually reaches your design system 8 min live

"AI can read our design system" is a sentence that hides five different mechanisms with five different gates. Knowing which one you are on decides whether token automation is realistic for your team or a demo you saw once. The single most important constraint: the Figma variables REST API is Enterprise-only - you must have a Full seat in an Enterprise org - so below Enterprise the selection-scoped MCP call is the only route to your tokens. The second most important: Figma Code Connect's framework-specific parsers lose updates and support from 2026-08-17, after which template files are the only maintained path. Both are dates and seat tiers, not opinions, so put them in your plan rather than your hopes.

RouteWhat it carriesGateFailure mode
Figma Code Connect The bridge between your codebase and Dev Mode, so a Figma component maps to the real component in code Dev or Full seat on Organization or Enterprise Framework-specific parsers lose updates and support from 2026-08-17. After that, template files are the only maintained path - plan the migration, do not discover it
Figma MCP server Remote https://mcp.figma.com/mcp or desktop http://127.0.0.1:3845/mcp. get_design_context (which replaced get_code), get_variable_defs for the variables and styles in the selection, get_code_connect_map, get_code_connect_suggestions, and remote-only search_design_system Figma seat plus an MCP-capable client get_variable_defs is scoped to the selection. It answers "what tokens are in this frame", never "what is our whole token set", so it is a handoff tool rather than a sync
Figma variables REST API Programmatic access to variables - the route people assume exists when they plan token automation Enterprise only - a Full seat in an Enterprise org Below Enterprise it simply is not available, and the selection-scoped MCP call is your only token route. This is the constraint that kills most token-automation plans
v0 (Vercel) Production Next.js / React / TypeScript / Tailwind / shadcn code. Design Systems 2.0 stores your system as a skill naming where the source lives and which components, props and tokens are safe to use, written to a v0.json Paid plan for real use - Free is limited, and Figma import needs a paid plan Once GitHub is connected, in Vercel's own words "it becomes the source of truth for your project". That is a genuine handoff, and it means the design file stops being the source of truth
Figma Make A working prototype, a downloadable code zip, a one-way GitHub push, and paste-back into Figma Design Code editing needs a Full seat on a paid plan Both bridges are lossy. The GitHub push is one-way and edits made in GitHub get overwritten on the next push, and pasted-back output produces layers that "aren't automatically tied to your design system"
LiveChoosing a route without lying to yourself4 min▶

Three honest questions, in order, and the answer falls out.

  • Are you on Enterprise? If yes, the variables REST API is available and real token automation is on the table. If no, stop planning a sync. You are on selection-scoped get_variable_defs through MCP, which is excellent for handing one frame's tokens to an engineer or an assistant and useless as a pipeline.
  • Does a real component library already exist in code? If yes, Code Connect is the highest-value route because it makes Dev Mode point at the actual component - and you now have the 2026-08-17 parser deadline on your roadmap. If no code library exists, Code Connect has nothing to connect to and v0's Design Systems 2.0 skill is the more realistic way to tell a generator what is safe to use.
  • Is the output going to production or to a conversation? v0 with GitHub connected is a production handoff and the repo becomes the source of truth. Figma Make is in-Figma prototyping with two lossy bridges, so treat its output as an argument, not an artifact.

The common mistake is picking a route by which demo was most impressive. Pick by seat tier and by whether code already exists, then design your handoff around what that route can actually carry.

Self-studyWhat "AI reads our system" does not mean3 min read▶

Every one of these routes moves a description of your system, and a description is not enforcement. Three things stay yours:

  • Nothing here prevents an off-system value. A generator handed your token list can still emit a hand-typed colour, and the result looks identical in a screenshot. The only way to catch it is to inspect the built code or measure the built screen, which is Part 3.
  • Selection scope is a real limit, not a beta. get_variable_defs returning the variables and styles in a selection is the design of the tool. Handing it a frame with three tokens and concluding your system has three tokens is a category error people make weekly.
  • Source-of-truth is a decision, and one of these routes makes it for you. When v0 has GitHub connected and the repo is the source of truth, your Figma file becomes documentation. That can be the right call - it just has to be a call, made out loud, rather than something you notice a month later.
Part 3 · where all the earlier work leaks

Reviewing what actually shipped 6 min live

The design-to-shipped gap is the drain every previous session empties into. A mock is a claim; the built screen is the product. So run the five checks from b5 on the built screen, in a browser, not on the file you approved - because computed values are what users get. The rounding, the inherited line-height, the token that was almost right, the padding that got typed in by hand: none of those exist in the mock and all of them exist in the browser.

Measure the built screen Not the mock ▶ Computed values are what ships File differences as defects
LiveWhat to look at in the inspector4 min▶

You do not need to write code for this. Open the built screen, open the browser inspector, and read four things - all of them computed, all of them arguable-free.

  • Real contrast ratios. Not the pair you specified, the pair that rendered. Opacity, overlays, inherited colours and a background image behind text all change the answer. Check at the computed font size and weight, because size and weight decide whether you owe 4.5:1 or 3:1.
  • Real spacing values. Read the computed padding, margin and gap. Anything not on your scale step is a defect even if it looks fine, because it means a value was typed rather than referenced.
  • Real font sizes. Count the distinct computed sizes on the page. If your scale has four rungs and the built screen has seven values, three of them came from somewhere you did not decide.
  • Focus order. Put the mouse away and press Tab through the whole screen. Watch where the focus ring goes and whether you can always see it. This is the check that finds reading-order bugs the eye cannot.
Self-studyFiling a difference as a defect, not a preference3 min read▶

The reason design feedback gets deprioritised is that most of it arrives as taste. Rewrite it as a failed criterion and it enters the same queue as every other bug. The shape:

  • Where - the screen, the component, the state. "Shared summary card, offline state."
  • Expected, in spec language - "disclosure line at text.body.s in colour.text.secondary, above the body in DOM order."
  • Actual, as a measurement - "13px, computed #B9A9B6 on #FFFFFF, ratio 2.1:1, and it comes after the body in the DOM."
  • The criterion it fails - "WCAG 2.2 SC 1.4.3 requires 4.5:1 at this size and weight." Cite the acceptance criterion you wrote in Part 1, which is exactly why you wrote it.

Two habits make this land. Separate the measurable list from the judgement list and send them as two different messages - a defect list gets fixed, a taste list gets discussed, and mixing them turns the whole thing into a discussion. And never file a difference you did not measure, because one wrong number in a list of ten costs you the other nine.

Self-studyUsing an AI reviewer here, honestly3 min read▶

An assistant looking at a screenshot or a chunk of code is genuinely useful at this step and genuinely unreliable in specific, predictable ways. Use it as a suspect generator, never as the measurement.

  • It is good at spotting missing states, naming what looks off-system, drafting the defect list from your notes, and reminding you which criteria you have not checked yet.
  • It hallucinates ratios. Asked for a contrast ratio it will produce a confident number that is often wrong. Ratios come from the inspector or a contrast tool, and this is the same failure mode you saw in b5.
  • It cannot see provenance. Looking at a rendered screen it has no way to know whether a colour came from a token or was typed in by hand. Those look identical, and the difference is the entire point of the handoff.
  • It reads the mock as reality. Hand it a design file export and it reports on the design, not the build. The whole argument of this session is that those are different documents.

So the working split: the assistant proposes the list of things to check, you measure, and only measured items get filed.

Build-along

Spec the Cadence summary, then verify it ★ 22 min · everyone runs it

Two halves. First you write the shared-summary spec using the anatomy from Part 1 - tokens, components, spacing steps, states, interaction, responsive intent, acceptance criteria. Then you verify a built result the way Part 3 says to. The lab below runs with all five levers on, which is 100 out of 100: this is what acceptance looks like - 100 with nothing measurably broken. Every value in that score is computed from the rendered screen, which is precisely the standard you are asking your engineer to hit.

Write the header. Component name, variant, surface token, radius token, padding and gap in scale steps. If you cannot name a token, mark it as a system gap now rather than shipping an override.

Enumerate the states. Empty, loading, partial, error, offline, plus the longest and shortest plausible strings from b8. Six rows minimum. This is the section that is always missing.

Write the interaction and responsive rules. Tab order, focus visibility, what happens on escape. Responsive stated as intent - what reflows, what moves, what stays - rather than three exact mocks.

Write the acceptance criteria. Contrast pairs by criterion number, minimum target size, reading order matching visual order, focus visible everywhere. These are the lines you will quote when you file defects.

Now verify. Run the lab with all five levers on, read the rows at 100, then Tab through the rendered screen and check the focus ring. Anything you cannot see is a defect you can file with a criterion attached.

What is real here, honestly The starting draft is scripted - the same composite of unbriefed generator output from b1. Every score is measured live in your browser: contrast ratios from the WCAG relative-luminance formula, spacing and font sizes read from getComputedStyle, hue families counted by converting each rendered colour to HSL. That is the point tonight. The lab is doing to a rendered screen exactly what you should be doing to your built screen, and it is why a mock cannot produce this number.
★ And now the honest caveat, one session before the capstone A 100 means nothing is measurably broken. It does not mean the work is good. The concept review still has to happen - is there an idea in this screen, is there one deliberate point of tension, is it right for this brand and this user at this moment. Acceptance criteria protect you from shipping something broken. They cannot protect you from shipping something forgettable, and b10 asks for both: a 100 on the lab plus a stated idea you can defend out loud.
1 · SPEC tokens and criteria 2 · BUILD engineer or generator 3 · MEASURE BUILT in a real browser 4 · FILE DEFECTS criterion, not taste 5 · RE-MEASURE until nothing fails THE MOCK IS A CLAIM one state, one width, drawn values THE BUILD IS THE PRODUCT computed values are what users get Acceptance is a measurement on the built screen, not a sign-off on a picture of it. A hand-typed value and a token look identical in a screenshot. Only the browser can tell you. And 100 with nothing broken is still not the same as good - the concept review is a separate pass.
🔍 Click to zoom - the acceptance loop, which closes on the build rather than the mock
Homework

Try it yourself - this week ◐ 35-45 min total

Source material

Official sources covered

This session covers handoff quality and the documented behaviour of the routes AI takes into a design system - not how to build the component, which stays with engineering. Seat tiers, tool names and deadlines were read from official documentation and are the kind of thing that moves, so re-check before you build a plan on them. This page covers:

✓Figma Code Connect - seat requirements and the 2026-08-17 parser deadlinePart 2 · template files become the only maintained path
✓Figma MCP server - endpoints and the token-relevant toolsPart 2 · get_design_context replaced get_code · get_variable_defs is selection-scoped
✓Figma variables REST API - Enterprise-only, and what that forcesPart 2 · the constraint that decides whether token automation is possible
✓v0 Design Systems 2.0 and Figma Make's two lossy bridgesPart 2 · source-of-truth and overwrite behaviour, in the vendors' own words
◐WCAG 2.2 as acceptance criteria - SC 1.4.3, 1.4.11, 2.5.8, focus and reading orderParts 1 and 3 · stated as criteria here · taught by number in b5
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · Your team is on a Figma Professional plan and wants to automate token sync. What is actually available to you?

The variables REST API requires a Full seat in an Enterprise org, so below Enterprise the selection-scoped MCP call is the only token route - excellent for handing one frame's tokens over, useless as a pipeline. Worth pairing with the other date in this session: Code Connect's framework-specific parsers lose updates and support from 2026-08-17, after which template files are the only maintained path.

2 · Why run the five checks on the built screen rather than on the approved mock?

The mock is a claim about one state at one width using drawn values. The browser reports what rendered: inherited line-heights, overlays and opacity changing a contrast pair, a padding that was typed rather than referenced. A screenshot cannot distinguish a token from a hand-typed value that happens to match, which is the whole reason acceptance happens in the browser.

3 · You ask an AI reviewer to check the built screen. What must you not take from it?

It flags suspects well and drafts lists well. It hallucinates ratios with total confidence, and it cannot see provenance at all - a token and a hand-typed value are identical on a rendered screen. So the assistant proposes what to check, you measure it, and only measured items get filed. One wrong number costs you the credibility of the whole list.

Designer session 9 cheat sheet · pin this

Spec anatomyToken names · component and variant names · spacing in scale steps · every state · interaction and focus · responsive intent · accessibility as criteria.
Always missingStates, focus behaviour, accessibility criteria and string extremes. That half of the spec is next quarter's bug list.
Names, not valuescolour.surface.raised not a hex, space-3 not 24px, Button/secondary not "the grey button". A value is a fact about today.
Code Connect deadlineDev or Full seat on Organization or Enterprise. Framework-specific parsers lose updates and support from 2026-08-17 - template files are then the only maintained path.
Token routesVariables REST API is Enterprise-only. Below that, selection-scoped get_variable_defs via the Figma MCP server is your only route - and get_design_context replaced get_code.
Lossy bridgesv0 with GitHub connected becomes the source of truth. Figma Make's GitHub push is one-way and gets overwritten, and paste-back layers are not tied to your design system.
Measure the buildReal contrast ratios, real computed spacing, count of distinct font sizes, Tab order. The browser, not the mock.
File as defectsWhere · expected in spec language · actual as a measurement · criterion failed. Measurable list and taste list go in separate messages.