ux
Blog · Comparison · 2026-05-28

AI-built websites in 2026 — why every one looks the same.

Vercel v0, Lovable, Bolt.new, Replit Agent, Tempo, and Claude Code can all ship a functioning marketing site in under five minutes. They also all ship the same marketing site. The same gradient. The same trio of cards under the hero. The same body face stretched into a 90-pixel headline. Here is the honest comparison — what each builder is actually good at, where the shared fingerprint comes from, and the deterministic rules layer that catches it.

The six builders, in one table

Every name on the list ships a working website from a prompt. The architecture varies; the output convergence does not. Star counts are pulled live from GitHub on 2026-05-28 where the project has a public repo.

Builder Stack output Hosting Where the design comes from
v0 by Vercel Next.js, Tailwind, shadcn/ui Vercel one-click Inline model output · no rules layer
Lovable React, Tailwind, Supabase backend Lovable hosted · export available Inline model output · no rules layer
Bolt.new by StackBlitz Any (WebContainer) Hosted or export Inline model output · no rules layer
Replit Agent Any (Replit Workspaces) Replit Deployments Inline model output · some Replit Designer assist
Tempo React, Tailwind, shadcn/ui Export to your stack Inline model output · some block library
Claude Code / Cursor / Windsurf / Cline Whatever you tell it Your stack · your hosting Reads project files · ux-skill plugs in here

The first five are end-to-end SaaS builders. The sixth row is the open IDE class — the model writes into your own repo, against your own files. Only the IDE class can read a deterministic rules layer from disk, which is why every blog post about the shared fingerprint ends up pointing at that side of the table.

The shared fingerprint, named in detail

Send the same one-line prompt — "build a marketing site for a finance ops product" — to all six. The output across all six rhymes hard enough that the screenshots are nearly interchangeable. Specifically:

None of those are wrong individually. The fingerprint is the combination. The model is not malicious or low-quality. It is reaching for the safest center of its training distribution every single time.

Six builders, one aesthetic. The training data converged before the prompt was even written.

Why all six converge

Three forces stack:

  1. Training-set bias. The set of public marketing sites from 2021–2024 overweights startup landings from a narrow YC-and-Vercel-adjacent aesthetic. The model learns that aesthetic as the default. Anyone who has read more than ten Show HN comment threads in 2024 has read the same critique of the same trio.
  2. Reward-model bias. Human raters who graded the post-training output preferred the safe option. Bright gradients and rounded cards score well in side-by-side preference tests. The reward model encodes that preference into the policy.
  3. Prompt brevity. A short prompt ("build a marketing site for X") leaves every design decision to the model. The model picks the median of its distribution, every time.

Each of the six builders has its own system prompt, but the system prompts converge too. They all want the model to ship something demoable in seconds. Demoable in seconds means safe, and safe means the median.

The two interventions that actually work

Adding ten lines of "do not use a body face at display size" to the system prompt fixes the issue for the first page. It does not fix it for the tenth. Prompt-only steering decays with context length, and every new chat throws the steering away.

The interventions that compound are upstream and downstream of the model:

Both interventions sit outside the model. Both work in any IDE that runs on a real filesystem — which is the entire sixth row of the table above.

How ux-skill plugs into the IDE class

ux-skill is a Python package with three install paths: pip install uxskill, npx uxskill@alpha, or the Claude Code plugin (/plugin install ux@ux-skill). After install, the engine exposes 22 commands across 17 IDEs and ships 120 deterministic regex rules over a 1,182-entry catalog.

The flow inside Claude Code, Cursor, Cline, Continue, Windsurf, Aider, Codex, or Roo Code is the same four steps:

  1. ux discover — 10-field intake. Project type, audience, tone, must-haves, forbidden list, references, density, motion budget, accessibility floor.
  2. ux recommend — five parallel lookups over the 1,182-entry catalog merge into one structured system. Output: tokens.css and manifest.json at the repo root, plus a per-IDE rules file (.cursorrules, CLAUDE.md, .windsurfrules, etc).
  3. Any vibe-coding prompt — the model reads the rules file as part of its context window and writes against your tokens instead of its defaults.
  4. ux lint — the gate. 120 regex rules over the generated code. Zero LLM cost. Exits non-zero on any high or critical finding. Plugs into pre-commit, GitHub Actions, GitLab CI, Husky, or any shell hook.

The hosted builders — what they can and cannot do

v0, Lovable, Bolt, Replit Agent, and Tempo can not read a rules file from your laptop. They can not run a deterministic lint at preview time because there is no filesystem under their preview. The only mitigations available inside those products are:

The honest take: if you want to ship a hosted-builder result that does not look like every other hosted-builder result, your last step is always to export. That export will fail the lint on the first run. The lint findings will name the fingerprint by id. Fixing them in your IDE takes minutes.

What an exported v0 page looks like under the lint

A typical v0 export of a 200-line marketing site, fresh from the prompt "build a SaaS landing for a logistics analytics product":

$ uxskill lint apps/web/src --threshold high
[FAIL] 7 findings at threshold high · exit 1

  high  font-stretched-display      src/components/Hero.tsx:14
                                    body face used at display size
                                    fix: pair the body face with a distinct display face

  high  saturated-multi-stop-grad   src/styles/hero.css:38
                                    wide-spread gradient over white surface
                                    fix: single restrained accent against neutrals

  high  three-equal-card-grid       src/pages/index.tsx:82
                                    three equal cards in a 3-column grid
                                    fix: asymmetric bento or 2-and-1 split

  high  filler-marketing-verbs      src/components/Hero.tsx:18
                                    filler verb in headline
                                    fix: name what the product actually does

  medium fade-in-up-everywhere      src/components/Section.tsx:24
                                    fade-in-up applied to every direct child
                                    fix: differentiate motion by role

  medium icon-emoji-stamp           src/components/Card.tsx:31
                                    emoji used as feature icon
                                    fix: use a real icon set, set aria-hidden

  medium inline-style-attribute     src/pages/about.tsx:44
                                    inline style on production component
                                    fix: move to tokens or utility class

Seven findings on a 200-line page, all named. The fix lines are written so the model can read them in its next prompt: "fix the inter-as-display finding on Hero.tsx line 14 by pairing the body face with a distinct display face from the recommendation." The next save passes the lint.

Comparison — rules layers across the hosted builders

Builder System prompt control Tokens file Deterministic lint Export to ux-skill
v0Custom instructions, paid tierNoNoYes — export to Next.js
LovableCustom knowledge fileNoNoYes — export to Vite
Bolt.newSystem prompt inputNoNoYes — export to local
Replit AgentReplit profile, agent.mdLimitedNoYes — pull repo
TempoProject preferencesLimitedNoYes — export to React
Claude Code · Cursor · Windsurf · ClineCLAUDE.md · .cursorrules · etcYes — via ux-skillYes — 120 rules, sub-secondNative
Honest scope

This is not an attack on the hosted builders.

v0, Lovable, Bolt, Replit Agent, and Tempo are excellent at what they do. Going from prompt to running site in two minutes is a real piece of engineering, and the median user benefits enormously from it. The fingerprint problem is architectural, not effort — you can not run a deterministic filesystem lint inside a preview sandbox without a filesystem.

The honest workflow for serious teams in 2026 is hybrid. Use the hosted builder for the first draft. Export to your IDE. Install ux-skill. Let the rules layer take you from "looks generated" to "looks specific." It is a one-time install, not a per-project cost.

The repeatable workflow

For the hosted-builder users, the loop is:

# 1. Generate the first draft inside v0 / Lovable / Bolt / Tempo
$ <use the hosted builder's prompt UI>

# 2. Export to a local repo
$ <the builder's "Download" or "Push to GitHub" action>
$ cd ./exported-site
$ git init && git add . && git commit -m "v0 export"

# 3. Install ux-skill
$ pip install uxskill
$ ux init                # detects the IDE, writes the rules file

# 4. Generate a system from a 2-minute intake
$ ux discover
$ ux recommend
$ ux persist save

# 5. Gate every future change
$ ux lint --threshold high
$ uvx pre-commit install   # or husky, or the GitHub Action

Total time on the loop: under fifteen minutes the first run, under ten seconds on every push after that.

Where each builder fits today

Pick a builder by the job, not by the marketing.

Related reading

Install the rules layer

Same prompt. Same builder. Different output.

120 deterministic regex rules, a 1,182-entry catalog, 22 commands across 17 IDEs. Drops in next to v0, Lovable, Bolt, Replit Agent, or Tempo — whichever shipped the first draft. MIT-licensed. No telemetry. No account.

$ /plugin marketplace add Laith0003/ux-skill
$ /plugin install ux@ux-skill
— or —
$ pip install uxskill
— or —
$ npx uxskill@alpha init