.row { display: flex; flex-direction: row; gap: var(--space-400); padding: var(--space-600); align-items: center;}gap Hug ≈ fit-content. Fill ≈ flex: 1. Close — not equal.
Two vocabularies for the same product, separated by a gap the industry calls the handoff. This study follows what happens to that gap when Figma, code, design systems and AI agents start reading the same context.
Every handoffintroducesinterpretation.
The same pixelscan containvery differentinformation.
A and B render identically. Switch to structure to see what a developer — or an agent — actually receives.
Button / Primarycomponent: Buttonsize: mediumstate: defaulttoken: color.action.primaryspacing: space.300radius: radius.controlMore context.Less guessing.
.row { display: flex; flex-direction: row; gap: var(--space-400); padding: var(--space-600); align-items: center;}gap Hug ≈ fit-content. Fill ≈ flex: 1. Close — not equal.
:root { --color-action-primary: #2C47C9;} .button { background: var(--color-action-primary);}gap A variable is a value with a scope. A token is a decision with a name.
type ButtonProps = { variant: "primary" | "secondary"; size: "sm" | "md" | "lg"; loading?: boolean;};gap Variants enumerate what exists. Props constrain what is allowed.
import { Button } from "@/ui/Button"; <Button>Place order</Button><Button>Save address</Button>gap Overrides become props. A detached instance becomes a fork nobody tracks.
[data-theme="dark"] { --color-surface: #141412; --color-text: #EDEBE5;}gap Modes switch values. Themes also switch context: imagery, contrast, density.
async function onSubmit() { setState("loading"); const res = await placeOrder(cart); if (!res.ok) return setState("error"); router.push("/confirmation");}gap A prototype shows one path. Runtime has to handle all of them.
Not identical. Related intent, different representations.
Figma aligns in space.CSS aligns on axes.
Change direction: justify-content and align-items trade places.
flex-direction: row;gap: var(--space-400);/* 16px */justify-content: flex-start;align-items: center;padding: var(--space-400);width: fit-content;.name { flex: none; }One decision.Five representations.
"color.action.primary": { $value: "{color.brand.primary}" // resolves to #2C47C9 }
--color-action-primary: #2C47C9;
<Button variant="primary" /> // bg: var(--color-action-primary)
now color/brand/primary = Cobalt · production renders Cobalt
Create this button.
export function PlaceOrderButton({ onClick }) { return ( <button onClick={onClick} style={{ background: "#2D48CA", padding: "14px 22px", borderRadius: 7, fontWeight: 600, }} > Place order </button> );}import { Button } from "@/ui/Button"; <Button variant="primary" size="lg" type="submit"> Place order</Button><Button variant="primary" size="lg"/>+16 lines · 1 new file · 4 new values+4 lines · 0 new files · 0 new values
The best componentan agent generatesmay be the oneit doesn’t generate.
A designer can infer intent from a picture. A developer can ask a colleague. An agent reads names, types and metadata — and nothing else.
Semanticsare machine-readableintent.
Designfor humans.Structurefor machines.
One checkout, two readers. Drag the seam: left of it is what a person sees, right of it is what an agent can read.
Machine view of the checkout: CheckoutHeader (step 3 of 3); OrderSummary containing LineItems and Totals; ShippingAddress (filled, editable through AddressDialog); PaymentMethod (RadioGroup, card selected); Button (primary, large, default then loading, submits CheckoutForm).
“make this look like the Figma”
Ruled out by context: <a> · <div onClick> · secondary · ghost · lg · sm · #3050D0 · #1E3A8A · new <SubmitBtn> · type="button"
Prompting is not the interface.Context is.
Not looking.Traversing.
With a structured bridge to Figma and access to the repository, an agent queries names, variables, layout and metadata on one side, and finds components, props, tokens, patterns and tests on the other.
plan Reuse Button (primary · lg · loading) inside <Stack gap="400"> in CheckoutForm, bound to useCheckoutForm. No new components. No new values.
| Variant = Primary | variant="primary" |
| Size = Large | size="lg" |
figma.connect(Button, "Button", { props: { variant: figma.enum("Variant", { Primary: "primary", Secondary: "secondary", }), size: figma.enum("Size", { Large: "lg", Medium: "md" }), loading: figma.boolean("Loading"), }, example: (props) => <Button {...props} />,});<Button variant="primary" size="lg"> Place order</Button>Four instances.One component. Zero lookalikes.
system contextoffon
11 components · 9 values3 components · 2 token groups
Without system context, five screens produce five slightly different buttons, three modal patterns, three input components, five spacing values and four blues. With system context they consolidate into a shared Button, Dialog and Input, and shared space and color tokens.
The graph collapseswhen the system is in context.
Design = codeΔ 1 · radiusΔ 2 · radius · loadingΔ 3 · radius · loading · colorSynced
Sync is not a state.It is a process.
Every candidate is right — about something different. Hover a source to see what it is authoritative for, and what it borrows from the others.
| truth ↓ · source → | Figma | Code | Design system | Tokens | Documentation | Production |
|---|---|---|---|---|---|---|
| Design intentwhat we meant | authoritative | references | references | not concerned | references | not concerned |
| Runtime behaviorwhat actually runs | references | authoritative | references | not concerned | references | references |
| Rules & usagehow things may be combined | references | references | authoritative | references | references | not concerned |
| Shared decisionsvalues everyone agreed on | references | references | references | authoritative | not concerned | references |
| Rationalewhy it is this way | references | not concerned | references | not concerned | authoritative | not concerned |
| Actual experiencewhat users actually get | not concerned | references | not concerned | not concerned | not concerned | authoritative |
There may not beone source of truth.
There may bea network ofauthoritative sources.
screenshot → magic → code
Intent → structure → system → context → implementation
Same five steps as the handoff.Opposite direction of information.
In scene 01 meaning leaked out at every step. Here every step adds context — and the one element the system cannot place is flagged for a person, not invented.
type ProductCardProps = { product: Product; size?: "compact" | "regular"; state?: "default" | "soldOut"; onAdd?: () => void;}; // surface.raised · radius.surface · space.400// @container (min-width: 360px) → regularThe flow is becomingbidirectional.
Code can describe itself to design. It cannot decide what design should do with that description. The projection needs a reviewer.
The handoffis becominga loop.
Design, system, agent, code, production and feedback form a chain that closes into a loop, then becomes four mutually connected participants: Figma, design system, agent and codebase.
What changes whendesigners also workwith agents?
Not a button that says generate. An agent that works on the file’s structure, proposes a change, and leaves the decision where it belongs.
Do these names match how the team talks about the product?
<div onClick={submit} style={{ background: "#2D48CA", padding: "14px 22px", borderRadius: 7 }}> Place order</div>import { Button } from "@/ui/Button"; <Button type="submit" size="lg" loading={form.isSubmitting}> Place order</Button>AI-native developmentis a context problem.
userbuild this screen
<Stack gap="400"> <Field label="Card number" {...field("card")} /> <Button type="submit" size="lg" loading={pending}> Place order </Button></Stack>Generate less.Discover more.
Namingis part ofthe interface.
The design systemis becomingan API for intent.
Automationdoes not removejudgment.
Agents can gather the evidence for every one of these questions. None of them is answered by the evidence alone.
AI changes the boundary.It does not erase responsibility.
Regions move. The accountable name on each decision does not.
| decision | accountable | executed by |
|---|---|---|
| requirements | product | product |
| intent | designer | designer |
| interaction | designer | designer |
| visual hierarchy | designer | designer |
| runtime | engineer | engineer |
| performance | engineer | engineer |
| architecture | engineer | engineer |
| shared rules | designer + engineer | designer + engineer |
| translation | designer + engineer | agent, reviewed |
| discovery | engineer | agent, reviewed |
| execution | engineer | agent, reviewed |
If code can generate design, and design can inform code, what is Figma for?
Pick a moment. The roles overlap; the moment decides which one leads.
Not a replacement question.A role question — and the role moves.
More connected.Not more magical.
No pass goes straight from intent to done. Each review sends the work back to a different place — that is what a loop looks like when it is working.
Context qualitychanges output quality.
Choose what the agent receives, then read what it “implements”. The outputs are hand-authored to show the mechanism — no model is running here.
// components/NewPayment.jsximport { useState } from "react"; export function NewPayment() { const [card, setCard] = useState(""); return <div style={{ display: "flex", gap: 13 }}> <input placeholder="Card number" /> <div onClick={pay} style={{ background: "#2D48CA" }}> Pay now </div> </div>;}Design is notbecoming code.
Code is notbecoming design.
The boundaryis becomingprogrammable.