Codex vs Claude

Mockup to Code: The Component Matches the Picture, Which Is the Problem

David Guzenburg/ / 10 min read

The generated markup matches the mockup exactly. The mockup is one width, one state, and the copy the designer happened to type.

toolingdesignconventionscode review

A mockup specifies one viewport, one state, one dataset

Handing a design to an agent and getting a component back is the most impressive-looking thing in this category, and the most quietly lossy. The generated markup will match the image. That is the problem: the image is a single sample of a system, and a component that matches one sample has hardcoded everything the system was supposed to vary.

A real interface has breakpoints, states, content of unpredictable length, and semantic structure. A PNG of a design has one width, one state, the copy the designer typed, and no semantics at all. Code generated from it encodes those absences as fixed values, and the fixed values are invisible until the day someone's name is long.

What the image genuinely carries

Structure, mostly. The agent can see that this is a card grid, that the sidebar is fixed and the content scrolls, that the header has a search field and an avatar cluster on the right, that there are three tiers of type and roughly what the rhythm between them is. Layout intent survives the translation to pixels well.

It also carries relative proportion. The agent can tell that the gutter is about twice the internal padding, that the card radius is small rather than pill-shaped, that the shadow is subtle. For getting from nothing to a screen that reads correctly, this is a large amount of signal, and it arrives in one step.

The four things it cannot carry

Breakpoints. A 1440-wide mockup says nothing about what happens at 390. The agent will guess, usually by stacking things, and the guess will be wrong in the specific way that a designer would have made a different decision about which element drops first.

States. Hover, focus, disabled, loading, error, empty, and the one where the list has one item instead of nine. None of these are in the picture. A component generated from a populated screen typically has no empty state at all, which is the state your users will see on their first day.

Content variance. The mockup's card titles are two words because the designer chose two words. Real titles are sometimes forty characters, and the layout in the image has no opinion about what happens then. Truncation, wrapping and minimum widths are decisions the picture does not contain.

Semantics. A pixel-perfect reproduction of a navigation bar built from <div> elements looks identical and is not a navigation bar. Headings, landmarks, lists, buttons versus links — the distinctions that assistive technology depends on are invisible in a rendering, and the agent's guess is driven by visual appearance rather than role.

The pixel-value trap

This is the tell that a component came from an image, and it is worth learning to spot in review.

<!-- Measured off the picture. Matches at 1440, matches nothing else. -->
<div class="mt-[13px] gap-[19px] p-[21px] text-[15px]
            rounded-[7px] w-[327px] shadow-[0_2px_7px_rgba(0,0,0,0.07)]">

<!-- Snapped to the scale the rest of the codebase uses. -->
<div class="mt-3 gap-5 p-5 text-sm rounded-md w-full max-w-sm shadow-sm">

Every arbitrary value in the first block is a measurement of an anti-aliased edge. Thirteen pixels is twelve pixels plus a rounding error. Nineteen is twenty. The agent is not being careless; it is reading pixels, and pixels are what it was given.

Arbitrary values are how a design system dies

One component with bracketed values is harmless. Twenty of them and your spacing scale no longer describes the product, so the next person measures off a screenshot too, because the tokens have stopped being true. Ban arbitrary values in the linter and the pressure resolves the right way.

Extract tokens first, build second

The reordering that fixes most of this: do not ask for a component. Ask for the design decisions, review those, then ask for the component constrained by them.

{
  "spacing_scale_observed": [4, 8, 12, 20, 32],
  "radius": { "card": 6, "control": 4, "avatar": "full" },
  "type": [
    { "role": "page-title", "px": 24, "weight": 650 },
    { "role": "card-title", "px": 15, "weight": 600 },
    { "role": "body",       "px": 14, "weight": 400 }
  ],
  "elevation": "single soft shadow, ~2px offset, low alpha",
  "uncertain": [
    "gap between cards measured 19-21px; assuming 20",
    "cannot determine focus treatment from a static image",
    "sidebar behaviour below 1024px not shown"
  ]
}

The uncertain array is the most valuable part of the file. It is the agent telling you what it had to guess, which converts four silent assumptions into four questions a designer can answer in a minute. Ask for it explicitly; models will happily produce confident output with no uncertainty section if you do not.

Give it the system, not just the picture

An agent generating UI in a repository that already has a design system should be reading the system, not inventing from the image. That means the token file, two or three existing components as reference, and an explicit instruction that new values are not permitted — if a spacing does not exist in the scale, it should say so rather than reach for brackets.

This is a specific instance of the general point in encoding architecture constraints: the constraint has to be present in context at the moment the code is written, because a constraint enforced only in review is a constraint that gets argued about after the work is done.

Where the generated component is simply correct

Throwaway prototypes. Internal tools with one viewport and known users. Marketing pages that genuinely are one fixed layout. A first pass that a human will restructure but that saves an hour of typing. In all of these the missing breakpoints and states are missing because they do not exist, and the pixel values are fine because nothing else in the file uses a scale.

It is also fine as a comprehension aid. Handing over a competitor's screenshot and asking how a layout is likely constructed produces a genuinely useful answer, and nobody is going to ship it.

Reviewing UI code that came from a picture

Six things, in order. Are there arbitrary bracketed values, or does it use the scale? Does an empty state exist? Does it survive a title three times longer than the mockup's? What happens at 390 pixels? Are the elements semantically what they appear to be — buttons that are buttons, headings in order, a <nav> that is a <nav>? Is there a visible focus style on every interactive element?

Five of those six are absent from the image by definition, which is why review has to look for them specifically rather than comparing the result to the mockup. Comparing to the mockup only verifies the part that was never at risk.

The loop that actually works

Mockup in. Tokens out, with uncertainties, reviewed by a human. Component built against the existing system with new values forbidden. Then a screenshot of the built component at several widths, compared back against the design — the technique from screenshot-driven UI debugging, run in the other direction.

That last step is what makes the whole thing closed-loop. Without it the agent has produced code it has never seen rendered, from an image it can no longer check against, which is exactly the situation in which a component looks right in the file and wrong on the screen.

The honest summary of the capability

Image-to-code compresses the boring part of implementation, which is real value and should not be dismissed. It does not compress the design work, because the design work is mostly decisions about the cases the picture does not show, and no amount of visual fidelity in the model changes that.

Treat the output as a first draft of the markup and never as a specification of behaviour, and the capability is straightforwardly useful. Treat it as a finished component and you have shipped a design system of one screen, at one width, in one state, with the empty case missing.

A data connection beats a picture, when you can get one

Everything above is about working from pixels because pixels are what you have. When the design tool itself is reachable, the whole problem changes shape: instead of measuring a rendering, the agent reads the properties — the actual spacing value, the actual token name, the actual font weight, the constraints that say what happens when the frame resizes.

That is a different quality of input, and it removes the entire category of error this article is about. There is no thirteen-pixel margin, because the value in the file is twelve and the agent read twelve. That route has its own trade-offs, and it is the subject of reading design tokens through MCP.

The reason to know both is that the picture route remains the common one. Most designs reach engineering as an image in a ticket, a screenshot in a chat, or a PDF, and will continue to. Knowing what that format cannot carry is what lets you ask for the missing parts rather than discovering them in staging.

Two failures that look like success

The first is the reviewer comparing the implementation to the mockup and approving it. That comparison verifies the only property that was never at risk. The agent optimised for matching the image; of course it matches. The review needs to look at the cases the image does not contain, which means the reviewer needs a checklist rather than a reference picture.

The second is more subtle: the component works, ships, and becomes the pattern. Someone building the next screen reads it as an example of house style and copies the bracketed values, because copying an existing component is exactly what you want people to do. One generated component with arbitrary values does not damage a design system. One generated component that becomes the reference does, and there is no signal distinguishing the two at the moment of review.

The defence is the linter rather than vigilance. A rule that rejects arbitrary spacing values costs nothing to add and removes the entire propagation path, which is worth more than any amount of care applied one pull request at a time.

Screenshots of other people's products

A common use is handing over a competitor's interface and asking how it is likely built. This is legitimately useful for understanding a technique and it is worth being clear about what you are producing.

Layout analysis is fine. Reproducing a distinctive visual identity is a different act, and an agent will do it without hesitating because nothing in the request signals a boundary. Trade dress, a recognisable component language, an icon set with a licence — these do not become yours because a model retyped them. Use the analysis, discard the markup, and never let a generated reproduction of someone else's interface reach a branch where it can be mistaken for original work.

What this changes about the estimate

The honest accounting: image-to-code compresses implementation, which was maybe a third of the work, and does nothing for the other two thirds. The missing states, the breakpoint decisions, the content variance, the semantics and the accessibility pass were always the bulk of building a real component, and they are unchanged.

Teams that plan around the demo — screen appears in ninety seconds, therefore the screen is a ninety-second task — end up with a schedule built on the compressible third. The screen appears quickly and then takes the same three days it always took, and the three days now feel like a failure rather than the work.

Takeaway

A mockup is one sample of a system: no breakpoints, no states, no content variance, no semantics. Code generated straight from it hardcodes those gaps as bracketed pixel values measured off anti-aliased edges. Ask for tokens and an explicit list of uncertainties first, review those with a designer, then build against your existing system with new values forbidden — and close the loop by screenshotting the built component at several widths and comparing back.

Keep reading
Codex vs Claude

Constructing SVG Icons in Code: viewBox, currentColor and the Rest Is Detail

What to check first in agent-written SVG: the coordinate contract, colour inheritance, non-scaling strokes, the labelled-versus-decorative decision, and a twenty-line linter that replaces the review comment you keep repeating.

Codex vs Claude

Generated Placeholder Assets: Borrowing Against a Design You Have Not Made

Agent-generated placeholder icons unblock a build and quietly ship to production. Path conventions no production file may import, a four-line CI gate, watermarks, and the provenance record that makes the licensing question answerable.

Codex vs Claude

One Agent, Many Surfaces: They Share a Model and Nothing Else

Terminal, editor, desktop, browser and hosted runner are different tools sharing an account. What differs, why consistency has to come from the repository, verifying permission denials per surface, and choosing a surface by the shape of the task.

Codex vs Claude

Why Claude Code Draws in SVG: Missing Tool, Not Missing Eyes

The reason an agent writes vector rather than raster is a tool list, not a rendering engine. What follows: source that diffs, deterministic rasterisation in the build, and where vector genuinely loses.

← Mobile Task Handoff or Workstation-Bound Sessions?  ·  Optimising SVG: The Byte Count Reports the Saving, Not the Damage →

All codex vs claude articles  ·  Every article