Last updated

Vibe Coding Design System: How to Keep AI-Generated Product UIs Consistent

Author

Renan Oliveira, Head of Design

Renan Oliveira, Head of Design

Vibe Coding Design System

Open any AI-built product and click through ten screens. Everything works: settings save, dashboards load, modals close. But the primary button is a different height on two screens. Four shades of gray almost match. The billing page's empty state makes it sound like a different company wrote it.

This is the "almost consistent" product. We see it all the time when founders bring AI-built apps to Foundey for an audit. It's harder to fix than a broken UI because no single screen looks wrong. The real cost shows up in sales demos that feel unfinished, users who hesitate because the product doesn't feel trustworthy, and redesign estimates that keep growing.

Don't stop vibe coding. Just give your AI tools a system they can't ignore. In this guide, I'll show you the vibe coding design system we use with AI-native startups: what to include, where it lives in Lovable, v0, Cursor, and Claude Code, how to enforce it, and how to retrofit it onto an app that's already drifted.

Why vibe-coded UIs drift

Drift isn't a bug. It's what happens when three forces work together.

The model defaults to the internet's average

When an agent doesn't get explicit instructions, it grabs what it knows: stock shadcn/ui, Tailwind's default palette, Inter, a soft purple gradient, a three-card feature grid. None of these are wrong; they belong to everyone. That's why so many AI-built products look the same. We break down the visual side of this in our guide to AI slop in UX design.

Every session starts from zero

Your agent doesn't remember that last Tuesday you decided destructive actions use an outlined red button. Unless that rule is written somewhere the tool reads every time, each new prompt is a fresh guess based on whatever code is in context. If the code is already inconsistent, the guess adds more drift.

Generating is cheaper than finding

For a model, writing a new card component takes seconds. Finding your existing Card, interpreting its props, and using it right takes context it probably doesn't have. So it just writes a new one. Do this across dozens of prompts, and you end up with five cards, three modals, and a button with eleven variants, all "correct" in their own pull requests.

What a vibe coding design system is (and is not)

A vibe-coding design system is built for two audiences: your team and the AI agents that write your UI. It has the same basics as any design system: tokens, components, usage rules, but it's designed to be read by a machine at the start of every session and enforced automatically when ignored.

It's not a Figma library your agent can't see. It's not a 40-page brand book. It's not just a longer prompt. If consistency depends on someone copying the right paragraph into every chat, you don't have a system. You have a habit, and habits break under deadline.

O'Reilly's Radar describes this well: the design system becomes the control plane for generated UI. If you want the underlying architecture (principles, tokens, components, documentation, governance), we covered it in the article "How to Build a Design System That Survives AI Tools." This post is the working setup: what to put where and how to keep agents inside it day-to-day.

The five-layer consistency stack

Each layer catches what the last one misses. The context file guides the agent. Tokens limit its choices. Components remove the need to invent. Checks catch what slips through. A human decides what changes.

Layer 1: A context file the agent reads every session

Start with a single plain-text file that explains how your UI works to every agent. Most teams use DESIGN.md, a spec from Google Labs that pairs machine-readable tokens in YAML with a markdown section for intent. There's also a CLI that lints the file, including WCAG contrast checks.

Each tool has its own instruction file: Claude Code reads CLAUDE.md, Cursor reads .cursor/rules, GitHub Copilot reads .github/copilot-instructions.md. Point all of them at the same DESIGN.md instead of maintaining three versions that drift apart.

What you put in the file matters more than the format. A good one covers:

  • Tokens: color roles, spacing scale, type scale, radius, shadows

  • Component rules: which component handles which job, using names that match your code

  • Required states: every new screen ships empty, loading, error, and permission-denied states

  • Copy rules: sentence case, verb-first buttons, one error message pattern

  • Hard bans: no raw hex values, no arbitrary pixel values, no new components without asking

Here is a simplified excerpt. Check the spec for exact field names before you copy it.

colors:

 action-primary: "#1F4FD8"

 action-primary-hover: "#1A43B8"

 surface: "#FFFFFF"

 surface-muted: "#F5F6F8"

 text-default: "#111827"

 text-muted: "#4B5563"

 feedback-danger: "#C2410C"

spacing: [4, 8, 12, 16, 24, 32, 48]

radius:

 control: 8px

 card: 12px

Rules for agents

- Use components from src/components/ui before writing new ones. If none fits, stop and ask.

- Never use raw hex values or arbitrary Tailwind values like p-[13px].

- One main button per view. Destructive actions use <Button variant="danger-outline">.

- Every list or table ships with empty, loading, and error states.

- Buttons use verbs within sentence case: "Create project", not "Submit".

Keep it short. If a rule needs a full paragraph, it probably belongs inside a component, not in the file.

Layer 2: Semantic tokens that live in code

Tokens are named values for color, spacing, type, and radius. Naming is where AI consistency is won or lost. A token called blue-500 indicates how a color looks. A token called action-primary tells it what the color is for,  which the model needs to choose correctly.

Put tokens in code first, as CSS variables mapped into your Tailwind theme (@theme in Tailwind v4, or theme.extend in older setups). Figma variables ought to mirror the code, not the other way around, because the agent reads your repo, not your Figma file. If you want a tool-neutral source of truth, use the W3C Design Tokens Community Group format and a build tool like Style Dictionary to generate both.

Layer 3: A component source the agent installs from

The strongest consistency move is to make your real components the easiest for an agent to reach. Two bridges matter most right now.

  • shadcn registry plus MCP. Package your components and tokens as a shadcn-compatible registry. The shadcn MCP server then lets agents in Cursor, Claude Code, VS Code, and other clients browse, search, and install from it, rather than generating fresh markup. v0 can also load a custom registry, so its prototypes start from your system rather than the stock theme.

  • Figma MCP server plus Code Connect. The Figma MCP server provides agents with structured design data (components, variables, layout) rather than a screenshot to eyeball. With Code Connect mappings in place, generated code uses your actual components. Code Connect is tied to Figma's higher-tier plans, so confirm yours supports it.

On Lovable, the equivalent is its design systems feature: a design system is itself a Lovable project, and other projects connect to it and inherit its components and styles.

Start small. Connect the ten or fifteen components you use most—button, input, select, card, modal, table, toast, empty state—before trying to cover everything.

Layer 4: Checks that fail the build

Instructions are just suggestions. Agents follow them most of the time, and that's exactly how drift starts. Add automated checks so anything off-system fails loudly.

  • Lint for raw values. Stylelint's color-no-hex rule blocks hex colors in CSS, and the stylelint-declaration-strict-value plugin can require variables for chosen properties. For Tailwind, eslint-plugin-tailwindcss offers no-arbitrary-value and no-custom-classname; check its support for your Tailwind version.

  • Lint the context file. If you use DESIGN.md, run its linter in CI so broken token references and failing contrast values never reach the agent.

  • Visual regression on core components. Render key components in Storybook and diff screenshots in CI with Chromatic or Playwright's screenshot assertions. When an agent "helpfully" restyles your Button, the diff shows it.

  • Ask one question on every pull request: "Does this add a new component or token?" If yes, a human signs off.

Layer 5: A human who owns the "no"

Every system we have seen survive AI tools has one named owner. Not a committee. One person who decides whether a new pattern joins the system or gets replaced with an existing one, and who runs a drift check every few weeks. In a five-person startup, that is often the first designer or a design-minded engineer. In our embedded engagements, it is usually the Foundey design lead.

The owner also closes the loop. If the team keeps correcting the same thing in prompts, that's a missing rule or a hard-to-find component. Fix it once in the system, not in chat forever.

Where your design system lives in each AI tool

The pattern is the same everywhere: one source of truth in the repo, a thin tool-specific file that points to it, and checks that don't depend on the tool behaving.


Lovable

Project Knowledge, plus a connected design system project

Inherited from the design system project

Changes to the design system project reach every connected project immediately, so version on purpose

v0

Project instructions plus a custom shadcn registry

Registry components and tokens

Output still needs adapting to your repo's conventions

Cursor

.cursor/rules files that reference DESIGN.md

shadcn MCP, Figma MCP

Rules are context, not enforcement; pair them with lint

Claude Code

CLAUDE.md, plus skills for repeat UI tasks

shadcn MCP, Figma MCP

Keep CLAUDE.md short and link to DESIGN.md instead of pasting it

GitHub Copilot

.github/copilot-instructions.md

Workspace context, MCP in VS Code

Reference the same DESIGN.md

Google Stitch

DESIGN.md (where the format started)

Exported code

Treat output as a starting point and re-map it to your components

How to retrofit a design system onto a vibe-coded app

Most founders reading this don't have a clean slate. You have a working app, paying users, and months of AI-made UI. The good news: you rarely need a rebuild. Here's the sequence we use.

  1. Run a drift census. Count what you have before deciding what you want. A few commands get you most of the way:

# Distinct hex colors and how often each appears

grep -rhoE '#[0-9a-fA-F]{6}\b' src | sort | uniq -c | sort -rn


# Arbitrary Tailwind values like p-[13px] or text-[15px]

grep -rhoE '[a-z-]+-\[[^]]+\]' src | sort | uniq -c | sort -rn


# Candidate duplicate components

find src -iname '*button*' -o -iname '*card*' -o -iname '*modal*'

  1. Collapse to a scale. Group near-duplicates: #F4F5F7, #F5F6F8, and #F3F4F6 are one gray, and pick a small set: a spacing scale, a type scale, and color roles. Name them semantically.

  2. Ship the tokens, then migrate in batches. Add tokens to code and let your agent handle the migration in small, reviewable passes: "Replace raw colors in /settings with tokens from DESIGN.md. Don't change layout." Once the target is defined, this is work AI is genuinely good at.

  3. Freeze the baseline with lint. Turn on raw-value rules as warnings for existing code and errors for new code. That way, drift stops growing while you clean up.

  4. Consolidate components along revenue paths foremost: onboarding, core workflow, billing. Merge duplicate cards and modals into one source, then work outward. Don't refactor screens nobody visits.

  5. Write DESIGN.md last, based on what's real. A context file that describes the system you actually shipped beats an aspirational one your code contradicts.

The census numbers are usually sobering. That's the point—they become your baseline, and you watch them drop.

If you'd rather have someone run the census and sequence the fixes, that's what our 5-day UX audit does at the system level: every finding is scored by impact and effort, with a 30-60-90-day roadmap. If you're also worried about security and architecture, pair it with our vibe-coded MVP audit checklist.

How much system you need at each stage

Over-building is a real risk too. A registry-backed system with visual regression testing is overkill if your team is still changing its core UI every week.


Pre-PMF, one or two builders

DESIGN.md, color, spacing, and type tokens, 5 to 8 shared components

Registry, Storybook, visual regression

Post-PMF or seed, three or more people shipping UI

Raw-value lint rules, a component inventory, Storybook for core components, a named owner

Full Figma Code Connect coverage

Series A and beyond

Registry plus MCP, Code Connect, visual regression in CI, a contribution process

Nothing; drift now costs more than the system

Here's the rule of thumb: build the full system once your product surface stabilizes and your team grows past the point where everyone remembers every decision. Invest too early, and you'll refactor it away. Invest too late, and you're budgeting for a redesign.

What we see go wrong most often

These patterns come up in most AI-built products we review.

  • The DESIGN.md is just a mood board. "Clean, modern, premium" gives a model nothing to act on. Tokens, component names, and explicit bans do.

  • Plenty of context. Teams paste the whole brand book into the rules file, then wonder why the agent ignores half of it. Short, specific, and linked beats long and complete every time.

  • The system lives only in Figma. Agents read the codebase. A beautiful library with no code counterpart is invisible to them.

  • Fixing in prompts rather than in the system. If you've typed "use our Button component" five times this week, the problem is discoverability, not the model.

  • Only colors and fonts get systematized. States, behavior, and copy drift just as fast. A single error-message pattern and an empty-state template prevent more "how do I" tickets than a perfect palette ever will. Check out our guide to AI UX debt for guidance on triaging these.

  • Agents can edit the tokens. Protect token files and the core component folder behind review. A model that "fixes" a contrast issue by tweaking a global token can restyle your whole app in one commit.

We saw a version of this with Fambot. The technology was real, but the app felt vibe-coded rather than designed. The fix was not a new palette. It was rebuilding the character, the product, and the story around what families actually needed.

Run a 20-minute consistency check

Do this today and count how many fail.

  • Open five screens. Does the primary button look and read the same on all of them?

  • Search your components for hex values. Are any outside your token file?

  • Create a fresh account. Is the empty state designed, with one definite next step?

  • Break a form on purpose. Does the error follow a pattern, and can you explain the fix?

  • In a branch, ask your agent to "add a notifications settings page." Did it reuse your components or create new ones?

  • Can someone on the team name who owns the design system?

Zero or one fail: your system is working. Two or three: start with lint rules and the context file. Four or more: pause new features and run the retrofit sequence above.

Keep the speed, lose the drift

AI tools amplify whatever foundation you give them. Point them at a vague system, and you get inconsistency at machine speed. Point them at a short context file, semantic tokens, real components, and checks that fail the build, and they become the fastest way to stay on-brand. The goal isn't to slow down. It's to make the consistent path the easiest one for your team and your agents.

At Foundey, we build and repair these systems inside AI startups every week. Athina's CEO credited our team with helping them "add a design system, and make our product more professional." Eileen got a scalable design system ahead of its seed round.

If your AI-built product is shipping fast but drifting, book a free audit, and we'll show you live where your system is breaking and what to fix first. For teams that need the system built and owned week to week, check out our embedded product design work.

FAQ

What is a vibe coding design system?

It is a design system packaged for both people and AI agents: a context file such as DESIGN.md, semantic tokens in code, components agents can install, and automated checks that flag off-system UI. Its job is to make AI-generated screens consistent by default.

Do I need a design system if I build with Lovable or v0?

Yes, though it can start small. Both tools generate polished screens quickly, but maintaining consistency across months of prompts and multiple builders requires a shared source of truth. Lovable supports connected design system projects, and v0 can load a custom shadcn registry.

What should go in a DESIGN.md file?

Color roles, spacing and type scales, radius and shadow tokens, which components to use for which jobs, required states for every screen, copy rules, and explicit bans such as raw hex values. Keep it short and specific, and skip descriptors like "modern."

Why does my AI coding tool keep changing my UI styles?

It does not remember earlier decisions, and it falls back on common patterns when context is thin. Persistent rules files, semantic tokens, reachable components, and lint checks remove the guesswork.

Can I add a design system to a vibe-coded app without rebuilding it?

Usually, yes. Run a drift census, collapse values into a token scale, migrate in small AI-assisted batches, freeze the baseline with lint, then consolidate components along your highest-revenue flows. A rebuild is only worth it when the information architecture itself is wrong.

Is shadcn/ui a design system?

It is a strong component foundation and distribution format, not your design system. Out of the box, it looks like thousands of other AI-built apps. It becomes your system once your tokens, variants, and usage rules are applied and packaged, ideally as your own registry.