Who this guide is for: founders, designers, and developers who build with vibe coding tools and want a consistent, professional result without a dedicated design process. This guide covers the four design variables that determine whether a vibe-coded product looks intentional or AI-generated, and the exact method for controlling each one.
Vibe coding tools generate code that functions correctly. They generate design inconsistently. The gap between "works" and "looks like a professional product" is almost always in four variables: typography, colour, spacing, and component style. When those variables are left to the model's training defaults, the result carries the visual signatures of AI generation. When they are fixed by a design reference before generation begins, the result looks like a considered product.
This guide explains each variable and how to control it.
Variable 1: Typography
Typography is the variable with the highest leverage. A page with strong typographic decisions looks considered even when every other design choice is neutral. A page with weak typographic decisions looks assembled even when the colour and layout are strong.
The AI default for typography is Inter at weight 400, line-height 1.5, no letter-spacing, with a flat size scale (14px body, 24px heading, nothing in between). This produces readable but undifferentiated text. Here is how to override each dimension:
Display headings
Apply negative letter-spacing to large headings. At 26–40px, tracking of -0.03em to -0.05em tightens the spacing between letterforms in a way that reads as considered rather than default. Combine this with font-weight 600 or 700 (not 500, which reads as undecided) and line-height 1.1 to 1.2. The result is a heading that looks like it was set by a typographer, not generated.
Body text
Set body text at 13–14px with line-height 1.7 to 1.8. The wider line-height at small text sizes is what makes body copy feel comfortable rather than cramped. Use color #555 to #666 rather than full black (#000) or the Tailwind default (text-gray-600, which is #4B5563). The slight warmth of a custom neutral reads as intentional. The Tailwind preset reads as default.
Size scale
Use at least four distinct sizes: display (26–32px), section heading (15–17px), body (13–14px), and caption or label (10–12px). The gap between section headings and body text is where most AI-generated pages collapse — both sizes end up near 14–16px, which makes the hierarchy illegible. A section heading that is clearly larger than body text creates visual structure the model would not produce on its own.
Variable 2: Colour
The AI colour default for a professional product is some version of indigo or blue-violet as the primary accent, with a neutral palette drawn from Tailwind's grey scale. This palette is not wrong. It is simply the palette that appears in the majority of modern SaaS products because those products were built with the same tools.
To escape it, control three colour decisions explicitly:
Primary accent
Choose one primary colour and specify it as a hex value, not a Tailwind class. #16a34a (green), #dc2626 (red), #d97706 (amber) all produce instantly distinct products. Apply this colour only to primary CTAs and active states. Everything else should be neutral. One accent colour used sparingly reads as a deliberate brand decision. Multiple accent colours used freely reads as a default palette.
Neutrals
Specify your neutral scale as three values: background, secondary text, and border. For a light product: #ffffff background, #666 secondary text, #f0f0f0 borders. These three values replace the dozen Tailwind grey variants the model would otherwise pull from. Fewer values, specified precisely, produce a more consistent result.
Background
The background decision has more visual impact than most designers expect. Pure white (#fff) is clean and reads as sharp. Near-white (#fafafa or #f8f8f9) is warmer and reads as considered. A dark near-black (#0f0f0f or #111) reads as premium. Any of these is fine as a deliberate choice. The AI default of alternating white and gray-50 section backgrounds (#f9fafb) reads as a template that was not customised.
Variable 3: Spacing
Spacing is the least visible design variable and among the most consequential. A well-spaced page at average type and colour reads better than a poorly-spaced page at excellent type and colour. The AI default spacing is based on Tailwind's 4px grid, applied inconsistently: sections get 80–100px of vertical padding, cards get 16–24px, and there is no consistent rhythm between them.
Controlling spacing in a vibe coding context means specifying it in the template rather than in words. A template that uses 14px card padding, 32px between sections within a group, and 80px between major sections establishes a specific density. The model reads that density and applies it. "Use generous spacing" or "keep it tight" are instructions that produce different results in every session.
Variable 4: Component style
Component style covers buttons, cards, inputs, badges, and the other repeating elements that appear throughout a product. The AI default for each is consistent: buttons are rounded-lg (8px), cards are rounded-xl (12px), inputs have a 1px gray-200 border. These defaults produce a product that matches the shadcn/ui component library visually, which is useful if that is what you want and a tell if it is not.
Border radius
Pick a radius strategy and specify it in your reference template. Sharp (2–4px) reads as technical and precise — good for developer tools and finance products. Medium (6–8px) reads as professional and approachable — the most versatile choice. Full rounding (rounded-full) should be reserved for pill badges and avatars only, not applied uniformly. The tell of a vibe-coded product is that every element shares the same radius, including things that should not.
Buttons
A primary button should use your specific accent hex colour as the background with white text. Specify the height (32–36px is the right range for most products), the horizontal padding (16–20px), and the font size (12–13px, font-weight 500). The AI default produces a button that is technically correct but sized inconsistently with the rest of the page. A template fixes the proportions before generation starts.
Cards
Specify whether cards use a border, a shadow, or a background colour to define their boundary. Border-only cards (1px, color #f0f0f0) read as editorial and light. Shadow cards read as floating and three-dimensional. Filled cards (background #fafafa) read as contained and structured. Mixing approaches across a page reads as unintentional. A template that commits to one approach ensures the model applies it consistently.
How to apply this guide with Moon templates
Every Moon template is built to the standards described in this guide. The typography uses explicit size scales with negative tracking on headings. The colour palette specifies custom neutrals rather than Tailwind defaults. The spacing is calibrated to a consistent density. The component styles commit to a single radius strategy.
To apply this guide in practice: choose a hero template whose visual direction matches your product category. Paste it into Bolt, Replit, Lovable, Claude Code, or Cursor before writing any product requirements. Add features, pricing, and navigation templates from the same visual family as you build out additional sections.
The model inherits the four variables from the templates. You inherit a product that looks like it was designed, not generated.
Frequently asked questions
What makes a vibe-coded product look AI-generated?
Four variables: typography at training defaults (Inter, default tracking, flat size scale), the AI colour palette (indigo gradients, Tailwind grey neutrals), inconsistent spacing with no clear density, and uniform component styles from shadcn/ui defaults. Any one of these in isolation reads as a minor inconsistency. All four together produce the recognisable AI-generated aesthetic.
Do I need to know CSS to control how my vibe-coded product looks?
Not in depth. You need to understand what font size, border radius, and hex colour values mean, and how to read them in an HTML template. Beyond that, the AI applies them. Paste a template that contains the right values, instruct the model to match them, and it handles the implementation.
How do I keep a consistent design across a multi-page vibe-coded product?
Use the same template as your design reference for every new page or section you generate. The template acts as a design system document that the AI reads each time. When the reference is consistent, the output is consistent. Style drift across pages is almost always caused by generating without a reference, or with a different reference, in later sessions.
What is the most impactful single change I can make to a vibe-coded product?
Apply negative letter-spacing to your display headings (-0.03em to -0.04em at 26px and above). This single change has more visible impact on perceived quality than changing the colour scheme, the border radius, or the button style. Typography at display sizes is the most immediately legible signal of intentional design.
Can vibe coding tools produce genuinely distinctive designs?
Yes, when given a sufficiently specific reference. The model is capable of reproducing any design system encoded in HTML and CSS. The constraint is not the model's ability but the specificity of the input. A generic prompt produces a generic output. A template with precise, calibrated values produces a precise, calibrated output.
Related Moon sections
Why vibe-coded websites look cheap
The six specific visual tells of a vibe-coded site, and the training data reason each one appears.
How to make a vibe-coded website look professional
The five-step method for using a design reference with any vibe coding tool.
Hero templates
Production-ready hero sections with calibrated typography, colour, and spacing to use as design references.
How to build a Stripe-style gradient hero
The exact CSS technique for a layered radial gradient hero that reads premium and distinct.


