Writing · 11 min read
What does a product design engineer actually do?
The same thing a product designer does, carried into the codebase. The component is the deliverable, and the design system is a folder of files everyone can read. The judgment does not move. It gets attached to evidence. The worked example is Agent Review, a React and Storybook system I built.
Key idea 1 of 8
The handoff did not move; it dissolved
For years a design job was a document that went somewhere else. You made the file, somebody built from it, and quality leaked out in the gap between the two. AI coding tools moved that line. A designer can now build the thing, verify it and stand behind it.
I came to this from product design, enterprise design systems and UX architecture, not engineering. I now use React, TypeScript and Storybook to carry that work into code. The evidence is one project built that way, Agent Review, and this site.
There is no far side. A design engineer is a designer whose deliverable is the thing itself, in the repository, next to everyone else’s. Every decision now has evidence attached. It is code that runs, and a colleague can open it.
Key idea 2 of 8
The component is the deliverable, and it lives in one place
In a product codebase the unit of design is a component: a button, a data table, a status line, a card. In React it is a function that takes properties and returns markup.
In TypeScript the properties are typed, so the contract between design and engineering is a list the compiler reads, not a note in a Figma frame.
Agent Review has fourteen components, and the Button is the plainest of them: primary, secondary, danger or ghost, default or compact, loading, disabled. That is one file, and ten stories show its states.
Storybook is the showroom for that file. It renders every component in every state on a page a designer can open without running the product. It is the design system’s own site, generated from the system, and the artifact a design engineer most clearly owns.
Agent Review has 258 stories, and every story is also a test. Vitest renders it in Chromium and runs axe on it, with violations set to fail. A state with no story is a state nothing checks.
It replaces
- The spec that described the states in words
- The redline that measured the padding by hand
- The second copy of the button, drawn again in another file
- The question “is this the current version?”
It keeps
- The judgment about what a button is for
- The eye for a corner that reads as a lozenge at that size
- The argument for why the disabled state is quieter, not lighter
- The person who says no to a fifth variant
This site is the same idea at a smaller scale. It has three token files and a component set in plain HTML and CSS, with Node scripts standing where a build would. Agent Review was built to answer a design question rather than to ship a product.
Agent Review has one author, one scenario and no users. What I can say about it is what it taught me about the work. I have not run a production React codebase, and I would rather say that here than have it discovered.
Key idea 3 of 8
Tokens flow one way, from a file everyone can read
A design system that lives in code has one source for every value. It is a file of tokens, usually JSON, that says what --color-accent is and what --space-lg is.
A tool such as Style Dictionary turns that file into whatever each platform needs: CSS custom properties for the web, constants for iOS and Android, a table for the documentation. Tokens Studio does the same from inside Figma.
The file is upstream of everything, so parity between the design and the code is not a review step; it is the only way the values exist.
The design-engineer postings’ vocabulary comes from this file. A primitive token is a raw value with a plain name: a green, a size. A semantic token says what the value is for: the accent, the text on a dark ground, the inset of a panel.
Semantic tokens point at primitives, components point at semantic tokens, and nothing points at a hex code. Change the green in one place and every button, badge and link moves with it, on every platform, in one pull request.
The file has a third reader now, a coding agent. In Agent Review’s experiment both agent runs stayed on it. Every value they wrote was a token, with the rules in front of them and without.
The check runs the other way. A token lint reads every declaration against a typed list of the layer’s names. On the branch I seeded with the failures the rules forbid, it reported seventeen values written where a token existed.
I have done this part of the job longest, on the Fiori program and in this site’s color spec. It is where the tooling changes least.
My color spec tabulates every ink on every ground with its measured ratio. Agent Review’s token layer does the same in a form a build and a lint can read. What the pipeline adds is that the discipline no longer depends on anyone remembering it.
Key idea 4 of 8
A pull request is a design review with the evidence attached
A pull request is a proposed change to the codebase, with its reasoning written above it and its difference rendered below it. A design engineer spends more of the day there than in any tool with a canvas.
Reading a diff shows what actually shipped, not what was intended. Opening a pull request proposes a change engineering can accept with a click instead of a meeting.
The postings say “comfortable participating in pull request reviews.” At nine in the morning that means: read the change, open the story, press the states, and leave a comment on the line rather than in a channel.
Agent Review is my attempt at designing that review for a change an agent wrote. The change opens to its findings, with the affected screen rendered from the branch beside them, before and after, at three widths. Selecting a finding puts the preview in the state that shows it.
On a team the review also runs the other way. An engineer reads a component I wrote and sees the failure modes I do not. So the review is not a gate the design has to pass; it is the second pair of eyes the design has been missing.
On this site almost every change goes through a branch and a pull request too, and I read my own diff there beside the checks.
Key idea 5 of 8
The prototype is a branch, not a file
Here is the day for a change that starts as an idea, not a ticket.
- Briefthe problem in one sentence everyone recognizes
- Storythe component and its states, in Storybook, before the product
- Branchthe prototype, working, on real inputs
- Reviewan engineer reads the diff; the design gets its second pair of eyes
- Shipthe merge is the handover, and there is no other
The tools that changed this write code from a description. They are Claude Code in a terminal, which Agent Review was built with, and editors such as Cursor. A working prototype on a branch used to cost a week of an engineer’s time. The mechanical part of it is now a session. The time goes to the decisions rather than the syntax.
Agent Review’s experiment is that list run three times: one feature request, bulk actions on a customer table, on three branches. Two were written by a coding agent, one with the rules in its context and one without. I wrote the third by hand. All three open in the review tool as changes with findings.
What those tools do not take out is the judgment. The posting that says a design engineer should use AI without relying on it has the emphasis right.
The two agent runs read the same rule about shared components and did opposite things. One changed twelve lines of the shared Table stylesheet and showed its measurement of the head row before and after. The other measured the same defect and flagged it instead. Both were defensible, and it took a person reading the measurement to say which was right.
The prototype is real because I can read what it does, not because something wrote it quickly.
Key idea 6 of 8
Motion is code you can review
The craft the postings name most precisely is motion: easing curves, spring physics, transitions that can be interrupted halfway and reversed without a stutter.
In a design tool those are a demo somebody plays in a meeting. In the codebase they are a handful of values in the token file and a component that reads them: a duration, a curve, a spring’s stiffness and damping.
Framer Motion, now simply called motion, does the physics for React. Plain CSS transitions do most of the rest. A motion spec of six durations and one curve covers a whole site.
Code does not make motion easier to write, but it does make it reviewable. A transition can be opened in Storybook, played, interrupted, played again at a reduced-motion setting, and commented on by line.
A spring that overshoots by a hair is a number a colleague can change, and the change is a diff. That is what “design owns quality end to end” means in the one part of the interface where quality used to be unownable. Nobody could point at it.
Key idea 7 of 8
The checks are part of the design system
A design rule that is not a script is a wish. Contrast floors, type scales, token coverage and whether a toolbar fits its box at tablet width can all be measured on the rendered page. A design engineer makes sure they are.
Agent Review has three instruments for it, and each caught a different part of the branch I seeded with drift.
- A token lint fails when a component writes a value where a token exists.
- Vitest runs every story in Chromium with axe set to fail on violations.
- Playwright holds the screens to their visual baselines and every toolbar to its own box at 768.
- 17
- values written where a token existed, from the token lint, each with its file and line
- 2.87:1
- the contrast of the selection count, found by axe on the Selected story, against a 4.5:1 floor
- 792 vs 734
- pixels: the selection bar’s width against its box at 768, found by the toolbar check
The seeded branch also found a check that could not fail. The first version of the 768 test measured the frame’s scroll width. The bar’s parent clips its overflow, so a bar 58 pixels too wide passed. Checks are code, and code has defects. A branch built to fail is how you find which of yours cannot.
This site holds itself to the older, larger version of the same instinct. It runs ten checks, and five of them render every page in a real browser. I wrote them because the rules were written down and nothing held the pages to them. A design engineer is the person on the team who thinks a design rule is a test, and writes it as one.
The first pass found failures no eye had caught, a caption on the hero among them, which the craft article tells.
Key idea 8 of 8
A green check and a live site are two different facts
A green check means the tree passed. It does not mean the site changed. The merge and the deploy are two separate machines that fail independently. I learned that from a merge that ran every check, went green, and never deployed at all. The site did not look broken. It looked unchanged, which is indistinguishable from a change nobody made.
Another deploy failed fourteen seconds in, on a green tree, because it carried one file the deploy machine could not follow. And a page fetched straight after a successful deploy can still show the old bytes, because the host caches for ten minutes.
It says
- The tree can be packaged for the host at all
- Every token the specs name exists
- Every color clears its floor, at rest and under a press
- Every rendered size is a step on the scale
It does not say
- The deploy ran
- The deploy finished
- The cache has let go of the old page
- A reader can see the change
Agent Review had the same lesson in miniature. Its first visual pass found a dev server from a different checkout already on the port. It measured that tree and passed, including a comparison it could not have passed.
The fix was for the tests to start their own server and never reuse one. A check can be green and still have measured the wrong thing.
So the last step of every change is to look at the page a stranger would get, with a cache-buster on the address. When the page says nothing, read the log. The interface goes quiet exactly when the record gets interesting. Once you have been caught by the gap between “it passed” and “it is live,” you stop confusing the two.
The honest map of the job, for me, has three regions.
- Tokens, systems, accessibility and the checks around them. I have done this work longest, in enterprise programs and on this site. I would run it on day one.
- React, TypeScript, Storybook, branches, pull requests and tests. I do this work now, on Agent Review and on this site. I would expect to be fluent in a team’s own conventions within a quarter.
- A production React codebase with a team shipping to customers on a release train. I have not run one, and one project with one author is not a substitute.
I would rather write that last line here than have someone else write it about me.