Why Cursor output looks inconsistent
Cursor reads your codebase. It sees your components, your utilities, your types. But it doesn't see your design intent. When you prompt "build a settings page," it makes aesthetic choices on the fly. Blue for buttons because that's a safe default. 16px padding because that's reasonable. System font stack because nothing told it otherwise.
The result: every generated component looks slightly different from the last one. Not broken, just inconsistent. The settings page has rounded-lg buttons while the dashboard uses rounded-md. The sidebar text is zinc-600 in one file and gray-500 in another. These small drifts compound into a product that feels unfinished.
This is not a Cursor problem. It's an input problem. You haven't told the model what your design system is. The .cursorrules file is where you fix that.
The .cursorrules file, explained
The .cursorrules file sits at the root of your project. Cursor reads it before every generation and treats its contents as persistent instructions. Think of it as a system prompt for your codebase. Anything you put here shapes every piece of code Cursor writes.
Most developers use it for code conventions: "use TypeScript strict mode," "prefer named exports," "use server components by default." That's fine. But the real power is using it for design constraints. When Cursor knows your exact colors, spacing scale, typography, and component patterns, it stops guessing and starts following.
Step 1: Define your color tokens
Colors are where the most drift happens. Without explicit tokens, Cursor pulls from Tailwind defaults, hardcodes hex values, or mixes color scales between components. Lock this down first.
# .cursorrules - Color System
## Design Tokens
When generating UI, use ONLY these color tokens:
- Background: bg-zinc-950 (primary), bg-zinc-900 (surface)
- Text: text-zinc-50 (primary), text-zinc-400 (secondary)
- Border: border-zinc-800
- Accent: bg-violet-500, hover:bg-violet-400
- Destructive: bg-red-500/10 text-red-400
- Success: bg-emerald-500/10 text-emerald-400
Never use arbitrary hex values. Never use colors outside
this palette. If a new color is needed, ask first.This block alone eliminates 80% of design inconsistency. Cursor will reference these tokens whenever it writes a className. The key is being explicit about what's not allowed. "Never use arbitrary hex values" is more effective than "prefer using tokens."
Step 2: Lock your typography
Typography drift is subtler than color drift, but it kills polish. One component uses text-sm, another uses text-xs for the same UI pattern. Font weights vary randomly. Line heights change between pages.
# .cursorrules - Typography
## Font Stack
- Headings: font-family "Instrument Serif", serif (italic)
- Body: font-family "Geist", sans-serif
- Code/mono: font-family "Geist Mono", monospace
## Type Scale (use these exact sizes)
- Page title: text-4xl font-normal italic (Instrument Serif)
- Section heading: text-xl font-semibold
- Body: text-sm leading-relaxed
- Caption: text-xs text-zinc-400
- Label: text-xs font-medium uppercase tracking-wider
Do not use text-base, text-lg, or text-2xl.
Do not mix font families within a component.The restrictive phrasing matters. "Do not use text-base" is clearer than "stick to the scale above." Language models respond better to explicit boundaries than implicit suggestions.
Step 3: Set spacing and radius conventions
Spacing is the skeleton of UI. Inconsistent padding and margins make an interface feel janky even when colors and fonts are right. Define the scale Cursor should use.
# .cursorrules - Spacing & Shape
## Spacing Scale
- Component internal padding: p-4 (16px)
- Between sections: space-y-8 (32px)
- Between related elements: space-y-2 (8px)
- Page padding: px-6 py-8
## Border Radius
- Cards and containers: rounded-xl
- Buttons and inputs: rounded-lg
- Badges and tags: rounded-full
- Never use rounded-sm or rounded-md
## Shadows
- Cards: shadow-none (use border instead)
- Dropdowns: shadow-lg shadow-black/20
- No other shadow usageStep 4: Component patterns
Beyond tokens, define how Cursor should structure components. This prevents it from reinventing layout patterns with each generation.
# .cursorrules - Component Patterns
## Buttons
- Primary: bg-violet-500 text-white rounded-lg px-4 py-2
- Secondary: bg-zinc-800 text-zinc-200 rounded-lg px-4 py-2
- Ghost: text-zinc-400 hover:text-zinc-200 px-4 py-2
- Always use <Button> from @/components/ui/button
## Cards
- bg-zinc-900 border border-zinc-800 rounded-xl p-4
- No shadows. Border only.
## Inputs
- bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2
- Focus: ring-2 ring-violet-500/50
- Placeholder: placeholder:text-zinc-600Notice the pattern: every rule includes both what to do and what to avoid. This dual framing is critical. Without the negative constraint, Cursor will treat your rules as suggestions rather than requirements.
The complete .cursorrules template
Here's the full structure. Copy this, replace the values with your design system, and drop it in your project root.
# Design System Constraints
You are building a [product type] with a [dark/light] theme.
Follow these design tokens exactly. Do not deviate.
## Colors
[your color tokens]
## Typography
[your font stack and type scale]
## Spacing
[your spacing scale and radius]
## Component Patterns
[your button, card, input patterns]
## Rules
- Never use arbitrary values (no bg-[#xxx])
- Never introduce new colors without asking
- Always check existing components before creating new ones
- Use server components by defaultGetting design tokens without Figma
The hard part is not writing the .cursorrules file. It's knowing what values to put in it. If you have a Figma design system, extract the tokens from there. But most developers working with Cursor don't have a designer handing them token sheets.
SeedFlip generates complete design systems that export directly to formats Cursor understands. One flip gives you colors, fonts, spacing, shadows, and border-radius in CSS variables, Tailwind config, or design tokens. You can also use the SeedFlip MCP server directly in your development workflow. The MCP server lets AI agents query curated design seeds programmatically:
# Install the SeedFlip MCP server
npx -y seedflip-mcp@latest
# Query a design seed by vibe
> get_design_seed({ query: "dark minimal SaaS" })
# Returns complete tokens: colors, fonts, spacing, radius, shadows
# Paste these directly into your .cursorrulesThis solves the cold-start problem. Instead of spending hours deciding whether your primary should be violet or indigo, whether your radius should be 8px or 12px, whether your body font should be Inter or Geist, you get a curated, cohesive set of decisions in one step. Then you paste those decisions into .cursorrules and Cursor follows them.
Common mistakes
Being too vague
"Use a clean, modern design" means nothing to a language model. It will interpret "modern" differently on every generation. Specificity is everything. "Use bg-zinc-950 for page background, border-zinc-800 for dividers, rounded-xl for cards" leaves no room for drift.
Forgetting negative constraints
Telling Cursor what to use is half the job. Telling it what not to use closes the gaps. "Never use shadow utilities" is clearer than "we prefer a flat design."
Overloading the file
Your .cursorrules competes with context window space. Keep design tokens tight. You don't need to document every edge case. Focus on the decisions that affect the most surface area: colors, fonts, spacing, component shapes.
Your .cursorrules file is the difference between a Cursor project that looks designed and one that looks assembled. It takes 20 minutes to set up and saves hours of manual cleanup on every feature you build. For more on integrating design tokens across AI tools, read how .cursorrules shapes design output. For the broader picture of AI-ready design systems, check Design Tokens for AI.