
Designer Skill
- 1 installs
- 27 repo stars
- Updated August 2, 2026
- pythoughts-labs/designer-skill
Helps with design & ui/ux tasks.
About
designer-skill is a Claude Code skill for design & ui/ux. It helps developers move faster with AI-assisted coding.
- designer-skill
- Design & UI/UX
- AI-coding skill
Designer Skill by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,609 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/pythoughts-labs/designer-skill --skill designer-skillAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 27 |
| Last updated | August 2, 2026 |
| Repository | pythoughts-labs/designer-skill ↗ |
What it does
Helps with design & ui/ux tasks.
Files
designer-skill
A composite design skill: one consolidated, framework-agnostic reference any coding agent can use to design, refactor, and enhance UI — spanning visual fundamentals, opinionated aesthetic systems, motion and interaction, engineering and performance, anti-AI-slop discipline, and a verb-driven command playbook.
This file is the router. It is intentionally short. The substance lives in ten reference files under reference/; read this, then open the file(s) the task needs. Do not work from memory — open the owner file and use its concrete values.
How to use it (session preflight)
Run this order before writing UI code:
0. Check for project context files. If PRODUCT.md / DESIGN.md exist at the project root, they are authoritative: DESIGN.md wins visual decisions, PRODUCT.md wins strategic/voice decisions, and PRODUCT.md anti-references beat the user's one-off prompt (they are the brand's standing position; the prompt is one moment). On greenfield work, offer to create them. 1. Scope the surface and register. What is it — landing page, marketing site, dashboard, product UI, component, form? Decide the register: brand (design is the product: marketing, landing, campaign, portfolio — distinctiveness is the bar) vs product (design serves the product: app, admin, dashboard, tool — earned familiarity is the bar). Infer from concrete signals — brand: routes like /, /about, /pricing, /blog/*, hero sections, big typography, scroll-driven sections; product: /app/*, /dashboard, /settings, auth routes, forms, data tables, app-shell components. Pick by first match: task cue → the surface in focus → the persisted register; the project default can be overridden per task (a product can still have a brand-register landing page). Write one sentence of physical scene (who uses this, where, under what light, in what mood) and let it force light-vs-dark and tone. 2. Read at least one representative project file (tokens, theme, global CSS, or a core component) before any UI code — even on net-new work, and even after loading a reference file. Learn the system that's already there; don't reinvent it. 3. Commit to ONE aesthetic system from reference/aesthetic-systems.md (Minimalist / Brutalist / Soft / High-end-Stitch / Brand-identity). One language per surface — never mix two systems' signatures. 4. Run the category-reflex check in reference/avoid-ai-slop.md (first-order + second-order) before committing to a palette/type direction. 5. Build on the neutral baseline (reference/design-principles.md) + the engineering layer (reference/engineering-and-performance.md), add motion last (reference/motion-and-interaction.md). 6. For existing UI, follow the audit → diagnose → redesign loop in reference/refactor-and-redesign.md instead of building from scratch — preserve functionality, change presentation surgically. 7. Verify before done (see the ship gate below).
To map a specific user request ("make it pop", "it feels off", "production-ready") to the right move, read reference/command-playbook.md — the intent→verb dispatch table. If the request clearly matches one verb ("fix the spacing" → layout, "rewrite this error" → clarify), load that verb's guidance and proceed as if it were invoked; if two verbs plausibly fit, ask once which one; with no clear match, run the general preflight above.
Project context files
PRODUCT.md and DESIGN.md at the project root persist design decisions across sessions — read them in preflight step 0, offer to create them on greenfield work:
- PRODUCT.md — strategy: register (
brand|product), users, product purpose, a 3-word brand personality, anti-references (named bad examples), 3-5 strategic design principles (strategic, never visual rules), accessibility commitments. - DESIGN.md — the visual system: design tokens plus named rules. The full authoring recipe lives in
reference/refactor-and-redesign.md.
The reference files (routing map)
| Open this | When the task is about |
|---|---|
reference/design-principles.md | Visual fundamentals — typography, spacing & rhythm, color & contrast, layout & grid, hierarchy, depth. The aesthetic-neutral baseline. |
reference/aesthetic-systems.md | Choosing or executing a specific look — the 5 opinionated design languages and when to use which. Concrete palettes, fonts, shadow tokens. |
reference/motion-and-interaction.md | What to animate, how fast, which curve; springs, micro-interactions, gestures, scroll, perceived performance, reduced-motion. |
reference/engineering-and-performance.md | Component architecture, design tokens/CSS vars, hardware acceleration, responsive/fluid, accessibility, Core Web Vitals, framework-honest output, real-data hardening. |
reference/avoid-ai-slop.md | Not looking "AI-made" — the cross-register ban-list, category-reflex checks, and the output-completeness contract. |
reference/refactor-and-redesign.md | Improving existing UI without breaking it — audit, diagnose generic patterns, the redesign loop, image/reference-to-code. |
reference/command-playbook.md | Which verb/move maps to the user's intent (build, polish, bolder, quieter, animate, harden, redesign, …). |
reference/interaction-design.md | Cognitive laws (Fitts, Hick, Miller, Doherty), state machines, form design, navigation patterns, error UX, feedback loops, loading states, gestures, emotional timing. |
reference/visual-critique.md | Seven-dimension critique instrument: visual hierarchy, composition, color, typography, affordance, information density, brand consistency. |
reference/design-systems.md | Token architecture (global→semantic→component), motion system, component specs, naming conventions, theming, pattern library, color/type/spacing scales. |
Precedence rule (read before treating any rule as absolute)
reference/design-principles.md is the aesthetic-neutral baseline — the default lean. When you commit to an aesthetic system, its scoped rules in reference/aesthetic-systems.md override the baseline. Examples: Inter is discouraged by default but required for Brutalist macro-type; pure white is discouraged by default but is the Minimalist canvas; blanket shadows are a cheap default but Soft requires diffused ambient shadows. Never treat a baseline "expensive vs cheap" verdict as law once a system is chosen — the system wins within its own surface.
There is a second axis: the aesthetic system beats the baseline, and existing brand identity beats both. Every reflex-reject list (fonts, lanes, palettes) governs new design choices only — on a variant or edit of a shipped surface, never second-guess the committed font, lane, or palette; identity preservation wins.
Cross-file ownership (don't re-derive, read the owner)
Each fact has one home; cross-reference instead of duplicating.
- Contrast ratios, type ramp, spacing scale, layout model →
design-principles.md - Concrete palettes, fonts, shadow tokens, per-system rules →
aesthetic-systems.md - Easing curves, durations, spring config →
motion-and-interaction.md - GPU/hardware-accel,
will-change, tokens, responsive, a11y engineering, CWV →engineering-and-performance.md - Cognitive laws, state machines, form/nav patterns, error UX, loading states, emotional timing →
interaction-design.md - Dimensional critique scoring (7 dimensions) →
visual-critique.md - Token architecture, component specs, naming conventions, theming, color/type/spacing scales →
design-systems.md
The always-run ship gate
reference/avoid-ai-slop.md is the gate every task passes before you declare it done:
- Run its Anti-Slop Checklist (category-reflex, color, layout, type, eyebrows, fake content, copy, emoji, completeness, and the register-matched slop test: brand = "could a viewer say AI made that?", product = "would a user fluent in Linear/Figma/Notion trust this?").
- The output-completeness contract is binding for all code generation: deliver the full file/all components/all sections. No
// rest of code, no placeholders, no "for brevity", no skeleton when a full implementation was asked for. Partial, placeholder, or truncated output is a hard failure. - Verify accessibility and responsiveness against real values: text ≥4.5:1 (AA), focus-visible rings, reduced-motion alternative, no horizontal scroll, touch targets ≥44×44px, tested at 375/768/1440px.
Aesthetic Systems
A menu of five opinionated, mutually exclusive design languages. Pick ONE per surface and execute it whole. These systems intentionally contradict each other — Minimalist bans shadows and gradients; Soft requires them; Brutalist forbids border-radius entirely. Every rule below is scoped to its own system, never universal. A value that is law in one profile is a banned anti-pattern in another (see the Cross-System Contradictions table).
Before anything: dark vs light is never a default. Write one sentence of physical scene — who uses this, where, under what ambient light, in what mood — and let it force the answer. If it doesn't, add detail until it does.
Shared motion mechanics (animate only transform/opacity, IntersectionObserver not scroll listeners, stagger formulas, blur/backdrop-filter perf guardrails) live in motion-and-interaction.md. This file carries each system's signature feel only.
---
When to use which
| System | Pick it when… | Substrate | One-line tell |
|---|---|---|---|
| Minimalist / Editorial | Document-style workspace tools (Notion-like), editorial calm, rejecting generic SaaS | Warm white / bone | Hairline borders, off-black serif heads, no shadows |
| Brutalist / Industrial | Data-heavy dashboards, portfolios, sites that should feel like declassified blueprints | Newsprint or dead CRT | 90° corners, monospace telemetry, single hazard red |
| Soft | Premium consumer / health / agency / lifestyle where haptic depth signals expense | OLED black or warm cream or silver | Glass, diffused ambient shadows, nested squircles |
| High-end / Premium (Stitch) | SaaS/product where calibrated restraint reads "expensive and intentional" | Warm-neutral Zinc/Slate | One sub-80% accent, whisper borders, weight-driven hierarchy |
| Brand-identity | Brand sites, campaigns, logo/identity systems where distinctiveness IS the bar | Whatever the voice demands | Committed color, named reference, font chosen by procedure |
| Product register | App shells, dashboards, settings — inside-the-product surfaces where trust IS the bar | Quiet neutrals, two layers | Second neutral layer, accent = action only, familiar affordances |
Minimalist, Brutalist, Soft, and Stitch are product/marketing build systems. Brand-identity and Product are fluid strategy registers — no fixed hexes; Brand-identity commits per project, Product overlays whichever build system the app runs on.
---
1. Minimalist / Editorial
Signature traits. Ultra-flat "document-style" surfaces, extreme typographic contrast, asymmetrical bento with hairline borders, massive macro-whitespace, color as a scarce resource.
Palette (warm monochrome + spot pastels).
| Role | Value |
|---|---|
| Canvas | #FFFFFF or warm bone #F7F6F3 / #FBFBFA |
| Card surface | #FFFFFF or #F9F9F8 |
| Border / divider | #EAEAEA or rgba(0,0,0,0.06) |
| Body text | never #000000 — use #111111 or #2F3437, line-height: 1.6 |
| Secondary text | muted gray #787774 |
| Spot pastels (tags/inline-code only) | Pale Red #FDEBEC/text #9F2F2D · Pale Blue #E1F3FE/#1F6C9F · Pale Green #EDF3EC/#346538 · Pale Yellow #FBF3DB/#956400 |
Typography (3-part stack). Sans (body/UI): 'SF Pro Display','Geist Sans','Helvetica Neue','Switzer',sans-serif. Editorial serif (hero/quotes): 'Lyon Text','Newsreader','Playfair Display','Instrument Serif',serif, letter-spacing -0.02em to -0.04em, line-height 1.1. Mono (code/keys/meta): 'Geist Mono','SF Mono','JetBrains Mono',monospace.
Spacing. Section padding py-24/py-32; constrain text to max-w-4xl/max-w-5xl; card internal padding 24px–40px; card radius 8px or 12px max, buttons 4px–6px.
Motion feel. Invisible, quiet. Scroll entry: translateY(12px) + opacity 0 → resolve over 600ms cubic-bezier(0.16, 1, 0.3, 1). Hover lift: shadow 0 0 0 → 0 2px 8px rgba(0,0,0,0.04) over 200ms. Active button scale(0.98). Stagger calc(var(--index) * 80ms).
Bans — within this system. No Inter/Roboto/Open Sans. No thin-line icons (Lucide, Feather, standard Heroicons) — use Phosphor (Bold/Fill) or Radix at standardized stroke. No shadow-md/lg/xl (shadows opacity < 0.05). No gradients, neon, or 3D glassmorphism (subtle navbar blur is the only exception). No rounded-full on large containers/cards/primary buttons (pills allowed at tag scale only). No primary-colored hero backgrounds.
---
2. Brutalist / Industrial
Signature traits. Fuses 1960s Swiss print + industrial manuals + aerospace/military terminals. Rigid CSS-grid blueprint, visible compartmentalization, bimodal density (dense monospace clusters vs vast negative space framing macro-type), engineered analog degradation.
Pick exactly ONE substrate and commit — never mix the two.
| Swiss Industrial Print (light) | Tactical Telemetry / CRT (dark) | |
|---|---|---|
| Background | #F4F4F0 or #EAE8E3 (matte paper) | #0A0A0A or #121212 (never pure #000000) |
| Foreground | #050505–#111111 carbon ink | #EAEAEA white phosphor |
| Accent | #E61919 / #FF2A2A aviation red — ONLY accent | same red, same rules |
| Extra | — | Terminal green #4AF626 on ONE element only, else omit |
Typography. Macro headers (neo-grotesque): Neue Haas Grotesk Black, Inter Extra Bold/Black (allowed here only), Archivo Black, Roboto Flex Heavy, Monument Extended — clamp(4rem, 10vw, 15rem), tracking -0.03em to -0.06em, line-height 0.85–0.95, UPPERCASE. Data/telemetry (mono): JetBrains Mono, IBM Plex Mono, Space Mono, VT323, Courier Prime — fixed 10px–14px, tracking 0.05em–0.1em, line-height 1.2–1.4, UPPERCASE. Serif (Playfair/EB Garamond/Times) exceedingly sparingly, only when degraded with halftone/1-bit dithering.
Spacing. Strict CSS Grid; elements anchored to tracks, never floating. 1px/2px solid borders and full-width <hr> delineate zones. Use display:grid; gap:1px with contrasting parent/child bg for razor-thin dividers. ASCII framing [ DELIVERY SYSTEMS ], < RE-IND >, >>>, ///; ®/©/™ as geometry; crosshairs + at intersections; strings like REV 2.6, UNIT / D-01.
Motion feel. Mechanical, not fluid. Texture over interpolation: CRT scanlines repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,0,0,0.1) 2px, rgba(0,0,0,0.1) 4px), global low-opacity SVG noise grain, halftone via mix-blend-mode: multiply + SVG dot patterns.
Bans — within this system. No border-radius anywhere — all corners exactly 90°. No gradients, no soft drop shadows, no modern translucency/glassmorphism. No consumer UI conventions. Colors simulate physical media or primitive emissive displays only.
---
3. Soft
Signature traits. Haptic, machined depth that signals expense; never the same layout twice. Before coding, roll the engine and pick one Vibe and one Layout.
Vibe (pick 1).
| Vibe | For | Palette + material |
|---|---|---|
| Ethereal Glass | SaaS / AI / Tech | OLED black #050505, glowing purple/emerald radial mesh orbs, vantablack cards with backdrop-blur-2xl + white/10 hairlines, wide geometric grotesk |
| Editorial Luxury | Lifestyle / Real Estate / Agency | warm cream #FDFBF7 / sage / espresso, high-contrast variable serif heads, film-grain opacity-[0.03] |
| Soft Structuralism | Consumer / Health / Portfolio | silver-grey or pure white, massive bold grotesk, unbelievably soft diffused ambient shadows |
Layout (pick 1). Asymmetrical Bento (col-span-8 row-span-2 beside stacked col-span-4; mobile → grid-cols-1, gap-6) · Z-Axis Cascade (overlapping cards, -2deg/3deg rotation; remove all rotation/overlap < 768px) · Editorial Split (massive type w-1/2 left, scrollable content right; mobile → full-width stack).
Component signatures. Double-Bezel (Doppelrand): outer shell bg-black/5 + ring-1 ring-black/5 + p-1.5/p-2 + rounded-[2rem]; inner core distinct bg + shadow-[inset_0_1px_1px_rgba(255,255,255,0.15)] + rounded-[calc(2rem-0.375rem)] for concentric curves. Button-in-button: pill CTAs rounded-full px-6 py-3; trailing ↗ nested in w-8 h-8 rounded-full bg-black/5 flush to inner padding. Ambient shadow (the Soft signature, concrete): a large-radius, low-opacity, slightly negative-spread stack — box-shadow: 0 24px 60px -20px rgba(0,0,0,0.12), 0 8px 24px -12px rgba(0,0,0,0.08) — never a harsh shadow-md / rgba(0,0,0,0.3).
Spacing. Macro-whitespace py-24 to py-40. Eyebrow tags rounded-full px-3 py-1 text-[10px] uppercase tracking-[0.2em]. Sections min-h-[100dvh], never h-screen.
Motion feel. Real-world mass and spring. transition-all duration-700 ease-[cubic-bezier(0.32,0.72,0,1)]. Scroll entry: translate-y-16 blur-md opacity-0 → translate-y-0 blur-0 opacity-100 over 800ms+. Magnetic hover: active:scale-[0.98], inner icon group-hover:translate-x-1 group-hover:-translate-y-[1px] scale-105.
Bans — within this system. No Inter/Roboto/Arial/Open Sans/Helvetica (use Geist, Clash Display, PP Editorial New, Plus Jakarta Sans). No generic 1px-solid-gray borders, no harsh dark shadow-md/rgba(0,0,0,0.3). No edge-to-edge sticky navbars glued to top (float a glass pill: mt-6 mx-auto w-max rounded-full). No symmetrical 3-column Bootstrap grids without whitespace. No linear/ease-in-out transitions.
---
4. High-end / Premium (Stitch)
Signature traits. Calibrated neutral restraint that reads expensive and intentional. Tune via dials — Creativity 8 / Density 4 / Variance 8 / Motion Intent 6 baseline; adapt to vibe. Hierarchy through weight and color, not screaming size.
Palette (one accent rule).
| Role | Value |
|---|---|
| Canvas | Canvas White #F9FAFB (warm-neutral, never blue-white) |
| Surface | Pure White #FFFFFF |
| Ink | Charcoal #18181B (Zinc-950, never pure black) |
| Body / meta | Steel #71717A; tertiary Muted Slate #94A3B8 |
| Border | Whisper rgba(226,232,240,0.5) |
| Shadow | Diffused rgba(0,0,0,0.05) |
| Accent — pick ONE, sat < 80% | Emerald #10B981 (growth) · Electric Blue #3B82F6 (SaaS/dev) · Deep Rose #E11D48 (creative) · Amber #F59E0B (social) |
Typography. Display: Geist/Satoshi/Cabinet Grotesk/Outfit, tracking -0.025em, weight 700–900, leading 1.1, clamp(2.25rem, 5vw, 3.75rem). Body: same family weight 400, leading 1.65, 65ch, color #71717A, 1rem/1.125rem. Mono: Geist Mono/JetBrains Mono at 0.8125rem; when Density > 7, all numbers switch to monospace.
Spacing. Grid-first, max-width: 1400px centered, padding 1rem/2rem/4rem (mobile/tablet/desktop). Cards rounded-[2.5rem], pure white, whisper border, shadow 0 20px 40px -15px rgba(0,0,0,0.05), padding 2rem–2.5rem — used ONLY when elevation serves hierarchy; high-density layouts replace cards with border-top dividers or negative space. Bento: Row 1 = 3 cols, Row 2 = 2 cols (70/30). Hero: inline-image typography (photos at type-height between words); centered hero banned when variance > 4; max 1 primary CTA.
Motion feel. Spring exclusively: stiffness: 100, damping: 20, no linear easing. Perpetual micro-loops (Pulse/Typewriter/Float/Shimmer) on active components. Stagger calc(var(--index) * 100ms).
Bans — within this system. No Inter (premium contexts). No generic serifs (Times New Roman/Georgia/Garamond/Palatino) — only Fraunces/Instrument Serif/Editorial New if needed; serif always banned in dashboards. No pure black, no neon/outer glows, no accents > 80% saturation, no overlapping elements, no 3-equal-card rows, no flexbox percentage math (calc(33% - 1rem)), no h-screen, no circular spinners (skeletal shimmer only), no fake round numbers (99.99% → 47.2%).
---
5. Brand-identity
Signature traits. Design IS the product. Distinctiveness is the bar; restraint without intent reads as mediocre. The real bar: a visitor asking "how was this made?" — not "which AI made this?". Run the inverse test before building: describe what you're about to build the way a competitor would describe theirs; if that sentence fits the category's modal landing page, restart. No fixed palette — commit per project and name a real reference.
Color (commitment axis — name the reference first).
| Strategy | Dosage | Reference |
|---|---|---|
| Restrained | tinted neutrals + one accent ≤10% | "Stripe purple-on-white restraint" |
| Committed | one saturated color carries 30–60% | "Klim #ff4500 orange drench" |
| Full palette | 3–4 named roles | "Liquid Death acid-green", "Mailchimp yellow" |
| Drenched | the surface IS the color | brand heroes / campaigns |
The ≤10% rule is Restrained-only; Committed/Full/Drenched deliberately exceed it. When Committed or Drenched, don't hedge with neutrals — commit. Palette IS voice; don't converge across projects; reach past the obvious cultural-symbol palette.
Typography (font-selection procedure — every project, never skip). (1) Write three physical-object brand-voice words ("warm and mechanical and opinionated", not "modern/elegant"). (2) List three reflex fonts; reject any on the reflex-reject list. (3) Browse a real catalog (Google Fonts, Pangram Pangram, Future Fonts, Adobe Fonts, ABC Dinamo, Klim, Velvetyne); find the font for the brand as a physical object; reject the first thing that "looks designy". (4) Cross-check — if the pick lines up with the reflex, start over. Reflex-reject (greenfield only): Fraunces · Newsreader · Lora · Crimson · Playfair Display · Cormorant · Syne · IBM Plex (Sans/Mono/Serif) · Space Mono · Space Grotesk · Inter · DM Sans/Serif · Outfit · Plus Jakarta Sans · Instrument Sans/Serif. Modular scale, fluid clamp(), ≥1.25 ratio between steps (flat 1.1× reads uncommitted).
Spacing & permissions. Asymmetric compositions, fluid clamp() spacing, intentional grid-breaking for emphasis; cards via repeat(auto-fit, minmax(280px, 1fr)) when cards are right. Take permissions product can't: ambitious first-load motion (reveals + typographic choreography, not fade-on-scroll-everything — some brands skip entrance motion entirely), single-purpose viewports, unexpected color, art direction per section.
Imagery (required when the brief implies it — zero images is a bug, not restraint). Four operational rules: (1) Search for the brand's physical object, not the category — "handmade pasta on a scratched wooden table" beats "Italian food"; "cypress trees above a limestone hotel facade at dusk" beats "luxury hotel". (2) One decisive photo beats five mediocre ones — hero imagery commits to a mood; padding an indecisive hero with more stock never rescues it. (3) Alt text is part of the voice — "Coastal fettuccine, hand-cut, served on the terrace", never "pasta dish". (4) "Imagery" is broader than photos — product screenshots, custom data-viz, generated SVG, canvas/WebGL all count; the all-typography page is the failure mode, not a style. Unsplash URLs take the shape https://images.unsplash.com/photo-{id}?auto=format&fit=crop&w=1600&q=80 — verify the IDs actually resolve, or pick fewer photos you're confident in.
Identity-board modes (for logo/identity decks). Default 3×3 board on a dark/light canvas, strong gutters, sparse type. Compact palette-mode map:
| Mode | Cues + palette |
|---|---|
| Dark Developer | near-black + mono, terminal/grid, cyan/blue/coral/lime |
| Dark Operator | black/dark-red/amber, glowing UI chips, reward motifs |
| Dark Nature/Calm | deep green + lime, misty landscapes, editorial grid |
| Dark Security | black/navy, shields, radar, red/blue alert chips |
| Light Editorial | warm ivory paper, small serif, seals, deep blue/red/gold |
| Luxury/Fashion | ivory/stone/espresso, serif wordmark, emboss, paper grain |
| Voice/Comms | dark indigo + lilac glow, waveform/mic |
| Cultural/Experimental | halftone/CRT/print, bold accent, poster panels |
Accents must repeat across panels; one accent can carry the system. Logo via one (max two) of: Monogram+Meaning, Product Action, Metaphor Fusion, Negative Space, Construction Geometry.
Bans — within this register. Monospace as lazy "technical" shorthand. Large rounded-corner icons above every heading. Single-family pages chosen by reflex (deliberate single family is fine). All-caps body copy. Timid palettes / average layouts (safe = invisible). Defaulting to editorial-magazine (serif + italic + drop caps) on non-magazine briefs. Repeated tiny uppercase tracked kickers above every section.
---
6. Product register
Signature traits. The tool disappears into the task. Inside the app, trust replaces distinctiveness as the bar; familiarity is a feature, not a failure. Applies on top of whichever build system the product uses.
Color (accent = action). Run two neutral layers: the content surface plus a second neutral — slightly warmer or cooler — for sidebars, toolbars, and panels, so structure reads without borders doing all the work. The accent means action and nothing else: primary actions, current selection, state indicators — never decoration. Restrained is the floor; a single surface may earn Committed (a drenched welcome screen, one category color carrying a report). Standardize a state-rich semantic vocabulary across every screen: hover, focus, active, disabled, selected, loading, error, warning, success, info — each state one consistent color treatment, everywhere.
Permissions. What's reflex-rejected on brand surfaces is legitimate here: system fonts and Inter are honest choices for UI. Standard navigation patterns (top bar + side nav, breadcrumbs, tabs, command palettes) are assets, not laziness. Density is a feature. Consistency beats surprise on every call.
Bans — within this register. Display fonts in UI labels, buttons, or data. Reinvented standard affordances — custom scrollbars, weird form controls, non-standard modals. Heavy or full-saturation color on inactive states. Inconsistent component vocabulary — if the save button looks different in two places, one of them is wrong. Modal as first thought — modals are usually laziness; exhaust inline and progressive-disclosure alternatives first.
The product slop test. Not "would someone say AI made this" — that's the brand test. Here: would a user fluent in Linear, Figma, Notion, Raycast, or Stripe sit down and trust this immediately, or pause at every subtly-off component? The product failure mode is strangeness without purpose, not flatness.
---
Cross-System Contradictions
The same property gets opposite verdicts. This is by design — proof the rules are scoped, not universal.
| Property | Minimalist | Brutalist | Soft | High-end (Stitch) |
|---|---|---|---|---|
Inter font | ❌ banned | ✅ required (Extra Bold/Black, macro-type) | ❌ banned | ❌ banned |
| Drop shadows | opacity < 0.05 | ❌ banned entirely | ✅ required (soft, diffused, ambient) | diffused rgba(0,0,0,0.05) only |
border-radius | crisp 4–12px | ❌ 90° / none | rounded-[2rem] squircles | rounded-[2.5rem] cards |
| Gradients | ❌ banned | ❌ banned | ✅ glass mesh orbs | ❌ no gradient text/neon |
| Color dosage | scarce spot pastels | single hazard red | vibe-driven | one accent < 80% sat |
| Motion | quiet 600ms fade | mechanical/static | spring blur-up 800ms | spring 100/20 + loops |
---
Never mix two systems' signatures in one surface
A page is one language. Glass orbs (Soft) on hairline-border bento (Minimalist) reads as confused, not eclectic. CRT scanlines (Brutalist) under whisper-shadow cards (Stitch) cancel each other. Brutalist itself forbids mixing its own two substrates (Swiss Print vs Tactical Telemetry). Brand-identity may art-direct different sections into different visual worlds — but that is one voice spanning worlds, not two systems colliding on the same surface. Pick one, commit, and let the bans of that system do their job.
Avoiding AI Slop
The bar is two tests, one per register. On brand surfaces: if someone can look at the interface and say "AI made that" without hesitation, it has failed. Average is no longer findable. AI landing pages have flooded the internet, so restraint without intent now reads as mediocre, not refined. On product surfaces familiarity is a feature, so the test flips: would a user fluent in Linear, Figma, Notion, or Stripe sit down and trust this, or pause at every subtly-off component? Product slop fails through strangeness without purpose, not through flatness. This file is the cross-register ban-list and the output-completeness contract. Aesthetic-specific palettes, fonts, and shadow systems live in aesthetic-systems.md; the neutral color/typography/layout baseline lives in design-principles.md; motion and reveal tells live in motion-and-interaction.md; loading states and real-data hardening live in engineering-and-performance.md.
Run two checks before you commit to a direction:
- First-order: if someone could guess the theme + palette from the category alone ("fintech → navy and gold", "AI tool → SaaS cream"), you reached for the first training-data reflex. Rework.
- Second-order: if someone could guess the aesthetic family from category-plus-anti-reference ("AI workflow tool that's not SaaS-cream → editorial-typographic"), you hit the trap one tier deeper. Rework until neither answer is obvious.
---
The Tells: Absolute Ban-List (any register)
These are hard bans. If you are about to write one, rewrite the element with different structure. Match-and-refuse.
Color
- Purple/blue "AI gradient": the single most recognizable fingerprint. Replace with a neutral base + one considered accent.
- `oklch(97% 0.01 60)` and its neighbors (warm cream/sand/beige body bg). The whole warm-neutral band (OKLCH L 0.84-0.97, C < 0.06, hue 40-100) reads as cream/paper. Token names
--paper,--cream,--sand,--bone,--linen,--parchment,--ivoryare tells. Tint toward the brand hue or stay neutral; never default-tint "for warmth." (see design-principles.md, aesthetic-systems.md.) - Pure `#000000` / pure `#ffffff`. Use off-black (
#0a0a0a,#121212, zinc-950) and true off-white. - The premium-consumer reflex palette (beige + brass + oxblood + espresso). Banned bg
#f5f1ea #f7f5f1 #fbf8f1 #efeae0 #ece6db #faf7f1 #e8dfcb; banned accents#b08947 #b6553a #9a2436 #9c6e2a #bc7c3a #7d5621; banned text#1a1714 #1a1814 #1b1814. Rotate alternatives, no repeat in a row. - Gradient text (
background-clip: text+ gradient bg) on large headers. Neon / outer glows by default. Oversaturated accents (keep saturation < 80%). Generic black `box-shadow` (tint shadows to the bg hue). - Dark-glow: dark background + colored
box-shadowglow as the default "cool" look. The dark-mode variant of the neon ban; if dark surfaces need depth, use surface lightness, not glow. - The AI hue bands: purple/violet at hue 260-310, and cyan at hue 160-200 on dark backgrounds, applied to headings or large text. These are the checkable numbers behind the purple/blue reflex.
Layout
- Three identical feature cards in a row: the most generic AI layout. Use 2-column zig-zag, asymmetric grid, scroll-pinned, horizontal-scroll, or masonry.
- Centered hero over a dark mesh/blob as the default. Evenly-spaced symmetric everything.
- Identical card grids (same-sized icon + heading + text, repeated). Cards nested inside cards. Use spacing and dividers for hierarchy. Cards earn their elevation; the border + shadow + white-bg card is a default, not a decision.
- The hero-metric template (big number + small label + supporting stats + gradient accent) when there is no real data behind it.
- Side-stripe borders:
border-left/border-right> 1px as a colored accent on cards, list rows, callouts, alerts. Use a full 1px hairline perimeter, a 4-8% surface tint, or a leading glyph instead. On a rounded card a thick one-sided accent (≥2px while the other sides are hairlines) clashes with the corners; ≥3px fails unconditionally. - Ghost-card:
border: 1px solid+box-shadowwith blur ≥16px on the same element. Commit to one: a defined edge, OR a soft elevation at ≤8px blur. Never both as decoration. - Over-rounding: border-radius ≥32px (and 24/28px) on cards, sections, or inputs is a generated-UI tell. Cards top out at 12-16px by default; full-pill stays at tag/button scale. (Soft systems deliberately override per the precedence rule.)
- Icon-tile-stack: a 32-128px rounded-square icon container stacked directly above a heading. The universal AI feature-card template; every generator outputs this exact shape. Put the icon side-by-side with the heading, or in flow without its own container.
- `border-t` + `border-b` on every row of a long list/spec table. Filled-track progress bars as comparison visuals (drop the
bg-zinc-200track). - Default left sidebar on every dashboard. Box-in-box-in-box nesting. (see design-principles.md.)
Typography
- Inter / Roboto / Open Sans / Arial / system default when personality matters. The most modern move is not the font everyone else uses. Note: Geist is approaching Inter-level saturation; it stays a fine deliberate product-register choice, but it is no longer a differentiator on its own.
- Reflex-reject display serifs as a default: Fraunces, Newsreader, Lora, Crimson, Playfair Display, Cormorant, Instrument Serif, DM Serif. Also reflex sans: DM Sans, Outfit, Plus Jakarta Sans, Space Grotesk, Syne. Identity-preservation wins when an existing brand already committed to a font.
- The editorial-typographic lane on a non-editorial brief: display serif (often italic) + small mono labels + ruled separators + monochromatic restraint. Use only when the brief literally is a magazine/terminal/signage system.
- Italic-serif display hero: an oversized italic serif (Fraunces, Recoleta, Playfair) as the primary hero headline. Reads as taste in isolation, but it is the universal AI-startup hero. Set it roman or change face; italic display earns its place only on genuinely editorial registers.
- The long-sentence display H1: the oversized-headline tell is a long, full-sentence headline at display size dominating the viewport. A punchy 1-2-word headline at the same size is fine; set long headlines smaller or tighten the copy.
- `<br>`-broken italic headlines ("for thirty\<br>years."). Vertical rotated text. Gradient headline as a shortcut for "premium." Lazy all-caps everywhere. (see design-principles.md, aesthetic-systems.md.)
Components & micro-UI
- Tiny uppercase tracked eyebrow above every section: the #1 violated rule (appears on 55-95% of generations). Max 1 eyebrow per 3 sections, hero counts as 1; if section A has one, the next 2 cannot. Count
uppercase trackinginstances mechanically before shipping; if count > ceil(sectionCount / 3), it fails. The per-hero detector shape: text ≤14px with letter-spacing ≥1.6px uppercase (or weight ≥700 in the accent color) sitting directly above an h1 or an h2 ≥48px, including as a pill chip. Best alternative: drop it. - Hand-drawn / sketchy SVG illustrations:
loose-sketch/doodle/wavyclass names,feTurbulence/feDisplacementMap"paper grain", crude 5-30-path scenes depicting a tangible subject. Reads amateurish, not whimsical; if the scene can't be rendered with real assets, ship no illustration. - `repeating-linear-gradient` stripe backgrounds as surface decoration (diagonal stripes in
body::beforeor behind sections). - Numbered section markers as scaffolding:
00 / INDEX,001 · Capabilities,06 · how it works,SECTION 01,QUESTION 05,01 / 4pagination, "Stage 1 / Step 1 / Phase 01." The step content is the label ("Install", "Configure", "Ship"). - Split-header (big left headline + small floating right explainer paragraph). Stack headline on top, body below at max 65ch, unless the right column carries a real visual/interactive element.
- Emoji icons in code, markup, visible text, or alt text. Replace with icon-library glyphs (Phosphor, Heroicons, Tabler). Allow only when the user explicitly asks for a playful/chat/social vibe, and then sparingly.
- Lucide/Feather as the exclusive set. Cliché icon metaphors (rocket = Launch, shield = Security → bolt, fingerprint, vault).
- Pill "New"/"Beta" badges, accordion FAQ, 3-card carousel testimonials with dots, modals for simple actions, sun/moon dark-mode toggle, filled + ghost button pair as the only CTA shape. All generic defaults; reach for the alternative listed in design-principles.md.
- Glassmorphism as default. Custom mouse cursors (perf- and a11y-hostile). Decorative colored status dots before nav links / list rows / badges. Middle-dot (`·`) as default separator (max 1 per metadata line).
- Decoration text strips at hero bottom (
TYPE / FORM / MOTION,DESIGN · BUILD · SHIP,ESTD. 2018 · LISBON). Locale/time/weather strips ("Lisbon 14:23 · 18°C"), banned for 99% of briefs. Scroll cues ("Scroll", "↓ scroll", animated mouse-wheel): the user is already looking at the hero.
Fake content (the "Jane Doe" effect)
| ❌ The tell | ✅ Ship instead |
|---|---|
Div-based fake product preview (fake task list, terminal, dashboard from <div> rectangles), the #1 LLM-design Tell | Real screenshot, generated image, real mini component, or skip the preview. Text + gradient blob is not a hero. |
| Fake version stamps: "v0.6.2-rc.1", "Build 0048", "last sync 4s ago · main" | Nothing. These are devtool fixtures, banned on marketing/landing/portfolio pages. |
| Generic names "John Doe", "Sarah Chan"; repeated avatars; SVG-egg / Lucide-user icons; identical blog dates | Locale-appropriate names, a unique asset per person, randomized dates. |
Fake round numbers 99.99%, 50%, 1234567; AI-invented specs 92%, 4.1×, 5.8 mm | Organic data 47.2%, $99.00, +1 (312) 847-1928. Specs only if sourced or labeled <!-- mock -->. |
| Placeholder brands "Acme", "Nexus", "SmartFlow", "Cloudly", "NovaCore"; Lorem Ipsum; plain text wordmarks on a social-proof wall | Contextual invented brand names; real draft copy; real SVG logos (https://cdn.simpleicons.org/{slug}/ffffff), no category labels underneath. |
| Broken Unsplash links from guessed IDs (404 → broken-image placeholder) | Verified URLs, or https://picsum.photos/seed/{descriptive-seed}/{w}/{h}. Image-led briefs (restaurant, hotel, magazine, product) must ship real imagery; a solid-color rectangle where a hero photo belongs is worse than a representative stock photo. |
Copy
- Em-dash (`—`) anywhere visible: the #1 visual tell, zero allowance. Banned in headlines, eyebrows, pills, buttons, body, quotes, attribution, captions, alt text. Also banned: en-dash separator (
–) and--substitute. Use comma, colon, semicolon, period, parentheses, or-. Ranges use a hyphen (2018-2026). - Buzzwords: streamline, empower, supercharge, leverage, unleash, transform, seamless, world-class, enterprise-grade, next-generation, cutting-edge, game-changer, elevate, delve, tapestry, robust, "in the world of...". Cliché loading copy ("Herding pixels", "Teaching robots to dance"). "Oops!" errors and exclamation-mark success messages.
- Performative-craftsman labels ("Quietly trusted by", "From the field", "Field notes"). Negation pivot ("It's not just X, it's Y"). Triadic everything (every list is three). Button labels are verb + object ("Save changes" beats "OK"); link text stands alone ("View pricing plans" beats "Click here").
- Aphoristic cadence: 3+ sections each landing on a short rebuttal sentence ("X. No Y." / "X. Just Y." / "Not a feature. A platform."). Once is voice; the repeated pattern is the tell.
- "Theater" framing: dismissing something as "X theater", or staging a strawman just to correct it. Make the specific claim instead.
---
Why It Happens (so you know what to override)
Slop is a behavioral default, not a memory or decoding failure. Controlled 2025 studies (GPT-4 variants, DeepSeek) found greedy-decoded truncation matched the model's highest-confidence solution and that 200-turn context degradation was minimal. So fix it with enforcement, not by re-feeding context.
| Cause | Mechanism | Override |
|---|---|---|
| Output limits | The model estimates a full response exceeds its ~8,000-token budget and preemptively compresses. | Chunk: outline → per-component → assembly. Pause/resume at clean breakpoints (below). |
| RLHF / compute | Stopping pressure is calibrated aggressively; short confident summaries are rewarded over exhaustive correct output. Safety tuning resists large codebases. | Replace weak "make it work" with explicit, verifiable completeness criteria. |
| Training-data bias | Tutorials, docs, forum answers, and blogs are full of # implement here and "similarly for the rest." The model assigns high probability to truncation tokens where complete code belongs. | Override aggressively; the tutorial pattern often beats a soft completeness instruction. |
| Cognitive shortcuts | On tasks it reads as straightforward, the model surface-summarizes. Even seasonal signals shift it (measurable December brevity; stating a non-winter month recovers length). | Pre-decompose every task into discrete steps; verify each requirement explicitly. |
| Design reflex | The first aesthetic the weights surface for a category dominates the distribution. | First-order + second-order category-reflex checks (top of file). |
---
Output-Completeness Rules (non-negotiable)
A partial output is a broken output. Treat every task as production-critical. If the user asks for a full file, deliver the full file. If they ask for 5 components, deliver 5. If the output is 500 lines, produce all 500.
Banned in code blocks (hard failures): // ... · // rest of code · // implement here · // TODO · /* ... */ · // similar to above · // continue pattern · // add more as needed · bare ... standing in for omitted code.
Banned in prose: "Let me know if you want me to continue" · "I can provide more details if needed" · "for brevity" · "the rest follows the same pattern" · "similarly for the remaining" · "and so on" (replacing real content) · "I'll leave that as an exercise" · "as mentioned earlier" / "see above" (to dodge repeating necessary context).
Banned structural shortcuts: A skeleton when a full implementation was requested · showing the first and last section while skipping the middle · replacing repeated logic with one example + a description · describing what code should do instead of writing it.
Scope → Build → Cross-check
1. Scope: read the full request, count distinct deliverables (files, functions, sections, answers), lock that number. 2. Build: generate every deliverable completely. No partial drafts, no "you can extend this later." 3. Cross-check: re-read the original request, compare your deliverable count against the locked count, add anything missing before responding.
When you approach the token limit
Do not compress remaining sections. Do not skip to a conclusion. Write at full quality to a clean breakpoint (end of a function, file, or section), then end with exactly:
[PAUSED - X of Y complete. Send "continue" to resume from: next section name]On "continue", pick up exactly where you stopped. No recap, no repetition.
Production bar for content
Ship real content with full state coverage: default, hover, focus-visible, active, disabled, loading, error, success, empty, overflow, long/short text, first-run. No placeholder copy/images, dead # links, fake controls, or unused scaffold at presentation. Do not replace required imagery with generic cards, bullets, emoji, fake metrics, decorative CSS panels, or filler copy. Battle-test every page with browser screenshotting and computer use before calling it done. (Real-data hardening: see engineering-and-performance.md.)
---
Anti-Slop Checklist
Run before declaring done.
- [ ] Category-reflex: neither first-order nor second-order guess is obvious.
- [ ] Color: no purple/blue gradient (hue 260-310; cyan 160-200 on dark), no dark-glow, no cream/sand bg, no beige+brass palette, no pure
#000/#fff, no gradient text on headers. - [ ] Layout: no three-equal cards, no nested cards, no ghost-card (1px border + ≥16px shadow), no ≥24px card radii, no icon-tile-stack, no decorative hero metric, no side-stripe or thick one-sided accent borders, no reflexive left sidebar.
- [ ] Type: not Inter/Roboto/Open Sans by reflex, no reflex display serif, no italic-serif hero, no full-sentence display H1, no editorial-typographic lane on a non-editorial brief.
- [ ] Eyebrows:
uppercase trackingcount ≤ ceil(sectionCount / 3), no eyebrow chip glued to the hero headline. No numbered section markers, no split-header, no sketchy SVG illustrations, no stripe backgrounds, no decoration strips, no scroll cues, no locale strips. - [ ] Fake content: no div fake-screenshots, no version stamps, no John Doe / Acme, no fake round numbers, no Lorem Ipsum, no broken image URLs; real imagery on image-led briefs.
- [ ] Copy: zero em-dashes (
—/–/--) anywhere visible; no buzzwords; no "Oops!"; no aphoristic rebuttal cadence (3+ sections); no "theater" framing; verb+object buttons; standalone link text. - [ ] No emoji in code, markup, text, or alt (unless explicitly requested).
- [ ] Completeness: no banned code/prose patterns; every requested item present and finished; code blocks are runnable, not described; nothing shortened to save space.
- [ ] Slop test: brand surface: could a viewer say "AI made that" without doubt? Product surface: would a fluent Linear/Figma/Notion/Stripe user pause at subtly-off components? If yes, rework before shipping.
Command Playbook
This is the intent-to-action dispatch table for designer-skill. Find the verb whose intent cue matches what the user wants, then read the file(s) in its Read column before you touch anything. The Read column points only to sibling reference files in this skill; open them, do not guess from memory. One verb usually owns the task; if two fit and one intent clearly dominates, pick it and let the other's file be a secondary read — if genuinely ambiguous, ask the user once which they mean. Concrete values in the moves are starting points, not laws.
Dispatch table
| Verb | When to invoke (intent cue) | What it does (concrete moves) | Read |
|---|---|---|---|
| build / craft | "build / make / create" a feature, page, or component end-to-end | Detect framework/library/icons first (ask once on greenfield), set baseline (type, spacing, contrast), commit to one aesthetic language, wire motion + tokens, ship production code with real content and all states; gate stages and run the visual iteration loop (see Build gates below) | design-principles.md, aesthetic-systems.md, engineering-and-performance.md, avoid-ai-slop.md |
| shape | "plan / spec / think through" a feature before code | Run a discovery interview (see Shape protocol below), pick color strategy + a one-sentence physical scene + 2-3 named anchor references, produce a brief, present it, and stop; write no code | design-principles.md, aesthetic-systems.md |
| audit | "check / review the implementation, a11y, perf, responsive" | Score accessibility, performance, theming, responsive, anti-patterns 0-4; tag findings P0-P3 with fix + suggested verb; for a11y, split automated-detectable findings from manual-review ones and never certify full WCAG conformance from automated checks alone; fix nothing | engineering-and-performance.md, avoid-ai-slop.md, refactor-and-redesign.md |
| critique | "is this good? / design review / does this feel AI?" | Design-director read: hierarchy, IA, cognitive load, heuristics, emotional journey; lead with the AI-slop verdict; list 3-5 priority issues; full instrument in the Scored review protocol below | design-principles.md, avoid-ai-slop.md |
| polish | "final pass / tighten before shipping" | Align to the design system, snap spacing to scale, complete every interaction state (hover/focus/active/disabled/loading/error), fix optical alignment, 150-300ms transitions | design-principles.md, engineering-and-performance.md |
| bolder | "too safe / bland / make it pop" | Amplify hierarchy: 3-5x scale jumps, weight 900 vs 200, one color owns ~60%, break the grid; reject gradient-text/glass/neon first | aesthetic-systems.md, avoid-ai-slop.md |
| quieter | "too loud / busy / aggressive" | Reduce intensity: desaturate to 70-85%, neutrals carry weight with accent ~10%, flatten cards, shorten motion to 10-20px; keep the POV | design-principles.md, aesthetic-systems.md |
| overdrive | "extraordinary / push past limits / wow" | Highest-ambition effects (View Transitions, scroll-driven, WebGL, virtual scroll). Propose 2-3 directions, get user pick, then build with graceful fallback at 60fps | motion-and-interaction.md, engineering-and-performance.md |
| animate | "add motion / it feels static / smooth this" | Add purposeful motion: 100/300/500ms by tier, ease-out-quart, sibling stagger (not section fade), reduced-motion alternative required | motion-and-interaction.md |
| delight | "personality / memorable / charm" | Earn specific moments (success, empty, error recovery) with custom copy + micro-interactions under ~1s; never on every interaction, never generic AI filler | motion-and-interaction.md, avoid-ai-slop.md |
| layout | "fix spacing / hierarchy / it feels off" | 4pt scale (4/8/12/16/24/32/48/64/96), tight grouping vs 48-96px section gaps, flex for 1D + grid for 2D, break card-grid monotony, pass the squint test | design-principles.md |
| typeset | "typography / fonts / hierarchy" | Replace invisible defaults, 5-size scale at >=1.25 ratio, weight + size + space hierarchy, 65-75ch measure, font-display: swap, cap 3 families | design-principles.md |
| colorize | "flat / grayscale / add color" | Pick a color strategy first, OKLCH ramp, 60-30-10 weight, tinted neutrals toward the brand hue, semantic meaning consistent, body text >=4.5:1 | design-principles.md, aesthetic-systems.md |
| harden | "production-ready / edge cases / real data" | Survive long/empty/CJK/RTL/emoji text, all API error states with recovery, 30-40% i18n space budget, no fixed text widths, server-side validation | engineering-and-performance.md |
| optimize | "slow / janky / perf" | Measure first, fix the actual bottleneck: LCP<2.5s, INP<200ms, CLS<0.1; image formats + lazy load, code split, transform/opacity over layout props | engineering-and-performance.md |
| distill | "too complex / cluttered / strip it back" | Remove elements that don't earn their place: one primary goal, progressive disclosure, 1-2 colors + neutrals, flatten nesting, halve the copy | design-principles.md |
| extract | "make reusable / tokens / design system" | Pull patterns used 3+ times with the same intent into tokens + components with a clear props API, migrate call sites, delete the old; avoid premature abstraction | engineering-and-performance.md |
| brand | "brand identity / distinctive look / not generic" | Choose an aesthetic language and a named reference, run the font-selection procedure (reject training-data defaults + saturated lanes), commit a palette strategy | aesthetic-systems.md, avoid-ai-slop.md |
| adapt | "mobile / tablet / different device or context" | Rethink the experience for the target (not scale pixels): single-column reflow, 44x44px touch targets, detect pointer/hover, content-driven breakpoints, safe-area insets | engineering-and-performance.md, refactor-and-redesign.md |
| redesign | "improve / fix this existing UI without breaking it" | Audit current state, diagnose generic AI patterns and drift, run the redesign loop preserving function; image-to-code when matching a visual target | refactor-and-redesign.md, avoid-ai-slop.md |
| clarify | "rewrite this error / these labels are confusing / fix the microcopy" | Verb+object button labels, what-happened/why/how-to-fix error copy, one term per concept, instructions before the field; run the Clarify kit below — this file owns UX copy | avoid-ai-slop.md |
| onboard | "first run / empty states / activation / product tour" | Shortest path to first value: 5-part empty-state anatomy, the five empty-state types, skippable 3-7-step tours; run the Onboard kit below | engineering-and-performance.md |
| document | "capture the design system / write or refresh DESIGN.md" | Scan tokens + components and generate or refresh DESIGN.md so later work stays on-brand; never overwrite without asking | refactor-and-redesign.md |
| variants | "show me options / 3 versions of this hero" | Variation within identity, never three different brands: extract the identity lock, pick default vs departure mode, vary each option on a different axis | refactor-and-redesign.md, avoid-ai-slop.md |
| form | "form design / form validation / input fields / multi-step form" | Single-column layout, top-aligned labels (never placeholder-only), blur validation (not every keystroke), error message directly below the failing field, multi-step when >7 fields — name each step in the indicator; mark optional not required | interaction-design.md, engineering-and-performance.md |
| navigate | "navigation / nav / sidebar / tab bar / breadcrumb / menu structure" | Match pattern to IA depth and platform: tab bar (mobile, 3-5 destinations), sidebar (desktop, many/nested), top nav (simple sites), breadcrumbs (deep hierarchies); active states distinguishable beyond color alone; never hamburger for primary nav on desktop | interaction-design.md, design-principles.md |
| states | "state machine / all states / every state / impossible state / model behavior" | Map the UI as finite states (idle/loading/success/error/empty); every state has one visual representation and at least one exit; eliminate impossible combinations (never loading + error simultaneously) | interaction-design.md, engineering-and-performance.md |
| feel | "feels flat / no personality / feels cold / humanize / feels dead / too sterile" | Name the felt state → find a physical analogue → extract a behavioral property → apply to easing, delay, copy tone, or duration; run the Copy voice by state table; motion-as-signal: ease-out lands softly, spring bounces, stiff spring = confident | interaction-design.md, motion-and-interaction.md |
| system | "design system / token architecture / theming / component library / dark mode system / naming convention" | Two-layer tokens: global primitives → semantic aliases; component specs cover all 8 states; naming {category}-{property}-{concept}-{variant}-{state}; themes override semantic tokens; dark mode reduces brightness, uses surface-elevation not shadows | design-systems.md, engineering-and-performance.md |
| score | "score the design / visual critique / dimensional critique / rate the design / critique the ui" | 7-dimension critique: visual hierarchy, composition, color, typography, affordance, information density, brand consistency — rate each pass / minor issue / major issue; lead with AI-slop verdict; report: verdict → 2-3 working things → 3-5 priority issues (observation/problem/fix) → provocative close | visual-critique.md, avoid-ai-slop.md |
Register modifiers
The toning verbs mean different things per register (the register decision lives in SKILL.md's preflight). Read your verb's row before amplifying or calming anything:
| Verb | Brand register | Product register |
|---|---|---|
| bolder | Extreme scale, unexpected color, typographic risk | Stronger hierarchy, clearer weight contrast, one sharper accent, more committed density — amplify clarity, not drama; theatrics erode trust |
| quieter | Restrain the palette, add air, keep the point of view intact | Fewer background accents, flatter cards — the tool disappears into the task |
| delight | Distributed across copy voice, transitions, discoverable details | Moments only: completion, first-time actions, error recovery, milestones |
| animate | One well-rehearsed entrance beats scattered micro-interactions | 150-250ms, state-conveying only, no page-load choreography |
| colorize | The palette IS the voice; dosage follows the color strategy | Semantic-first; almost always a Restrained strategy |
| layout | Asymmetry, fluid clamp, deliberate grid-breaking | Predictable grids, structural responsiveness — consistency is itself an affordance |
| typeset | Run the font procedure; fluid clamp, scale ratio >=1.25 | One family, fixed rem sizes, scale ratio 1.125-1.2 |
The intensity dial
The toning verbs sit on one axis:
quieter ← distill ← (polish / baseline) → bolder → overdrive
Move right when the design is timid, low-contrast, generic, or forgettable: bolder for stronger hierarchy and committed color, overdrive when the brief wants a technically extraordinary moment (propose 2-3 directions and get user confirmation before building). Move left when the design is loud, noisy, or cluttered: quieter reduces intensity (desaturate, flatten, calm the motion) while keeping every element; distill goes further and removes elements down to the essence. polish is the neutral center: it refines what's there without shifting the volume in either direction.
Verbs also chain in a fixed pipeline: evaluate (audit / critique) → fixing verbs → polish → ship gate. Evaluation verbs fix nothing — they end by mapping each finding to the verb that fixes it, and suggest a re-run after fixes to watch the score move. Fixing verbs hand off to polish for the final pass; polish is always last and never runs before the thing is functionally complete.
Shape protocol
shape is a discovery interview, not a form. The discipline:
- 2-3 questions per round, then wait for answers. Run at least one real answer round before drafting unless the repo or docs directly answer; round 1 covers purpose / audience / content / visual direction, round 2 only if material gaps remain. Never synthesize a full brief from a sparse prompt and ask for blanket confirmation.
- Assert, then confirm — don't menu. When context makes one option obvious, "This reads as Restrained — confirm?" beats a four-option list.
- Always ask scope: fidelity (sketch / mid-fi / high-fi / production), breadth (one screen / a flow / the whole surface), interactivity (static / prototype / shipped), time intent (quick exploration vs polish-until-it-ships). Task-scoped — never persisted.
- Ask about content reality: realistic data ranges (0 / 5 / 500 items), what's dynamic, which visual assets are real content.
- Ask the anti-goal: what should this NOT be; the biggest risk of getting it wrong.
- Size the brief to the ambiguity: compact (3-5 bullets ending "confirm or override?") when the prompt + context pin everything; the full brief structure only when genuinely ambiguous or multi-screen. Don't pad to look thorough.
- Present the brief, then STOP. User confirmation is the gate — don't skip the pause to look efficient.
- Decide, don't list. If you'd write "Recommend: X" next to an open question, just decide X and assert it.
Build gates & the visual iteration loop
For build / craft — and any verb shipping substantial new UI:
Step 0 — project foundation. Detect the framework, component library, and icon set before anything else. On greenfield, ask the framework question once (a content-led brand site, an in-app product surface, and a one-shot demo each suggest different answers) — never pick silently.
Gates. Each stage ends with the user: brief → direction → palette → mock. Shape confirmation is not code-green; compressing gates because the brief felt complete is the dominant failure mode.
The visual iteration loop. Once code renders, look at what you built like a designer:
1. Screenshot at mobile / tablet / desktop minimum. If your tool returns a file path, read the image back — a screenshot you didn't read doesn't count. 2. On long pages, inspect major sections individually; full-page thumbnails hide spacing, clipping, and cascade defects. 3. Write an honest critique against the brief and the ban-lists, patch material defects, re-inspect. 4. Don't invent defects to demonstrate iteration — "first pass clean, shipping" beats a fake fix. 5. Detector or automated QA output is defect evidence, never proof the work is finished.
Exit bar: would this hold up in a high-end studio review? When presenting, show the primary state, summarize viewports checked and post-inspection fixes, walk the key states, explain decisions against the brief, disclose accepted deviations honestly, and ask what's working and what isn't.
Clarify kit (UX copy)
This file owns UX copy; clarify's moves in full.
Button labels — verb + object, never vague:
| Instead of | Write |
|---|---|
| OK | Save changes |
| Submit | Create account |
| Yes | Delete message |
| Cancel (in a destructive confirm) | Keep editing |
| Click here | Download PDF |
Errors — three parts, every time: what happened, why, how to fix it. Per-situation templates:
- Format: "[Field] needs to be [format]. Example: [example]."
- Missing required: "[Field] is required so we can [reason]."
- Permission: "You don't have access to [thing]. Ask [role] to grant it."
- Network: "Couldn't reach the server. Check your connection and try again."
- Server: "Something went wrong on our end. Try again in a moment."
Don't blame the user ("Please enter the date as MM/DD/YYYY", not "You entered an invalid date"). Never humor in errors — the user is already frustrated.
Terminology — one word per concept, everywhere: Delete (not Remove/Trash), Settings (not Preferences/Options), Sign in (not Log in), Create (not New/Add). Pick one and hold it across every screen.
Voice constant, tone shifts by moment:
| Moment | Tone |
|---|---|
| Success | Celebratory, brief |
| Error | Empathetic, concrete |
| Loading | Reassuring, expectation-setting |
| Destructive confirm | Serious, plain |
Form copy: placeholders are never labels (they vanish on focus); instructions go before the field, not after the mistake. Loading copy sets expectations — say what is happening and how long it usually takes ("Analyzing your data — usually 30-60 seconds", never bare "Loading...").
Onboard kit (first-run & empty states)
This file owns onboarding; onboard's goal is time-to-value — get the user to their first "aha" moment, not teach everything.
Empty-state anatomy — all five parts: (1) what will be here, (2) why it matters, (3) how to get started — a clear CTA, ideally with a template or sample option, (4) visual interest (not a gray void), (5) contextual help.
The five empty-state types get different treatments:
| Type | Treatment |
|---|---|
| First use | Full anatomy above — sell the value, offer a starting point |
| User cleared | Acknowledge or celebrate ("Inbox zero"); no tutorial |
| No results | Say what was searched; offer to broaden or fix the query |
| No permission | Say who can grant access and how to ask |
| Error | What happened + a retry path; never a bare sad face |
Principles: show, don't tell; everything skippable; teach the 20% that delivers 80% of the value; context over ceremony — teach at the point of use, not in a welcome lecture; track dismissals and never re-show what was dismissed.
Tours: 3-7 steps max, spotlight one thing at a time, always skippable, always replayable, workflow-focused ("Create your first project", not "This is the project button").
Appendix: scored review protocol
The full instrument behind critique — this file owns the UX-review layer; the visual/technical audit table lives in refactor-and-redesign.md.
Nielsen's 10 heuristics, scored 0-4 each (/40): visibility of system status, match with the real world, user control & freedom, consistency & standards, error prevention, recognition over recall, flexibility & efficiency, aesthetic & minimalist design, error recovery, help & documentation. Anchors: 0 = absent or actively violated, 1 = major gaps, 2 = inconsistent, 3 = solid with minor gaps, 4 = genuinely excellent. Bands: 36-40 excellent (ship), 28-35 good, 20-27 acceptable, 12-19 poor (overhaul), 0-11 critical (redesign). Honesty calibration: a 4 means genuinely excellent — most real interfaces score 20-32.
Cognitive-load checklist — 8 items: single focus per screen; chunking <=4 per group; visual grouping; clear hierarchy; one decision at a time; <=4 visible options per decision point; no memory bridges between screens; progressive disclosure. Scoring: 0-1 failures = low load, 2-3 = moderate, 4+ = critical. The eight named violations, each with its one-line fix: the Wall of Options (chunk or pick a default), the Memory Bridge (carry the context forward), the Hidden Navigation (make wayfinding visible), the Jargon Barrier (use the user's words), the Visual Noise Floor (cut decoration competing with content), the Inconsistent Pattern (one pattern per job), the Multi-Task Demand (one task per screen), the Context Switch (keep the user in flow).
Severity: P0 blocks core tasks, P1 major friction, P2 noticeable annoyance, P3 cosmetic. Tiebreak: would a user contact support about this? If yes, it's at least P1.
Persona walk-throughs — pick by interface type, report what broke for them, not generic descriptions:
| Persona | Red flags |
|---|---|
| Alex — impatient power user | Forced tutorials, no keyboard path, unskippable animation, no batch actions, redundant confirms |
| Jordan — confused first-timer | Icon-only nav, jargon, no help, ambiguous next step, no success confirmation |
| Sam — accessibility-dependent | Click-only interactions, invisible focus, color-only meaning, unlabeled fields, timed actions |
| Riley — stress tester | Silent failures, broken error recovery, useless empty states, data loss on refresh, inconsistent behavior |
| Casey — distracted mobile user | Primary actions outside the thumb zone, no state persistence, typing where selection would do, heavy assets, tiny targets |
| Interface type | Walk it through as |
|---|---|
| Landing page | Jordan, Riley, Casey |
| Dashboard | Alex, Sam |
| Checkout | Casey, Riley, Jordan |
| Onboarding | Jordan, Casey |
| Data-heavy | Alex, Sam |
| Forms | Jordan, Sam, Casey |
Anchoring discipline: form your own design-review verdict before consulting any detector or automated checker output — deterministic findings anchor judgment. Then weave: where you and the tool agree, what it caught that you missed, which of its findings are false positives.
Trend loop: persist the score per target; re-run after fixes and report the trend ("24 → 28 → 32").
Report shape: lead with the AI-slop verdict; overall impression; 2-3 things that are working (be specific about why); 3-5 priority issues, each with what / why it matters / concrete fix / suggested next verb; minor observations; close with provocative questions ("What would a confident version of this look like?").
Always-run gate
Every verb ends by running the avoid-ai-slop.md Anti-Slop Checklist before declaring done; it is the universal ship gate even when it is not in a row's Read column. Partial, placeholder, or truncated output is a hard failure under the output-completeness contract in avoid-ai-slop.md.
Design Principles
The aesthetic-agnostic visual foundation. These rules hold whether the brief is brutalist, editorial, luxury, dark-tech, or consumer-warm. Concrete palettes, named token systems, and worked examples live in aesthetic-systems.md; motion, easing, hover transforms, and live-mode params live in motion-and-interaction.md. This file is the neutral baseline every aesthetic builds on.
The bar for any decision: pick from a defined set, commit to it, and apply it everywhere. Arbitrary values are the tell.
---
Typography
Type carries most of the information on the page. Replace invisible defaults (Inter, Roboto, Arial, Open Sans, system fallback at a flat scale) with type that reflects the brand and scales with intentional contrast.
Type scale and ratio
Five sizes cover most needs. Pick one ratio and commit; the common failure is too many sizes too close together (14px, 15px, 16px, 18px), which produces muddy hierarchy.
| Role | Size | Use |
|---|---|---|
| xs | 0.75rem | Captions, legal |
| sm | 0.875rem | Secondary UI, metadata |
| base | 1rem | Body |
| lg | 1.25-1.5rem | Subheadings, lead |
| xl+ | 2-4rem | Headlines, hero |
- Ratios: 1.25 (major third), 1.333 (perfect fourth), 1.5 (perfect fifth). Keep ≥1.25 between steps; a flat 1.1× scale reads as uncommitted.
- Product UI runs tighter: a 1.125-1.2 ratio on closely-spaced steps, on a fixed
remscale (no fluidclamp()in dense app UI; users view at consistent DPI, and a heading that shrinks in a sidebar looks worse). - Bolder needs drama: 3×-5× size jumps, not 1.5×.
- Fluid headings use
clamp(min, preferred, max); bound itmax ≤ 2.5 × min. Cap hero/display at ≤6rem (~96px); 8-11rem reads comically loud. Keep body text fixed even on marketing pages.
Families and weights
- Cap families at 3 (display + body + optional mono). More than 3 reads as indecision; more than 2-3 is almost always a mess.
- Cap weights at 3-4 (Regular 400, Medium 500, SemiBold 600, Bold 700 is plenty). Load only the weights you use. Stop shipping only 400 + 700; intermediate weights create nuanced hierarchy.
- Pair on a contrast axis: serif + sans, geometric + humanist, condensed + wide. Never pair two similar-but-not-identical families (two geometric sans-serifs). One family in multiple weights beats two competing typefaces.
- Bolder pairs extremes: 900 with 200, not 600 with 400.
- Emphasis stays in-family: italic or bold of the same font. Injecting a random serif word into a sans headline is an amateur tell.
- Default sans with character: Geist, Outfit, Cabinet Grotesk, Satoshi. Inter is discouraged as a default (acceptable only for explicit neutral/Linear-style or public-sector/accessibility briefs). Serif is very discouraged as default; reach for it only when the brief names a serif or the aesthetic is genuinely editorial/luxury/heritage with an articulable reason.
FrauncesandInstrument_Serifare banned defaults.
Tracking, measure, line-height
- Tracking scales inversely with size. Negative tracking on large display; floor at ≥ -0.04em (default -0.05 to -0.085em makes letters touch; -0.02 to -0.03em is plenty for a tight grotesque). Add +0.05em to +0.12em to short all-caps labels and eyebrows; capitals sit too close at default spacing.
- Measure: 45-75 characters for body (ideal 65-75ch). Set
max-widthinchunits. Data and compact UI can run denser; tables at 120ch+ are fine. - Line-height: tighter for headings (1.1-1.2), looser for body (1.5-1.7). It scales inversely with line length: narrow columns want tighter leading, wide columns want more.
- Light-on-dark loses perceived weight on three axes; fix all three: bump line-height +0.05 to +0.1, add letter-spacing +0.01 to +0.02em, and optionally step body weight up one notch (e.g. 350 instead of 400). Body on dark sits comfortably at line-height 1.65-1.8, measure 65-75ch.
- Rags: use
text-wrap: balanceon h1-h3,text-wrap: prettyon long prose to kill orphans. Italic display words with descenders (y g j p q) clip atleading-none; useleading-[1.1]minimum pluspb-1/mb-1reserve. - Casing: sentence case for headers, not Title Case on every header. Vary all-caps subheaders (lowercase italics, small-caps). No all-caps body copy. Tracked uppercase is for short system markers only.
- Always: body ≥16px / 1rem;
remnotpx(respects user zoom); never disable zoom (user-scalable=no). Usefont-variant-numeric: tabular-numsfor data and numbers that align in columns. - Vertical rhythm: line-height is the base unit for all vertical spacing. Body at line-height 1.5 on 16px (= 24px) means spacing in multiples of 24px. Paragraph rhythm: space-between OR first-line indent, never both.
Hard floors (checkable, not judgment calls)
Mechanical pass/fail thresholds. Everything above is judgment; these are not.
- Line-height ≥1.3× on any multi-line text. 1.5-1.7 stays the body target; below 1.3 fails outright.
- Body text never below 12px. Below 12px is an outright fail; 14px is the minimum for body content, 16px the ideal.
- Letter-spacing on body caps at +0.05em. Wider tracking disrupts character groupings; wide tracking is for short uppercase labels only.
- Never skip heading levels. h1 → h3 with no h2 breaks the screen-reader outline.
- No `text-align: justify` without `hyphens: auto`. Unhyphenated justification creates rivers; default body to left-align.
- Line length hard ceiling ~80ch. 65-75ch stays the ideal; text wrapping beyond ~80ch fails.
---
Spacing and rhythm
Space is the most underused design tool. Layout problems are often the root cause of an interface feeling "off" even when color and type are fine.
- Use a 4pt base scale:
4, 8, 12, 16, 24, 32, 48, 64, 96px. Prefer it over 8pt; 8pt is too coarse and you will constantly want 12px between 8 and 16. Never use values outside the scale (no random 13px gaps). Pull every gap from the set. - Rhythm comes from variety, never equal spacing: tight grouping for related elements (8-12px between siblings), generous separation between distinct sections (48-96px), varied gaps within a section (not every row needs the same gap). Marketing pages double the spacing; dense data dashboards can pack tighter. When in doubt on a marketing page, double the whitespace. Monotony self-check: among 10+ gaps on a page, one value covering >60% of them with ≤3 unique values total = no rhythm; rework.
- Hard floors — checkable, not judgment calls: text inside any bordered, outlined, or colored container gets ≥8px padding, ideally 12-16px. Two failure shapes to catch: the element's own padding too low for its font size, and a near-zero-padding wrapper whose text children land flush against a visible boundary. Body paragraphs sit ≥16px (ideally 24-32px) from the viewport edge, via a container or
max-width+ auto margins. - Bolder uses dramatic 100-200px gaps, not 20-40px. Quieter evens out extreme variations into consistent rhythm.
- Use
gapfor sibling spacing instead of margins (no margin-collapse hacks). Useclamp()for fluid spacing that breathes on large screens. - Optical vertical padding: mathematically equal top/bottom looks bottom-heavy; bottom padding often needs to be slightly larger.
---
Color and contrast
More color ≠ better. Strategic color beats rainbow vomit. Use OKLCH, not HSL: it is perceptually uniform, so equal lightness steps look equal. To build a ramp, hold chroma and hue roughly constant and vary lightness, but reduce chroma as you approach white or black so it does not go garish.
Building a palette
| Role | Purpose | Shades |
|---|---|---|
| Primary | Brand, CTAs, key actions | 1 color, 3-5 |
| Neutral | Text, backgrounds, borders | 9-11 scale |
| Semantic | Success, error, warning, info | 4 colors, 2-3 each |
| Surface | Cards, modals, overlays | 2-3 elevation levels |
- Choose 2-4 colors max beyond neutrals. Skip secondary/tertiary unless you need them; most apps work with one accent. Use exactly one accent and lock it for the whole page (a warm-grey site does not get a blue CTA in section 7).
- Kill pure gray. Add chroma 0.005-0.015 to all neutrals, hued toward this brand's color, small enough not to read as tinted. Stick to one gray family; never mix warm and cool grays. The hue comes from the specific brand, not a "warm = friendly, cool = tech" formula. Avoid the lazy default of always tinting toward warm orange or cool blue.
- 60-30-10 by visual weight, not pixel count: 60% neutral backgrounds/surfaces/whitespace, 30% secondary (text, borders, inactive states), 10% accent (CTAs, highlights, focus). Accents work because they are rare; flooding the page kills their power.
- Accent saturation < 80%. Desaturate so accents blend with neutrals instead of screaming. Bolder = one bold color owning ~60% plus a sharp accent; quieter = 70-85% saturation with neutral dominance. Avoid the AI purple/blue glow and the purple-to-blue gradient.
- Gradients: allowed when subtle and palette-matched (low-chroma tonal grades, single-hue atmospheric washes, noise-textured). Break uniform linear 45° fades with radial, noise-overlay, or mesh variants. Banned slop: rainbow/mesh blobs, purple-to-blue "AI" defaults, pink-to-orange "creator" defaults, gradient text as a premium shortcut.
Contrast (WCAG, verify on every text element)
| Content | AA minimum | AAA target |
|---|---|---|
| Body text | 4.5:1 | 7:1 |
| Large text (≥18px, or ≥14px at weight ≥700) | 3:1 | 4.5:1 |
| UI components, icons | 3:1 | 4.5:1 |
| Placeholder text | 4.5:1 | — |
The single biggest reason AI designs feel hard to read: muted gray body text on a tinted near-white "for elegance." When close, bump the body color toward the ink end of the ramp. Dangerous combos that commonly fail: light gray on white (the #1 fail), red on green (8% of men can't distinguish), yellow on white, thin light text on images. Don't trust your eyes; test with a contrast checker. Never rely on color alone to convey information.
Never put gray text on a colored background. It looks washed out. Use a darker shade of the background's own hue, or a transparency of the text color.
Dark mode
Dark mode is not inverted light mode. Never use pure black or pure white; use off-black or a brand-tinted near-black (#0a0a0a, #121212, oklch ~12-18% works). Depth comes from surface lightness, not shadow: build a 3-step surface scale where higher elevations are lighter (e.g. 15% / 20% / 25% lightness), same hue/chroma as the brand, varying only lightness. Reduce body text weight slightly and desaturate accents. Use two token layers: primitives (--blue-500) and semantics (--color-primary); for dark mode, redefine only the semantic layer. Heavy alpha use is a smell that signals an incomplete palette; define explicit overlay colors instead (exception: focus rings and interactive states).
---
Layout and grid
- Flexbox for 1D (rows, nav bars, button groups, component internals). Grid for 2D (page structure, dashboards, data-dense interfaces). Don't default to Grid when
flex-wrapis simpler; don't do flexbox percentage math (w-[calc(33%-1rem)]) where Grid is cleaner. - Breakpoint-free responsive grids:
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)). Use container queries for components, viewport queries for page layouts. - Contain page width to ~1200-1440px with auto margins; edge-to-edge content on wide screens destroys readability.
- Asymmetry creates interest. Break centered/symmetrical layouts with offset margins, mixed aspect ratios, or left-aligned headers over centered content. Throw out the golden ratio; try 70/30 or 80/20 splits. Use negative margins for overlap and layering. Centered hero is OK only for editorial/manifesto/launch briefs where the message is the design.
- Cards are the lazy answer. Use them only when elevation communicates real hierarchy; otherwise group with
border-t,divide-y, or negative space. Never nest cards inside cards. Vary card sizes and mix with non-card content to break monotony. Allow variable card heights or masonry when content length differs; force-equalized heights look rigid. Pin CTAs to card bottoms so they form a clean horizontal line, and start feature lists at the same Y across pricing/comparison columns. - Bento grids: exactly as many cells as you have content for (3 items → 3 cells; 5 → 5). No empty cell in the middle or end; re-shape the grid, never paste a blank tile. Use
grid-flow-denseand verify col-span/row-span interlock. Give multi-cell grids real visual variation (image, palette-matched gradient, pattern, tinted background); all-text white-on-white cards read as default. - Vary layout families. Each family appears at most once per page; an 8-section page uses ≥4 different families. Cap consecutive image+text zigzag at 2; the 3rd is broken.
- Hero discipline: headline ≤2 lines, subtext ≤20 words and ≤3-4 lines, CTAs visible without scroll. A 4-line hero headline is a font-size error, not a copy-length one. Cap hero top padding at
pt-24(~6rem). Max 4 text elements; trust strips, taglines, pricing teasers, and logo walls move below the hero. - Navigation renders on a single line at desktop (condense or hamburger if it won't fit); cap height at 80px (default 64-72px).
- Theme lock: one theme for the whole page; sections do not invert mid-scroll. Section-level tints within the same family are fine; flipping to a cream section between dark sections is broken. Set the theme once at the page root.
- Touch targets are 44×44px minimum even when the visual element is smaller; expand the hit area with padding or a pseudo-element.
Optical alignment
Adjust only when something genuinely looks wrong, never speculatively. Text at margin-left: 0 looks indented due to letterform whitespace; nudge -0.05em to optically align. Geometrically centered glyphs look off (play icons shift right, arrows shift toward their direction); icons next to text often need 1-2px adjustment. Align shared elements (titles, prices, buttons) across side-by-side items, or the layout looks broken. Standardize icons to one stroke weight.
---
Visual hierarchy
Direct the eye with the fewest dimensions needed. Space alone is often enough; add color or size only when simpler means aren't sufficient. The strongest hierarchy combines 2-3 dimensions at once.
| Dimension | Strong | Weak |
|---|---|---|
| Size | 3:1 ratio or more | <2:1 |
| Weight | Bold vs Regular | Medium vs Regular |
| Color | High contrast | Similar tones |
| Position | Top/left (primary) | Bottom/right |
| Space | Surrounded by whitespace | Crowded |
The squint test: blur your eyes. If you can still identify the most important element, the second, and clear groupings, the hierarchy works. The most important content should be obvious within 2 seconds. Group by proximity; create clear groupings through spacing and separation. To quiet a loud design, reduce weights (900→600, 700→500), shrink scale jumps, and lean on weight/size/space instead of color and boldness.
Cognitive load
Humans hold ≤4 items in working memory. Cap simultaneous decision options at 4: nav ≤5 top-level, ≤4 form fields per group, 1 primary + 1-2 secondary actions, ≤4 dashboard metrics, ≤3 pricing tiers. One screen, one focus. Option bands: ≤4 is manageable, 5-7 is pushing it, 8+ and users skip, misclick, or abandon.
Three kinds of load, three treatments:
- Intrinsic (the task is genuinely complex): structure it with discrete steps, scaffolding, and progressive disclosure.
- Extraneous (the interface adds friction): eliminate ruthlessly: confusing nav, unclear labels, clutter, inconsistent patterns, unnecessary steps.
- Germane (effort that builds the user's mental model): this load is good; support it with consistent patterns and clear feedback.
Eight-point self-check, one point per failure (0-1 = low load, 2-3 = moderate, 4+ = critical): single focus per screen / chunks of ≤4 per group / visual grouping matches meaning / clear hierarchy / one decision at a time / ≤4 visible options per decision point / no memory bridges between screens / progressive disclosure for the rest.
| Violation | One-line fix |
|---|---|
| The Wall of Options | Group, default, and progressively disclose; show ≤4 at once |
| The Memory Bridge | Carry needed info forward; never make users remember it across screens |
| The Hidden Navigation | Keep primary paths visible; don't bury them behind gestures or unlabeled icons |
| The Jargon Barrier | Use the user's words, not the system's |
| The Visual Noise Floor | Strip decoration until every element earns its place |
| The Inconsistent Pattern | One interaction pattern per job, reused everywhere |
| The Multi-Task Demand | One task per screen; split parallel demands into steps |
| The Context Switch | Keep related actions in one place; don't bounce users between areas |
---
Depth, borders, and radius
The system should read mostly flat. Depth comes from material contrast and hairlines before shadow.
- Hairline first. Use a 1px border or a background shift before reaching for a drop shadow. Group with
border-tordivide-yinstead of wrapping everything in elevated cards. - Shadow scale: build a consistent
sm → md → lg → xland keep shadows subtle. Use elevation to reinforce hierarchy, not as decoration. All shadows imply a single light source; audit for inconsistent direction. - Tint shadows to the background hue. No pure-black low-opacity shadows on colored or light backgrounds; a black shadow on a colored surface looks muddy and bolted-on.
- Radius consistency. Pick one scale and apply it everywhere: all-sharp (0), all-soft (12-16px), or all-pill (full radius on interactive). Mixed systems are allowed only under a documented rule followed everywhere (e.g. buttons full-pill, cards 16px, inputs 8px). Round buttons in a square layout is broken. When nesting, vary radius optically: tighter on inner elements, softer on outer containers.
- Default-lean on roundness: cards top out at 12-16px. Card, section, or input radii of 24, 28, 32, or 40px read as generated UI; full-pill radius stays at tag/button scale. Soft and high-end consumer systems deliberately override this (the precedence rule applies).
- Glassmorphism: go beyond
backdrop-filter: blur. Add a 1px inner border (border-white/10) and a subtle inner shadow (inset 0 1px 0 rgba(255,255,255,0.1)) to simulate edge refraction. Provide a solid-fill fallback forprefers-reduced-transparency.
---
Expensive vs cheap
These are default-lean verdicts for the aesthetic-neutral baseline — what to do when no aesthetic system has overridden them. A deliberately selected system can flip specific cells: Minimalist's canvas is literally #FFFFFF, Brutalist requires Inter Black for macro-type, Soft requires diffused ambient shadows. See aesthetic-systems.md (Cross-System Contradictions) for the scoped exceptions.
| ✅ Expensive | ❌ Cheap |
|---|---|
| Off-black / brand-tinted near-black ground | Pure #000000 or pure #FFFFFF |
| Neutrals tinted with brand chroma (0.005-0.015) | Dead pure gray; warm and cool grays mixed |
| One locked accent at <80% saturation | AI purple/blue glow; multiple competing accents |
| Subtle palette-matched gradients (radial, mesh, noise) | Even linear 45° purple-to-blue fade |
| Shadows tinted to background hue, one light source | Pure-black drop shadows, inconsistent lighting |
| Hairlines and surface contrast for depth | Blanket drop shadows on every card |
| Committed type scale, ≥1.25 between steps | Flat 1.1× scale; 14/15/16/18px muddle |
| Geist/Satoshi/Cabinet Grotesk with real weight contrast | Inter everywhere; only 400 + 700 |
| Same-family italic/bold emphasis | Random serif word dropped into a sans headline |
| Measure capped 65-75ch, generous whitespace | Edge-to-edge text, cramped equal spacing |
| Asymmetric 70/30 splits, varied layout families | Centered-over-dark hero, 6 zigzag rows, repeated cards |
| Bento cells = content count, dense interlock | Empty bento cells, nested cards |
| Cards at 12-16px radius; pill only at tag/button scale | 24-40px radii on cards, sections, inputs |
| Subtle grain/noise/texture on flat fields | Sterile flat vectors; perfectly even gradients |
| Sentence-case headers, clean rags | Title Case everywhere, orphaned last-line words |
Most of these details users never consciously notice. That is the point: in the aggregate, the unseen corrections compound into an interface people trust without knowing why. Ship beautiful defaults rather than relying on configuration, because most users never customize.
Design Systems
The specification and governance layer. Read this when building, extending, or auditing a design system — tokens, component specs, naming conventions, motion, theming, and pattern library. These govern how to systematize design decisions so they scale. The other reference files cover how to design; this covers how to make those decisions durable.
---
Token Architecture
Design tokens are the single source of truth for visual decisions. Two-layer hierarchy is the minimum viable structure.
Layer 1 — Global (primitive) tokens: Raw values. No semantics — just named constants.
/* Color */
--color-blue-500: oklch(60% 0.2 260);
--color-neutral-100: oklch(95% 0.003 260);
--color-neutral-900: oklch(18% 0.005 260);
/* Spacing */
--space-4: 4px;
--space-8: 8px;
--space-16: 16px;
--space-32: 32px;Layer 2 — Semantic (alias) tokens: Reference global tokens by purpose. Themes override this layer, not the primitives.
--text-primary: var(--color-neutral-900);
--text-secondary: var(--color-neutral-600);
--surface-default: var(--color-neutral-50);
--surface-card: var(--color-neutral-100);
--action-primary: var(--color-blue-500);
--border-subtle: var(--color-neutral-200);Layer 3 — Component tokens (optional): Scoped to a specific component. Add only when a component needs a value that doesn't fit any semantic token.
--button-color-primary: var(--action-primary);
--button-radius: var(--radius-md);
--input-border-error: var(--status-error);Naming pattern: {category}-{property}-{concept}-{variant}-{state} Examples: color-surface-overlay, space-inset-sm, border-width-input-focus, color-text-disabled
Rules:
- Name by role, not value:
--text-bodynot--font-size-16. A token named after its current value becomes misleading the moment the value changes. - No hardcoded colors in components — always reference a semantic token.
- Declare new colors in OKLCH; never add a hex value outside the global token layer.
- CSS variable inheritance warning: changing a token on a parent recalculates all children. Set transforms directly on the element when you need to avoid cascade side effects.
- Themes override semantic tokens, not component tokens or global tokens.
---
Token Categories
| Category | Global examples | Semantic examples |
|---|---|---|
| Color | color-blue-500, color-neutral-900 | text-primary, surface-card, action-primary, status-error |
| Spacing | space-4, space-8, space-16 | inset-sm, inset-md, stack-md, inline-lg |
| Typography | font-size-14, font-weight-600, line-height-normal | text-body, text-heading-sm, text-caption |
| Border | border-width-1, radius-4, radius-full | border-default, radius-sm, radius-pill |
| Shadow / elevation | shadow-sm-values, shadow-lg-values | elevation-card, elevation-modal, elevation-tooltip |
| Motion | duration-100, duration-300, ease-out-expo | transition-interactive, transition-enter, transition-exit |
| Z-index | Semantic scale only | z-dropdown: 100, z-sticky: 200, z-modal-backdrop: 300, z-modal: 400, z-toast: 500, z-tooltip: 600 |
---
Motion System
Define motion as a token layer, not a collection of one-off animations. Without a system, each component invents its own duration and easing; transitions feel inconsistent; design and engineering have no shared language.
Duration scale (4–6 values is enough):
| Token | Value | Use |
|---|---|---|
duration-instant | 50ms | Checkbox tick, toggle — changes that must feel immediate |
duration-fast | 100ms | Tooltip appear, chip dismiss, small element transitions |
duration-normal | 200ms | Default UI transitions: dropdown open, focus ring, tab switch |
duration-moderate | 300ms | Modal entry, panel slide, medium element transitions |
duration-slow | 400ms | Page-level transitions, complex choreography |
duration-deliberate | 600ms | High-emphasis, intentionally paced moments (onboarding reveal) |
Don't create more tokens than distinct use cases. Add a new one only when nothing in the existing scale fits.
Easing scale:
| Token | Curve | Use |
|---|---|---|
ease-standard | cubic-bezier(0.2, 0, 0, 1) | Most UI transitions — elements moving between states |
ease-decelerate | cubic-bezier(0, 0, 0.2, 1) | Elements entering the screen |
ease-accelerate | cubic-bezier(0.3, 0, 1, 0.3) | Elements leaving the screen |
ease-spring | cubic-bezier(0.34, 1.56, 0.64, 1) | Playful or tactile interactions (FAB expand, drawer bounce) |
ease-linear | linear | Looping animations only — progress spinners, shimmer |
Choreography rules:
- Stagger: related elements entering together stagger 30–50ms; lead with the most important.
- Total staggered sequence: under 500ms.
- Direction consistency: elements sliding in from the right → related outgoing elements slide out to the left.
- Coordination: elements in the same semantic group use the same duration and easing.
Reduced motion — apply at the system level:
@media (prefers-reduced-motion: reduce) {
:root {
--duration-instant: 0ms;
--duration-fast: 0ms;
--duration-normal: 0ms;
--duration-moderate: 0ms;
--duration-slow: 0ms;
--duration-deliberate: 0ms;
}
}Preserve animations that convey essential state (loading spinners, progress bars). Opacity-only fades are generally acceptable under reduced-motion. Remove sliding, scaling, and rotation.
---
Component Specification
Every component needs a spec before implementation. The spec is the contract between design and engineering.
Required sections:
1. Overview — name, one-sentence description, when to use, when NOT to use. 2. Anatomy — visual breakdown with labels for each sub-element; required vs. optional parts. 3. Variants — size (sm/md/lg), style (primary/secondary/ghost), layout variations. 4. States — default, hover, focus, active, disabled, loading, error, success. Every state must have a visual representation. 5. Props/API — name, type, default, description, required flag. One row per prop. 6. Behavior — interaction sequence, animation (duration + easing tokens), responsive behavior, edge cases. 7. Accessibility — ARIA role, keyboard navigation sequence, screen reader behavior, focus management. 8. Usage guidelines — do/don't examples, content rules (max label length, icon requirements), related components.
State rule: never implement a component without specifying all eight interaction states. A component with a loading state that wasn't designed gets a default browser spinner in a random location. A component with no error state silently fails.
---
Naming Conventions
Predictable names are the most underrated design system feature. If a contributor can guess the name before looking it up, the system is working.
Principles: Predictable. Consistent. Scalable. Unambiguous. Names describe purpose, never appearance.
Patterns by artifact:
| Artifact | Pattern | Example |
|---|---|---|
| Component (Figma / file) | [Category]/[Name]/[Variant]/[State] | Form/Input/Default/Error |
| Token | {category}-{property}-{concept}-{variant}-{state} | color-text-primary, space-inset-sm |
| CSS class | kebab-case | .button-primary, .input-error |
| JS/TS component | PascalCase | <ButtonPrimary />, <InputField /> |
| Props | camelCase | isDisabled, onSubmit, labelText |
| Icon asset | icon-{name}-{size} | icon-chevron-right-16 |
| Illustration | illust-{scene}-{variant} | illust-empty-state-default |
Common pitfalls:
- Abbreviations only the author understands (
btn-pri-hovvs.button-primary-hover). - Inconsistent separators (
__in some places,-in others). - Names based on appearance (
color-blue) instead of purpose (color-action-primary) — the name becomes misleading when the value changes. - Using numbers that depend on the current value (
gray-200) instead of the role (neutral-subtle).
---
Theming Architecture
One component library, multiple visual themes through token mapping. Themes are layer-2 overrides; the components never change.
Three-layer override model:
- Layer 1 (global tokens): Never change between themes — these are the raw palette.
- Layer 2 (semantic tokens): Themes override here. Light mode, dark mode, brand variant, high-contrast — all expressed as semantic token overrides.
- Layer 3 (component tokens): Inherit from semantic tokens; rarely need to be themed directly.
Theme types:
- Color modes: light (default), dark, high-contrast, dimmed.
- Brand themes: primary brand, sub-brand, white-label, seasonal campaign.
- Density: comfortable (default), compact (data-heavy views), spacious (reading/editorial).
Dark mode design:
- Never just invert — reduce brightness thoughtfully.
- Use lighter surfaces for elevation rather than shadows (drop shadows don't read in dark mode).
- Desaturate colors 10–20% — saturated colors vibrate against dark backgrounds.
- Text: use off-white (e.g.
oklch(87% 0.01 260)) not pure white. - Surface hierarchy: each elevation step is 2–4% lighter: background → surface-1 → surface-2 → surface-3 → overlay.
- Test every component in dark mode; never assume it just works.
Implementation:
/* Light mode (default) */
:root {
--surface-default: var(--color-neutral-50);
--text-primary: var(--color-neutral-900);
--action-primary: var(--color-blue-500);
}
/* OS-level dark mode detection */
@media (prefers-color-scheme: dark) {
:root {
--surface-default: var(--color-neutral-950);
--text-primary: var(--color-neutral-100);
--action-primary: var(--color-blue-400);
}
}
/* Manual toggle — takes precedence over OS detection */
[data-theme="dark"] {
--surface-default: var(--color-neutral-950);
--text-primary: var(--color-neutral-100);
--action-primary: var(--color-blue-400);
}Provide both prefers-color-scheme detection and a manual [data-theme] attribute toggle.
---
Pattern Library
A pattern library documents reusable solutions to recurring problems — not just component appearance, but the interaction patterns that span multiple components.
Pattern entry structure: 1. Problem — what recurring need does this address, and in what contexts? 2. Solution — the pattern; key principles; visual + interaction description. 3. Anatomy — constituent components, layout, required vs. optional elements. 4. Variants — context-specific implementations, responsive adaptations. 5. Behavior — user flow, state changes, error handling. 6. Examples — good implementations + anti-patterns with explanations. 7. Accessibility — inclusive design considerations, assistive tech support. 8. Related patterns — similar patterns, commonly combined patterns, patterns this builds upon.
Common pattern categories: Navigation, Data entry (forms), Data display (tables, lists, cards), Feedback (toasts, banners, inline), Onboarding, Empty states, Error states, Search, Dialogs / overlays.
Quality bar: a pattern entry is not complete until it includes at least one anti-pattern (what NOT to do) with a specific explanation of why it fails. Patterns without anti-patterns teach the solution without teaching the failure mode.
---
Accessibility Integration
Accessibility is integrated into component development, not added as a post-hoc audit.
WCAG 2.2 POUR framework:
- Perceivable: text alternatives for non-text content, captions, adaptable content, color contrast.
- Operable: keyboard access, no seizure-inducing content, navigation, input modalities.
- Understandable: readable, predictable, input assistance.
- Robust: assistive technology compatibility, semantic markup, correct ARIA.
Severity for triage: Critical (blocks access entirely) → Major (significant difficulty) → Minor (workaround available) → Enhancement (beyond compliance improvement).
Minimum checks per component:
- Contrast ratios: 4.5:1 for body text, 3:1 for large text and UI components against adjacent surfaces.
- All interactive elements keyboard-reachable and operable with Enter/Space.
- Focus ring: visible, 2–3px, 3:1 contrast against the surrounding surface, offset outside the element.
- Labels programmatically associated with inputs (
<label for>oraria-labeloraria-labelledby). - Error messages associated with their field via
aria-describedby. - No color-only information — always pair color with a text label or icon.
- Dynamic state changes announced via
aria-liveregion or role-based announcement.
Rule: automated checks catch ~30–40% of WCAG 2.2 issues. Never certify WCAG 2.2 AA compliance from automated output alone. Manual keyboard navigation and screen reader testing are required.
---
Color System Architecture
Build in three layers: raw palette → semantic role mapping → component-specific tokens.
Step 1 — Generate tonal scales: For each hue (primary, secondary, accent, neutrals, semantics: error/success/warning/info), generate a tonal scale from lightest (50) to darkest (950). Use OKLCH for perceptually uniform steps across the scale.
--color-brand-50: oklch(97% 0.02 260);
--color-brand-100: oklch(93% 0.04 260);
--color-brand-300: oklch(78% 0.12 260);
--color-brand-500: oklch(60% 0.20 260);
--color-brand-700: oklch(42% 0.15 260);
--color-brand-900: oklch(25% 0.08 260);
--color-brand-950: oklch(18% 0.06 260);Step 2 — Map semantic roles:
| Semantic token | Purpose |
|---|---|
color-text-primary | Primary body text |
color-text-secondary | Secondary / supporting text |
color-text-disabled | Disabled text (must still pass 3:1) |
color-surface-default | Page background |
color-surface-card | Card and panel backgrounds |
color-surface-overlay | Modal / dialog backgrounds |
color-action-primary | Primary interactive color (buttons, links) |
color-action-secondary | Secondary interactive color |
color-status-error | Error state backgrounds and icons |
color-status-error-text | Error state text (must pass 4.5:1 against its background) |
color-status-success | Success states |
color-status-warning | Warning states |
color-border-default | Standard border color |
color-border-strong | Emphasized / focus border |
Step 3 — Validate all pairings: Every foreground/background semantic pair in use must be verified for contrast. A color system is not complete until every combination used in components has been checked. Document failing pairs — don't ship them as known issues.
---
Typography Scale
A mathematical ratio generates harmonic size relationships. Pick one ratio and apply it consistently.
Common ratios: Major Third (×1.25), Perfect Fourth (×1.333), Augmented Fourth (×1.414).
Example scale using Major Third from a 16px base:
| Token | Size | Line-height | Use |
|---|---|---|---|
text-caption | 12px | 1.4 | Fine print, timestamps, metadata |
text-body-sm | 14px | 1.5 | Secondary body, dense UI |
text-body | 16px | 1.5 | Primary body text (floor for desktop) |
text-body-lg | 20px | 1.5 | Lead / intro paragraphs |
text-heading-sm | 24px | 1.3 | Card titles, subsection headings |
text-heading-md | 32px | 1.2 | Section titles |
text-heading-lg | 40px | 1.15 | Page titles |
text-display | 48–64px | 1.1 | Hero headings |
Paired dimensions per token: font-size, line-height, letter-spacing, font-weight. Define all four for each scale step; don't let components set them ad hoc.
Letter-spacing guide: tight (−0.02em) for large display headings; 0 for body; wide (+0.05em) for uppercase labels and captions only.
Rules:
- Body minimum: 16px on desktop, 14px on mobile.
- Line length (measure): 45–75 characters for body. Apply with
max-width: 65chon prose containers. - Limit to 4–5 active sizes in regular UI; display / hero are supplementary.
- Test with real content — lorem ipsum hides length and line-break edge cases.
---
Spacing System
A base unit multiplied into a scale. 4px or 8px base. Never use arbitrary values in components.
4px base scale:
| Token | Value | Typical use |
|---|---|---|
space-1 | 4px | Minimal gap: icon + label, badge padding |
space-2 | 8px | Tight internal padding: chip, tag |
space-3 | 12px | Input vertical padding, small component gap |
space-4 | 16px | Default padding, standard gap between siblings |
space-6 | 24px | Component-to-component gap, card padding |
space-8 | 32px | Large component gap, section breathing room |
space-12 | 48px | Section-to-section spacing |
space-16 | 64px | Major section dividers |
space-24 | 96px | Hero padding, page-level vertical rhythm |
Spatial types:
- Inset (padding): equal
inset-sm: 8px; squishinset-squish-sm: 4px 8px(tighter top/bottom than left/right); stretchinset-stretch-sm: 12px 8px(taller than wide). - Stack: vertical gap between stacked elements.
- Inline: horizontal gap between inline or flex-row elements.
- Grid gap: gap between grid / flex children.
Density modes: compact (reduce each spacing value one step down), comfortable (default), spacious (increase one step up). Never mix modes within a component.
Rules:
- Related items: smaller spacing (
space-1,space-2). - Distinct sections: larger spacing (
space-8,space-12). - Minimum padding in bordered or contained components: 8px (
space-2). - Consistent within a component; larger between unrelated groups.
Interaction Design
The behavioral layer: cognitive load, state modeling, input patterns, feedback loops, and emotional timing. Read alongside motion-and-interaction.md (which covers animation mechanics). This file covers the why of behavior; motion covers the how of animating it.
---
Cognitive Laws
Four empirically-grounded constraints on interaction speed and accuracy. Apply before specifying any interactive pattern.
Fitts's Law — target size and distance
Acquisition time scales with distance and shrinks with target size. Large targets near the pointer are fast; small targets far away are slow and error-prone.
Hard rules:
- Touch targets ≥ 44×44pt (Apple HIG) / 48×48dp (Material). This is the interactive area, not the visual icon — a 16px icon can have a 44px tap area via padding.
- Pointer targets: 24×24px minimum; more for dense UIs.
- Screen edges are infinite targets (pointer cannot overshoot) → use for persistent navigation (macOS menu bar, taskbar).
- Bottom-of-screen placement reduces reach distance for right-hand thumb on mobile.
- Destructive actions: intentionally small and distant to prevent accidental activation.
| Pattern | Fitts's Law application |
|---|---|
| Primary CTA | Large, high-contrast, in thumb reach zone |
| Floating action button | Bottom-right on mobile |
| Navigation tabs | Bottom nav on mobile beats top nav for one-handed use |
| Modal actions | Buttons near bottom of modal, not scattered across it |
| Form submit | Full-width or prominent, directly below last field |
| Close button | Large hit target; consider bottom-dismiss on mobile |
| Destructive action | Small, distant, away from the primary flow |
Audit: test on real devices — what looks adequate in design tools is routinely too small in hand. High mis-tap rates are almost always Fitts's Law failures.
Hick's Law — choice and decision time
Decision time grows logarithmically with the number of simultaneous choices. Adding options always costs something, even if not proportionally.
Hard rules:
- Group before reducing — categorization reduces apparent complexity more than deletion.
- Navigation: limit top-level items (≤7); group secondary items in overflow menus.
- Toolbars: surface most-common actions; tuck the rest behind an overflow control.
- Onboarding: one decision per step, not multiple choices per screen.
- Pricing: three tiers is the sweet spot; more creates analysis paralysis.
- Smart defaults: for high-frequency, low-variance decisions, skip the choice entirely.
Do not confuse "fewer simultaneous choices" with "less functionality." The goal is reducing cognitive load at any moment, not removing features.
Miller's Law — working memory chunks
Realistic working memory limit: 4 ± 1 meaningful chunks (Cowan 2001). The "magic 7" is outdated and misapplied. A chunk is whatever has meaning to the person — a word, a familiar pattern, a concept.
Hard rules:
- Navigation: group menu items by category; flat lists of 10+ items are harder to scan than 3 groups of 3–4.
- Forms: break into named sections; each section should feel completeable as a unit.
- Codes and numbers: format as chunks (
555-867-5309,XXXX-XXXXverification codes). - Data tables: visual grouping (alternating rows, section headers) to break long lists.
- Onboarding: 3–5 named phases rather than a raw step count of 12.
- Feature lists: 3–5 bullet points per tier; beyond that, users stop reading.
Structure first, count second. Meaningful groupings matter more than hitting any number.
Doherty Threshold — response time and flow
Under 400ms → user stays in flow. Over 400ms → they notice the wait; cognitive engagement drops.
| Response time | User perception |
|---|---|
| 0–100ms | Instant — system feels like a direct extension of the action |
| 100–300ms | Fast — perceptible but not disruptive |
| 300–400ms | Approaching the edge — some users notice |
| 400ms–1s | Slow — response indicator required |
| 1s+ | Broken flow — progress feedback required |
| 10s+ | Task-level disruption; users switch context |
Hard rules:
- Button visual state change on press: within 100ms regardless of whether the underlying action completes.
- Search / filter: results begin appearing before 400ms; if not, show skeleton immediately.
- Autocomplete: first suggestions within 300ms of typing.
- If you cannot meet the threshold: acknowledge within 100ms (button state change), then skeleton/spinner if completion takes 400ms–3s, then progress if 3s+.
- Optimistic UI: update the interface immediately, reconcile on server response.
- Never show a loading indicator for actions that complete under 400ms — a flash of spinner is itself disruptive.
---
State Machines
Model every non-trivial UI component as a finite state machine to eliminate impossible states and make behavior predictable.
Components:
- States — Distinct modes the UI can be in:
idle,loading,success,error,empty,disabled,editing - Events — Things that cause transitions: click, submit, API response, timeout, validation
- Transitions — Valid state-to-state paths:
on event X in state A → go to state B - Guards — Conditions on transitions:
isValid,hasPermission,isOnline - Actions — Side effects during transitions: fetch data, show toast, log event
Standard machines:
| UI pattern | State sequence |
|---|---|
| Form | idle → editing → validating → submitting → success / error → idle |
| Data fetch | idle → loading → success / error; error → retrying → success / error |
| Authentication | logged-out → authenticating → logged-in → logging-out → logged-out |
| Multi-step wizard | step1 → step2 → … → review → submitting → complete |
| Toggle | off ↔ on (add pending for async toggles) |
| File upload | idle → selecting → uploading → success / error |
Rules:
- Every state has at least one way out. No dead ends.
- No impossible combinations: never
loading+errorsimultaneously — these are separate states. - Every state maps to exactly one UI representation (including loading, empty, error).
- Start with the happy path, add error and edge states after.
- Keep machines focused — one per concern.
Why it matters: State machines give design and engineering a shared language. Every UI branch (loading skeleton, error message, empty state, disabled form) is a deliberate state, not an afterthought to discover in QA.
---
Form Design
Single column, almost always. Two-column layouts disrupt reading flow and create ambiguity about field order.
Layout:
- Field width reflects expected input length: a postcode field is narrow; a bio field is wide. Width is an affordance for what belongs there.
- Top-aligned labels — faster to scan, more resilient to long labels than left-aligned or placeholder-only patterns.
- Group related fields using proximity and section headings.
- Mark optional, not required — when most fields are required, flagging optional reduces visual noise.
Labels and instructions:
- Every field has a persistent, visible label. Never rely on placeholder text as the only label (it disappears on input; it fails accessibility).
- Helper text: below the label, above the field. "Format: DD/MM/YYYY."
- Character counts: show remaining characters when limits exist; show them always, not only on approach.
- Labels: sentence case, not ALL CAPS.
Input type selection:
| Data type | Input type |
|---|---|
| Short text | Text input |
| Long text | Textarea (with visible resize handle) |
| One from ≤5 options | Radio buttons (all visible simultaneously) |
| One from 6+ options | Select / combobox |
| Multiple from few options | Checkboxes |
| Date | Date picker or segmented fields (day/month/year) — never freeform text for structured dates |
| Phone / card numbers | Formatted text input with masking |
| Password | Password input with show/hide toggle |
Validation:
- On blur (when the user leaves the field), not on every keystroke — real-time typing validation is distracting.
- Error placement: directly below the field, not at the top of the form.
- Error messages: explain what went wrong and how to fix it. "Email address must include @" not "Invalid email".
- Success indication: subtle checkmark for fields with non-obvious correctness (password strength, username availability).
- Server-side errors: surface inline to the field if possible; summarize at top if multiple fields are affected.
Multi-step forms:
- Show a step indicator that names the steps, not just "Step 2 of 5."
- Each step completeable as a unit — related fields together.
- Allow back navigation without losing data.
- Auto-save or "save and continue" for long forms.
- Confirm before discarding partial input.
Accessibility:
- Every field:
<label for>oraria-label. - Error messages:
aria-describedbypointing to the field. - Focus order follows visual order.
- Error summary at top: keyboard-focusable, links to each failing field.
- Never rely on color alone for required or error states.
Minimum: remove every optional field you can. Fewer fields = higher completion.
---
Navigation Patterns
Selecting the wrong navigation pattern is the most expensive IA mistake — it compounds across every screen in the product.
Pattern selection:
| Situation | Recommended pattern |
|---|---|
| Mobile, 3–5 primary destinations | Bottom tab bar |
| Desktop app, many destinations or nested structure | Side navigation / sidebar |
| Simple marketing site or docs | Top navigation bar |
| Deep content hierarchy | Breadcrumbs + local sidebar |
| Parallel views of the same content | Tabs or segmented control |
| Occasional, non-primary access | Utility nav or overflow menu |
Pattern notes:
- Bottom tab bar: icons + labels; always visible; 3–5 destinations maximum.
- Side navigation: vertical list; scales to many items; supports nested structure with expand/collapse.
- Top nav bar: horizontal links in header; 4–7 destinations; simpler hierarchies only.
- Breadcrumbs: essential in deep hierarchies; show the path from root to current page.
- Hamburger / drawer: hides navigation; reduces discoverability — reserve for secondary nav or extremely constrained contexts, never for primary navigation on desktop.
- Segmented control: compact tab variant for 2–4 tightly related views.
Four design principles: 1. Orientation — Users always know where they are: active state, breadcrumb, page title. 2. Wayfinding — Users can predict where a destination takes them before clicking (label scent). Validate with first-click tests. 3. Reachability — Primary destinations in thumb reach (bottom of screen on mobile). 4. Consistency — Navigation placement and structure never change between screens.
Active states: must be distinguishable across default, hover, focus, active, disabled, and notification badge. Distinguish by more than color alone — add weight, underline, or indicator bar.
Common mistakes:
- Hamburger menu for primary navigation on desktop.
- Mixing global + local navigation in the same visual component.
- Using internal product names users don't recognize as labels.
- More than 7 top-level destinations without revisiting the IA.
- Inconsistent active states across sections.
---
Error Handling UX
A four-layer system, not a single error message.
Hierarchy: 1. Prevention — inline validation before submission, smart defaults, confirmation dialogs for destructive actions, constraint-based inputs, auto-save to prevent data loss. 2. Detection — real-time field validation (on blur), form-level validation on submit, network error detection, timeout handling, permission and auth checks. 3. Communication — human language (not error codes); always: what happened + why + what to do; place message near the source; appropriate severity (error / warning / info / success). 4. Recovery — preserve user input (never clear forms on error), offer retry for transient failures, auto-retry with backoff for network errors, undo for accidental actions, alternative paths.
Error message format:
[What happened]. [Why, if helpful]. [What to do — one specific action.]
| ✓ | Your session expired. Sign in again to continue. |
|---|---|
| ✗ | Error 401. Unauthorized. |
| ✓ | Email address must include @. Check for typos. |
| ✗ | Invalid email. |
Error states by context:
| Context | Approach |
|---|---|
| Form field | Inline error directly below the field; summary at top if multiple fields fail |
| Full-page failure | Full-page error with retry + back option |
| Network / API failure | Toast or banner with retry action |
| Zero search results | Explain what was searched; suggest corrections and alternatives |
| Permission denied | Explain what access is needed and how to request it |
Never blame the user. Preserve their data. Test error paths as thoroughly as happy paths.
---
Feedback Patterns
Every user action needs acknowledgment. The question is what kind and where.
Hierarchy (innermost wins): 1. Inline / contextual — closest to the action (preferred) 2. Component-level — within the current component 3. Page-level — toast or banner 4. System-level — notification outside the current view
Types:
| Type | Examples |
|---|---|
| Immediate | Button state change on click, inline validation on input, toggle visual response |
| Confirmation | Success toast, completion animation, undo option |
| Status | Progress bars, status badges, typing / uploading / syncing indicators |
| Notification | In-app alerts, badge counts, banners, push |
Timing:
- Toasts: auto-dismiss after 3–5 seconds.
- Errors: persist until resolved or dismissed by the user.
- Confirmations: brief display with an undo window.
- Status: persist while relevant.
Channels: Visual (color, icon, animation) / Text (toast, inline label) / Haptic (mobile). Never rely on one channel alone — color without text or icon fails accessibility.
Rules:
- Acknowledge every user action.
- Match feedback intensity to action importance (silent for trivial, explicit for consequential).
- Don't interrupt flow for minor confirmations.
- Prefer undo over "Are you sure?" dialogs — undo keeps flow; confirmation breaks it.
---
Loading States
Pattern selection:
| Pattern | Use when |
|---|---|
| Skeleton screen | Content structure is known; fill layout shapes with shimmer; preferred over spinner |
| Indeterminate spinner | Unknown content structure or duration under ~10s |
| Determinate progress bar | Duration or percentage is measurable |
| Optimistic UI | High confidence the action will succeed; show result immediately, reconcile on server response |
| Progressive loading | Critical content first, enhance progressively; blur-up images (low-res placeholder → full) |
Duration guidelines:
| Duration | Indicator |
|---|---|
| Under 100ms | Nothing — no indicator needed |
| 100ms–1s | Subtle: skeleton appear, opacity fade |
| 1–10s | Clear loading state; determinate progress if measurable |
| Over 10s | Detailed progress, estimated time, background-continue option |
Transition rules:
- Fade content in — don't pop.
- Stagger list items 30–50ms intervals.
- Avoid layout shifts when content loads (
aspect-ratioon image containers prevents CLS). - Maintain scroll position on refresh.
- Skeleton shapes must match actual content proportions — an avatar skeleton for a text block is worse than no skeleton.
---
Gesture Patterns
Core gestures:
| Gesture | Primary uses |
|---|---|
| Tap | Select, activate, toggle |
| Double-tap | Zoom, like / favorite |
| Long-press | Context menu, reorder mode, peek / preview |
| Swipe | Navigate between views, dismiss, reveal row actions |
| Pinch | Zoom in / out |
| Drag | Move, reorder, adjust slider values |
| Pull | Pull-to-refresh |
Design rules:
- Every gesture must pair with a visible affordance. Users don't discover gestures by accident.
- Every gesture must have a non-gesture alternative (a button or menu item). Non-negotiable on touch.
- Provide immediate visual response when a gesture starts.
- Show threshold indicators — snap points, rubber-banding — so users know when the gesture will commit.
- Direction lock: after initial movement, lock to horizontal or vertical to resolve scroll vs. swipe conflict.
- System gestures take priority — never fight back-swipe or notification-pull.
Accessibility: every gesture must have a non-gesture alternative; support switch control and voice control; document custom gestures.
---
Interfaces That Feel
Technical correctness is the floor. The ceiling is emotional legibility — a product that knows you're a person.
Translation process: 1. Name the felt state — What is the person actually experiencing? Waiting anxiously. Recovering from a mistake. Celebrating a small win. Being overwhelmed by options. 2. Find the physical analogue — What in the physical world has that quality? A soft surface absorbs impact. The slow release of a door closing. A held breath before exhaling. 3. Extract the behavioral property — Weight, resistance, speed, recovery arc, rhythm. 4. Apply to the interface — Easing curve, delay, copy tone, color temperature, spacing, animation duration.
Copy voice by state:
| State | Voice |
|---|---|
| Loading | Present and calm — "Getting your data" not "Loading…" |
| Empty | Invitational — tell them what belongs here and what to do first |
| Error (user-caused) | Clear, directive, blame-free — one specific next step |
| Error (system failure) | Own it, apologize briefly, offer a path forward |
| Success | Warm and brief — acknowledge without overdoing it |
| Onboarding | Contextual — what they can do, not how the app works |
Emotional timing:
- Heavy news arrives slowly; good news can be instant.
- After an error: give 300–600ms before the next prompt — don't rush the recovery.
- System error copy must own the failure; never make the user feel responsible.
- Micro-wins deserve acknowledgment — silent success is a missed connection.
- The loading state sets expectation; match its mood to what's coming.
Motion as emotional signal:
- Ease-in conveys weight and momentum.
- Ease-out conveys natural deceleration, something landing softly.
- Stiff spring: snappy and confident.
- Loose spring: playful and forgiving.
- Duration for UI response: 150–300ms. For transitions that carry meaning: 400–600ms.
Review check — run on every state:
- What is the person feeling when they hit this state?
- Is the interface acknowledging that feeling or ignoring it?
- Does the copy sound like a person wrote it?
- Does the motion convey intent or just fill time?
- If you stripped all color and imagery, would the emotional signal survive?