Why every AI-coded app looks like shadcn/ui (and the real fix)

By The WAALEE Team · · 4 min read

Why every AI-coded app looks like shadcn/ui (and the real fix)

Open ten apps built this year with Claude, Lovable, v0, Cursor or Bolt and at least six of them will share a face: the same rounded cards, the same muted slate palette, the same Inter type, the same soft shadow. That's not a coincidence and it's not a limitation of the models. It's shadcn/ui, and by now it's less a component library than the default skin of AI-generated software.

shadcn didn't get generic. The defaults did.

shadcn/ui was never meant to be a finished look, it ships as copy-pasted source you're supposed to edit. But almost nobody does. As one recent breakdown of the problem put it, people "run the install command, accept the default theme, accept the default radius, accept the default Inter font, and start building." That would be a minor style tic if a human made the call once per project. It compounds because AI agents do the same thing on every project, every time, gravitating to whatever pattern shows up most in their training data, which by now is unedited shadcn.

The five tokens that actually decide how it looks

The fix isn't a new component kit, it's five CSS variables shadcn already exposes and almost nobody touches:

  • Neutral colors: swap the default slate/zinc grey for something with an actual undertone.
  • Border radius: commit to sharp, soft, or pill. The safe middle ground is what reads as "default kit."
  • Typography: pick a real pairing instead of Inter doing every job on the page.
  • Accent color: one saturated color doing real work, not a muted brand-safe blue.
  • A signature detail: one texture, shadow, or easing curve shadcn doesn't ship with.

Change those five and the components underneath are untouched, but every screen your agent generates stops looking like the demo. The catch is you still have to decide what those five values are, and "pick something that isn't grey" is not a design system.

A brief tells the agent what to feel. It still needs real values.

The best response to this so far is DESIGN.md, a plain-markdown brief that ships alongside a theme and describes intent, not just hex codes: color roles, when to use which weight, spacing rhythm, the "taste rules" that keep an agent from improvising. Drop it in your repo root or `.agents/` folder and Claude or Cursor read it before generating a new screen. It's a real improvement, agents stop guessing hierarchy and density from nothing.

It also has a ceiling. DESIGN.md describes a look somebody already decided on, usually by hand, usually once. If your brand doesn't have that decision made yet, or you're trying to match a reference site's actual feel rather than write a new one from scratch, a prose brief is still starting from a blank page. It tells the agent how to feel about colors it doesn't have yet.

Give it real values before it has to guess

The more direct fix is to skip writing the brief and pull the actual values from somewhere real: your own site if you have one, or a reference whose look you're trying to hit. That's the same five tokens above, plus type scale and spacing, read straight off a rendered page instead of typed in from memory. Feed those into your shadcn `globals.css` and the agent isn't improvising a personality anymore, it's applying a decision that already exists.

Where each approach actually helps

None of these are competitors, they solve different parts of the same problem:

  • DESIGN.md (Shadcnblocks): A markdown brief for a theme you've already designed. Best once your look is decided and you want agents to stop drifting from it.
  • The five-token rewrite: The minimum manual fix: five CSS variables to override by hand so your build stops reading as unedited shadcn.
  • WAALEE: Paste a live URL and get the actual color, type, spacing and radius values off the rendered page as W3C tokens, ready to drop into shadcn's globals.css, plus a prompt for Claude, Lovable, v0, Cursor or Bolt. No blank page.

shadcn is a fine foundation, the component quality is real and that's not what's generic. What's generic is shipping it untouched. Whether you write the brief by hand or extract the values from a reference, the point is the same: the agent needs a decision to apply, not defaults to fall back on.

Latest from the blog