Generate two or three alternative layouts in minutes with v0-class tools, harvest the best ideas, then re-implement on your design system. The throwaway boundary is the whole discipline: prototypes are for deciding, and the code that ships is written against your primitives, your tokens, your tests.
Tier: Foundation · Workflow area: Component development · Tools: v0, Claude artifacts, Cursor
Prompt-to-UI tools are the fastest ideation instruments frontend has ever had — and the fastest way to pollute a codebase with off-system markup if you paste their output straight into a PR. This playbook gives you a repeatable exploration loop with a hard line between "prototype" and "production."
Write one exploration brief and reuse it verbatim across tools. Divergence between outputs should come from the model, not from you rephrasing. Keep the brief about the problem, not the implementation:
Design a billing-history screen for a B2B SaaS app. Users: finance admins
who reconcile 50-500 invoices/month. Must support: filter by status
(paid/overdue/void), date-range picker, bulk export, per-row actions
(download PDF, resend). Density matters more than whitespace. Show the
empty state and the "filters returned nothing" state too. Desktop-first,
1280px. Do not use a data-fetching library; hardcode 12 realistic rows.
Fan out to two or three generators in parallel. Paste the brief into v0 (v0.dev), a Claude artifact, and optionally a scratch Cursor project. For the Cursor variant, isolate it so nothing touches your repo:
mkdir ~/scratch/billing-explore && cd ~/scratch/billing-explore
npm create vite@latest . -- --template react-ts
cursor .
In Cursor's agent panel, use the same brief with one addition: Build this as a single self-contained page in src/App.tsx. Inline styles or plain CSS only.
Iterate each direction two or three times, no more. Prompt for variation, not polish — polish is a production concern:
Variant B: replace the table with grouped-by-month sections, sticky month
headers, and move bulk actions into a selection toolbar that appears only
when rows are checked.
A good output at this stage looks like: three visibly different information architectures, each demonstrating the empty state, with realistic data — not three shades of the same table.
Harvest decisions, not code. Screenshot each direction and write a decision note. This is the artifact that crosses the boundary — nothing else does:
DECISION NOTE — billing history exploration, 2026-08-05
Chosen: v0 variant B (month-grouped) for scannability at high volume.
Stolen ideas: selection toolbar from Claude variant, overdue-first sort
from Cursor variant. Rejected: card grid (too sparse at 500 rows).
States to spec: empty, no-results, single-row selection, 50+ selection.
Re-implement on-system in your real repo. Start a fresh branch and build with your primitives, referencing only the screenshots and decision note. If you have instruction files (pb-02), this is where they earn their keep:
git checkout -b feat/billing-history
claude
Implement the billing-history screen per docs/decisions/billing-history.md
and the attached screenshots. Use only components from @acme/ui — Table,
Toolbar, DateRangePicker, EmptyState. Match our token scale for spacing
and color. Do not copy any code from the prototype.
Delete the prototypes. Literally. rm -rf ~/scratch/billing-explore, delete the v0 chat, close the artifact. If the prototype survives, someone will ship it.
The most expensive words in frontend are "the prototype basically works, let's just merge it." Prompt-to-UI output ships its own component library, its own spacing scale, and zero accessibility guarantees. The cost lands three months later as visual drift and a WCAG audit failure.
npm create vue@latest, ng new scratch-app --minimal) so interaction patterns translate directly.Prompt-to-UI tools compress a week of layout debate into an afternoon — but only decisions cross the throwaway boundary, never code. Explore in a sandbox, write down what you learned, delete the sandbox, and build the real thing on your design system.