Opinion8 min read

Why AI-Generated Websites All Start Looking the Same

Ask three different agents to "make it modern" and you get three versions of the same page. That is not a failure of the model. It is a gap in what you told it.

On this page

You have probably seen this page. Centered hero, headline in a large geometric sans, subheading in grey, two buttons where the first is filled and the second is an outline. Below it, three cards with icons. Below that, a testimonial. Somewhere there is a gradient going from violet to blue at a 135 degree angle, and everything has a 12px border radius.

I have generated that page. You have generated that page. If you have used Cursor, Claude Code, v0 or anything similar with a prompt like "build a landing page for my SaaS, make it modern and clean", you have generated that page too, and it probably looked fine, and it probably looked like everyone else's.

It is worth understanding why, because the reason is not "AI is bad at design".

"Modern and clean" is not a design decision

Think about what you actually asked for. "Modern" is a word that describes a very large set of possible pages. "Clean" narrows it slightly. "Professional" narrows it not at all.

Now think about what the agent has to produce: a specific hex value for the background, a specific font family, a specific font size for the h1, a specific spacing value between sections, a specific border radius. Dozens of concrete decisions, none of which you made.

So it makes them for you. And with nothing to go on, it picks whatever is most strongly associated with those words across everything it has seen. That is not a bug. Given the input, it is close to the only sensible behaviour.

The output converges because the input is vague in the same way every time. Three agents, three prompts, one aesthetic.

The prompt has no memory of your taste

There is a second problem, and it shows up on the second page rather than the first.

You generate the homepage. It comes out okay. You nudge it: bigger headline, less purple, tighter spacing. After a few rounds it looks decent. Then you open a new session and ask for the pricing page.

The agent does not know about any of those nudges. The corrections lived in a conversation that has ended. So the pricing page arrives with the original headline size, the original purple, the original spacing, and you do the same round of corrections again. Then again for settings. Then again for the dashboard.

This is the part that surprises people. The first page is a design problem. Every page after it is a memory problem.

Screenshots help, but less than you would expect

The usual next move is to paste in a screenshot of a site you like and say "make it look like this".

This genuinely helps. Vision models are good at reading a screenshot, and the agent will pick up the general mood — light or dark, roughly how much space, roughly what kind of type.

But a screenshot is a rendering, not a specification. A few things it cannot tell you:

  • Whether that heading is 44px or 48px, and what its line height is
  • Whether the tracking is -0.02em or zero, which is most of why display type looks tight and deliberate rather than default
  • Which of the four greys in the image is the body text colour and which is a border
  • What the button does on hover
  • What any of it does at 375px wide

So the agent approximates. It gets a colour that is close to the one in the screenshot but not the one in the screenshot. It gets 40px where the original is 44px. Individually these are invisible. Together they are the difference between a page that looks designed and a page that looks nearly designed.

And you still have the memory problem, because a screenshot pasted into one conversation is not available in the next one.

What actually changes the output

The thing that helps most is boring: write the decisions down, in the repo, in a file the agent reads every time.

Not a mood board. Actual values, with the role each one plays:

colors:
  canvas: "#FFFEFB"      # page background, never pure white
  ink: "#201515"         # headings and body text
  primary: "#FF4F00"     # the one accent, primary actions only
  hairline: "#C5C0B1"    # 1px borders and dividers

typography:
  display-xl: { size: 56px, weight: 500, lineHeight: 1.0, tracking: -0.02em }
  body-md:    { size: 16px, weight: 400, lineHeight: 1.6 }

radius:
  none: 0px
  md: 12px

Two things are happening here that a prompt does not do.

First, every value has a role. primary is not "the orange", it is "the one accent, primary actions only". That constraint is the actual design decision. Without it an agent will cheerfully use your accent for a border, a badge, a hover state and an icon, and the page will feel loud in a way that is hard to point at.

Second, it is a file. It does not expire when the conversation does. The pricing page gets the same rules as the homepage because the rules are sitting in the repo, not in a chat log.

A small example

I had an agent build a pricing section for a side project. First attempt, no context beyond "match the rest of the site": three cards, each with a border, a shadow, a gradient on the recommended one, and a 24px heading. Fine. Generic.

Then I added four lines to the file it reads:

Elevation is surface colour, not shadow. Do not use box-shadow.
The recommended tier is marked by inverting its surface, not by a gradient.
Section headings are display-lg. Card headings are heading-md.
The accent appears once per section at most.

Same request, new session. The cards came back flat, separated by hairlines, with the middle one inverted to the dark surface and a single accent on its button. It took one attempt and it looked like it belonged to the same product as the homepage.

None of that was clever prompting. It was just the decisions written down where the agent could find them.

The uncomfortable part

You still have to make the decisions. Nothing here removes that. If you do not know whether your product should feel warm or cold, dense or airy, an agent cannot decide for you, and it will fall back to the average of everything it has seen — which is exactly the page we started with.

What you can skip is the transcription. If there is a site whose visual language already works for what you are building, the decisions are sitting there in its rendered CSS: the real hex values, the real type scale, the real radius language. Reading them off by hand is an afternoon of work in devtools.

That afternoon is roughly what DesignMD does — it reads a live site and writes the design context as a DESIGN.md your agent can follow, with colours named by the job they do rather than by their hue. If you want to see the shape of the output before generating one, Discover has documents for sites you will recognise.

But the file matters more than where it came from. Write it by hand if you like. The point is that it exists, that it names roles rather than colours, and that it lives next to the code instead of in a conversation you are about to close.

Read next