diff --git a/.agents/skills/interface-design/SKILL.md b/.agents/skills/interface-design/SKILL.md index 92e1df4..f609d53 100644 --- a/.agents/skills/interface-design/SKILL.md +++ b/.agents/skills/interface-design/SKILL.md @@ -5,7 +5,7 @@ description: Craft-first interface design for dashboards, admin panels, SaaS app # Interface Design -Build product interfaces with the craft of a top design team — Linear, Vercel, Stripe, Apple. The difference between those and generic output is not talent. It is that every decision was *decided*, the hierarchy is unmistakable, and a hundred small details are correct at once. This skill is how you get there. +Build product interfaces with the craft of a top design team — Linear, Vercel, Stripe, Apple. The difference between those and generic output is not talent. It is that every decision was _decided_, the hierarchy is unmistakable, and a hundred small details are correct at once. This skill is how you get there. ## Scope @@ -23,7 +23,7 @@ You will generate generic output. Your training has seen thousands of dashboards This happens because intent lives in prose, but code generation pulls from patterns. The gap between them is where defaults win. Process helps, but it doesn't guarantee craft. You have to catch yourself, and you have to know the concrete moves that defaults don't. -**The bar:** If another AI, given a similar prompt, would produce substantially the same output, you have failed. Not different for its own sake — different because the interface emerged from *this* user, *this* task, *this* world. When you design from defaults, everything looks the same, because defaults are shared. +**The bar:** If another AI, given a similar prompt, would produce substantially the same output, you have failed. Not different for its own sake — different because the interface emerged from _this_ user, _this_ task, _this_ world. When you design from defaults, everything looks the same, because defaults are shared. --- @@ -31,9 +31,9 @@ This happens because intent lives in prose, but code generation pulls from patte Defaults disguise themselves as infrastructure — the parts that feel like they just need to work, not be designed. -- **Typography feels like a container.** But type isn't holding your design, it *is* your design. The weight of a headline, the personality of a label, the texture of a paragraph shape how the product feels before anyone reads a word. Reaching for your usual font means you're not designing. -- **Navigation feels like scaffolding.** But navigation *is* the product — where you are, where you can go, what matters. A page floating in space is a component demo, not software. -- **Data feels like presentation.** But a number on screen is not design. What does it *mean* to the person looking? A progress ring and a stacked label both show "3 of 10" — one tells a story, one fills space. +- **Typography feels like a container.** But type isn't holding your design, it _is_ your design. The weight of a headline, the personality of a label, the texture of a paragraph shape how the product feels before anyone reads a word. Reaching for your usual font means you're not designing. +- **Navigation feels like scaffolding.** But navigation _is_ the product — where you are, where you can go, what matters. A page floating in space is a component demo, not software. +- **Data feels like presentation.** But a number on screen is not design. What does it _mean_ to the person looking? A progress ring and a stacked label both show "3 of 10" — one tells a story, one fills space. - **Token names feel like implementation detail.** But `--ink` and `--parchment` evoke a world; `--gray-700` and `--surface-2` evoke a template. Someone reading only your tokens should guess what product this is. There are no structural decisions. Everything is design. The moment you stop asking "why this?" is the moment defaults take over. @@ -50,7 +50,7 @@ Before touching code, answer these. Keep it a compact working brief unless the d If the prompt is too vague to identify the human, task, and feel, ask one concise question. If context allows a responsible assumption, state it briefly and proceed. -**Intent must be systemic.** Saying "warm" then using cold colors is not following through. If the intent is warm: surfaces, text, borders, accents, semantic colors, type — all warm. If dense: spacing, type size, information architecture — all dense. Check every token against the stated intent. For every choice — layout, color temperature, typeface, spacing scale, hierarchy — you must be able to say *why*. "It's common" or "it works" means you defaulted. +**Intent must be systemic.** Saying "warm" then using cold colors is not following through. If the intent is warm: surfaces, text, borders, accents, semantic colors, type — all warm. If dense: spacing, type size, information architecture — all dense. Check every token against the stated intent. For every choice — layout, color temperature, typeface, spacing scale, hierarchy — you must be able to say _why_. "It's common" or "it works" means you defaulted. --- @@ -61,7 +61,7 @@ This is where defaults get caught — or don't. Generic path: Task type → visu **Produce all four before proposing any direction:** - **Domain** — concepts, metaphors, vocabulary from this product's world. Not features — territory. Minimum 5. -- **Color world** — what colors exist *naturally* here? Not "warm" or "cool" — go to the actual world. If this product were a physical space, what would you see? List 5+. +- **Color world** — what colors exist _naturally_ here? Not "warm" or "cool" — go to the actual world. If this product were a physical space, what would you see? List 5+. - **Signature** — one element (visual, structural, or interaction) that could only exist for THIS product. If you can't name one, keep exploring. - **Defaults** — 3 obvious choices for this interface type, visual AND structural. You can't avoid patterns you haven't named. @@ -75,7 +75,7 @@ If an inline visual-rendering tool is available in the session (e.g. a `show_wid Render at three moments: -1. **Proposing a direction.** Alongside the Suggest + Ask block, render a small live specimen: the palette as actual swatches, the type scale in the real typeface, the surface-elevation steps as stacked cards, the signature element as a real component. The person should *see* "warm like a notebook," not read the words. +1. **Proposing a direction.** Alongside the Suggest + Ask block, render a small live specimen: the palette as actual swatches, the type scale in the real typeface, the surface-elevation steps as stacked cards, the signature element as a real component. The person should _see_ "warm like a notebook," not read the words. 2. **Designing a component.** Render the actual component (or a tight before/after, both variants side by side) so the craft decisions — spacing, borders, hierarchy, states — are visible, not asserted. Render the real states (default, hover, empty, error) where they matter. 3. **Critiquing or auditing.** Render the current version and the improved version together so the gap is shown, not narrated. @@ -83,8 +83,8 @@ Rules when rendering: - The widget shows the **visual only**. All reasoning, the domain exploration, the rejected-defaults list, and the recommendation stay in your response text — never paste prose into the widget. - Match the rendering tool's own design-system contract (load its `read_me`/guidance if it has one). Use its theme variables so the specimen inherits light/dark mode and sits native in the host. Don't fight the host chrome. -- The specimen must still pass the checks below. A rendered default is still a default — rendering is how craft gets *seen*, not a substitute for it. -- This renders to the *conversation*, not the project. The actual implementation still lands in the codebase through normal edits. +- The specimen must still pass the checks below. A rendered default is still a default — rendering is how craft gets _seen_, not a substitute for it. +- This renders to the _conversation_, not the project. The actual implementation still lands in the codebase through normal edits. The point: collapse the loop between "here's my thinking" and "here's what it looks like" into a single message the person can react to. @@ -92,7 +92,7 @@ The point: collapse the loop between "here's my thinking" and "here's what it lo # Visual Hierarchy & Composition -The single biggest driver of "this looks designed" versus "this looks generated." Defaults produce *flatness* — everything the same size, weight, and spacing, so nothing leads and the eye has nowhere to go. Craft produces *hierarchy* — the eye knows instantly what matters. These are concrete moves, not vibes. +The single biggest driver of "this looks designed" versus "this looks generated." Defaults produce _flatness_ — everything the same size, weight, and spacing, so nothing leads and the eye has nowhere to go. Craft produces _hierarchy_ — the eye knows instantly what matters. These are concrete moves, not vibes. ## One focal point per view @@ -100,15 +100,15 @@ Every screen has one thing the user came to do. That thing dominates — through ## Type scale is a ratio, and weight beats size -Don't pick sizes by feel. Pick a ratio and step it: ~1.2 (minor third) for dense/calm UI, ~1.25 for most product UI, ~1.333 for expressive. From a 14–16px body that yields a *visibly* distinct scale, not 15/16/17 mush. A 14px base at 1.25: `caption 11 · body 14 · h4 16 · h3 18 · h2 22 · h1 28 · display 44+`. Round to whole pixels and to your spacing grid. +Don't pick sizes by feel. Pick a ratio and step it: ~1.2 (minor third) for dense/calm UI, ~1.25 for most product UI, ~1.333 for expressive. From a 14–16px body that yields a _visibly_ distinct scale, not 15/16/17 mush. A 14px base at 1.25: `caption 11 · body 14 · h4 16 · h3 18 · h2 22 · h1 28 · display 44+`. Round to whole pixels and to your spacing grid. The Apple/Linear move: **weight and color do more hierarchy work than size.** A single 14px size holds three tiers through weight + opacity alone — `value: 600 / primary`, `label: 500 / secondary`, `meta: 400 / muted` — separating more cleanly than two regular weights two points apart. Build from three levers together (size, weight, color/opacity), never size alone. If you squint and can't tell headline from body from label, the hierarchy is too weak. -Worked example — a metric, flat vs decided. *Flat:* `Revenue` / `$48,200` both 14px regular gray, three identical boxes, no focal point. *Decided:* `REVENUE` 11px/500/muted/tracked · `$48,200` 28px/600/primary/tabular-nums (the hero) · `↑12%` 12px/500/success. Same data, opposite legibility — the figure leads through size+weight+one accent, the label is demoted, secondary metrics drop to a lower tier. +Worked example — a metric, flat vs decided. _Flat:_ `Revenue` / `$48,200` both 14px regular gray, three identical boxes, no focal point. _Decided:_ `REVENUE` 11px/500/muted/tracked · `$48,200` 28px/600/primary/tabular-nums (the hero) · `↑12%` 12px/500/success. Same data, opposite legibility — the figure leads through size+weight+one accent, the label is demoted, secondary metrics drop to a lower tier. ## Density is a decision, expressed in px -Linear is tight; Stripe is airy. Neither is default — both are *chosen*, and the choice is the same number repeated everywhere. Decide the density up front and name the values: a tool panel at 12–16px padding feels workbench-tight; the same card at 24px feels like a brochure. The same number can be right in one context and lazy in another. Pick deliberately, then hold it. +Linear is tight; Stripe is airy. Neither is default — both are _chosen_, and the choice is the same number repeated everywhere. Decide the density up front and name the values: a tool panel at 12–16px padding feels workbench-tight; the same card at 24px feels like a brochure. The same number can be right in one context and lazy in another. Pick deliberately, then hold it. ## Spatial rhythm — breathe unevenly @@ -121,7 +121,7 @@ A 280px sidebar next to full-width content says "navigation serves content." A 3 ## Distribution and restraint (the "expensive" look) - **~60/30/10**: a dominant neutral surface, a secondary tone, and ~10% accent. Color is a scarce resource — most of the screen is structure. -- **One accent, used with intention**, beats five colors used without thought. Gray builds structure; color *communicates* (status, action, identity). Unmotivated color is noise. +- **One accent, used with intention**, beats five colors used without thought. Gray builds structure; color _communicates_ (status, action, identity). Unmotivated color is noise. - **Hierarchy through space and weight, not lines.** Reach for whitespace and tonal shift before borders and dividers. The most premium interfaces are mostly invisible structure. - **Optical sizing on large type**: tighten letter-spacing as type gets bigger (headings slightly negative tracking); loosen line-height on body for readability (~1.5). Tight type reads as crafted; default tracking on a 32px heading reads as a document. @@ -131,13 +131,13 @@ A 280px sidebar next to full-width content says "navigation serves content." A 3 ## Subtle Layering (the backbone) -Regardless of direction, this applies to everything. You should *barely notice the system working* — when you look at Vercel's dashboard you don't think "nice borders," you just understand the structure. Invisible craft is working craft. +Regardless of direction, this applies to everything. You should _barely notice the system working_ — when you look at Vercel's dashboard you don't think "nice borders," you just understand the structure. Invisible craft is working craft. **Surface elevation.** Surfaces stack: a dropdown sits above a card sits above the page. Build a numbered system — base, then increasing levels. Each jump is only a few percentage points of lightness — e.g. dark mode base → +7% → +9% → +12%; light mode stays light and adds shadow instead. You can barely see one step in isolation, but stacked, the hierarchy emerges. Whisper-quiet shifts you feel rather than see. - **Sidebars:** same background as canvas, not a different color. Different colors fragment the space into "sidebar world" and "content world." A subtle border is enough. - **Dropdowns/popovers:** one level above their parent surface, or they blend in and layering is lost. -- **Inputs:** slightly *darker* than surroundings, not lighter. Inputs are inset — they receive content. A darker fill signals "type here" without heavy borders. +- **Inputs:** slightly _darker_ than surroundings, not lighter. Inputs are inset — they receive content. A darker fill signals "type here" without heavy borders. **Borders.** Should disappear when you're not looking for them, but be findable when you need structure. Low-opacity rgba blends with the background and defines an edge without demanding attention; solid hex borders look harsh by comparison. Dark mode lives around `rgba(255,255,255,0.06–0.12)`, light mode slightly higher. Build a progression — standard, softer separation, emphasis, focus-ring — and match intensity to the importance of the boundary. @@ -145,7 +145,7 @@ Regardless of direction, this applies to everything. You should *barely notice t ## Infinite Expression -Every pattern has infinite expressions — **no two interfaces should look the same.** A metric display could be a hero number, inline stat, sparkline, gauge, progress bar, comparison delta, or trend badge. Same sidebar width, same card grid, same icon-left-number-big-label-small metric boxes every time *signals AI-generated immediately* and is forgettable. Linear's cards don't look like Notion's; Vercel's metrics don't look like Stripe's. Same concepts, infinite expressions. Before building, ask: what's the ONE thing users do here, and what product solves a similar problem brilliantly? +Every pattern has infinite expressions — **no two interfaces should look the same.** A metric display could be a hero number, inline stat, sparkline, gauge, progress bar, comparison delta, or trend badge. Same sidebar width, same card grid, same icon-left-number-big-label-small metric boxes every time _signals AI-generated immediately_ and is forgettable. Linear's cards don't look like Notion's; Vercel's metrics don't look like Stripe's. Same concepts, infinite expressions. Before building, ask: what's the ONE thing users do here, and what product solves a similar problem brilliantly? ## Color Lives Somewhere @@ -178,7 +178,7 @@ The most common way AI degrades a codebase: it hand-rolls what already exists. A ## Controls: native → primitive → hand-roll 1. **Native HTML first** where it works. A `