I'll explain what I mean.
The setup
I had a Figma file with a full website design and a Shopify Horizon theme that needed to match it. Eleven sections on the homepage. Five sub-pages. A product template. Mobile and desktop. The kind of job where you sit down on a Monday and look up on Thursday wondering where the week went.
The temptation was to feed the whole Figma to Claude and say "build this." That doesn't work. The model can't see what it's building. It writes some Liquid, it can't tell whether the result looks right, it keeps editing, and three hours later you have a homepage that's vaguely correct and nothing's matched the design.
So I gave up on doing it in one shot and built a loop instead.
The loop
Six steps. Same six steps every section, every page.
- Slice the Figma. Open the full-page PNG export in Python with Pillow, crop out just the section I'm working on, save it to a scratch folder.
- Screenshot the live render. Headless Chrome at 1440 wide, pointed at the local Shopify dev server, save the result next to the Figma slice.
- Write a gap list. Open both PNGs. Write down what's different, in bullets, grouped by layout / typography / colour / imagery / content. Be specific. "Heading is wrong" is useless. "Heading copy should be 'Better for little ones' not 'Better for the little ones', and the font weight should be 800 not 600" is useful.
- Decide where to fix each gap, smallest blast radius first. JSON template setting before section schema setting before Liquid markup before section CSS before global CSS. Most fixes turn out to be JSON.
- Edit. Wait three seconds for the file watcher to push. Re-screenshot.
- Compare. Iterate or move on. Three-pass limit - if you can't close the gap in three passes, something's off (usually you're missing an asset, or a brand call has to be made by a human).
Then commit. One commit per section. Move to the next section. Repeat.
The trick
The model isn't the trick. The model can stitch together Liquid and CSS just fine. The trick is the model being able to see its own output. Without screenshots, it's writing into a void. With screenshots, it's running its own QA loop.
The whole thing hinged on three boring infrastructure choices:
- Figma exported as a single full-page PNG, not the live Figma API. Local file, no rate limits, no auth, slice with PIL in a hundred milliseconds.
- Headless Chrome for screenshots, not a browser driver. Open the URL, take a PNG, exit. No browser state to manage.
- A
.scratch/folder, gitignored, for every Figma slice and every live screenshot. Treat it as ephemeral scratch space. Don't try to organise it.
That's it. Once those three things were in place, the model could run the loop without me in it.
The gotchas
You always find some.
The dev server needed an interactive password prompt the first time. The model can't type that. So the dev server runs in a separate terminal I keep open, the model talks to it over HTTP, and when it dies I bring it back up myself.
The CSS file watcher misses new files sometimes. Touch the file or restart the CLI. Cost: thirty seconds, every two days or so.
Image references uploaded via the admin Files section don't always resolve in local dev. The fix is to fall back to a theme asset URL. Worth knowing before you waste an hour wondering why a logo is blank.
Headless Chrome's --window-size isn't a perfect mobile viewport at 360-400 pixels. At 1440 it's reliable. For mobile, double-check on a real device.
Default JSON templates get auto-edited by the Shopify admin theme editor. The local file gets a /* this file is auto-generated */ comment header. Don't fight it. Just keep editing the JSON underneath. The comment is harmless.
There's a CSS rule in Horizon's base.css that makes the last section flex-grow to fill the viewport on short pages. Good for cart and empty pages. Disastrous for screenshots taken with a tall window-size. Either use a tighter window or accept the trailing white gap.
The compounding gain
Here's the thing I didn't expect. Each section taught the model the patterns for the next section. By the time we got to the third or fourth section, decisions that would have taken thirty back-and-forth messages were getting made in one. "The eyebrow uses a yellow color from scheme-5" stopped being a question. "Cards in this section should be boxed with a circular icon backdrop" stopped being a question. The model had internalised the brand patterns.
So the loop got faster as it went. The first section took maybe forty minutes of polish. The fifth section took ten. By the time we got to the secondary pages, I was bringing them to a clean state in twenty minutes total per page.
The commit cadence helped too. One commit per section is annoying at first - six commits to ship one homepage feels excessive. But when you're three days in and a section regresses, you can git revert exactly one section without touching the rest. The granularity buys time on the back end.
What I'd tell someone starting
If I were starting fresh tomorrow, I'd do three things:
One: do the boring setup first. Figma exports saved locally. Dev server running in its own terminal. Scratch folder gitignored. Pillow installed. Get all of that out of the way before you start polishing anything.
Two: pick one section. Just one. Run the full loop on it. Don't move on until that section matches. The shape of the loop matters more than which section you start with.
Three: trust the model to drive the loop, but read every gap list it writes. The gap lists are where bad decisions hide. If a gap list says "deferred - looks fine," but you know it doesn't look fine, push back. If a gap list says "needs an asset I don't have," believe it and supply the asset.
The result
By the end of the project, the model was producing pixel-close output to the design across every page. Not because the model got smarter mid-project, but because the loop got faster and the model's pattern memory got deeper.
The whole thing is, in retrospect, embarrassingly simple. Take a screenshot. Compare to the reference. Write down what's wrong. Fix it. Take another screenshot.
It's the same thing a junior designer would do at the start of their career, just executed by a language model on a thirty-second cycle instead of a human on a thirty-minute cycle.
The loop is the product.