project-design
Original:🇺🇸 English
Translated
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.
42installs
Added on
NPX Install
npx skill4agent add starchild-ai-agent/official-skills project-designTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Project Design Skill
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 |
| references/components.md | Building UI components — navigation, cards, tables, buttons, forms, hero sections, CTAs |
| references/animations.md | Adding motion — scroll reveals, hover effects, modals, drawers, page load sequences |
| references/charts.md | 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:
Design Dials: Surface=USER(Dark) · Accent=3(Orange, #e87040) · Type=USER(Serif) · Family=2(Editorial) → Playfair Display
Step 0: Design Read (MANDATORY)
Before writing ANY code, silently analyze the brief and output a single-line Design Read:
Design Read: [page type] · [audience] · [atmosphere word] · [aesthetic family] · [light/dark/tinted]
How to infer each signal:
| Signal | Source | Example |
|---|---|---|
| Page type | Explicit in brief or inferred from content | SaaS dashboard, editorial blog, dev tool, portfolio |
| Audience | Who will use this? | Enterprise buyers, indie developers, Gen-Z consumers |
| Atmosphere | One word capturing the emotional register | Clinical, playful, austere, warm, raw, luxurious |
| Aesthetic family | The design tradition this belongs to | Swiss/International, Neo-brutalist, Editorial, Soft-tech, Industrial |
| Surface | Light, dark, or tinted background | Dark with blue tint, warm off-white, pure white |
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 FamilyDial 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 |
| 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 |
| 6 | Neutral Dark | True dark — near-black with NO color tint. Pure |
| 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 |
| 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 |
Dial C: Typography (mod 6)
| Index | Mood | Example Fonts (pick ONE — these are suggestions, not the only options) |
|---|---|---|
| 0 | Serif | Libre Baskerville, Newsreader, Lora, Playfair Display, Cormorant Garamond, Source Serif 4 |
| 1 | Geometric Sans | Instrument Sans, Geist, Sora, Urbanist, Figtree, Albert Sans |
| 2 | Humanist Sans | IBM Plex Sans, Nunito Sans, Atkinson Hyperlegible, Lexend |
| 3 | Monospace | JetBrains Mono, Space Mono, IBM Plex Mono, Fira Code |
| 4 | Display / Decorative | Fraunces, Bricolage Grotesque, Clash Display, Cabinet Grotesk |
| 5 | Slab / Mechanical | Roboto Slab, Zilla Slab, Bitter, Arvo |
Dial D: Aesthetic Family (mod 12)
| Index | Family | Surface Tendency | Typography | Accent Style | Layout |
|---|---|---|---|---|---|
| 0 | Swiss/International | Pure white or light gray | Geometric sans | Single saturated, sparse | 12-col grid, strict alignment |
| 1 | Neo-brutalist | White or bright color | System mono or bold sans | Black + one loud color | Broken grid, thick borders |
| 2 | Editorial/Magazine | Off-white (not cream) | Serif display + sans body | Muted, editorial | Asymmetric, generous whitespace |
| 3 | Soft-tech | Tinted light | Rounded sans | Pastel gradient | Rounded cards, soft shadows |
| 4 | Industrial/Utilitarian | Near-black or concrete gray | Monospace | Single neon or warning | Dense grid, no decoration |
| 5 | Art Deco/Geometric | Deep color (navy, forest) | Display serif or geometric sans | Gold, brass | Symmetric, geometric patterns |
| 6 | Organic/Natural | Earth tones | Humanist sans | Warm, natural | Flowing, irregular shapes |
| 7 | Retro-futuristic | Dark with color tint | Display sans or pixel font | Neon, holographic | Asymmetric, layered |
| 8 | Minimalist/Zen | Pure white, max whitespace | Thin sans (weight 300-400) | Single muted tone, barely there | Extreme whitespace, few elements |
| 9 | Data-dense/Mission Control | Dark or neutral | Monospace + condensed sans | Status colors (green/amber/red) | Multi-panel, dense grid, no wasted space |
| 10 | Playful/Toy-like | Bright, saturated background | Rounded/bouncy sans | Multiple bold colors | Irregular, overlapping, rotated elements |
| 11 | Luxury/Refined | Deep black or dark color | Thin serif or elegant sans | Metallic (gold, silver, copper) | Generous spacing, minimal elements, large type |
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.
Output Your Spin
Before writing any code, output:
Design Dials: Surface=index · Accent=index · Type=index · Family=index → [specific font choice]
Example:
Design Dials: Surface=2(Tinted Dark, wine) · Accent=1(Gold, #d4a030) · Type=0(Serif) · Family=5(Art Deco/Geometric) → Libre Baskerville
Rules
- 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.
Step 2: Build with Craft
Implement working HTML/CSS/JS that is:
- Production-grade: Clean, semantic HTML. Well-organized CSS with custom properties. Functional JS.
- 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,charsetmetaviewport - Google Fonts loaded via with
<link>preconnect - All colors defined as semantic CSS custom properties in
:root - A media query that disables animations
prefers-reduced-motion - 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 (light theme) and
:root(dark theme)[data-theme="dark"] - Add a toggle button (sun/moon icon) in the page header or navigation
- Detect system preference via as the initial default
prefers-color-scheme: dark - Store user preference in so it persists across page reloads
localStorage - 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
- Define all colors as CSS custom properties in
Do NOT copy a fixed HTML skeleton. Structure the document to match the content.
Design Rules
Typography
- Load fonts via Google Fonts (or CDN for fonts not on Google Fonts). Always load 2+ weights.
<link> - 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 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.
clamp() - 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 . Name them to reflect purpose, not appearance (e.g., "surface", "emphasis", not "light-gray").
:root - 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 (), AI purple (
#3b82f6,#8b5cf6), AI purple-500 (#6366f1). 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.#a855f7 - BANNED dark surfaces: The blue-black range (
#0a-#0f,#0a0e1a,#0d1117,#0f172a,#111827). These are THE AI dark mode default. Use the Scene Sentence and Dark Surface Tint Guide to choose a non-blue dark surface.#1e1b4b - 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. 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.#e8dfcb - BANNED premium accents: brass/clay/oxblood family (,
#b08947,#b6553a,#9a2436,#9c6e2a,#bc7c3a) and espresso text (#7d5621,#1a1714,#1a1814). These are the AI "premium-consumer" defaults. Alternatives for premium-consumer briefs (rotate, do not reuse):#1b1814- Cold Luxury: silver-grey + chrome + smoke (think Tesla, Apple Watch)
- 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: between 1100-1400px (vary it), centered with auto margins and horizontal padding.
max-width - Use not
min-height: 100dvh.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: 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.
border-radius - Buttons: Clear hover state + active press ().
scale(0.97-0.98) - Tables: Use for number columns.
font-variant-numeric: tabular-nums - 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 and
transform. Never animate layout properties.opacity - No . Specify exact properties.
transition: all - No or default
linear. Use custom cubic-bezier curves — but choose different curves for different projects.ease-in-out - 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 (, 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.
generate_image - Real web images second — Use for placeholder photography (seed should describe the section, e.g.
https://picsum.photos/seed/{descriptive-seed}/{w}/{h}). Or use Unsplash/Pexels direct URLs.crypto-dashboard-hero - Last resort: tell the user — If neither is possible, leave clearly-labeled placeholder slots () and note what images are needed.
<!-- TODO: hero product photo, 1600x900 -->
Rules:
- Always include text on all images. Decorative images use
alt.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 () or generate simple monogram SVGs. Do NOT use plain text wordmarks (
https://cdn.simpleicons.org/{slug}/{color}styled in a row). Logo wall = logos only, no industry/category labels below each logo.<span>Acme Co</span> - No pills/labels overlaid on images: No overlays on photos with tags like "Brand · 02" or "Field notes". Let the image speak alone, or add a caption below (outside the image).
<span> - 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 without providing an alternative.
outline - Alt text: All meaningful images must have descriptive text. Decorative images use
alt.alt="" - Heading hierarchy: Use sequential →
h1, no level skipping. Oneh6per page.h1 - 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 . Form inputs must have associated
aria-label.<label> - Skip link: Include a "Skip to main content" link as the first focusable element.
- Reduced motion: Respect — disable or simplify all animations.
prefers-reduced-motion: reduce
Forms & Feedback
- Visible labels: Every input must have a visible , not just a placeholder.
<label> - 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 attributes (
type,email,tel,number) to trigger correct mobile keyboards.url - 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 () for tactile feel.
scale(0.97-0.98) - 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 (
–). Number ranges use hyphens (2018-2026).€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×must come from real data or be explicitly labeled as mock. Don't fake engineering precision.48k - 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 in
--var(light) and:root(dark).[data-theme="dark"] - Toggle UI — add a simple toggle button (sun/moon icon) in the header/nav. Store preference in .
localStorage - System preference detection — use as the initial default if no stored preference.
prefers-color-scheme: dark - 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 preference
const stored = localStorage.getItem('theme');
const prefersDark = matchMedia('(prefers-color-scheme: dark)').matches;
document.documentElement.dataset.theme = stored || (prefersDark ? 'dark' : 'light');
// Toggle handler
function toggleTheme() {
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) — use Scene Sentence to anchor a non-blue tint#111827 - ❌ Centered hero + three equal feature cards (the #1 AI layout)
- ❌ Same-sized card grid repeated endlessly
- ❌ on cards
border-radius: 24px+ - ❌ or
transition: alleasinglinear - ❌ Emoji as navigation/action icons
- ❌ Gradient text () — use solid colors for text
background-clip: text - ❌ Gray text below 4.5:1 contrast ratio
- ❌ for full-height sections (use
100vh)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 on
repeating-linear-gradientor section backgrounds. Rule: banned. Use other surface treatments from references/aesthetics.md.body::before - Gradient text on headings — Claude frequently applies + gradient to large headings. Rule: banned. Use solid colors for all text.
background-clip: text - Deep blue-black default — When asked for dark mode, Claude almost always picks the blue-black range. Rule: must use Scene Sentence to anchor a specific, non-blue dark tint.
#0a-#0f
The AI Slop Test (Two Layers)
Before delivering, run both layers:
Layer 0: Production-Test Tells (73-Brand Benchmark)
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 |
| 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 for responsive sizing
clamp() - 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 () or AI purple (
#3b82f6,#8b5cf6,#6366f1)#a855f7 - Background is not cream/beige/sand (,
#f5f1ea,#f7f5f1, etc.) unless Design Read demands it#fbf8f1 - Background is not blue-black (,
#0a0e1a,#0d1117,#0f172a) — verify hex value#111827 - Accent is not brass/clay/oxblood (,
#b08947,#b6553a) unless Design Read demands it#9a2436 - 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 blue-black range (Scene Sentence must anchor the tint)
#0a-#0f
Technical
- media query present
prefers-reduced-motion - Entrance animation strategy present (scroll reveal / page-load stagger / state-driven — one of three)
- No anywhere
transition: all - No easing on UI elements
linear - No (use
100vh)100dvh - No horizontal scroll at 375px width
- All images have text (decorative images use
alt)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)
- selector defines dark theme values
[data-theme="dark"] - detected for initial theme if no stored preference
prefers-color-scheme: dark - 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 per page
h1 - Icon-only buttons have
aria-label - Form inputs have associated elements
<label> - 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 (range with blue hue) unless the dial explicitly selected it
#07-#0f - Font is NOT Inter, Plus Jakarta Sans, Space Grotesk, DM Sans, or Manrope