TL;DR
- The model skims your prompt, reads your types carefully, and treats your seed data as gospel.
- Three short happy-path rows produce a demo UI. Twenty messy rows produce a real one.
- Write the fixture before the Figma frame and before the prompt.
- Ship four fixture variants per entity: populated, empty, loading, error.
- Same prompt + different seed = different product.
The single biggest change to my design-to-code workflow this year wasn't a new tool. It was moving the seed data file from the end of a feature ticket to the front. Once the fixture leads, the model starts building the UI the fixture implies — and the fixture, unlike a Figma frame, is something engineers, PMs, and designers can all edit in the same file without merge pain.
Here's the workflow, why it works, and the specific shapes of seed data that make the model produce good vs. bad output.
The design brief the model actually reads is your seed data
When you ask an LLM to build a dashboard, it doesn't read your prompt as tightly as you think it does. It reads:
- The prompt (skimmed)
- The type definitions (carefully)
- The seed / mock data (as gospel — this is what the UI has to accommodate)
If your mockUsers.ts has three users, all with 4-character first names and no avatars, the model builds a UI that assumes short names and shows initials. If your mockUsers.ts has 40 users with a mix of "Amélie", "李", "Björn-Alexander", and one 60-character corporate email address, the model builds a UI that truncates, wraps, and reserves space for avatars — because the data forced it to.
Same prompt. Different seed. Different product.
Before / after: same prompt, two seed files
Prompt (identical in both runs): "Build a customer list page with a search bar and a table."
Seed A (what most people ship as a fixture)
export const customers = [
{ id: 1, name: "Alice", email: "a@x.com", plan: "pro" },
{ id: 2, name: "Bob", email: "b@x.com", plan: "free" },
{ id: 3, name: "Cara", email: "c@x.com", plan: "pro" },
];
What the model built: a table with 4 columns, left-aligned, no empty state, no pagination, no plan badge styling — just plain text.
Seed B (fixture designed to stress-test the UI)
export const customers = [
{
id: "cus_9f3a2b",
name: "Alice Chen",
email: "alice@acme.co",
plan: "pro",
mrr: 149,
lastActiveAt: "2026-07-28T14:20:00Z",
signupAt: "2024-03-11T09:00:00Z",
avatarUrl: "https://...",
tags: ["enterprise-lead", "champion"],
},
{
id: "cus_1c8d",
name: "Bob", // deliberately short — tests min-width
email: "bob.a.verylonglocalpart@somecompany.example.com", // tests truncation
plan: "free",
mrr: 0,
lastActiveAt: "2025-11-02T03:11:00Z", // stale, tests "inactive" styling
signupAt: "2025-10-30T09:00:00Z",
avatarUrl: null, // tests fallback initials
tags: [],
},
// ... 38 more, including one with a right-to-left name, one with a null email
];
What the model built off Seed B: a table with plan badges (because plan was one of a known set), a relative-time formatter for lastActiveAt (because dates were varied and some were old), avatar fallbacks with initials (because one was null), email truncation with a tooltip (because one was long), and a tag chip row under each name.
Same prompt. The seed did all the design work.
A seed-first workflow: fixtures before figma, fixtures before prompt
The order I now run:
- Write the fixture first. Before Figma, before a prompt, before a ticket description — write the 15-20 rows of seed data that represent the full messy reality of the domain. Long names. Missing fields. Stale timestamps. One extreme outlier.
- Show the fixture to the PM and the designer. This is faster than a mock. Everyone can look at the JSON, argue about whether "tags" is actually a thing, whether MRR should be integer cents or a float, whether we care about right-to-left names. Alignment happens in 20 minutes instead of 2 days.
-
Then draft the Figma / write the prompt. Both now reference the fixture as the source of truth. Designer sizes components to accommodate the longest string in the seed. Prompt says "build the UI implied by
fixtures/customers.ts, using the design tokens intheme.ts." - Model generates. Because the fixture is comprehensive, the UI is comprehensive on the first pass. Iteration count drops.
On our team the average "draft to reviewable UI" time went from ~3 hours to ~50 minutes once we moved to this order. Not because the model got faster — because the inputs got denser.
Anti-patterns: the 3 seed shapes that make AI output collapse
Seeds that reliably produce bad AI code:
- The three happy rows. Every field populated, every string short, every date recent. The model builds a UI that only works for demos.
- The single-row seed. Model can't infer variability, so it builds no empty state, no pagination, no sort. You'll fix all of these later.
- The lorem-ipsum seed. Placeholder text with no semantic hints. "lorem ipsum dolor sit amet" doesn't tell the model whether this is a title, a bio, or a comment. Ambiguous input, ambiguous output.
Good seeds are boring to write and dramatic in effect. Budget 30 minutes per feature for them. It's the highest-ROI 30 minutes in the whole cycle.
A repeatable folder structure
What we settled on across three products:
src/
fixtures/
customers.ts # 15-20 rows, messy realism
customers.empty.ts # explicit empty state fixture
customers.loading.ts # skeleton fixture (shape only)
customers.error.ts # error object fixture
...
Every fixture file has four variants: populated, empty, loading, error. The prompt then reads "build the four states for customers using the fixtures in src/fixtures/customers.*" and gets all four screens in one generation pass, instead of one screen that assumes data always exists.
Storybook picks up the fixtures automatically for visual regression. Playwright picks them up for E2E. Designers can open the JSON in a code sandbox and edit values live. One artifact, four consumers, and it lives in the repo where it can be code-reviewed.
If you're setting up a new project and don't want to reinvent this scaffolding, the fixture-per-state pattern is the kind of workflow default that lives inside a good template starter — see the ones on AppLighter for how the fixtures/, stories/, and e2e/ folders wire together on day one so the model has good bones to build against from your first prompt.
The general principle is simple enough to fit on a sticky note: the model doesn't design your product from your prompt. It designs it from your data. So design your data first.
What does your fixture file look like right now — three happy rows, or the messy version? Drop a comment with the nastiest edge case you deliberately seed in.
Top comments (0)