
Project Design
- 198 installs
- 21 repo stars
- Updated August 3, 2026
- starchild-ai-agent/official-skills
Use project-design for development tasks
About
project-design: A skill for development. This provides functionality for development workflows.
- project-design
Project Design by the numbers
- 198 all-time installs (skills.sh)
- +5 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #2,050 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/starchild-ai-agent/official-skills --skill project-designAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 198 |
|---|---|
| repo stars | ★ 21 |
| Last updated | August 3, 2026 |
| Repository | starchild-ai-agent/official-skills ↗ |
What it does
Use project-design for development tasks
Files
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:
1. User-specified settings (highest priority) — explicit requests like "use dark mode", "make it blue", "use Playfair Display font", "I want a minimalist style" 2. Design Read inference — signals inferred from the brief content and context 3. 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 #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) |
|---|---|---|
| 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: 1. Proper DOCTYPE, charset, viewport meta 2. Google Fonts loaded via <link> with preconnect 3. All colors defined as semantic CSS custom properties in :root 4. A prefers-reduced-motion media query that disables animations 5. Box-sizing reset and font-smoothing 6. 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
7. 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: darkas the initial default - Store user preference in
localStorageso 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-#0fblue-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): - 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:
max-widthbetween 1100-1400px (vary it), centered with auto margins and horizontal padding. - Use
min-height: 100dvhnot100vh. - 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-radiusmax 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-numsfor 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
transformandopacity. Never animate layout properties. - No
transition: all. Specify exact properties. - No
linearor defaultease-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: 1. 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. 2. Real web images second — Use https://picsum.photos/seed/{descriptive-seed}/{w}/{h} for placeholder photography (seed should describe the section, e.g. crypto-dashboard-hero). Or use Unsplash/Pexels direct URLs. 3. 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
outlinewithout providing an alternative. - Alt text: All meaningful images must have descriptive
alttext. Decorative images usealt="". - Heading hierarchy: Use sequential
h1→h6, no level skipping. Oneh1per 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
typeattributes (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×,48kmust 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: 1. Would a human copywriter write this? Or does it sound like ChatGPT? 2. Is this specific to the product, or could it apply to any product in the category? 3. Does the heading actually say something, or is it a vague platitude? 4. Are there any grammatically broken phrases or AI-hallucinated wordplay? 5. 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:
1. CSS custom properties for all colors — define all colors as --var in :root (light) and [data-theme="dark"] (dark). 2. Toggle UI — add a simple toggle button (sun/moon icon) in the header/nav. Store preference in localStorage. 3. System preference detection — use prefers-color-scheme: dark as the initial default if no stored preference. 4. 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):
1. Scene sentence: Write a Scene Sentence (see Step 0.5) to anchor the dark palette. Do NOT default to blue-black. 2. Surface hierarchy: Dark backgrounds need MORE levels of elevation than light (at least 4 distinct surface levels). 3. Contrast independence: Verify contrast ratios independently for dark mode — don't assume light-mode-passing colors work on dark surfaces. 4. Accent adjustment: Accent colors often need to be lighter/more saturated on dark backgrounds to maintain the same visual weight. 5. Token strategy: Use the same CSS custom property names with different values:
: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 */
}6. Toggle implementation:
// 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,#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: allorlineareasing - ❌ Emoji as navigation/action icons
- ❌ Gradient text (
background-clip: text) — use solid colors for text - ❌ Gray text below 4.5:1 contrast ratio
- ❌
100vhfor full-height sections (use100dvh) - ❌ 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:
1. 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. 2. border-radius inflation — Claude tends to use 24px-40px border-radius on cards. Rule: cards max 16px; pill shapes only for tags/badges/buttons. 3. 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. 4. 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. 5. Gradient text on headings — Claude frequently applies background-clip: text + gradient to large headings. Rule: banned. Use solid colors for all text. 6. 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.
---
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 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
1. Could someone tell this was AI-generated? If yes → the design lacks a distinctive point-of-view. Redesign. 2. 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. 3. Does every section look the same? If yes → vary the layout rhythm. Mix card sizes, alternate text/image placement, break the grid. 4. 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.
5. 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. 6. 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. 7. 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. 8. 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: 1. Spacing consistency: Are all margins and paddings following the spacing system? Any awkward gaps? 2. Color harmony: Does every color on the page serve the same design direction? Any rogue shades? 3. Typography rhythm: Are heading sizes, weights, and letter-spacing consistent across sections? 4. Component polish: Do all buttons have hover + active states? Do all cards have consistent border-radius? 5. Copy quality: Re-read every visible string. Any AI-sounding phrases? Any em-dashes that slipped through? 6. Dark mode parity: Switch to the other theme. Does it look equally polished, or is one theme clearly an afterthought? 7. 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-#0fblue-black range (Scene Sentence must anchor the tint)
Technical
- [ ]
prefers-reduced-motionmedia query present - [ ] Entrance animation strategy present (scroll reveal / page-load stagger / state-driven — one of three)
- [ ] No
transition: allanywhere - [ ] No
lineareasing on UI elements - [ ] No
100vh(use100dvh) - [ ] No horizontal scroll at 375px width
- [ ] All images have
alttext (decorative images usealt="") - [ ] 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: darkdetected 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
h1per 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-#0frange with blue hue) unless the dial explicitly selected it - [ ] Font is NOT Inter, Plus Jakarta Sans, Space Grotesk, DM Sans, or Manrope
Aesthetic Direction Reference
Color Strategy: Choose a Level First
Before picking any colors, decide your strategy level. This determines how much color your design uses.
| Level | Description | When to Use | Example |
|---|---|---|---|
| Restrained | Near-monochrome. One accent used sparingly (links, active states, one CTA). Surface does the work. | Data tools, documentation, professional dashboards | Notion, Linear, Stripe Docs |
| Committed | One accent color used boldly — in headers, illustrations, key UI elements. Still disciplined. | SaaS products, portfolios, marketing pages | Vercel, Figma, Raycast |
| Full palette | 3-5 harmonious colors, each with a role. Requires careful balance. | Creative tools, consumer apps, editorial | Slack, Notion (with databases), Pitch |
| Drenched | Color IS the brand. Saturated backgrounds, colored surfaces, bold combinations. | Fashion, entertainment, gaming, art | Spotify, Discord, Gumroad |
The strategy level should match your Design Read. A clinical developer tool at "Drenched" will feel wrong. A gaming landing page at "Restrained" will feel lifeless.
---
How to Build a Color Palette From Scratch
Do NOT copy a preset palette. Build one from your design direction.
Step 1: Pick a Base Surface Color
Start with the background — the most impactful decision.
- Light surfaces: Pure white or a very subtle tint. To tint, add 1-3% of your accent hue to white. Avoid warm neutrals (cream, beige, sand) unless the Design Read explicitly calls for warmth.
- Dark surfaces: Near-black, not pure
#000. Add 2-5% of your accent hue for depth. Write a "scene sentence" first — what physical space does this dark mode evoke? See the Dark Surface Tint Guide below for scene-to-color mapping. NEVER use the default#0a-#0fblue-black range. - Colored surfaces: A saturated or muted color AS the background (deep navy, forest green, dusty rose). This is bold — commit fully.
Step 2: Derive Your Neutral Scale
From your base surface, create 3-5 shades for hierarchy. Name them by purpose, not appearance:
- Primary surface → your base background
- Secondary surface → slightly offset for sections, sidebars, alternating areas
- Elevated surface → cards, containers, floating elements
- Interactive surface → hover and active states
For dark themes: each step adds ~5-10% lightness. You need MORE levels than light themes (at least 4). For light themes: each step subtracts ~2-5% lightness.
Choose your own CSS custom property names that make sense for your project. Don't use the same naming scheme every time.
Step 3: Choose Your Accent Color
Pick a single accent color that:
- Has meaning for the content OR deliberately subverts expectations
- Contrasts well against your surface (test at 4.5:1 ratio)
- Is NOT the AI default (avoid generic blue and AI purple)
- Is NOT the "anti-AI-default" default (teal/emerald have become the new AI purple — vary further)
- Is NOT in the banned accent list (see Banned Color Reference below)
Derive a hover state by adjusting lightness ±10%.
Subversion principle: If the topic strongly implies a color (blue for finance, green for health, red for food), consider whether a less obvious choice would be more distinctive. A finance dashboard in warm amber or deep indigo can be more memorable than yet another blue one.
Step 4: Set Text Colors
Create 3 levels of text hierarchy:
- Primary text → high contrast against surface (≥ 7:1 for body text)
- Secondary text → medium contrast (≥ 4.5:1) for supporting text
- Muted text → lower contrast (≥ 3:1) for captions, timestamps, labels
For dark themes: white → light gray → medium gray For light themes: near-black → dark gray → medium gray
Step 5: Define Semantic Colors
Always include functional colors regardless of aesthetic:
- A success green that works on your surface
- A warning amber that works on your surface
- An error red that works on your surface
- A subtle border/separator color
Step 6: Assemble as CSS Custom Properties
Define all colors in :root using semantic names. Choose names that reflect your project's vocabulary — there is no single correct naming convention. The goal is clarity and consistency within the project, not conformity across projects.
For dark mode: use the same property names with different values under a theme selector ([data-theme="dark"], .dark, or prefers-color-scheme: dark).
---
How to Choose Typography
Step 1: Match Font Character to Content
| Content Type | Font Character | Why |
|---|---|---|
| Data/analytics dashboard | Geometric sans or monospace | Precision, clarity, tabular alignment |
| Creative portfolio | Distinctive display font | Personality, memorability |
| Professional tool | Clean humanist sans | Readability, trust |
| Editorial/content | Serif or humanist sans | Reading comfort, authority |
| Developer tool | Monospace | Code familiarity, alignment |
| Playful/social | Rounded sans | Friendliness, approachability |
Step 2: Browse Google Fonts with Intent
Go to fonts.google.com and filter by:
- Category (sans-serif, serif, monospace, display)
- Number of styles (pick fonts with 4+ weights for flexibility)
- Trending / recently updated (for freshness)
The anti-repetition rule: If you've used a font in a recent generation, pick a different one. Also avoid converging on the same "safe alternative" fonts (Space Grotesk, DM Sans, Outfit, Plus Jakarta Sans, Manrope) — these have become AI anti-defaults. When a Style Preset is active, use the preset's specified font instead of choosing your own.
Step 3: Set Up the Type Scale
Build a consistent type scale. Use clamp() for responsive heading sizes. Key constraints:
| Level | Size Range | Weight | Line Height | Letter Spacing |
|---|---|---|---|---|
| h1 | Responsive, max ~3rem | 600-800 | 1.05-1.15 | -0.02em to -0.03em |
| h2 | Responsive, max ~2rem | 600 | 1.15-1.25 | -0.01em |
| h3 | Responsive, max ~1.25rem | 500-600 | 1.25-1.35 | normal |
| Body | 16px minimum | 400 | 1.5-1.6 | normal |
| Small | 14px | 400-500 | 1.4 | normal |
| Caption | 12px | 400-500 | 1.3 | 0.01em |
Adjust the specific values to match your design direction — airy designs use larger sizes with more spacing, dense designs use tighter scales. Don't use the exact same values every time.
Real-World Typography References (from 73 major brands)
These are actual values extracted from production websites. Use them as calibration points, not templates. Organized by aesthetic category.
Minimal / Developer Platform
| Brand | Display Size | Display Weight | Display Letter-Spacing | Body Size | Body LH | Body LS |
|---|---|---|---|---|---|---|
| Apple | 56px | 600 | -0.28px | 17px | 1.47 | 0 |
| Vercel | 48px | 600 | -2.4px | 16px | 1.5 | 0 |
| Linear | 56px | 500 | -3px | 16px | 1.5 | 0 |
| Expo | 64px | 600 | -1.92px | 16px | 1.5 | 0 |
| Ollama | 36px | 500 | 0 | 16px | 1.5 | 0 |
Editorial / Magazine
| Brand | Display Size | Display Weight | Display Letter-Spacing | Body Size | Body LH | Body LS |
|---|---|---|---|---|---|---|
| ElevenLabs | 64px | 300 | -1.92px | 16px | 1.5 | +0.16px |
| Mistral | 84px | 400 | -1.5px | 16px | 1.55 | 0 |
| Resend | 96px | 400 | -0.96px | 16px | 1.5 | -0.8px |
| Wired | 64px | 400 | -0.5px | 19px (serif) | 1.47 | +0.108px |
| Replicate | 72px | 700 | -1.8px | 16px | 1.5 | 0 |
Enterprise / Infrastructure
| Brand | Display Size | Display Weight | Display Letter-Spacing | Body Size | Body LH | Body LS |
|---|---|---|---|---|---|---|
| IBM | 76px | 300 | -0.5px | 16px | 1.5 | +0.16px |
| HashiCorp | 80px | 700 | -2.5px | 16px | 1.5 | 0 |
| HP | 72px | 500 | 0 | 16px | 1.38 | 0 |
| NVIDIA | 48px | 700 | 0 | 16px | 1.5 | 0 |
| MongoDB | 72px | 500 | -1.5px | 16px | 1.55 | 0 |
Consumer / Commerce
| Brand | Display Size | Display Weight | Display Letter-Spacing | Body Size | Body LH | Body LS |
|---|---|---|---|---|---|---|
| Airbnb | 28px | 700 | 0 | 16px | 1.5 | 0 |
| Uber | 52px | 700 | 0 | 16px | 1.5 | 0 |
| Meta | 64px | 500 | 0 | 16px | 1.5 | -0.16px |
| Shopify | 96px | 330 | +2.4px | 16px | 1.5 | 0 |
| 70px | 600 | -1.2px | 16px | 1.4 | 0 | |
| Mastercard | 64px | 500 | -1.28px | 16px | 1.4 | 0 |
| Revolut | 136px | 500 | -2.72px | 16px | 1.5 | +0.24px |
Luxury / Automotive
| Brand | Display Size | Display Weight | Display Letter-Spacing | Body Size | Body LH | Body LS |
|---|---|---|---|---|---|---|
| Ferrari | 80px | 500 | -1.6px | 14px | 1.5 | 0 |
| Lamborghini | 120px | 400 | 0 | 16px | 1.5 | 0 |
| SpaceX | 80px | 700 | +1.6px | 16px | 1.5 | +0.32px |
| Renault | 56px | 700 | 0 | 16px | 1.4 | 0 |
AI / Developer Tools
| Brand | Display Size | Display Weight | Display Letter-Spacing | Body Size | Body LH | Body LS |
|---|---|---|---|---|---|---|
| MiniMax | 80px | 600 | -2px | 16px | 1.5 | 0 |
| Mintlify | 72px | 600 | -2px | 16px | 1.5 | 0 |
| Miro | 80px | 500 | -2px | 16px | 1.5 | 0 |
| Intercom | 72px | 500 | -2.0px | 16px | 1.5 | 0 |
| Sanity | 112px | 400 | -4.48px | 16px | 1.5 | 0 |
Entertainment / Gaming
| Brand | Display Size | Display Weight | Display Letter-Spacing | Body Size | Body LH | Body LS |
|---|---|---|---|---|---|---|
| PlayStation | 54px | 300 | -0.1px | 18px | 1.5 | +0.1px |
| The Verge | 107px | 900 | +1.07px | 16px | 1.6 | 0 |
| Vodafone | 144px | 800 | -1px | 18px | 1.56 | 0 |
| Superhuman | 64px | 540 | 0 | 16px | 1.5 | 0 |
Key insights from 73 brands: 1. 85% use negative letter-spacing on display — the range is -0.28px to -4.48px. AI skips this entirely. 2. Display weight 400-500 is the sweet spot — 45% of brands use this range. Only 15% use 700+. 3. Body line-height clusters at 1.5 — with 1.4-1.55 as the full range. 1.6+ is rare outside editorial. 4. Positive body letter-spacing is a premium signal — IBM +0.16px, ElevenLabs +0.16px, Revolut +0.24px, SpaceX +0.32px. 5. Display sizes go much larger than AI defaults — Vodafone 144px, Revolut 136px, Lamborghini 120px, Sanity 112px. AI rarely exceeds 64px.
Real-World Border-Radius References (from 73 major brands)
Sharp / Angular (0-4px)
| Brand | Buttons | Cards | Pills/Tags | Input Fields | Signature |
|---|---|---|---|---|---|
| IBM | 0px | 0px | 0px | 0px | Carbon: everything square |
| Ferrari | 0px | 0px | 9999px (badge) | 4px | Luxury precision |
| Lamborghini | 0px | 0px | 2px | 20px (switch) | Aggressive angular |
| NVIDIA | 2px | 2px | 2px | 2px | Engineering grade |
| Warp | 3px | 3px | 9999px | 3px | Terminal aesthetic |
| OpenCode | 4px | 4px | 4px | 4px | Monospace discipline |
Moderate (6-12px)
| Brand | Buttons | Cards | Pills/Tags | Input Fields | Signature |
|---|---|---|---|---|---|
| Vercel | 6px | 12px | 999px | 6px | Developer standard |
| Expo | 8px | 12px | 9999px | 8px | React Native standard |
| Intercom | 8px | 12px | 9999px | 8px | SaaS standard |
| Mistral | 8px | 12px | 9999px | 8px | Editorial sober |
| Sentry | 8px | 12px | 4px | 8px | Developer playful |
| Kraken | 12px | 12px | 6px | 12px | Crypto standard |
Soft (16-32px)
| Brand | Buttons | Cards | Pills/Tags | Input Fields | Signature |
|---|---|---|---|---|---|
| Apple | 980px (pill) | 18px | 980px | 12px | Pill buttons + soft cards |
| Airbnb | 8px | 14px | 999px | 8px | Warm marketplace |
| Uber | 999px (pill) | 16px | 36px | 8px | Pill + moderate cards |
| HP | 4px | 16px | 9999px | 4px | Sharp buttons + soft cards |
| 16px | 16px | 9999px | 16px | Unified 16px | |
| Meta | 100px (pill) | 32px | 100px | 8px | Pill + large cards |
| Miro | 9999px (pill) | 28px | 9999px | 8px | Pill + pastel cards |
Extreme (40px+ / Full Pill)
| Brand | Buttons | Cards | Pills/Tags | Input Fields | Signature |
|---|---|---|---|---|---|
| Mastercard | 20px | 40px | 999px | 999px | Stadium shapes |
| MiniMax | 9999px | 32px (hero) / 16px (std) | 9999px | 8px | Dual-radius system |
| Revolut | 9999px | 20px | 9999px | 8px | Fintech pill |
| MongoDB | 9999px | 12px | 6px | 8px | Green pill + moderate cards |
Key insights from 73 brands: 1. Card radius: 12px is the mode — 35% of brands use 12px for cards. 16px is second at 20%. 24px+ is rare (~10%). 2. Button radius is bimodal — either sharp (0-8px, ~30%) or full pill (9999px, ~40%). The 12-16px middle ground is uncommon. 3. The "two-tier" pattern — many brands use sharp/moderate buttons with softer cards (HP: 4px buttons + 16px cards) or pill buttons with moderate cards (MongoDB: pill + 12px cards). 4. 0px radius = luxury/enterprise signal — IBM, Ferrari, Lamborghini all use 0px. It reads as precision and authority. 5. AI over-rounds everything — AI defaults to 24px+ cards and 8-12px buttons. Real brands are either sharper or more committed to pills.
---
How to Design Layout
Match Layout to Content Type
| Content | Layout | Why |
|---|---|---|
| Dashboard with KPIs + charts | Sidebar + grid content | Navigation always visible, data organized |
| Single-purpose tool | Top nav + centered content | Focus on the task |
| Portfolio / showcase | Full-width sections | Each project gets full attention |
| Data-heavy table view | Top nav + full-width table | Maximum horizontal space |
| Multi-panel monitoring | Bento grid | Different data types, different sizes |
| Article / documentation | Single column, max-width 65ch | Optimal reading experience |
| Marketing / landing page | Full-width sections with varied layouts | Visual storytelling |
Layout Variety Within a Page
A page with 5+ sections must NOT repeat the same layout pattern. Audit your sections top-to-bottom:
- If section 1 is centered text, section 2 should NOT also be centered text
- If sections 2-3 alternate image-left/image-right (zigzag), section 4 must break the pattern
- Vary content width: some sections full-bleed, some contained, some narrow
Don't Default to the Same Layout
If your last generation used a sidebar layout, try top nav or bento grid next. If it was a card grid, try a table or split panel. Variety in layout is as important as variety in color.
---
Surface Treatments (Optional Depth)
These are techniques to add visual depth. Use 0-2 per project, not all of them. Implement fresh each time — don't copy the same code.
| Technique | What It Does | When to Use | When NOT to Use |
|---|---|---|---|
| Noise/grain texture | SVG feTurbulence overlay at very low opacity on a fixed pseudo-element | Editorial, analog, luxury aesthetics | Clean/minimal designs, data-dense dashboards |
| Gradient orbs | Radial gradients using accent color at low opacity, positioned as fixed background | Dark tech/AI themes that need atmospheric depth | Light themes, corporate/clean designs |
| Glass/blur cards | backdrop-filter: blur with semi-transparent background and hairline border | Dark themes with layered depth, floating nav bars | Scrolling content areas (kills mobile perf), light themes |
| Nested card (double-bezel) | Outer shell with subtle bg + inner content card with smaller border-radius | Premium/luxury feel, hero feature cards | Every card on the page (use sparingly, 1-2 max) |
| Subtle gradient background | Linear or radial gradient on body, very low saturation | Pastel/soft aesthetics, wellness/education | Data dashboards, professional tools |
| Dot grid pattern | Repeating radial-gradient dots at low opacity | Technical/engineering aesthetics | Organic/warm designs |
Rules:
- Pick 0-2 treatments per project. More than 2 is visual noise.
- A clean surface with no effects is always a valid choice — often the best one.
backdrop-filter: bluronly on fixed/sticky elements, never on scrolling containers.- All overlays must be
pointer-events: noneandposition: fixed.
---
Dark Surface Tint Guide
When the Design Dials select a dark or tinted surface (indices 2, 3, or 4), use the Scene Sentence to determine the tint direction. NEVER default to the `#0a-#0f` blue-black range — this is the #1 cause of AI design sameness.
Scene-to-Tint Mapping
| Scene Environment | Tint Direction | Example Base | Example Elevated | CSS Custom Property Hint |
|---|---|---|---|---|
| Studio with warm lighting | Warm charcoal | #1a1816 | #242220 | --surface: hsl(30, 8%, 9%) |
| Forest cabin at night | Deep green-black | #0f1512 | #1a201c | --surface: hsl(150, 15%, 7%) |
| Wine cellar / luxury lounge | Deep wine/burgundy | #1a1014 | #24181c | --surface: hsl(340, 25%, 8%) |
| Industrial workshop | Warm gray-brown | #1c1a18 | #26241f | --surface: hsl(40, 8%, 10%) |
| Cinema / theater | Pure neutral black | #111111 | #1a1a1a | --surface: hsl(0, 0%, 7%) |
| Underwater / aquatic | Deep teal-black | #0f1614 | #1a211e | --surface: hsl(160, 20%, 7%) |
| Desert night | Warm sand-black | #181614 | #22201c | --surface: hsl(30, 10%, 8%) |
| Arctic / ice | Cool blue-gray | #14161a | #1e2024 | --surface: hsl(220, 12%, 9%) |
How to Use This Table
1. Write your Scene Sentence (see SKILL.md Step 0.5) 2. Find the closest matching environment in the table above 3. Use the example colors as a starting point, then adjust to match your specific scene 4. Derive 4+ surface levels by incrementing lightness by 5-10% per step 5. Verify all text contrast ratios against your chosen surface
Banned Dark Surface Colors
These specific hex values are absolutely banned as dark surface backgrounds — they are the AI default dark mode palette:
/* BANNED — AI default blue-black surfaces */
#0a0e1a /* Most common AI deep blue-black */
#0d1117 /* GitHub-style deep blue-black */
#0f172a /* Tailwind slate-900 */
#111827 /* Tailwind gray-900 */
#1e1b4b /* Tailwind indigo-950 */Any background color in the #07-#0f range with a blue hue component is suspect. If your dark surface has more blue than any other hue channel, reconsider.
---
Banned Color Reference
A comprehensive list of colors to avoid as defaults. These are the most common AI-generated color choices across thousands of outputs.
AI Default Accents
/* BANNED as default accent — AI's go-to colors */
#3b82f6 /* Tailwind blue-500 — the #1 AI accent */
#6366f1 /* Tailwind indigo-500 */
#8b5cf6 /* Tailwind violet-500 */
#a855f7 /* Tailwind purple-500 */Exemption: Only if the Design Read explicitly demands blue/purple (e.g., a brand whose identity IS blue), document the justification in a code comment.
AI Default Warm Neutral Backgrounds
/* BANNED as default background — 2025-2026 AI warm neutral wave */
#f5f1ea
#f7f5f1
#fbf8f1
#efeae0
#ece6db
#faf7f1
#e8dfcbAny warm neutral with OKLCH L 0.84-0.97, C < 0.06, hue 40-100 falls in this category.
AI Default Premium Accents
/* BANNED as default — AI "premium-consumer" palette */
#b08947 /* brass */
#b6553a /* clay */
#9a2436 /* oxblood */
#9c6e2a /* ochre */
#bc7c3a /* amber-brown */
#7d5621 /* dark gold */
/* BANNED — AI "premium" text colors */
#1a1714 /* espresso */
#1a1814 /* espresso variant */
#1b1814 /* espresso variant */Anti-Default Defaults (the trap one tier deeper)
These aren't banned outright, but be aware they are becoming the new AI defaults:
- Teal/emerald — has become "the new AI purple" (the go-to when told to avoid blue/purple)
- Warm amber/gold — becoming the "sophisticated alternative" to blue
- Sage green — the "calming, natural" default
When you find yourself reaching for these, ask: "Am I choosing this because it's right for the content, or because it's my safe alternative?" If the latter, explore further.
---
Curated Color Palettes by Aesthetic Family
These are starting points, not templates. Pick one as inspiration, then adjust to match your specific Design Read. Never copy a palette verbatim across projects.
Swiss/International
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #fafafa | #141414 | Near-white / near-black, no tint |
| Elevated | #ffffff | #1e1e1e | Pure contrast |
| Accent | #e63946 | #ff6b6b | Swiss red, bold and singular |
| Text | #1d1d1f | #f0f0f0 | Maximum readability |
| Muted | #86868b | #8e8e93 | Functional gray |
Neo-brutalist
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #fffdf5 | #1a1a1a | Warm white / true black |
| Elevated | #ffffff | #2a2a2a | With thick black borders |
| Accent | #ff5722 | #ff7043 | Loud, unapologetic |
| Secondary | #ffeb3b | #fdd835 | Yellow highlight |
| Text | #000000 | #ffffff | Pure black/white |
| Border | #000000 (3px) | #ffffff (3px) | Thick, visible |
Editorial/Magazine
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #f8f6f3 | #1c1917 | Warm paper / warm dark |
| Elevated | #ffffff | #262220 | Subtle warmth |
| Accent | #c2452d | #e05a3a | Editorial red-orange |
| Text | #2c2825 | #e8e2da | Warm, not pure black |
| Caption | #8a8078 | #9a9088 | Warm gray |
Soft-tech
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #f0f4ff | #161a2e | Soft blue tint |
| Elevated | #ffffff | #1e2240 | Gentle lift |
| Accent | #6c5ce7 | #a29bfe | Soft purple |
| Secondary | #00cec9 | #55efc4 | Mint complement |
| Text | #2d3436 | #dfe6e9 | Soft contrast |
| Shadow | rgba(108,92,231,0.08) | rgba(162,155,254,0.12) | Tinted shadows |
Industrial/Utilitarian
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #e8e6e3 | #141413 | Concrete / carbon |
| Elevated | #f2f0ed | #1c1c1a | Subtle lift |
| Accent | #f59e0b | #fbbf24 | Warning amber |
| Status Green | #22c55e | #4ade80 | System go |
| Status Red | #ef4444 | #f87171 | System alert |
| Text | #1c1917 | #d4d4d4 | Functional |
| Mono | JetBrains Mono | JetBrains Mono | Monospace throughout |
Art Deco/Geometric
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #1a1a2e | #0d0d1a | Deep midnight |
| Elevated | #25254a | #16162e | Rich depth |
| Accent | #d4af37 | #e8c547 | True gold |
| Secondary | #c9a96e | #d4b87a | Antique brass |
| Text | #f0e6d3 | #e8dcc8 | Warm cream on dark |
| Pattern | rgba(212,175,55,0.1) | rgba(212,175,55,0.15) | Geometric overlays |
Organic/Natural
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #f5f2ed | #1a1c18 | Parchment / forest floor |
| Elevated | #faf8f4 | #242620 | Natural warmth |
| Accent | #5a7247 | #7d9a6a | Moss green |
| Secondary | #c17f59 | #d4956e | Terracotta |
| Text | #2d2a26 | #e0dcd6 | Earth tone |
| Muted | #8a8279 | #9a9289 | Stone gray |
Retro-futuristic
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #1a0a2e | #0a0518 | Deep purple-black |
| Elevated | #2a1548 | #150d28 | Neon-ready dark |
| Accent | #00ff88 | #00ff88 | Neon green |
| Secondary | #ff006e | #ff3388 | Hot pink |
| Tertiary | #00b4d8 | #48cae4 | Cyan |
| Text | #e0ffe8 | #d0ffd8 | Green-tinted white |
| Glow | 0 0 20px rgba(0,255,136,0.3) | 0 0 30px rgba(0,255,136,0.4) | Neon glow effect |
Minimalist/Zen
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #ffffff | #111111 | Pure, no tint |
| Elevated | #fafafa | #1a1a1a | Barely there |
| Accent | #9ca3af | #6b7280 | Muted gray as accent |
| Text | #374151 | #d1d5db | Soft, not harsh |
| Muted | #d1d5db | #4b5563 | Whisper |
| Border | #f3f4f6 | #1f2937 | Nearly invisible |
Data-dense/Mission Control
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #f1f3f5 | #0c0c0e | Cool neutral |
| Elevated | #ffffff | #161618 | Panel background |
| Accent | #3b82f6 | #60a5fa | Functional blue (allowed here) |
| Success | #10b981 | #34d399 | System nominal |
| Warning | #f59e0b | #fbbf24 | Attention needed |
| Critical | #ef4444 | #f87171 | Alert |
| Text | #1e293b | #e2e8f0 | High contrast |
| Grid | rgba(0,0,0,0.06) | rgba(255,255,255,0.06) | Panel borders |
Playful/Toy-like
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #fff8e1 | #1a1520 | Warm yellow / playful dark |
| Elevated | #ffffff | #252030 | Bouncy cards |
| Primary | #ff6b6b | #ff8a8a | Coral red |
| Secondary | #4ecdc4 | #6ee7de | Turquoise |
| Tertiary | #ffe66d | #fff08a | Sunny yellow |
| Quaternary | #a06cd5 | #b88ae0 | Playful purple |
| Text | #2d3436 | #f0eef5 | Warm dark |
Luxury/Refined
| Role | Light Theme | Dark Theme | Notes |
|---|---|---|---|
| Surface | #0a0a0a | #050505 | Deep black |
| Elevated | #141414 | #0f0f0f | Subtle lift |
| Accent | #c9a55c | #d4b06a | Matte gold (not shiny brass) |
| Secondary | #8a7e6b | #9a8e7b | Warm stone |
| Text | #e8e4de | #f0ece6 | Warm white |
| Muted | #6b6560 | #7a746e | Understated |
| Border | rgba(201,165,92,0.15) | rgba(201,165,92,0.2) | Gold whisper |
Usage Notes
- Light-first families (Swiss, Editorial, Organic, Minimalist, Playful): The light theme is the "hero" — design it first, then derive the dark variant.
- Dark-first families (Art Deco, Retro-futuristic, Luxury, Industrial): The dark theme is the "hero" — design it first, then derive the light variant.
- Neutral families (Neo-brutalist, Soft-tech, Data-dense): Both themes are equally important.
- Never use these palettes as-is — they are starting points. Adjust hue, saturation, and lightness to match your specific Design Read and Scene Sentence.
---
The Creativity Rule
The examples and techniques in this file are starting points for thinking, not templates to copy. The best designs come from:
1. Understanding the content and audience first (Design Read) 2. Choosing a color strategy level that matches the atmosphere 3. Making intentional choices for each dimension 4. Combining familiar techniques in unfamiliar ways 5. Knowing the rules well enough to break them purposefully
If you find yourself reaching for the same combination you used before, stop and explore a different direction. The goal is that every project feels like it was designed specifically for its content — not generated from a template.
Animation & Motion Reference
Guidelines and timing standards for UI animation. These are constraints and principles — implement the actual CSS/JS fresh each time based on your design direction.
---
Core Principles
1. Animate only `transform` and `opacity`. Never animate width, height, top, left, margin, padding — they trigger layout recalculation. 2. No `transition: all`. Always specify exact properties: transition: transform 200ms, opacity 200ms. 3. No `linear` or default `ease-in-out`. Use custom cubic-bezier curves that match your design's personality. 4. Exit faster than enter. Exit animations should be ~70% of enter duration. 5. Motion must have purpose. Every animation should communicate something (feedback, orientation, continuity). Decorative-only animation is noise. 6. Respect `prefers-reduced-motion`. Provide a reduced alternative (opacity fade or instant) for every animation. 7. Delight scales inversely with frequency. High-frequency interactions (button clicks, tab switches) need near-invisible transitions. Low-frequency moments (page load, first reveal) can be more expressive.
---
Easing Philosophy
Choose easing curves that match your design's atmosphere. Define them as CSS custom properties, but use your own names and values — don't copy the same curves every time.
Guidelines for choosing curves:
- Entrances and reveals: Ease-out curves (fast start, gentle landing). The element "arrives" with confidence.
- Slides and panels: Slightly less aggressive ease-out. Smooth, continuous movement.
- Dramatic reveals: Exponential ease-out for hero animations and page-load sequences.
- Micro-interactions: Quick, subtle curves. The user should feel the response, not watch it.
Never use: linear (robotic), ease-in alone (sluggish entrances), default ease-in-out (generic, the browser default).
Real-world easing references (from major brands — use as starting points, not templates):
| Brand | Signature Curve | Feel |
|---|---|---|
| Apple | cubic-bezier(0.25, 0.1, 0.25, 1) | Smooth, confident |
| Stripe | cubic-bezier(0.4, 0, 0.2, 1) | Quick start, gentle land |
| Linear | cubic-bezier(0.16, 1, 0.3, 1) | Snappy, precise |
| Framer | cubic-bezier(0.76, 0, 0.24, 1) | Dramatic, poster-like |
| Spotify | cubic-bezier(0.3, 0, 0, 1) | Fast, musical |
| Tesla | cubic-bezier(0.5, 0, 0, 0.75) | Engineered, restrained |
| Airbnb | cubic-bezier(0.2, 0, 0, 1) | Warm, welcoming |
Vary your curves between projects. If every project uses the same cubic-bezier values, the motion becomes an AI signature. Adjust the control points to match the design's energy — snappier for technical tools, softer for editorial, bouncier for playful contexts.
---
Timing Standards
These are ranges, not fixed values. Choose within the range based on your design's density and energy.
| Element | Enter Duration | Exit Duration | Notes |
|---|---|---|---|
| Button hover/press | 80-150ms | 80-100ms | Should feel instant. High-frequency. |
| Card hover | 150-250ms | 120-180ms | Subtle lift or border change. |
| Tooltip/popover | 120-180ms | 80-120ms | Fast in, faster out. |
| Dropdown/select | 150-250ms | 120-180ms | Match card hover timing. |
| Modal/dialog | 200-300ms | 150-220ms | Scale + opacity. |
| Drawer/panel | 250-350ms | 200-280ms | Slide from edge. |
| Scroll reveal | 400-700ms | — | One-shot, no exit needed. |
| Page load stagger | 300-600ms | — | Stagger delay 30-80ms per item. |
Asymmetric timing rule: For high-frequency UI (tabs, toggles, accordions), consider making the entrance near-instant (0-50ms) and only animating the exit (100-150ms). The user's action should feel immediate.
---
Scroll Reveal
Every page should have scroll reveal on content sections. Use IntersectionObserver to add a class when elements enter the viewport.
Implementation approach (not a template — write fresh each time): 1. Mark revealable elements with a data attribute or class 2. Set their initial state in CSS (hidden: reduced opacity, slight transform offset) 3. Create an IntersectionObserver that adds a "visible" class on intersection 4. The "visible" class transitions to the final state using your easing variables 5. Unobserve after revealing (one-shot, not toggle)
Reveal styles — choose ONE per page and use it consistently:
- Fade up: opacity 0 + slight translateY → visible
- Fade in: opacity 0 → visible (simpler, calmer)
- Scale up: opacity 0 + slight scale → visible (more dramatic)
- Slide in: opacity 0 + translateX → visible (directional, editorial)
Stagger rules for grids/lists:
- Delay per item: 30-80ms (vary based on energy level)
- Total stagger duration: never exceed 400ms (so max ~5-8 items staggered)
- For longer lists, only stagger the first visible batch
---
Reduced Motion
Always include a prefers-reduced-motion media query that effectively disables animations and transitions. This is a hard requirement, not optional.
The implementation should:
- Set all
animation-durationandtransition-durationto near-zero - Apply to all elements including pseudo-elements
- Use
!importantto override inline styles
---
Interaction Feedback
- Button press: Slight scale-down on
:activefor tactile feedback - Card hover: Subtle lift (translateY) OR border/shadow change. Not both.
- Link hover: Color change or underline animation. Keep it simple.
- Focus: Visible focus ring for keyboard navigation. Never remove
:focus-visiblestyles.
---
Modal & Overlay Animation
- Overlay: Fade in opacity with optional backdrop blur
- Modal content: Scale from slightly smaller + fade in. Never start from
scale(0)— nothing appears from nothing. - Drawer: Slide from edge (translateX or translateY depending on direction)
- Exit: Reverse the animation, but faster (70% of enter duration)
- Overlay and content animate independently — the overlay fades while the content transforms
---
Skeleton Loading
- Use a horizontal shimmer effect (gradient sweep from left to right)
- Match skeleton shapes to the content they replace (text lines, avatars, cards)
- Animation: infinite loop, ~1.5s duration
- Disable shimmer animation when
prefers-reduced-motionis active — show static placeholder instead
---
Anti-Patterns
- ❌
transition: all— animates unintended properties, causes jank - ❌ Animating layout properties (
width,height,top,left,margin) - ❌
lineareasing on UI elements - ❌ Starting from
scale(0)— nothing appears from nothing - ❌ Permanent
will-change— only during active animation - ❌
backdrop-bluron scrolling containers — kills mobile performance - ❌ Symmetric enter/exit timing — exit should be faster
- ❌ Animations without
prefers-reduced-motionfallback - ❌ Bouncy/elastic easing on UI elements (save for marketing/playful contexts only)
- ❌ Same easing curves and timing on every project — vary to match the design's energy
- ❌ Scroll-triggered animations that replay on scroll-up (use one-shot reveals)
Charts & Data Visualization Reference
Guidelines for creating professional charts in single-HTML dashboards. These are design standards — implement the actual chart code fresh each time.
---
Library Selection
Load via CDN in <script> tag:
| Library | Use When |
|---|---|
Chart.js (chart.js@4) | Most dashboards. Simple API, good defaults, lightweight (~65KB) |
ECharts (echarts@5) | Complex/interactive dashboards. Rich features, larger (~300KB) |
uPlot (uplot@1) | High-performance time series. Minimal, fast (~35KB) |
Default to Chart.js unless the dashboard needs advanced interactions (drill-down, linked charts, complex tooltips).
---
Chart Type Selection
| Data Pattern | Use | Don't Use |
|---|---|---|
| Trend over time | Line chart | Bar chart (unless discrete periods) |
| Comparing categories | Vertical bar chart | Pie chart |
| Long category labels | Horizontal bar chart | Vertical bar (labels get truncated) |
| Parts of a whole (≤5 segments) | Donut chart | Pie chart with >5 segments |
| Parts of a whole (>5 segments) | Horizontal bar chart | Pie or donut (too many slices) |
| Distribution | Area chart | Pie chart |
| Single metric vs target | Progress bar or gauge | Full chart (overkill) |
| Inline trend indicator | Sparkline (canvas mini-chart) | Full chart in a stat card |
Never use: 3D charts, radar charts for simple data, pie charts with >5 segments.
---
Styling Rules
Colors
- Use your page's CSS custom properties for chart colors. Never use library default colors.
- Read CSS variables with
getComputedStyle(document.documentElement).getPropertyValue(...). - For multi-series: derive variations from your accent (adjust opacity or lightness), or use a harmonious set that matches your palette.
- All data colors must pass 3:1 contrast against the chart background.
Grid & Axes
- Grid lines: very subtle — use your border/separator color or lower opacity. Grid should never compete with data.
- Axis labels: use your muted text color, 12px font size.
- Include units on axis labels ($ / % / K / M).
- Hide the axis border line.
- X-axis grid: usually hidden. Y-axis grid: subtle horizontal lines.
Tooltips
- Style tooltips to match your page theme (background, text color, border, border-radius).
- Show exact values on hover/tap.
- Use crosshair or index mode for better hover behavior on line/area charts.
Legend
- Always show legend for multi-series charts.
- Position: below the chart or inline with the title. Never detached far from the chart.
- Use point-style (small circles) instead of rectangles for cleaner look.
Responsiveness
- Charts must resize with their container. Set responsive mode and disable fixed aspect ratio.
- Set chart container height explicitly (e.g., 200-320px range depending on importance).
- On mobile, consider simplifying: fewer data points, abbreviated labels, hidden legend.
---
Chart Container Anti-Expansion (CRITICAL)
Problem: Chart.js and ECharts in responsive mode will infinitely expand their height if the container doesn't have a strictly fixed height. This happens because: 1. The chart reads the container's height → renders at that height 2. The render increases the container's scrollHeight → triggers a resize observer 3. The resize observer re-reads the (now larger) height → re-renders taller 4. Infinite loop → page becomes unusable
The fix — always use this exact container pattern:
<!-- ✅ CORRECT: Fixed-height wrapper with position:relative + canvas -->
<div class="chart-card">
<h3>Chart Title</h3>
<div class="chart-container" style="height: 280px; position: relative;">
<canvas id="myChart"></canvas>
</div>
</div>/* ✅ CORRECT: Chart container CSS */
.chart-container {
position: relative; /* REQUIRED — canvas positions relative to this */
height: 280px; /* REQUIRED — explicit px height, NOT min-height, NOT auto */
width: 100%; /* OK — width can be flexible */
overflow: hidden; /* SAFETY — prevent any overflow from expanding parent */
}
/* ❌ WRONG — these will cause infinite expansion: */
.chart-container {
height: auto; /* ❌ auto height = chart decides = infinite growth */
min-height: 280px; /* ❌ min-height without max = can grow forever */
flex: 1; /* ❌ flex child without explicit height = expansion */
height: 100%; /* ❌ percentage of flex/grid parent = unstable */
}Chart.js configuration (mandatory):
new Chart(ctx, {
// ...
options: {
responsive: true,
maintainAspectRatio: false, // REQUIRED — let container control height
// ...
}
});ECharts configuration (mandatory):
const chart = echarts.init(container);
// Container MUST have explicit px height before init
// If you need to handle resize:
window.addEventListener('resize', () => {
chart.resize(); // ECharts resize — reads container dimensions
});
// Do NOT call chart.resize() inside a ResizeObserver on the chart container itself — infinite loop!Additional safety rules:
- Never put a chart container inside a CSS Grid or Flexbox child without an explicit
heightin px - Never use
height: 100%on a chart container unless the parent chain all the way up has explicit heights - Never call
chart.resize()orchart.update()inside a ResizeObserver that observes the chart's own container - Always set
overflow: hiddenon the chart container as a safety net - If using CSS Grid for dashboard layout, set
grid-template-rowswith explicit values (e.g.,280px), notautoor1fr
---
Chart Container Design
Every chart should be wrapped in a card with: 1. Title (left-aligned, semibold) 2. Optional period selector (right-aligned, small toggle buttons) 3. Chart area (fixed height via explicit px, responsive width) 4. Optional footer (summary text or legend)
---
Empty & Error States
- No data: Show a centered message with a muted icon. Never show an empty chart frame with axes but no data.
- Loading: Show a skeleton placeholder matching the chart's dimensions. Not a spinner.
- Error: Show error message with a retry action. Never show a broken/partial chart.
---
Mock Data
When generating dashboards, create realistic mock data:
Time Series
- Generate 7-30 data points with natural fluctuation (random walk with mean reversion)
- Don't use round numbers (not 1000, 2000, 3000 — use 1,247, 2,089, 2,834)
- Include a general trend (upward, downward, or seasonal) — not flat lines
- Use realistic date labels
Category Data
- Use real-world category names (actual product names, city names, department names)
- Values should have natural variance — not evenly distributed
- Include both positive and negative changes where appropriate
Proportional Data
- Segments should have realistic proportions (not equal slices)
- Include one dominant segment (40-60%) and several smaller ones
- Labels should be specific ("Desktop Chrome" not "Category A")
---
Dashboard Layout Principles
Don't copy a fixed layout template. Instead, follow these principles:
Information Hierarchy
1. KPI summary row at the top — the most important metrics at a glance (typically 3-5 stat cards) 2. Primary chart — the main data story, given the most space 3. Supporting charts — secondary data, smaller than the primary 4. Detail table — granular data for users who want to drill down
Layout Guidelines
- Use CSS Grid. Vary column spans — not every chart should be the same width.
- The primary chart should be visually dominant (wider or taller than supporting charts).
- KPI cards stack to 2-column on tablet, single column on mobile.
- Charts stack vertically on mobile.
- Tables get horizontal scroll on mobile.
Constraints
- Maximum 3-4 charts + 1 table per dashboard view. More than that overwhelms.
- Not every chart should be the same height. Vary: one tall primary + shorter supporting charts.
- Choose the 4-6 most important KPIs. Don't show every metric.
---
Checklist
- [ ] Chart type matches the data pattern
- [ ] Colors match the page palette (not library defaults)
- [ ] Axis labels include units
- [ ] Tooltips show exact values
- [ ] Grid lines are subtle
- [ ] Chart is responsive
- [ ] Empty/error states handled
- [ ] Mock data looks realistic (not round numbers, has variance)
- [ ] Legend visible for multi-series
- [ ] Font sizes readable (≥12px)
- [ ] Dashboard layout varies chart sizes (not all identical)
- [ ] Primary chart is visually dominant
Component Design Reference
Rules for building UI components. These are constraints and quality standards — not templates to copy. Implement each component fresh based on your design direction.
---
Navigation
Sidebar Navigation
- Width: 240-280px, fixed position, full viewport height
- Items: icon (20px) + label, 10-12px vertical padding per item
- Active state: must be visually obvious — background highlight, accent color, or bold text. Pick one approach and commit.
- Mobile: hide sidebar off-screen, reveal with hamburger toggle. Use
transform: translateXfor the slide animation. - Dividers between nav groups, not between every item
Top Navigation
- Height: 64-72px (the most common range across 73 major brands; max 80px). Never let the nav eat >10% of the viewport.
- Must render on a single line at desktop (1024px). If items don't fit, condense labels or use hamburger.
- Sticky with
backdrop-filter: bluron scroll - Logo left, nav links center or left, actions right
- Active link: distinct from hover state (different treatment)
- Mobile: collapse nav links into hamburger menu
General Nav Rules
- Never mix sidebar + bottom nav + top nav at the same hierarchy level
- Active state must be visible without relying on color alone
- Navigation placement stays the same across all pages
Navigation Anti-Example
A top nav with a blurred sticky bar, centered logo, and hamburger on the right looks polished — but when every AI-generated page uses the exact same pattern, it becomes a tell. Vary: logo position, nav link placement (left-aligned vs centered vs right), sticky behavior (always sticky vs sticky-after-scroll vs static), and mobile treatment (hamburger vs bottom tab bar vs slide-out drawer).
---
Hero Sections
The hero is the first thing users see. It sets the tone for the entire page.
Structure Discipline
- Maximum 4 text elements in the hero stack. Common combinations:
- Heading + subheading + CTA (3 elements)
- Eyebrow + heading + subheading + CTA (4 elements — the maximum)
- Heading + CTA (2 elements — bold and minimal)
- More than 4 text elements creates visual noise and decision paralysis.
Viewport Fit
- The hero should fill the viewport on load. The primary CTA must be visible without scrolling at 768px viewport height.
- Top padding should not exceed 20vh. Excessive padding pushes content below the fold.
Layout Variety
- Not every hero needs to be centered. Consider:
- Left-aligned text with right-side visual
- Split-screen (text left, image/visual right)
- Asymmetric layout with off-center text
- Full-bleed image with overlaid text
- Editorial style with large typography and minimal imagery
- Choose based on the Design Read, not habit. If you always default to centered or always default to split-screen, you're creating a pattern.
Hero Anti-Patterns
- ❌ Centered heading + 3 equal feature cards below (the #1 AI layout)
- ❌ Hero with more than 4 text elements
- ❌ CTA below the fold at 768px height
- ❌ Div-based fake screenshots as hero images
- ❌ Generic stock photo backgrounds
Hero Anti-Example
A split-screen hero (text left, gradient orb right) with a geometric sans heading and a single CTA button looks premium — until you realize it's the go-to "anti-centered-hero" that most AI agents converge on. If you find yourself building this exact layout, ask: could this hero be editorial (large serif, minimal imagery)? Could it be full-bleed image with overlaid text? Could it be asymmetric with off-center positioning?
---
Cards
Design Rules
border-radius: 8-16px maximum (12px is the most common across 73 major brands). Never 24px+ on cards — that's the AI tell.- Choose ONE card treatment and use it consistently: border only, shadow only, or background contrast. Never combine thick border + heavy shadow. Real brand trend: 60% of major brands prefer hairline borders (1px) over drop shadows for card elevation. Shadows are used sparingly, mainly on hover or for floating elements.
- Shadows should be subtle: max blur 16px, low opacity. Heavy shadows look dated.
- Hover: subtle lift (
translateY(-2px)) or border color change. Not both. - Padding: 20-28px. Consistent within the same card type.
- Cards are not the answer to everything. Consider: tables for tabular data, inline lists for simple items, sections with dividers for sequential content.
Card Anti-Example
Three equal-width cards in a row with an icon on top, a heading, and a short description is the single most common AI card layout. It looks "clean" but is instantly recognizable as generated. Vary: card sizes (span 2 columns for the featured item), mix cards with non-card elements (inline stats, pull quotes), or replace the card grid entirely with a different pattern (accordion, timeline, comparison table).
Stat/KPI Cards
- Structure: label (small, muted) → value (large, bold, tabular-nums) → change indicator (badge with color)
- Value should be the visually dominant element
- Change badges: green for positive, red for negative. Include direction arrow or +/- sign — don't rely on color alone.
- Optional: sparkline or mini chart below the value
Content Cards
- Structure: optional icon/image → title → description → optional action
- Don't make every card the same size. Vary grid spans for visual interest.
- If you have 3+ cards in a row that look identical, reconsider the layout.
---
Buttons & CTAs
Button Design
- Primary: filled background with accent color. One primary button per view. Real brand trend: ~25% of major brands (Nike, Uber, Figma, Shopify, Expo, Intercom) use pure black as their primary CTA color — a confident, editorial choice. ~40% use pill-shaped buttons (border-radius: 9999px), ~30% use sharp corners (0-8px). Commit to one shape system, don't mix.
- Secondary: outlined or ghost (transparent bg + border). For secondary actions.
- Hover: brightness shift or color darken. Not a completely different color.
- Active/press:
scale(0.97-0.98)for tactile feedback - Disabled: reduced opacity (0.4-0.5) +
cursor: not-allowed - Loading: disable button + show inline spinner. Never let users double-submit.
- Labels: verb + object ("Save changes", "Export data"). Not just "Submit" or "OK".
- Icon buttons: minimum 36×36px touch target. Include
aria-label.
CTA Discipline
- No duplicate intent: Two CTAs on the same page must not say the same thing. "Get Started" in the hero and "Get Started" in the footer = duplicate intent. Differentiate: "Start free trial" vs "See pricing".
- Button text wrapping: CTA text must never wrap to two lines. If it wraps, shorten the text or increase the button's min-width.
- Contrast check: Primary CTA must have ≥ 4.5:1 contrast between text and button background. Test this explicitly.
- One primary per viewport: At any scroll position, only one primary-styled button should be visible. Multiple competing primaries dilute the call to action.
CTA Anti-Example
A rounded pill button with a gradient background and a right-arrow icon (→) has become the AI-default "premium CTA". If you catch yourself building this, consider: a sharp-cornered button with no icon, a text-link CTA with an underline animation, a ghost button with a bold border, or a button that uses the page's accent color as a flat fill without gradients.
---
Tables
- Use
font-variant-numeric: tabular-numsfor number columns — prevents layout shift - Header row: smaller font, uppercase or muted color, sticky if table is long
- Row hover: subtle background change
- Align numbers and currency to the right
- Wrap table in a container with
overflow-x: autofor mobile - Zebra striping is optional — if used, keep the contrast very subtle
- Don't truncate important data. If columns don't fit, prioritize which columns to show on mobile.
---
Badges & Status
- Shape: pill (
border-radius: 999px) or rounded rect - Size: small (font-size 11-12px, padding 2px 8px)
- Semantic colors: green=success, amber=warning, red=error, gray=neutral
- Always pair color with text label or icon — never color alone (accessibility)
- Don't overuse badges. If everything has a badge, nothing stands out.
---
Forms
- Every input must have a visible
<label>. Never use placeholder as the only label. - Input height: 40-44px for comfortable touch targets
- Focus state: accent-colored border + subtle ring shadow. Must be visible.
- Error messages: below the field, in red/error color, with specific guidance ("Email must include @")
- Group related fields visually (fieldset or spacing)
- Required fields: mark with asterisk or "(required)" text
- Submit button: disabled until form is valid, with loading state during submission
Form Anti-Example
Rounded input fields with a light gray background, no visible border, and a floating label that animates up on focus — this pattern is clean but has become the default AI form style. Vary: use bordered inputs with a visible 1px border, use underline-only inputs for minimal aesthetics, or use a traditional label-above-input layout. The "right" choice depends on the Design Read, not on what looks most modern.
---
Loading States
- Use skeleton placeholders that match the shape of the content they replace
- Skeleton animation: horizontal shimmer (gradient sweep), not pulsing opacity
- Show skeletons immediately — don't show a blank screen then suddenly populate
- For actions (button clicks, form submits): inline spinner or progress indicator
- If loading takes >3 seconds: show a message explaining what's happening
---
Empty States
- Never show a blank area. Always show:
1. An icon or illustration (subtle, not dominant) 2. A clear title ("No projects yet") 3. A helpful description ("Create your first project to get started") 4. A primary action button
- Empty states are an opportunity to guide the user, not just fill space
---
Tooltips & Popovers
- Appear on hover (desktop) or tap (mobile)
- Position: above the trigger by default, flip if near viewport edge
- Animation: fade + slight translateY, quick timing
- Dismiss: on mouse leave or click outside
- Keep text short (1-2 lines max)
- Use
aria-describedbyfor accessibility
---
Modals & Drawers
- Overlay: semi-transparent dark backdrop with optional
backdrop-filter: blur - Modal: centered, scale from slightly smaller + fade in
- Drawer: slides from edge
- Always provide a close button AND clicking the overlay to dismiss
- Trap focus inside the modal while open
- Exit animation should be faster than enter
---
Icons
- Use ONE icon library per project. Don't mix Lucide with Heroicons with Phosphor.
- Consistent stroke width across all icons
- Sizes: 16px (inline text), 20px (buttons), 24px (navigation)
- Never use emoji as structural icons (navigation, status, actions)
- Emoji is acceptable only in user-generated content or deliberately playful contexts
---
Data Display
- Numbers: always use
font-variant-numeric: tabular-numsin data contexts - Currency: include symbol, use locale-appropriate formatting
- Percentages: include % sign, color-code positive/negative
- Dates: use relative time for recent ("2 hours ago"), absolute for older ("Jan 15, 2026")
- Large numbers: abbreviate with K/M/B suffix (e.g., "12.4K" not "12,400")
- Trend indicators: up/down arrow + color. Green=up is not always correct — for costs, up=red.