Professional UI design system — the visual quality gate for all HTML output.
MUST USE together with project-builder when building any HTML page, dashboard, landing page,
portfolio, or web application. project-builder handles engineering workflow; this skill handles
visual design decisions (color palette, typography, layout, animation).
Ensures every generated UI looks professional, modern, and unique — never generic AI slop.
Generate production-grade, visually distinctive web interfaces. Every page must look like it was designed by a professional — not generated by AI.
When to Use
This skill applies whenever you generate HTML/CSS/JS for any visual web output — dashboards, landing pages, web apps, tools, portfolios, or any other page type.
Reference Files
File
Read When
references/aesthetics.md
Building a color palette, choosing typography, designing layout — the methodology for making design decisions
Creating charts — Chart.js/ECharts setup, chart type selection, mock data generation, dashboard layouts
Priority Override: User Settings Come First
If the user (or the brief) explicitly specifies any design preference, that preference overrides the corresponding Design Dial result. The priority order is:
User-specified settings (highest priority) — explicit requests like "use dark mode", "make it blue", "use Playfair Display font", "I want a minimalist style"
Design Read inference — signals inferred from the brief content and context
Design Dials (lowest priority) — time-based random selection, used only for dimensions the user didn't specify
How this works in practice:
User says "build me a dark portfolio" → Surface is locked to dark, skip the Surface dial. Other dials (Accent, Typography, Family) still spin randomly.
User says "use green and serif font" → Accent is locked to Green, Typography is locked to Serif. Surface and Family still spin randomly.
User says nothing about design → all 4 dials spin randomly (the default behavior).
User says "make it look like Apple's website" → this is a complete design direction. Skip all dials, infer the aesthetic from the reference.
Never argue with the user's taste. If they want purple gradient on a cream background, do it well. Document the user override in the Design Dials output line:
The Design Read anchors every subsequent decision. If two choices conflict, the Design Read wins.
Step 0.5: Scene Sentence (MANDATORY for dark/tinted surfaces)
If your Surface dial (Step 1) selects a dark or tinted direction (indices 5 or 6), you MUST write a Scene Sentence before choosing any colors. This anchors the dark palette to a physical environment instead of defaulting to generic blue-black.
Scene: [who] is using this [where], under [what lighting], in [what mood]
Examples:
"A portfolio manager reviewing positions on a matte-black standing desk, single desk lamp, focused and alert"
"A music producer in a dimly lit studio with purple LED strips, creative and immersed"
"A researcher in a university library at dusk, warm overhead lights, contemplative"
"A bartender checking inventory on a tablet behind a walnut bar, amber pendant lights, unhurried"
"An architect reviewing blueprints in a concrete loft, overcast daylight through floor-to-ceiling windows, precise"
The Scene Sentence determines your dark surface tint:
Studio with purple LEDs → deep purple tint, not blue-black
Library at dusk → warm charcoal, not blue-black
Standing desk with desk lamp → neutral near-black with warm accent
Walnut bar with amber lights → warm brown-black
Concrete loft with daylight → cool gray, not blue-black
BANNED default scene: "a developer's monitor in a dark room" — this is the AI default scene that produces the same blue-black every time. Be specific and varied.
See references/aesthetics.md § Dark Surface Tint Guide for the full scene-to-tint mapping table.
Step 1: Spin the Design Dials (MANDATORY)
You have no memory of previous generations and WILL converge on the same dark-blue-card layout every time if left unchecked. To prevent this, you MUST spin four independent dials before writing any code. These dials constrain your direction but leave you full creative freedom within that direction.
How to Spin
Take the current UTC time and compute four indices:
dial_A = UTC_minute mod 8 → Surface
dial_B = (UTC_minute + 3) mod 7 → Accent Hue
dial_C = (UTC_hour) mod 6 → Typography
dial_D = (UTC_hour + UTC_minute) mod 12 → Aesthetic Family
Dial A: Surface (mod 8)
Index
Direction
Description
0
Warm Light
Off-white with warm undertone (cream-adjacent but NOT generic cream — add personality). Light cards, dark text.
1
Cool Light
White or blue-tinted white. Crisp, clinical, airy. Think Arctic, not generic.
2
Pure White
Clean
#ffffff
or
#fafafa
. Maximum contrast, no tint. Let typography and accent do the work.
3
Tinted Light
Light background with a subtle color tint — pale sage, lavender wash, soft peach, ice blue. Not white, not cream.
4
Light with Color Pop
White/light base with one bold colored section or element (colored hero, colored sidebar, colored footer). Mostly light.
5
Tinted Dark
Dark background with a NON-BLUE tint — try deep green, wine, charcoal-brown, dark purple, or slate-olive. NOT the
#0a-#0f
blue-black that AI always picks. Use Scene Sentence to anchor the tint.
6
Neutral Dark
True dark — near-black with NO color tint. Pure
#111
or
#0f0f0f
. Monochrome surface, let accent do the talking. Use Scene Sentence.
7
Mixed
Light header/hero + dark content area, or alternating light/dark sections. Two-tone page.
Dial B: Accent Hue (mod 7)
Index
Hue Family
Suggested Range (pick your own specific shade)
0
Warm Red
Vermillion, terracotta, rust, brick — NOT generic
#ef4444
1
Gold / Amber
Marigold, honey, saffron, brass — warm and rich
2
Green
Sage, olive, emerald, lime, mint — pick one, NOT teal
3
Orange / Coral
Tangerine, peach, salmon, burnt orange
4
Pink / Magenta
Rose, fuchsia, hot pink, dusty pink — bold or muted
5
Violet / Purple
Lavender, grape, plum, electric purple — own it fully
6
Cool Blue
Cobalt, cerulean, sky, steel — but NOT the generic
#3b82f6
or
#6366f1
Dial C: Typography (mod 6)
Index
Mood
Example Fonts (pick ONE — these are suggestions, not the only options)
Note: The Aesthetic Family is a tendency, not a hard constraint. It guides your overall design language but the Surface/Accent/Typography dials take precedence for their specific dimensions. Use the family to inform layout decisions, spacing rhythm, border treatments, and overall visual language.
Follow your dials. Do not override them because another combination "feels safer".
Creative freedom within the direction. The dials set the direction (e.g., "warm light surface + gold accent + serif font + Art Deco family"), but you choose the specific shades, spacing, layout, animations, and component styles.
Layout is NOT dialed — choose the best layout for the content type (sidebar for dashboards, full-width for landing pages, bento for multi-metric views, etc.). The Aesthetic Family informs layout style (e.g., strict grid vs broken grid) but not layout type.
The dials produce 8×7×6×12 = 4032 combinations. This is intentional — enough variety that consecutive generations will look dramatically different.
A crypto dashboard on a warm light surface with serif font in an Organic/Natural family is intentionally unconventional — that's the point. Lean into it.
Visually striking: A clear aesthetic point-of-view, not a generic template.
Cohesive: Every element — typography, color, spacing, motion — serves the same design direction.
Responsive: Works at 375px mobile width. Stacks gracefully.
Required Elements (not a template — implement fresh each time)
Every generated page must include:
Proper
DOCTYPE
,
charset
,
viewport
meta
Google Fonts loaded via
<link>
with
preconnect
All colors defined as semantic CSS custom properties in
:root
A
prefers-reduced-motion
media query that disables animations
Box-sizing reset and font-smoothing
An entrance animation strategy (choose ONE per project, vary across projects):
Scroll reveal — IntersectionObserver triggers fade/slide on viewport entry
Page-load stagger — elements animate in sequence on initial load, no scroll dependency
State-driven transitions — elements transition between states (collapsed→expanded, hidden→visible) driven by user interaction, not scroll position
Light/Dark theme toggle (MANDATORY) — every page must support both light and dark themes with a toggle button:
Define all colors as CSS custom properties in
:root
(light theme) and
[data-theme="dark"]
(dark theme)
Add a toggle button (sun/moon icon) in the page header or navigation
Detect system preference via
prefers-color-scheme: dark
as the initial default
Store user preference in
localStorage
so it persists across page reloads
The Surface dial determines the default/primary theme direction, but the other theme must also be fully designed
See the Theme Support section below for implementation details
Do NOT copy a fixed HTML skeleton. Structure the document to match the content.
Design Rules
Typography
Load fonts via Google Fonts
<link>
(or CDN for fonts not on Google Fonts). Always load 2+ weights.
NEVER use these as primary font — they are AI defaults or AI anti-default defaults:
AI defaults: Inter, Roboto, Arial, Open Sans, Helvetica
AI anti-defaults (the fonts AI picks when told to avoid the defaults): Space Grotesk, DM Sans, Outfit, Plus Jakarta Sans, Manrope
AI favorite serifs (banned as default): Fraunces, Instrument Serif — the two LLM-favorite display serifs
If a Style Preset specifies a font, use that font. The preset fonts are chosen to be distinctive and varied.
Serif discipline: Serif is discouraged as the default for any project. "It feels creative/premium/editorial" is NOT a reason to reach for serif — this is the most common AI tell. Serif is acceptable ONLY when: (a) the brand brief literally names a serif font, OR (b) the aesthetic family is genuinely editorial/luxury/publication AND you can articulate why this specific serif fits this specific brand. For everything else, default to sans-serif display fonts.
Max 2 font families per page. One well-tuned family with weight contrast usually beats two competing typefaces.
Body: 16px minimum, line-height 1.4-1.6 (real-world range: Apple 1.47, Stripe 1.4, Notion 1.55), max-width 65ch. Some brands add subtle positive body tracking: IBM +0.16px, ElevenLabs +0.15-0.18px — a precision detail that separates professional from generic.
Headings: Use
clamp()
for responsive sizing. Use negative letter-spacing on display text — 85% of major brands use negative tracking on display sizes (Apple -0.28px, Vercel -2.4px, Linear -3px, Stripe -1.4px, Intercom -2.0px, Miro -2.0px, MiniMax -2.0px, Revolut -2.72px@136px). AI tends to skip letter-spacing entirely. Exception: SpaceX uses +1.6px positive tracking for an engineered/industrial feel.
Font weight variety: Don't default to 600-700 for all headings. Across 73 major brands, display weight 400-500 is the most common range (~45%). IBM and ElevenLabs use 300 (ultra-light), Shopify uses 330, Ferrari uses 500, Runway uses 400. Only ~15% of brands use 700+ for display. Consider lighter weights (300-500) for a more refined, editorial feel.
Single-font discipline: ~40% of major brands use ONE font family across the entire site (different weights for hierarchy). HashiCorp, MongoDB, Miro, NVIDIA, Vodafone, Renault, Lamborghini all use a single proprietary sans. Don't assume you need two font families — one well-tuned family with weight contrast often beats two competing typefaces.
See references/aesthetics.md § Real-World Typography References for exact values from 15+ major brands.
Color
Define ALL colors as semantic CSS custom properties in
:root
. Name them to reflect purpose, not appearance (e.g., "surface", "emphasis", not "light-gray").
Build your palette from scratch — see references/aesthetics.md for the method.
Body text contrast ≥ 4.5:1. Large text ≥ 3:1.
ONE accent color per page, used consistently everywhere. Black CTA trend: ~25% of major brands (Expo, Intercom, Lovable, MiniMax, Miro, Ollama, Shopify) use pure black as their primary CTA color — a confident, editorial choice that works on both light and dark surfaces.
BANNED by default: purple/violet gradients, generic blue (
#3b82f6
), AI purple (
#8b5cf6
,
#6366f1
), AI purple-500 (
#a855f7
). Exemption: if the Design Read explicitly demands one of these (e.g., a brand whose identity IS purple), document the justification in a comment and verify contrast.
BANNED dark surfaces: The
#0a-#0f
blue-black range (
#0a0e1a
,
#0d1117
,
#0f172a
,
#111827
,
#1e1b4b
). These are THE AI dark mode default. Use the Scene Sentence and Dark Surface Tint Guide to choose a non-blue dark surface.
BANNED warm neutrals as default background: cream, beige, sand, linen, ivory, champagne — any warm neutral with low saturation (HSL hue 30-60, saturation < 15%). Specific banned hex values:
#f5f1ea
,
#f7f5f1
,
#fbf8f1
,
#efeae0
,
#ece6db
,
#faf7f1
,
#e8dfcb
. These are the 2025-2026 AI default. Exemption: use them ONLY when the Design Read explicitly calls for warmth (e.g., bakery, wellness, artisan) AND you can articulate why no other surface works.
BANNED premium accents: brass/clay/oxblood family (
#b08947
,
#b6553a
,
#9a2436
,
#9c6e2a
,
#bc7c3a
,
#7d5621
) and espresso text (
#1a1714
,
#1a1814
,
#1b1814
). These are the AI "premium-consumer" defaults. Alternatives for premium-consumer briefs (rotate, do not reuse):
Forest: deep green + bone + amber accent (think Filson, Patagonia)
Black and Tan: true off-black + warm tan, sharp contrast, no beige
Cobalt + Cream: saturated blue against a single neutral, no brass
Terracotta + Slate: warm rust against cool grey, no brass
Olive + Brick + Paper: muted olive plus brick-red accent
Pure monochrome + pop: off-white + off-black + one bright accent (electric blue, emerald, hot pink)
WATCH for anti-default defaults: Teal/emerald has become the new AI purple (the go-to when told to avoid blue/purple). Warm amber/gold is becoming the "sophisticated alternative". Be aware and vary further.
Layout
Use CSS Grid for 2D layouts, Flexbox for 1D.
Spacing system: multiples of 4px (8, 12, 16, 24, 32, 48, 64). Section spacing: real brands use 80-120px between major sections (96px is the most common across 73 brands). Hero sections often use 120px+. AI tends to under-space sections at 48-64px.
Container:
max-width
between 1100-1400px (vary it), centered with auto margins and horizontal padding.
Use
min-height: 100dvh
not
100vh
.
Mobile: everything stacks to single column below 768px.
Section-Layout-Repetition Ban: No two consecutive sections may use the same layout family (e.g., two centered text blocks, two zigzag image-text pairs). Audit your sections top-to-bottom. A page with 8 sections must use at least 4 different layout families.
Eyebrow Restraint: Eyebrow labels (small uppercase text above headings) — maximum 1 per 3 sections. If every section has an eyebrow, none stands out.
Zigzag Cap: Maximum 2 consecutive alternating image-text sections. After 2, break with a different layout entirely.
Split-Header Ban: The pattern "left big headline + right small explainer paragraph" as a section header is banned as default. If you need both a headline and an explainer, stack them vertically (headline on top, body below, max-width 65ch).
Bento Background Diversity: Bento and feature-grid sections cannot be all white-on-white cards with text inside. At least 2-3 cells in any multi-cell grid need real visual variation: a real image, a brand-appropriate gradient, a pattern, or a tinted background.
Content Density: Default content shape per section: short headline (≤ 8 words) + short sub-paragraph (≤ 25 words) + one visual asset OR one CTA. Anything more must be justified by the section's job.
Hero Section Discipline
Viewport fit: Hero should fill the viewport on load but not force scrolling to see the first CTA. Test at 768px height.
Stack discipline: Maximum 4 text elements in the hero stack (e.g., eyebrow + heading + subheading + CTA). More than 4 creates visual noise.
Top padding cap: Hero top padding should not exceed 20vh. Excessive top padding pushes content below the fold.
Anti-center bias: Not every hero needs to be centered. Consider left-aligned, split-screen, or asymmetric layouts based on the Design Read.
CTA Discipline
No duplicate intent: The same page must not have two CTAs with the same intent (e.g., two "Get Started" buttons in different sections). Each CTA should have a distinct purpose.
Button contrast check: Primary CTA must have ≥ 4.5:1 contrast ratio between button text and button background.
Button text wrapping ban: CTA text must never wrap to two lines. If it does, shorten the text or increase button width.
One primary per viewport: Only one primary-styled button should be visible at any scroll position.
Components
See references/components.md for detailed patterns.
Cards:
border-radius
max 16px (never 24px+). The most common card radius across 73 major brands is 12px (~35%), followed by 16px (~20%). Meta's 32px and Mastercard's 40px are rare exceptions for hero-level showcase cards, not standard content cards. Subtle border or shadow, not both.
Buttons: Clear hover state + active press (
scale(0.97-0.98)
).
Tables: Use
font-variant-numeric: tabular-nums
for number columns.
Status: Always use color + icon/text, never color alone.
Loading: Skeleton placeholders, not spinners.
Empty states: Helpful message + action button, never blank.
Animation
Only animate
transform
and
opacity
. Never animate layout properties.
No
transition: all
. Specify exact properties.
No
linear
or default
ease-in-out
. Use custom cubic-bezier curves — but choose different curves for different projects.
Choose an entrance animation strategy from the three options in Required Elements #6. Do NOT default to IntersectionObserver every time.
Respect
prefers-reduced-motion: reduce
.
See references/animations.md for timing guidelines.
Charts
Use Chart.js or ECharts via CDN.
Match chart type to data: trends → line, comparison → bar, proportion → donut.
Use your page's color palette for chart colors — never library defaults.
Always include: axis labels, tooltips, legend.
See references/charts.md for setup guidelines.
Icons
Use inline SVG or a CDN icon library. Recommended libraries (priority order): Phosphor, Lucide, Heroicons, Tabler, Radix Icons, Solar (via Iconify).
One icon family per project. Consistent stroke width (standardize globally, e.g., 1.5 or 2.0).
Never use emoji as structural icons.
Never hand-roll SVG icons — if a glyph is missing from your chosen library, install a second library or use a simple geometric shape. Hand-drawn SVG paths are consistently low quality.
Image & Visual Asset Strategy
Priority order for visual assets:
Image-generation tool first — If ANY image-gen tool is available in the environment (
generate_image
, MCP image tool, etc.), use it to create section-specific assets: hero photography, product shots, texture backgrounds. Generate at the right aspect ratio for the section.
for placeholder photography (seed should describe the section, e.g.
crypto-dashboard-hero
). Or use Unsplash/Pexels direct URLs.
Last resort: tell the user — If neither is possible, leave clearly-labeled placeholder slots (
<!-- TODO: hero product photo, 1600x900 -->
) and note what images are needed.
Rules:
Always include
alt
text on all images. Decorative images use
alt=""
.
Never fake screenshots: Do not build div-based fake app screenshots, fake browser chrome, or fake terminal windows as hero images. This is the #1 AI design tell. If a screenshot is needed, use a real image or skip the preview entirely.
Decorative images: Use CSS gradients, SVG patterns, or abstract shapes — not stock photos of people pointing at screens.
Logo placeholders for social proof: For "Trusted by / Used by" logo walls, use real SVG logos from Simple Icons CDN (
https://cdn.simpleicons.org/{slug}/{color}
) or generate simple monogram SVGs. Do NOT use plain text wordmarks (
<span>Acme Co</span>
styled in a row). Logo wall = logos only, no industry/category labels below each logo.
No pills/labels overlaid on images: No
<span>
overlays on photos with tags like "Brand · 02" or "Field notes". Let the image speak alone, or add a caption below (outside the image).
No photo-credit captions as decoration: Strings like "Field study no. 12 · Ines Caetano" under stock images are pretentious. Photo credit only for real photographers being credited.
Hero needs a real visual: Text + gradient blob is not a hero — it's a placeholder. Even minimalist sites need at least 2-3 real images.
Mock Data
Use plausible numbers with natural variance (not round numbers).
Use real-world labels (actual names, realistic dates).
Time series: 7-30 data points with natural fluctuation.
Accessibility (CRITICAL)
Contrast: Body text ≥ 4.5:1, large text ≥ 3:1, UI components ≥ 3:1 against adjacent colors.
Focus states: All interactive elements must have visible focus rings (2-4px outline). Never remove
outline
without providing an alternative.
Alt text: All meaningful images must have descriptive
alt
text. Decorative images use
alt=""
.
Heading hierarchy: Use sequential
h1
→
h6
, no level skipping. One
h1
per page.
Color not only: Never convey information by color alone. Always pair with icon, text, or pattern.
Keyboard navigation: Tab order must match visual order. All interactive elements reachable via keyboard.
Aria labels: Icon-only buttons must have
aria-label
. Form inputs must have associated
<label>
.
Skip link: Include a "Skip to main content" link as the first focusable element.
Reduced motion: Respect
prefers-reduced-motion: reduce
— disable or simplify all animations.
Forms & Feedback
Visible labels: Every input must have a visible
<label>
, not just a placeholder.
Error placement: Show error messages directly below the related field, not only at the top of the form.
Required indicators: Mark required fields with an asterisk or "(required)" text.
Submit feedback: Show loading state on submit, then success or error state.
Empty states: When no data exists, show a helpful message + action button, never a blank area.
Confirmation dialogs: Confirm before destructive actions (delete, reset, clear all).
Input types: Use semantic
type
attributes (
email
,
tel
,
number
,
url
) to trigger correct mobile keyboards.
Error clarity: Error messages must state the cause and how to fix it (not just "Invalid input").
Interaction States
Hover feedback: All clickable elements must have a visible hover state (color change, underline, or subtle transform).
Active/press feedback: Buttons should scale slightly on press (
scale(0.97-0.98)
) for tactile feel.
Disabled states: Disabled elements use reduced opacity (0.4-0.5) +
cursor: not-allowed
+
pointer-events: none
.
Loading states: Use skeleton placeholders for content loading, spinner only for actions. Show loading feedback for any operation > 300ms.
Touch targets: All interactive elements must be at least 44×44px on mobile. Use padding to expand hit area if the visual element is smaller.
Copy Rules (Text Content)
AI-generated text is one of the most obvious tells. Apply these rules to ALL visible text:
Banned Patterns
No em-dashes (
—
) anywhere. Use commas, periods, or semicolons instead. Em-dashes are the #1 LLM text signature. This is a zero-tolerance rule — not "use sparingly", but zero.
No en-dashes (
–
) as separators. Date ranges use hyphens (
2018-2026
). Number ranges use hyphens (
€40-80k
).
No marketing buzzwords: "Revolutionize", "Supercharge", "Unleash", "Seamlessly", "Cutting-edge", "Next-generation", "Game-changing", "Empower", "Elevate", "Transform your workflow". Write like a human, not a press release.
No aphoristic cadence: Avoid short, punchy, parallel sentence structures that read like motivational posters. ("Simple. Fast. Powerful." / "Built for speed. Designed for scale.")
No numbered section markers: Don't label sections "01", "02", "03" unless the content is genuinely sequential (like steps in a process). No "00/INDEX", "001/Capabilities" style eyebrows.
No decoration text strips: Don't add scrolling marquees or repeated text strips that say things like "INNOVATION · DESIGN · EXCELLENCE" or "BRAND · MOTION · SPATIAL".
No version labels in hero: "V0.6", "BETA", "INVITE-ONLY PREVIEW" — banned unless the brief is explicitly about a product launch.
No scroll cues: "Scroll", "↓ scroll", "Scroll to explore", animated mouse-wheel icons — banned. Users know how to scroll.
No locale/weather strips: "LIS 14:23 · 18°C" in headers/footers — banned unless the brief is genuinely about a place or timezone-distributed studio.
No fake-precise numbers: Numbers like
92%
,
4.1×
,
48k
must come from real data or be explicitly labeled as mock. Don't fake engineering precision.
One copy register per page: Don't mix technical mono ("47 tasks · 0.6 ctx-switches/day"), editorial prose, and marketing punch in the same composition.
Quotes ≤ 3 lines: Testimonial quotes must fit in a glance. Attribution: name + role + (optionally) company. Never name only ("- Sarah").
Copy Self-Audit
Before delivering, read every visible string on the page and ask:
Would a human copywriter write this? Or does it sound like ChatGPT?
Is this specific to the product, or could it apply to any product in the category?
Does the heading actually say something, or is it a vague platitude?
Are there any grammatically broken phrases or AI-hallucinated wordplay?
Does any string read like "an LLM trying to sound thoughtful"? (passive-aggressive humility, fake-craftsman labels, mock-poetic micro-meta)
Theme Support (Light / Dark — MANDATORY)
Every generated page MUST include a light/dark theme toggle. This is not optional. Users expect to be able to switch themes on any modern website.
Default Behavior (Light/Dark Toggle)
The Surface dial determines which theme is the primary (shown on first load if no system preference), but both themes must be fully implemented:
CSS custom properties for all colors — define all colors as
--var
in
:root
(light) and
[data-theme="dark"]
(dark).
Toggle UI — add a simple toggle button (sun/moon icon) in the header/nav. Store preference in
localStorage
.
System preference detection — use
prefers-color-scheme: dark
as the initial default if no stored preference.
Both themes must be fully designed — not just "invert the colors". Each theme needs its own surface hierarchy, contrast verification, and accent adjustment.
Dark Mode Design Rules
When designing the dark variant (which every page needs for its dark theme):
Scene sentence: Write a Scene Sentence (see Step 0.5) to anchor the dark palette. Do NOT default to blue-black.
Surface hierarchy: Dark backgrounds need MORE levels of elevation than light (at least 4 distinct surface levels).
Contrast independence: Verify contrast ratios independently for dark mode — don't assume light-mode-passing colors work on dark surfaces.
Accent adjustment: Accent colors often need to be lighter/more saturated on dark backgrounds to maintain the same visual weight.
Token strategy: Use the same CSS custom property names with different values:
css
:root{--surface-primary:#fafafa;--surface-elevated:#ffffff;--text-primary:#1a1a1a;--accent:#d4a030;}[data-theme="dark"]{--surface-primary:#1a1816;/* from Scene Sentence */--surface-elevated:#242220;--text-primary:#e8e4e0;--accent:#e8b84a;/* lighter for dark bg */}
Toggle implementation:
js
// Detect system preference, respect stored preferenceconst stored =localStorage.getItem('theme');const prefersDark =matchMedia('(prefers-color-scheme: dark)').matches;document.documentElement.dataset.theme= stored ||(prefersDark ?'dark':'light');// Toggle handlerfunctiontoggleTheme(){const current =document.documentElement.dataset.theme;const next = current ==='dark'?'light':'dark';document.documentElement.dataset.theme= next;localStorage.setItem('theme', next);}
Anti-Patterns (NEVER DO THESE)
❌ Inter, Roboto, Arial as primary font
❌ Purple/violet gradient backgrounds as default (exemption: brand-mandated, documented)
❌ Cream/beige/sand as default background (exemption: Design Read explicitly demands warmth with articulated rationale)
❌ Blue-black dark surfaces (
#0a0e1a
,
#0d1117
,
#0f172a
,
#111827
) — use Scene Sentence to anchor a non-blue tint
❌ Centered hero + three equal feature cards (the #1 AI layout)
❌ Same-sized card grid repeated endlessly
❌
border-radius: 24px+
on cards
❌
transition: all
or
linear
easing
❌ Emoji as navigation/action icons
❌ Gradient text (
background-clip: text
) — use solid colors for text
❌ Gray text below 4.5:1 contrast ratio
❌
100vh
for full-height sections (use
100dvh
)
❌ Horizontal scroll on mobile
❌ Em-dashes in any visible text
❌ Marketing buzzwords in headings
❌ Numbered section markers ("01", "02", "03")
❌ Div-based fake screenshots or browser chrome
❌ Eyebrow label on every section
❌ More than 2 consecutive zigzag layouts
❌ Same layout family in consecutive sections
❌ Two CTAs with the same intent on one page
❌ Copying the same design you generated last time
Claude-Specific Defects (known failure modes)
These are patterns Claude specifically tends to produce. Watch for and avoid them:
border + box-shadow combo — Claude likes to add both a 1px border AND a large box-shadow to the same element, creating a "ghost card" effect. Rule: choose one or the other, never both on the same element.
border-radius inflation — Claude tends to use 24px-40px border-radius on cards. Rule: cards max 16px; pill shapes only for tags/badges/buttons.
Hand-drawn SVG illustrations — Claude will attempt to hand-draw SVG illustrations as decoration. The quality is consistently poor. Rule: use icon libraries (Lucide, Phosphor, Heroicons) or CSS-based decorative elements, never hand-drawn SVGs.
Repeating-linear-gradient stripes — Claude likes to add diagonal stripe patterns via
repeating-linear-gradient
on
body::before
or section backgrounds. Rule: banned. Use other surface treatments from references/aesthetics.md.
Gradient text on headings — Claude frequently applies
background-clip: text
+ gradient to large headings. Rule: banned. Use solid colors for all text.
Deep blue-black default — When asked for dark mode, Claude almost always picks the
#0a-#0f
blue-black range. Rule: must use Scene Sentence to anchor a specific, non-blue dark tint.
These are the specific measurable differences between AI-generated UI and real production websites, derived from analyzing 73 major brand design systems:
Tell
AI Default
Real Brand Range
Fix
Display weight
600-700
300-500 (45% of brands)
Try 400-500 for display; 300 for editorial
Display letter-spacing
0 (none)
-0.28px to -3px (85% negative)
Add
letter-spacing: -1px
to -2px on display
Body letter-spacing
0
0 to +0.24px (IBM +0.16px, Revolut +0.24px)
Consider subtle positive tracking on body
Card border-radius
24px+
12px (35%), 16px (20%)
Cap at 16px for cards
Button shape
8-12px radius
9999px pill (40%) or 0-8px (30%)
Commit to pill OR sharp, avoid the middle
Section spacing
48-64px
80-120px (96px most common)
Use 96px between major sections
Shadow strategy
box-shadow on cards
Hairline border or surface-lift (60%)
Prefer 1px border over drop shadow
CTA color
Blue #3b82f6
Black (25%), brand-specific (30%)
Try black pill CTA
Canvas warmth
Same cream every time
Each brand's warm-white is unique
Vary the warm-white hue per project
Font families
2 families
1 family (40% of brands)
Consider single-family with weight contrast
Layer 1: First-Order Check
Could someone tell this was AI-generated? If yes → the design lacks a distinctive point-of-view. Redesign.
Could someone guess the topic just from the color scheme? If yes → the palette is too cliché (blue for finance, green for health). Find a less obvious choice.
Does every section look the same? If yes → vary the layout rhythm. Mix card sizes, alternate text/image placement, break the grid.
Is this the same design you made last time? If yes → change at least the font, color palette, and layout structure.
Layer 2: Second-Order Check (Anti-Anti-Default)
The first layer catches obvious AI defaults. This layer catches the defaults you reach for when avoiding the obvious defaults — the "anti-default defaults" that shift over time.
Is your "alternative" choice actually the most common alternative? When you avoid one cliché, you often land on the next most popular option. Ask: "If 100 AI agents all avoided the obvious default, what would most of them pick instead?" — then pick something else.
Can someone guess your aesthetic family from the page type alone? (e.g., "developer tool = dark mode + monospace + green accent", "fintech = navy + white + clean sans") If yes → subvert the expectation.
Are you using the same "safe alternative" font/color/layout you used last time? The anti-default becomes the new default through repetition. Track what you've used recently and deliberately avoid it.
Does your design feel like it belongs to a recognizable "AI aesthetic school"? (e.g., "the Linear clone", "the Vercel look", "the Stripe style") If it clearly belongs to one school → mix in elements from a different tradition.
Refinement Pass (MANDATORY)
After completing the initial build, take a second pass to refine and polish. Do NOT add more elements — instead, make what exists more cohesive and crisp. This is inspired by the canvas-design skill's principle: "The user already said it isn't perfect enough. It must be pristine."
During the refinement pass, ask:
Spacing consistency: Are all margins and paddings following the spacing system? Any awkward gaps?
Color harmony: Does every color on the page serve the same design direction? Any rogue shades?
Typography rhythm: Are heading sizes, weights, and letter-spacing consistent across sections?
Component polish: Do all buttons have hover + active states? Do all cards have consistent border-radius?
Copy quality: Re-read every visible string. Any AI-sounding phrases? Any em-dashes that slipped through?
Dark mode parity: Switch to the other theme. Does it look equally polished, or is one theme clearly an afterthought?
Mobile check: Does everything stack cleanly at 375px? Any horizontal overflow?
The instinct to add more is wrong. If something feels incomplete, the fix is usually better spacing, better contrast, or better typography — not another gradient, another animation, or another section.
Pre-Delivery Checklist
Run every item. Each must pass mechanically — no subjective judgment.
Design Dials & Design Read
Design Dials line is present (Surface + Accent + Typography + Aesthetic Family indices and choices)
Design Read line is present (page type · audience · atmosphere · aesthetic family · surface)
Surface character matches the dialed direction (light/dark/tinted as specified)
Accent hue matches the dialed hue family
Font matches the dialed typography mood
Aesthetic Family influence is visible in layout style and visual language
Scene Sentence (dark/tinted surfaces only)
Scene Sentence is present (for Surface indices 5 or 6)
Scene is NOT "a developer's monitor in a dark room" or equivalent generic scene
Dark surface tint matches the scene environment (not default blue-black)
Typography
Font loaded via Google Fonts (or CDN) with 2+ weights
Primary font matches the dialed typography mood
Primary font is NOT Inter / Roboto / Arial / Open Sans / Helvetica / Space Grotesk / DM Sans / Plus Jakarta Sans / Manrope
Body text ≥ 16px with line-height 1.5-1.6
Headings use
clamp()
for responsive sizing
Max 2 font families used
Color & Surface
All colors defined as CSS custom properties in
:root
Custom property names are semantic (not
--light-gray
)
Accent color is not generic blue (
#3b82f6
) or AI purple (
#8b5cf6
,
#6366f1
,
#a855f7
)
Background is not cream/beige/sand (
#f5f1ea
,
#f7f5f1
,
#fbf8f1
, etc.) unless Design Read demands it
Background is not blue-black (
#0a0e1a
,
#0d1117
,
#0f172a
,
#111827
) — verify hex value
Accent is not brass/clay/oxblood (
#b08947
,
#b6553a
,
#9a2436
) unless Design Read demands it
Body text contrast ≥ 4.5:1 verified
Large text contrast ≥ 3:1 verified
CTA button text/background contrast ≥ 4.5:1
Layout
No two consecutive sections share the same layout family
Eyebrow count ≤ ceil(sectionCount / 3)
No more than 2 consecutive zigzag alternations
Hero fits viewport at 768px height without scrolling to see CTA
Hero has ≤ 4 text elements in its stack
Container max-width is set and content is centered
Copy
Zero em-dashes (
—
) in any visible text
Zero marketing buzzwords in headings
No aphoristic parallel sentence structures
No numbered section markers (unless genuinely sequential)
No decoration text strips or meaningless marquees (e.g., "BRAND · MOTION · SPATIAL")
No version labels in hero (e.g., "v2.0", "Beta") unless brief explicitly demands it
No scroll cues (e.g., "Scroll ↓", arrow-down indicators)
Every heading says something specific (not a vague platitude)
CTA & Buttons
No two CTAs share the same intent text
CTA text does not wrap to two lines
Only one primary button visible per viewport
All buttons have hover + active states
Claude-Specific Defects
No border + box-shadow combo on the same element (choose one)
No border-radius > 16px on cards (pill shapes only for tags/badges/buttons)
No hand-drawn SVG illustrations
No repeating-linear-gradient stripe backgrounds
No gradient text (
background-clip: text
)
Dark surface is NOT in the
#0a-#0f
blue-black range (Scene Sentence must anchor the tint)
Technical
prefers-reduced-motion
media query present
Entrance animation strategy present (scroll reveal / page-load stagger / state-driven — one of three)
No
transition: all
anywhere
No
linear
easing on UI elements
No
100vh
(use
100dvh
)
No horizontal scroll at 375px width
All images have
alt
text (decorative images use
alt=""
)
Focus states visible for keyboard navigation
No div-based fake screenshots or browser chrome
Theme Toggle
Light/dark theme toggle button is present (sun/moon icon in header/nav)
All colors use CSS custom properties (no hardcoded hex in component styles)
[data-theme="dark"]
selector defines dark theme values
prefers-color-scheme: dark
detected for initial theme if no stored preference
Theme preference stored in
localStorage
Both light and dark themes have verified contrast ratios (≥ 4.5:1 body text)
Dark theme is NOT just "inverted colors" — it has its own designed surface hierarchy
Accessibility
Heading hierarchy is sequential (h1 → h2 → h3, no skipping levels)
One
h1
per page
Icon-only buttons have
aria-label
Form inputs have associated
<label>
elements
Color is never the only indicator (always paired with icon/text/pattern)
Interactive elements are reachable via keyboard (tab order matches visual order)
Touch targets ≥ 44×44px on mobile
Forms & Interaction (if applicable)
Every input has a visible label (not placeholder-only)
Error messages appear below the related field
Required fields are marked
Disabled elements have reduced opacity +
cursor: not-allowed
All clickable elements have visible hover state
Buttons have active/press state (
scale(0.97-0.98)
)
Anti-Slop (Layer 2)
Design follows the dialed directions — not your "safe default"
Aesthetic family cannot be guessed from page type alone (e.g., crypto ≠ always dark)
Design does not clearly belong to one recognizable "AI aesthetic school" (the Linear clone, the Vercel look, etc.)
Surface is NOT dark-blue-black (
#07-#0f
range with blue hue) unless the dial explicitly selected it
Font is NOT Inter, Plus Jakarta Sans, Space Grotesk, DM Sans, or Manrope