product-design
Specifies interaction choices, action scope, reversibility, recovery, and reachable states. Use when asked to "design the flow", "should delete be undoable", "choose the control", or "review this product decision". For visual implementation use ui-design; for motion use ui-animat
Install
npx skills add https://github.com/mblode/agent-skills/tree/main/skills/product-design
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install mblode-agent-skills@llmmart
git clone https://github.com/mblode/agent-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole mblode/agent-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Product Design
Decide what the interface should do, then route who builds and verifies it: pick the right interaction, make scope and consequence clear, cover reality beyond the happy path.
- IS: the decision layer. From a brief, spec, mockup, intent, or existing UI: choose the interaction and control, name the object, scope, and consequence of each action, settle reversibility and the safeguard it implies, enumerate every reachable state, set resilience expectations, and require accessibility as task completion. It decides, then routes build, verification, and wording out.
- IS NOT:
- whether a feature deserves investment or fits the product: the external
product-judgmentskill from Brandwriter. - building or styling UI, visual direction, palettes, type:
ui-design. - auditing the built result (rendered quality, a11y markup, keyboard, layout, performance, React or Next code-level UX with a ship verdict):
ui-designAudit mode. - copy wording, persuasion, or AI-ism removal:
copywriting. - motion, gesture physics, or deep typography:
ui-animation,typography-audit. - whether an agentic feature earns trust:
ax-audit.
- whether a feature deserves investment or fits the product: the external
Routing boundary
product-design owns action semantics, scope, reversibility, and contested state choices. ui-design builds and styles those states. ui-animation owns timing, gestures, and measured motion. A routine missing loading or error state stays with the UI build; a gesture replacing a control needs a product decision and an accessible alternative before its physics.
Request modes
Resolve one mode from the user's verb and artifact before acting, then load that mode's references. references/rules.md loads in every mode: every finding cites a rule ID from it, and you cannot conclude that no rule governs a decision without the registry in front of you.
| Mode | Dispatch when the user asks for | Load (plus references/rules.md) |
|---|---|---|
| shape (default) | "design the flow for", "what control here", "how should this work", "is this the right pattern", a brief with no settled UI | references/product-judgment.md, references/surfaces.md |
| spec | "spec the right interaction", "define the expected states", judgment applied before or during a build | references/product-judgment.md, references/surfaces.md, references/naming-and-copy.md; route the build to ui-design |
| review | "review this flow for product correctness", "what's wrong with this UX decision", "is this the right interaction" | references/interface-quality.md |
| action | "what should this action affect", "should this be undoable", "do we need a confirm dialog", or reversibility is unsettled | references/naming-and-copy.md; route final wording to copywriting |
| harden | "make this resilient", "what breaks here", error, permission, offline, expiry, and destructive paths | references/surfaces.md, references/interface-quality.md, references/product-judgment.md |
Review mode is about a flow, not an artifact. "Audit this component", "check my UI", and "design QA this page" point at built markup and belong to ui-design Audit mode. This skill's review asks whether the decisions behind a flow are right, and stops at decision altitude.
Modes chain: shape leads into spec; review leads into harden. When intent is ambiguous, use the narrowest mode the verb supports. A URL, screenshot, route, or component identifies scope; it does not authorize edits.
references/lint-patterns.md has no mode: read it when deciding whether a standard belongs in the consuming project's linter or in this skill. evals/evals.json never loads during a user task; it is the regression set for anyone changing this skill.
Workflow
Product design pass:
- [ ] Step 1: Classify the request into one mode
- [ ] Step 2: Locate authority (user constraints, project design system, AGENTS.md)
- [ ] Step 3: Load rules.md plus that mode's reference files
- [ ] Step 4: Write the internal brief (shape, spec, harden); stop and ask if job, outcome, or consequence is unfillable
- [ ] Step 5: Name object, scope, consequence, and reversibility for each action in scope (spec, action, review)
- [ ] Step 6: Enumerate reachable states and check coverage (shape, spec, harden)
- [ ] Step 7: Emit output with a rule ID or labeled coverage gap per finding or decision; route follow-on work to siblings
- [ ] Step 8: Check the decision contract and identify unresolved product decisions
Steps 5 and 6 are mode-scoped because their references are: a pure action pass has no state matrix to enumerate, and a shape pass has no built actions to name yet.
Output length follows the work, not the template. A single settled decision is a short answer; drop the sections a pass did not need rather than filling them.
Decision authority
Conflict order, highest first:
- The user's explicit goal and constraints.
- Verified user and product evidence, and what the system actually does.
- Project-canonical guidance:
AGENTS.mdorCLAUDE.md, the project's design system, routed sibling skills. - Sibling-skill ownership: route, do not duplicate.
- This skill's standards (below).
- General interface and platform conventions (WCAG 2.2, NN/g, Apple HIG, Material, GOV.UK), which
references/rules.mdcites per rule.
When a request spans authorities, name the owning skill and hand off.
Product design standards
Five pillars, each naming its rule IDs in references/rules.md and the reference that details it.
- Right interaction. Pick the control from the choice's shape; keep options visible and reversible; prefer inline disclosure over a modal; every gesture has a control alternative; choose the smallest coherent intervention.
rule/control-matches-cardinality,rule/navigation-vs-action,rule/inline-before-modal,rule/no-nested-modals,rule/gesture-has-control-alternative,rule/smallest-intervention. Detail:references/product-judgment.md. - Action naming and consequence. Name the object, scope, and consequence; settle reversibility first, then the pattern; an irreversible action gets review, check, or named confirmation; undo appears only when honest.
rule/name-object-scope-consequence,rule/destructive-names-action,rule/destructive-proportional,rule/irreversible-action-safeguard,rule/undo-only-when-honest,rule/preserve-user-input. Detail:references/naming-and-copy.md. - State coverage. Design every reachable state, not just the populated one: empty states name the object and a first action; errors explain and offer recovery; timers warn before they discard.
rule/cover-reachable-states,rule/empty-state-action,rule/error-states-recovery,rule/loading-stable-labels,rule/time-limit-adjustable. Detail:references/surfaces.md. - Resilience. Overflow, extreme data, localization and RTL, offline, and network failure are designed states; every fetch lands in one. Shares
rule/cover-reachable-states: it is the same requirement pointed at adverse inputs. Detail:references/surfaces.md> Resilience. Whether the built UI renders them isui-designAudit mode's check. - Accessibility as task completion. Every control has a name; the primary flow completes by keyboard with visible focus; nothing already entered is retyped; authentication allows assistance; state and consequence are understandable, not just labeled.
rule/accessible-name-required,rule/keyboard-complete-flow,rule/no-custom-focus-bypass,rule/no-redundant-entry,rule/auth-allows-assistance. Detail:references/interface-quality.md. Markup and target-size checks route toui-designAudit mode.
Review output
In review and harden modes, lead with findings ordered by user impact (P0 to P3), each with location, verification status, rule ID, user consequence, and the smallest concrete fix with the skill that owns it. Keep findings at decision altitude; a line-level code or framework fix is ui-design Audit mode's output. Rubric and finding format: references/interface-quality.md > Severity rubric.
Pass self-check
Use these as the decision contract. Report unresolved decisions; omit a separate ceremony when the output already carries them:
- Every finding and non-mechanical decision carries a rule ID that appears verbatim in
references/rules.md, or an inline coverage gap labeled proposed. - The internal brief is present with job, desired outcome, and consequence filled, for shape, spec, and harden.
- Every destructive or consequential action in scope has its reversibility stated and a matching pattern.
- Follow-on work is routed by name (
ui-design,ui-animation,copywriting), never done here.
Gotchas
- A confirmation dialog on a reversible action (archive, remove from list, unsubscribe) trains users to click through, so the one confirmation that matters, permanent delete, gets the same reflexive click. NN/g's "cry wolf" finding. Act and offer undo instead (
rule/destructive-proportional). - An undo toast as the only recovery path: it vanishes in about five seconds, and the object is gone. Either the object stays recoverable (Trash, Archive) or the action is irreversible and needs a safeguard. Do not call it undo otherwise (
rule/undo-only-when-honest, WCAG 2.2.1). - Swipe-to-delete or drag-to-reorder with no button or menu equivalent fails WCAG 2.5.1 and 2.5.7 outright and is undiscoverable to everyone else. Spec the alternative before routing the physics to
ui-animation(rule/gesture-has-control-alternative). - A segmented control with three fixed-width English labels: strings under 10 characters grow 200 to 300% in translation (W3C), so "Day / Week / Month" becomes a wrapped or clipped mess in German. Decide the wrap or stack behavior in the spec.
- Reusing the "No projects yet, Create project" empty state for a filtered-to-zero list. The user creates a duplicate because the item they searched for exists behind the filter. Three empties, three designs (
references/surfaces.md). - A checkout or sign-up that asks again for something entered two steps earlier (billing address after shipping, email after account) fails WCAG 3.3.7 and is the step where mobile users leave (
rule/no-redundant-entry). - Emitting a line-level fix (a prop, a hook, a
className) instead of the decision. It arrives without the rendered check that would validate it, and the product decision it was supposed to carry goes unstated. Route it toui-designAudit mode. - Citing a plausible-sounding rule ID that does not exist (
rule/clear-labels). The citation resolves to nothing, so the finding cannot be deduped against aui-designaudit or traced to a rule. Record a coverage gap instead.
Related skills
ui-design: visual direction and building the decided interaction in code; its Audit mode covers the built result, rendered quality and accessibility markup, with a ship verdict.copywriting: exact wording for names, errors, and empty and loading copy; defines the shared copy rule IDs in itsreferences/ui-states.md.ui-animation: the passage between two states (timing, easing, springs, gesture physics). This skill settles whether a gesture replaces a control and what its alternative is; that skill builds the motion.ax-audit: whether a built agentic feature earns trust; this skill decides what it should do first.typography-audit: deep type.
Files (agent-skills)
-
evals
-
evals.json 2.9 KB
{ "skill_name": "product-design", "evals": [ { "id": 1, "prompt": "We're adding a 'Delete workspace' button to the settings page. It should be a red button with a confirm dialog that says 'Are you sure?' with OK and Cancel. Spec the right interaction.", "expected_output": "A spec that names object, scope, and consequence; treats the action as irreversible and wide-scope; replaces OK/Cancel with a typed or named confirmation; enumerates in-progress and failure states; routes the build to ui-design and final wording to copywriting.", "files": [], "assertions": [ "Cites rule/irreversible-action-safeguard or rule/destructive-proportional for the safeguard choice", "Cites rule/destructive-names-action or rule/no-confirm-ok-labels and rejects OK as the confirm label", "States the scope (everything in the workspace, every member) before the user commits", "Does not emit a code patch, className, or prop change", "Every cited rule ID appears verbatim in references/rules.md" ] }, { "id": 2, "prompt": "Design the flow for reordering items in our mobile task list. Product wants drag-to-reorder like Things 3.", "expected_output": "Drag-to-reorder accepted as the primary interaction, with a single-pointer alternative (move up/down or a Move-to menu) required, the states enumerated (sparse list, drag in progress, save failure with rollback), and the gesture physics routed to ui-animation.", "files": [], "assertions": [ "Cites rule/gesture-has-control-alternative and names a concrete non-drag alternative", "Cites rule/cover-reachable-states and lists a failure state for the reorder save", "Routes the gesture implementation to ui-animation, not to itself", "Includes an internal brief with job, desired outcome, and consequence filled" ] }, { "id": 3, "prompt": "What breaks here? Our checkout collects shipping address on step 2, then asks for the billing address on step 4 with no prefill. Session times out after 10 minutes and dumps you back to the cart. Unsaved fields are lost.", "expected_output": "A harden-mode findings list ordered P0 to P3: redundant entry (billing not prefilled from shipping), silent session expiry that discards input, lost user input, each with rule ID, user consequence, and the smallest fix and owning skill.", "files": [], "assertions": [ "Cites rule/no-redundant-entry for the billing address re-entry", "Cites rule/time-limit-adjustable for the session timeout and proposes a warning plus extension or draft persistence", "Cites rule/preserve-user-input for the lost fields", "Findings carry a P0-P3 level and a user consequence, not only a code observation", "Records a coverage gap instead of inventing a rule ID for anything uncovered" ] } ] }
-
-
references
-
interface-quality.md 3.3 KB
# Interface Quality Load in `review` and `harden` modes. Holds the accessibility-as-task-completion standard, the review scan order, and the severity rubric and finding format. Not visual aesthetics or implementation audits: both route to `ui-design` (Direction and Build modes for aesthetics, Audit mode for the built result). ## Accessibility as task completion This skill owns whether a user can complete the task with assistive technology or constrained input. The implementation-level markup audit (roles, `aria-*`, contrast, axe output) is `ui-design` Audit mode's. The test at this altitude: can a keyboard-only, screen-reader, switch, or one-handed touch user finish the job, not just reach the first control? - Every interactive control has an accessible name (`rule/accessible-name-required`). - The primary flow is keyboard-completable with visible focus and sensible order; focus moves into new surfaces, returns on close, and is never fully hidden behind sticky chrome (`rule/keyboard-complete-flow`, `rule/no-custom-focus-bypass`). - Every gesture-triggered action has a single-pointer, non-timed control that does the same thing (`rule/gesture-has-control-alternative`). - Information entered earlier in the flow is not retyped (`rule/no-redundant-entry`). - Authentication does not rest on memory or transcription; paste and password managers work (`rule/auth-allows-assistance`). - State and consequence are understandable, not merely present: an error a screen reader announces as "error" with no detail fails even when technically labeled (`rule/reads-without-seeing`). - Target size is a rendered check: `ui-design` owns the 44 and 24 CSS-pixel numbers (`interaction-target-size`). This skill's decision is upstream: whether the action is on a control at all, rather than a gesture or a tiny inline glyph. ## Review scan order In `review` mode, walk the flow once per category in `rules.md`, in this order: action naming and consequence (the highest-impact failures live here), state coverage, interaction and control selection, accessibility as task completion, hierarchy and structure. Stop at decision altitude: the finding is "this delete has no safeguard", not "add `onConfirm`". ## Severity rubric Report findings ordered by user impact. Use these levels exactly. - P0: blocks the primary task, a severe accessibility failure, or unrecoverable user harm (data loss, a permission bypass, a destructive action the user cannot understand or undo). - P1: likely task failure, a misleading consequence, a missing critical state, or a major responsive or accessibility defect. - P2: meaningful friction, inconsistency, weak hierarchy, or a recoverability issue that does not block the task. - P3: minor craft or consistency improvement. For each finding include: - Location: the screen, step, or component; file and line when reviewing from source. - Verification status: verified in source, verified rendered, or unverified (and why). - Rule ID: the `rule/` slug it violates, or a labeled coverage gap. - User consequence: what goes wrong for the user, not just what the code does. - Smallest concrete fix: the narrowest change that resolves it, and which skill owns it. A line-level React bug with a code patch is `ui-design` Audit mode's output; hand it over rather than writing the fix here. -
lint-patterns.md 3 KB
# Lint Patterns Read when deciding whether a product-design standard belongs in a linter or this skill, or when encoding a standard's deterministic slice as a lint rule in a consuming project. Deterministic, structural, single-file checks belong in a linter; judgment that needs product context stays in this skill. These patterns are not a shippable package: each rule must point at the consuming project's own components (its `Modal`, its `Select`, its spacing scale), so encode them in that project's ESLint config, wired to its design system. ## The decision tree ```text Can code identify the failure from one file's AST, without rendering? No -> agent guidance (this skill). Yes -> Can the rule avoid likely false positives? No -> agent guidance. Yes -> Does the violation have a concrete, mechanical fix? Yes -> a lint rule (encode it in the project). No -> a warning, or agent guidance. Needs product or codebase context (which object, what consequence)? -> agent guidance. Establishes a new standard or product policy? -> human decision first. ``` For either path, add a test or eval catching the regression. If a rule needs many exceptions, move it back to agent guidance. Examples of the split: - Counting 2 to 3 static options is mechanical, so prefer-radio is a lint rule. - Naming the right object and consequence for a destructive action needs product context: it stays here (`rule/name-object-scope-consequence`) and in `copywriting` for wording. - Detecting a nested modal is structural: a lint rule. Whether the second step should exist is judgment. - Whether a gesture has a control alternative (`rule/gesture-has-control-alternative`) needs the whole surface, not one file: judgment. Whether a control's rendered box meets the target-size floor is `ui-design`'s `interaction-target-size` rule, not a lint rule here. ## Three deterministic rules worth encoding Each points at a `product-design` rule ID. Configure each against the project's own component names; none should hardcode a design system. | Rule | Rule ID | Suggested default | What it catches | |------|---------|-------------------|-----------------| | prefer-radio-for-few-options | `rule/control-matches-cardinality` | warn | A select with 2 to 3 static options that should be radios or a segmented control | | no-nested-modals | `rule/no-nested-modals` | error | A modal opened inside another modal | | icon-button-accessible-name | `rule/accessible-name-required` | error | An icon-only button with no accessible name | Keep formatting in a faster tool (oxfmt or Biome); let ESLint own these JSX-semantic rules, which do not overlap with formatting. Implementation notes: for prefer-radio-for-few-options, bail on dynamically rendered children (a `.map`, a spread) since the count is not statically known, then report only a static option count in range; for no-nested-modals, track modal-element depth and report any modal opened while already inside one. -
naming-and-copy.md 4.5 KB
# Naming and Consequence Load in `action` and `spec` modes, and whenever an action's object, scope, consequence, or reversibility is unsettled. Owns the product decision of what the action is and what it must communicate. Wording craft (persuasion, tone, AI-ism removal, the full state-copy rules, the canonical verb table) lives in `copywriting`. Decide here; route wording there. ## The split with copywriting - `product-design` decides: whether the action should exist, which object it affects, its scope, its consequence, whether it is reversible, and which safeguard pattern that implies. - `copywriting` writes: the exact strings, the canonical verb per operation, and error, success, empty, loading, and permission copy. Its `references/ui-states.md` defines the shared copy rule IDs, restated in this skill's `rules.md` so citations resolve. When the decision is settled and the user needs one label, name it inline. When the work expands into multiple strings, tone, or persuasion, route to `copywriting`. ## Object, scope, consequence Before naming an action, identify three things (`rule/name-object-scope-consequence`): - Object: the exact product noun. Not "this", but "the project", "3 members", "your API key". - Scope: how many, and whose. Deleting one item, all items, or a shared team resource are different actions and read differently. - Consequence: reversible or permanent, and who else is affected. Archive (reversible) and delete (permanent) must not look the same. Label, surrounding copy, and friction together make all three legible before the user commits. A bulk action states its count in the label ("Delete 3 files"), because the count is the scope. ## Reversibility decides the pattern Settle reversibility first; the interaction pattern follows from it (`rule/destructive-proportional`, `rule/irreversible-action-safeguard`). | The system can | Pattern | Not | |----------------|---------|-----| | Fully reverse it, and the object stays recoverable afterwards | Act immediately, offer undo, keep the object in Trash or Archive | A confirmation dialog | | Reverse it only during a short window (undo send) | Act with a visible countdown and undo; the window is the mechanism | A dialog plus a toast | | Not reverse it, single object, routine | One confirmation naming object and consequence, Verb plus Noun button | "Are you sure?" with OK | | Not reverse it, wide scope or shared (a workspace, a repo, a team's data) | Review step or typed confirmation naming the object | A one-click red button | | Not reverse it, and it commits money or legal terms | A check-answers page with change links, then a confirmation page with a reference and what happens next | Submit from the last form step | An undo control appears only when the first two rows are true (`rule/undo-only-when-honest`). "Undo" that half-restores is worse than no undo. ## Naming actions - Destructive and primary CTAs use Verb plus Noun naming the object: `Delete project`, `Remove member`, `Discard changes` (`rule/destructive-names-action`). - No `Confirm`, `OK`, `Yes`, `Submit`, or bare verb on a consequential action (`rule/no-confirm-ok-labels`). `Cancel` always means "do nothing and close". - One canonical verb per operation across the product (`rule/canonical-verb`). The verb carries the consequence: `Delete` permanent, `Remove` detach, `Archive` recoverable, `Cancel` abandon in-progress, `Discard` drop unsaved edits. The full verb table with reversibility per verb is in the copywriting skill's `references/ui-states.md`. ## State copy at a glance Product-level expectations; strings are `copywriting`'s: - Error: what happened, why when known, the recovery action; no raw exceptions (`rule/error-states-recovery`). - Success: past tense, names the object, weight proportional to the action (`rule/success-state-specific`). A consequential submission's success also carries a reference and what happens next. - Empty: name the object, offer the first action (`rule/empty-state-action`). - Loading: specific over "Loading..." when the target is known (`rule/loading-state-specific`). - Permission: user benefit before the ask, in context of first use (`rule/permission-benefit-first`). - All of the above work when heard, not just seen (`rule/reads-without-seeing`). ## When to route to copywriting Hand off when the work is about words, not the action decision: rewriting multiple strings for tone or voice; persuasion, hero copy, or marketing CTAs; removing AI-isms or running the copy sweeps; choosing between two acceptable phrasings on style grounds. -
product-judgment.md 7.8 KB
# Product Judgment Load in `shape`, `spec`, and `harden` modes, and for any material product or flow decision. Decide what should exist before how it looks: visual execution belongs to `ui-design`, the decision belongs here. A material decision changes the user's task, default, scope, consequence, navigation, interaction surface, or reachable states. Copy mechanics, token swaps, and established component substitutions usually are not. ## Contents - [Write the brief first](#write-the-brief-first) - [Separate facts from decisions](#separate-facts-from-decisions) - [Control selection](#control-selection) - [Gestures](#gestures) - [Surface persistence](#surface-persistence) - [Smallest coherent intervention](#smallest-coherent-intervention) - [Hierarchy and structure](#hierarchy-and-structure) - [Semantics](#semantics) - [Evidence over taste](#evidence-over-taste) - [The decision checklist](#the-decision-checklist) ## Write the brief first Before proposing UI, write a compact internal brief. Length follows the decision: a one-control question fills three fields, a new flow fills all ten. - User: who is acting, and what they know coming in. - Job: what they want to accomplish, in their words. - Current behavior: what happens today, and where it fails. - Desired outcome: the behavior that solves the job. - Success signal: how you would know it worked. - Non-goals: what this explicitly does not do. - Object: the product noun being acted on. - Action, scope, consequence: what changes, how much, and whether reversible. - Permissions: who can do this, and the unprivileged path. - Open decisions: product questions still unresolved. If job, desired outcome, and consequence cannot be filled in, stop and ask: the interface is unbuildable until they are clear, and guessing produces confident, wrong work. ## Separate facts from decisions Mark assumptions and unresolved choices explicitly, so a reviewer sees at a glance what is known versus decided. Shipped code is evidence of what exists, not proof it is correct: check it against current components, real product behavior, and explicit guidance before treating it as precedent. One shipped file is not a standard. ## Control selection Pick the control from the choice's shape, not from habit. | The choice is | Use | Avoid | |---------------|-----|-------| | 2 to 3 static, mutually exclusive options | Radio or segmented control (all visible) | A select that hides options (`rule/control-matches-cardinality`) | | 4 to 7 static, mutually exclusive options | Stacked radios | A select; GOV.UK treats select as a last resort | | Many options, or dynamic | Combobox with typeahead, or a select | A long radio list | | Data the user knows by heart (birth date, postcode, country) | A text field with forgiving formatting and validation | A dropdown; typing "NY" beats scrolling to it (NN/g) | | A binary that takes effect immediately | Switch | A checkbox that needs a save | | A binary saved with a form | Checkbox | A switch; NN/g: separate controls with instant effect from those that wait for Submit | | One action | Button | A menu with one item | | Navigation to a location | Link (`rule/navigation-vs-action`) | A button that pushes history | When two controls both fit, choose the one keeping options visible and reversible. Radios and checkboxes ship unselected unless a default is genuinely right for most users; a preselected radio cannot be cleared, so include "None of these" where it is a real answer (GOV.UK radios). ## Gestures A gesture that replaces a control (swipe-to-delete, drag-to-reorder, hold-to-confirm) is a capability decision, settled here before `ui-animation` builds its physics. - Every gesture-reachable action also has a visible or menu-reachable control that does the same thing (`rule/gesture-has-control-alternative`). Swipe needs a button or overflow item; drag-to-reorder needs move up/down or a "Move to" menu; a slider drag needs click-to-position or arrow keys. - Hold-to-confirm fires on release after the hold completes, never on the press, and lifting early aborts it. It replaces a confirmation dialog only for reversible or routine actions; it is not a safeguard for the irreversible (`rule/irreversible-action-safeguard`). - A swipe that reveals a destructive action and a swipe that performs it are different designs. Reveal is the default; perform-on-swipe needs undo that meets `rule/undo-only-when-honest`. ## Surface persistence Match surface weight to decision importance. - Inline disclosure first: expand in place, reveal a section, anchor a popover to its trigger; context stays (`rule/inline-before-modal`). - Modal for a focused, interrupting decision that needs full attention: a critical error, information the process cannot continue without, stopping an irreversible action. NN/g's checks: not for content unrelated to the current flow, not inside a high-stakes process such as checkout, not for a decision that needs information the modal cannot show. No stacked modals (`rule/no-nested-modals`). - Toast or snackbar for acknowledgement and undo only; it carries no decision and needs no dismissal. - New page or route when the task is large, shareable, or its own destination. - Expose advanced controls without forcing the default path to carry their complexity: the common case stays simple, power is available, not mandatory. ## Smallest coherent intervention Before adding UI, work through cheaper options in order (`rule/smallest-intervention`): 1. A better default. Can the right thing happen without the user choosing? 2. A behavior change. Can the system do this automatically and reliably? 3. Reuse. Does an existing pattern already solve this job? 4. New UI. Only when the above do not. Strong defaults and direct behavior beat configuration the user must learn and maintain. Adding a toggle defers the decision to the user; it does not make one. NN/g's slip-prevention list (helpful constraints, suggestions, good defaults, forgiving formatting) is the same ladder applied to input: prevent the error before designing the error state. ## Hierarchy and structure - One primary action per surface (`rule/one-primary-action`). The primary task and action are unmistakable; everything else recedes. - Group with hierarchy, spacing, and alignment before reaching for containers (`rule/structure-before-containers`). - Preserve the user's context and mental model unless changing it solves a verified problem (`rule/preserve-mental-model`). - Order a flow so its core value moment lands before any secondary interruption: OS permission prompt, sign-up or paywall, gamification, upsell (`rule/value-before-interruption`). Each ask waits for first use in context; Apple's HIG asks the same of permission prompts. ## Semantics Navigation components for navigation, action components for actions (`rule/navigation-vs-action`). The semantic, not the styling, determines keyboard behavior, focus role, and assistive-technology output. A `div` with an onClick is not a button. ## Evidence over taste Trace each non-mechanical decision to something in SKILL.md's Decision authority order. Two evidence sources sit below project-canonical guidance and above general heuristics: an accepted product or design decision with stable evidence, then a verified adjacent shipped pattern in the same product area. If a decision rests only on heuristics or preference, say so and flag it open. Do not present taste as evidence. ## The decision checklist For each non-mechanical change, answer: - What user problem does this solve? - Why is this component or interaction appropriate? - What consequence must the interface communicate? - Which evidence supports the decision? - What is the smallest coherent change that achieves it? If any answer is missing, the decision is not ready to build. Resolve information architecture, component semantics, interaction, and state behavior before styling or rewriting copy. -
rules.md 21.3 KB
# Product Design Rules Stable rule IDs cited across every mode. Each finding or decision in `product-design` names a rule ID so it is traceable, dedupable against a `ui-design` audit, and verifiable. Lint rules, reviews, and exemplars reference the same slug. Cite an ID exactly as written (`rule/destructive-names-action`). If no rule below covers a decision, record a coverage gap rather than citing a slug that does not exist. ## Contents - [How to read a rule](#how-to-read-a-rule) - [Categories](#categories) - [Recording a coverage gap](#recording-a-coverage-gap) - [Copy rule IDs (defined in copywriting)](#copy-rule-ids-defined-in-copywriting) - [Interaction and control selection](#interaction-and-control-selection) - [Action naming and consequence](#action-naming-and-consequence) - [State coverage](#state-coverage) - [Accessibility as a product concern](#accessibility-as-a-product-concern) - [Hierarchy and structure](#hierarchy-and-structure) - [External sources](#external-sources) ## How to read a rule | Field | Meaning | |-------|---------| | Scope | Surface or decision the rule governs | | Rule | The decision as an observable constraint, not an adjective | | Why | The user consequence when violated | | Source | Where it is detailed or grounded: a reference section, a sibling skill, or a key in External sources | | Enforcement | `lint` (deterministic, see `lint-patterns.md`), `judgment` (this skill), or `copy` (defined in `copywriting`) | A rule is observable when you can point at the interface and say it passes or fails without invoking taste. "Destructive actions use Verb plus Noun" is observable; "Buttons should be clear" is not and does not belong here. ## Categories - Interaction and control selection - Action naming and consequence - State coverage - Accessibility as a product concern - Hierarchy and structure Visual-token integrity (design-system overrides, raw shadows, off-grid spacing, modal scroll structure) is a rendered or lint concern owned by `ui-design` and the project's visual lint. This skill decides whether a modal should exist; whether its body scrolls correctly is `ui-design` Audit mode's check. ## Recording a coverage gap When a decision needs a rule no ID below covers, record a coverage gap inline in the pass output, where the citation would have gone: - Proposed slug: `rule/<kebab-case>`, labeled proposed so it never reads as a real citation. - Decision it would govern: one line, observable in the sense above. - Category: one of the five above, or `new category` plus a name. Example: `coverage gap (proposed) rule/autosave-signals-state`: an autosaving editor shows whether the current content is saved, saving, or failed to save. Category: State coverage. A gap stays in the pass output. Promoting one into this file is a separate, deliberate edit. ## Copy rule IDs (defined in copywriting) These IDs are authored and worded in the copywriting skill's `references/ui-states.md`; this skill cites them for the product decision and routes the wording there. Restated so a citation resolves without opening another skill's file. Entries below for these IDs carry `Scope`, `Why`, `Source`, and `Enforcement` but no `Rule` line: the constraint's wording has one owner. | ID | The decision it governs | |----|-------------------------| | `rule/destructive-names-action` | Destructive and primary CTAs use Verb plus Noun naming the object, never `Confirm`/`OK`/`Yes`. | | `rule/no-confirm-ok-labels` | No bare `Confirm`, `OK`, `Yes`, or `Submit` on a consequential action. `Save`, `Cancel`, and `Close` are exempt: they name their own outcome. | | `rule/canonical-verb` | One canonical verb per operation, consistent across the product. | | `rule/error-states-recovery` | An error states what happened, why when known, and the recovery action; never raw exception text. | | `rule/success-state-specific` | A success message confirms in past tense what happened to which object, proportional to the action. | | `rule/empty-state-action` | An empty state names the object and offers the first action; no dead ends. | | `rule/loading-state-specific` | Prefer specific loading copy over a bare "Loading..." when the target is known. | | `rule/permission-benefit-first` | A permission request states the user benefit before the ask, in context of first use. | | `rule/reads-without-seeing` | Copy works when heard: errors read sensibly after the field label, links name the destination, no directional words. | ## Interaction and control selection ### rule/control-matches-cardinality - Scope: choosing a control for a small set of mutually exclusive options. - Rule: 2 to 3 static, mutually exclusive options use radio buttons or a segmented control with every option visible, not a select. A select is the last resort for a long list, never the default for a short one. - Why: a select hides choices behind a click, so the user cannot compare options at a glance. GOV.UK's research found users unable to close selects, confusing focused with selected, and losing their place in long lists. - Source: `lint-patterns.md`; `product-judgment.md` > Control selection; GOV.UK select and radios; NN/g dropdowns. - Enforcement: lint plus judgment. ### rule/navigation-vs-action - Scope: any clickable element. - Rule: a link for navigation (changes location, shareable, back-button safe) and a button for an action (mutates state, submits, opens an overlay). Do not style one as the other. - Why: the wrong semantic breaks the back button, open-in-new-tab, keyboard activation, and the screen-reader role. - Source: `product-judgment.md` > Semantics; `ui-design` Audit mode (`nav-semantic-links`) for the rendered check. - Enforcement: judgment. ### rule/no-nested-modals - Scope: overlays. - Rule: a modal does not open a second modal. Resolve the first, use one multi-step surface, or move the second step inline. - Why: stacked modals break focus trapping, escape-key order, and layering, and hide the original context. Material's guidance: confirmation dialogs "should avoid launching additional simple dialogs". - Source: `lint-patterns.md`; `surfaces.md` > Overlays; Material dialogs. - Enforcement: lint plus judgment. ### rule/inline-before-modal - Scope: revealing secondary content or controls. - Rule: prefer inline disclosure (expand in place, a section, a popover anchored to its trigger) over a modal. Reserve a modal for a focused, interrupting decision: a critical error, information the process cannot continue without, or stopping an irreversible action. - Why: a modal severs the user from context and forces a full-attention detour for work that often does not need it. NN/g: "if you must interrupt, make sure it's worth the cost." - Source: `product-judgment.md` > Surface persistence; NN/g modal dialogs. - Enforcement: judgment. ### rule/gesture-has-control-alternative - Scope: swipe, drag, multi-finger, and press-and-hold interactions that trigger or complete an action. - Rule: every action reachable by a gesture is also reachable by a single-pointer, non-path, non-timed control (a button, a menu item, a keyboard command) that does the same thing. Hold-to-confirm completes on release, with a way to abort before it fires. - Why: a gesture-only action is invisible to users who cannot perform it (motor impairments, switch access, screen readers) and to everyone who never discovers it. WCAG 2.5.1 (A) requires a single-pointer alternative to path-based gestures such as swipes; 2.5.7 (AA) requires a non-dragging alternative to drag; 2.5.2 (A) requires an abort path for anything that fires on a press. - Source: `product-judgment.md` > Gestures; WCAG 2.5.1, 2.5.2, 2.5.7; `ui-animation` builds the gesture once the alternative is settled. - Enforcement: judgment. ### rule/smallest-intervention - Scope: any proposed change that adds UI. - Rule: before adding a control, setting, or surface, evaluate a better default, a behavior change, or reuse of an existing pattern. Add UI only when none solve the job. - Why: every added control is a permanent cost to learn and maintain. Configuration is not a substitute for a correct default. - Source: `product-judgment.md` > Smallest coherent intervention; NN/g slips (constraints, defaults, forgiving formatting). - Enforcement: judgment. ## Action naming and consequence ### rule/destructive-names-action - Scope: confirmation and primary buttons for destructive or irreversible actions. - Why: a generic label hides what is about to happen, so the user confirms without reading. Apple HIG: avoid "OK" unless the alert is purely informational; a title like "Delete" or "Erase" says what the button does. - Source: defined in the copywriting skill's `references/ui-states.md`; cited by `naming-and-copy.md`; Apple HIG alerts. - Enforcement: copy plus judgment. ### rule/name-object-scope-consequence - Scope: any action that mutates, deletes, shares, bills, or changes permissions. - Rule: the interface states the object (what), the scope (how many, whose), and the consequence (reversible or not, who is affected) before the user commits. - Why: without scope and consequence the user cannot judge the action's blast radius. NN/g: a confirmation that does not say what will happen ("Are you sure?") provides no protection. - Source: `naming-and-copy.md` > Object, scope, consequence; NN/g confirmation dialogs. - Enforcement: judgment. ### rule/irreversible-action-safeguard - Scope: actions that delete or overwrite user data, commit money or legal terms, or send something to other people. - Rule: an action the system cannot reverse has at least one of: a review step showing what will be submitted with a way to change it, input checking with a chance to correct before commit, or a confirmation that names object, scope, and consequence. Routine saves are exempt. - Why: this is the floor beneath which data loss is designed in. WCAG 3.3.4 (AA) requires reversible, checked, or confirmed for exactly this class of submission; GOV.UK's check-answers page is the review-step form of it. - Source: `naming-and-copy.md` > Reversibility decides the pattern; WCAG 3.3.4; GOV.UK check answers. - Enforcement: judgment. ### rule/destructive-proportional - Scope: destructive actions. - Rule: friction is proportional to impact and irreversibility. A reversible action gets no confirmation dialog: act, then offer undo. A permanent single-object delete gets one named confirmation. Typed confirmation is reserved for high-impact, irreversible, wide-scope actions (a workspace, a repository, a billing account). - Why: under-protecting a permanent delete causes data loss; over-protecting a reversible one habituates users to click through, so the confirmation that matters gets the same reflexive click. NN/g: "if you cry wolf too many times, people will stop paying attention." - Source: `surfaces.md` > Destructive state; NN/g confirmation dialogs; NN/g heuristic 3 (user control and freedom). - Enforcement: judgment. ### rule/undo-only-when-honest - Scope: any undo affordance, including undo toasts and snackbars. - Rule: an undo control appears only when activating it restores the object and its relationships completely. A timed undo toast is honest only when the object stays recoverable after the toast disappears (Trash, Archive, version history) or the delay itself is the mechanism (undo send). Otherwise treat the action as irreversible and apply `rule/irreversible-action-safeguard`. - Why: an undo that half-restores, or that vanishes after five seconds with no other recovery path, teaches users the product lies about safety; the next "Undo" gets trusted and fails. WCAG 2.2.1 exempts a disappearing message only when an alternative exists that does not rely on the timer. - Source: `surfaces.md` > Destructive state; Material snackbar; WCAG 2.2.1. - Enforcement: judgment. ### rule/preserve-user-input - Scope: forms, editors, and any input across validation, error, or navigation. - Rule: user input survives validation failures and recoverable errors. A failed submit does not clear fields, passing or failing. - Why: discarding entered data on error forces re-entry and loses the user's work and trust. GOV.UK: "Do not clear any form fields when showing the Error message component." - Source: `surfaces.md` > Validation and error; `ui-design` Audit mode (`forms-lost-data-on-error`) for the React-level check; GOV.UK error message. - Enforcement: judgment. ## State coverage ### rule/cover-reachable-states - Scope: any surface that loads, mutates, or depends on data, time, or permissions. - Rule: design every state the surface can actually enter: loading, empty, sparse, populated, partial or stale, validation, error, permission-denied, disabled, optimistic, destructive-in-progress, expired or timed out, offline. A happy-path-only design is incomplete. - Why: unhandled states ship as blank screens, spinners that never resolve, or actions that silently fail. - Source: `surfaces.md` (the full enumeration); Hurff UI stack. - Enforcement: judgment. ### rule/empty-state-action - Scope: empty and zero-data states. - Why: a bare "No items" leaves the user with nothing to do and no way to begin. - Source: defined in the copywriting skill's `references/ui-states.md`; `surfaces.md` > Empty state. - Enforcement: copy plus judgment. ### rule/error-states-recovery - Scope: error states and failure messages. - Why: an error without a recovery path strands the user. NN/g heuristic 9: plain language, precise problem, constructive suggestion. - Source: defined in the copywriting skill's `references/ui-states.md`; `surfaces.md` > Validation and error; GOV.UK error message. - Enforcement: copy plus judgment. ### rule/loading-stable-labels - Scope: controls in a loading or busy state. - Rule: keep the control's label stable while busy and use the component's loading or busy affordance. Do not swap the label for "Loading..." or change its width. - Why: a shifting label causes layout jump and hides which action is in flight. - Source: `surfaces.md` > Loading state; `loading-state-specific` in `copywriting`. - Enforcement: judgment. ### rule/loading-state-specific - Scope: loading copy. - Why: specific feedback tells the user the system is working, not stuck. - Source: defined in the copywriting skill's `references/ui-states.md`. - Enforcement: copy. ### rule/time-limit-adjustable - Scope: any state that expires on a timer: session timeouts, one-time codes, reservation holds, undo windows, auto-dismissing messages. - Rule: before a timer discards work or closes a path, the user is warned and can extend it, or the work survives the expiry (a draft, a re-sendable code, a recoverable object). Time limits that are essential to the activity (a live auction) are the exception. - Why: a silent expiry is data loss the user cannot see coming. WCAG 2.2.1 (A) requires turn off, adjust, or extend for content-set time limits unless real-time, essential, or over 20 hours. - Source: `surfaces.md` > Expired and offline; WCAG 2.2.1. - Enforcement: judgment. ## Accessibility as a product concern ### rule/accessible-name-required - Scope: icon-only buttons, icon links, and form controls. - Rule: every interactive control has an accessible name (visible label, `aria-label`, or associated `<label>`). Icon-only controls are never nameless. - Why: a nameless control is unusable by screen readers and ambiguous for everyone under load. - Source: `lint-patterns.md`; `interface-quality.md` > Accessibility as task completion; `ui-design` (`a11y-icon-controls-labeled`). - Enforcement: lint plus judgment. ### rule/keyboard-complete-flow - Scope: any multi-step or interactive flow. - Rule: the primary task is completable by keyboard alone, with visible focus and a sensible focus order. Focus moves to new surfaces and returns on close, and the focused control is never fully hidden behind sticky chrome. - Why: keyboard and screen-reader users must finish the job, not just reach the first control. WCAG 2.4.11 (AA) fails when a sticky header, footer, or banner entirely covers the focused element. - Source: `interface-quality.md` > Accessibility as task completion; WCAG 2.4.11; rendered checks to `ui-design` Audit mode (`interaction-keyboard-operable`, `focus-*`). - Enforcement: judgment. ### rule/no-custom-focus-bypass - Scope: focus styling. - Rule: do not remove or replace the shared focus ring with a custom outline that bypasses the design system's focus token. Keep focus visible and consistent. - Why: invisible or inconsistent focus makes keyboard navigation impossible to follow. - Source: `lint-patterns.md`; `interface-quality.md`; `ui-design` (`interaction-focus-visible`). - Enforcement: lint plus judgment. ### rule/no-redundant-entry - Scope: multi-step flows, checkouts, sign-up, and any process that asks for information more than once. - Rule: information the user already entered or was shown earlier in the same process is prefilled or offered for selection ("Billing address same as shipping"), not retyped. Exceptions: re-entry for security (a password), re-entry essential to the task, or information that is no longer valid. - Why: retyping is the point where users on mobile, with motor or cognitive impairments, or simply in a hurry abandon. WCAG 3.3.7 (A). - Source: `surfaces.md` > Validation and error; WCAG 3.3.7. - Enforcement: judgment. ### rule/auth-allows-assistance - Scope: sign-in, sign-up, step-up verification, and any authentication step. - Rule: no authentication step depends on the user remembering, transcribing, or solving something unless an alternative method exists or assistance is allowed. Password fields accept paste and password managers; a code sent by SMS or email can be pasted; a puzzle CAPTCHA has a non-puzzle alternative. - Why: blocking paste or a password manager turns a security step into a memory test that locks out users with cognitive impairments and frustrates everyone else. WCAG 3.3.8 (AA). - Source: `interface-quality.md` > Accessibility as task completion; WCAG 3.3.8; `ui-design` (`forms-dont-block-paste-ime`) for the built check. - Enforcement: judgment. ## Hierarchy and structure ### rule/one-primary-action - Scope: any surface or section. - Rule: the primary task and its primary action are unmistakable. At most one primary (emphasized) action per surface; everything else is secondary or tertiary. - Why: competing primary actions split attention and slow every decision. - Source: `product-judgment.md` > Hierarchy and structure. - Enforcement: judgment. ### rule/structure-before-containers - Scope: layout. - Rule: use hierarchy, spacing, and alignment to group content before adding borders, cards, or boxes. - Why: container-first layouts produce nested boxes that add weight without meaning. - Source: `product-judgment.md` > Hierarchy and structure; visual execution to `ui-design`. - Enforcement: judgment. ### rule/preserve-mental-model - Scope: navigation and context changes. - Rule: preserve the user's current context and mental model unless changing it solves a verified problem. Do not relocate the user or reset their state as a side effect. - Why: unexpected context shifts disorient the user and lose their place. - Source: `product-judgment.md` > Hierarchy and structure. - Enforcement: judgment. ### rule/value-before-interruption - Scope: onboarding and first-run flows. - Rule: the flow reaches its core value moment before any secondary interruption (OS permission prompt, sign-up or paywall, gamification, upsell). Each interruption waits for first use in context; none is front-loaded at launch. - Why: an ask that arrives before the user grasps the product's value gets declined or abandoned, pushing the aha moment past the drop-off point. Apple's HIG asks for permission requests in context, when the feature is used, with the benefit stated. - Source: `product-judgment.md` > Hierarchy and structure; permission wording to `rule/permission-benefit-first`; Apple HIG privacy. - Enforcement: judgment. ## External sources Keys used in `Source` fields above. Consult when a decision needs the primary text. | Key | Reference | |-----|-----------| | NN/g heuristics | Nielsen, 10 Usability Heuristics: nngroup.com/articles/ten-usability-heuristics/ | | NN/g confirmation dialogs | nngroup.com/articles/confirmation-dialog/ | | NN/g modal dialogs | nngroup.com/articles/modal-nonmodal-dialog/ | | NN/g toggle switches | nngroup.com/articles/toggle-switch-guidelines/ | | NN/g dropdowns | nngroup.com/articles/drop-down-menus/ | | NN/g slips | nngroup.com/articles/slips/ | | Apple HIG alerts | developer.apple.com/design/human-interface-guidelines/alerts | | Apple HIG privacy | developer.apple.com/design/human-interface-guidelines/privacy | | Material dialogs | m1.material.io/components/dialogs.html (M3 dialog and snackbar pages carry the same rules, rendered client-side) | | Material snackbar | m3.material.io/components/snackbar/guidelines | | GOV.UK select | design-system.service.gov.uk/components/select/ | | GOV.UK radios | design-system.service.gov.uk/components/radios/ | | GOV.UK error message | design-system.service.gov.uk/components/error-message/ | | GOV.UK check answers | design-system.service.gov.uk/patterns/check-answers/ | | GOV.UK confirmation pages | design-system.service.gov.uk/patterns/confirmation-pages/ | | WCAG 2.x.y | w3.org/WAI/WCAG22/Understanding/ (one page per criterion: 2.2.1 Timing Adjustable, 2.4.11 Focus Not Obscured, 2.5.1 Pointer Gestures, 2.5.2 Pointer Cancellation, 2.5.7 Dragging Movements, 2.5.8 Target Size, 3.3.4 Error Prevention, 3.3.7 Redundant Entry, 3.3.8 Accessible Authentication) | | W3C text size | w3.org/International/articles/article-text-size | | Hurff UI stack | scotthurff.com/posts/why-your-user-interface-is-awkward-youre-ignoring-the-ui-stack/ | -
surfaces.md 7.8 KB
# Surfaces and Reachable States Load in `shape`, `spec`, and `harden` modes. A happy-path mockup is incomplete, not done: design every state the surface can actually enter, and only those. `rule/cover-reachable-states` governs coverage. Map only reachable states: invent no permission-denied state for a surface everyone reaches, and do not stop at the populated success case. The checklist below extends Scott Hurff's five-state UI stack (ideal, empty, error, partial, loading) with the states that data-mutating, permissioned, and time-bound surfaces add. ## Contents - [Map the surface before the states](#map-the-surface-before-the-states) - [The reachable-state checklist](#the-reachable-state-checklist) - [Loading](#loading) - [Empty, sparse, populated](#empty-sparse-populated) - [Partial and stale](#partial-and-stale) - [Validation and error](#validation-and-error) - [Permission and disabled](#permission-and-disabled) - [Optimistic updates](#optimistic-updates) - [Destructive state](#destructive-state) - [Expired and offline](#expired-and-offline) - [Overlays](#overlays) - [Resilience: extreme data, localization, viewport](#resilience-extreme-data-localization-viewport) ## Map the surface before the states Inventory the surface first: - Entry points: how and from where the user arrives, including deep links and back navigation. - Visible regions: header, body, actions, secondary panels. - Overlays: modals, popovers, sheets, toasts. - Transitions: what changes on action, what animates (`ui-animation` owns the motion). - Exits and return paths: where the user lands on success, cancel, or error, and how back behaves. Then walk the state list and mark each reachable or not for this surface. ## The reachable-state checklist ```text State coverage: - [ ] Loading (initial, and per-action busy) - [ ] Empty (never had any / filtered to zero / user cleared) - [ ] Sparse (one or a few items; layout still holds) - [ ] Populated (the success case) - [ ] Partial / stale (some data, some pending or outdated) - [ ] Validation (inline, before submit) - [ ] Error (the action or load failed) - [ ] Permission-denied (the user cannot do this) - [ ] Disabled (the action is unavailable right now, and why) - [ ] Optimistic (shown applied before the server confirms) - [ ] Destructive-in-progress (confirm, pending, undo window) - [ ] Expired / timed out (session, code, hold, undo window) - [ ] Offline / degraded (no network, slow network, partial outage) - [ ] Responsive (compact and wide; long content; large values) ``` ## Loading - Keep the trigger's label stable while busy (`rule/loading-stable-labels`). - Distinguish initial load from per-action busy; a page skeleton and a button spinner are different states. - For known targets, prefer specific loading copy over a bare "Loading..." (`rule/loading-state-specific`). - A load that can hang resolves into the error state; nothing spins forever. ## Empty, sparse, populated - Name the object and offer the first action (`rule/empty-state-action`): "No projects yet" plus "Create project", not "No data". - Three empties, three designs: never-had-any (onboarding, guide the first step), filtered-to-zero (offer to clear the filter; a "Create" CTA here produces duplicates), user-cleared (confirm completion, say when new content appears; the one empty state that needs no CTA). - Layout holds with one item, not twenty: a grid of one should not look broken. - The populated case is the baseline, not the finish line. ## Partial and stale - When data is pending or outdated, show what is known and mark what is not; do not block the surface on the slowest part. - Mark stale data stale and offer a refresh rather than silently presenting old values as current. ## Validation and error - Validate inline before submit, so the user fixes problems in context; on submit, summarize every error once and link each to its field (the GOV.UK error-summary shape). - On failure, preserve every field the user entered, passing and failing (`rule/preserve-user-input`). - Error copy states what happened, why when known, and the recovery action; never raw exception text and never "invalid" (`rule/error-states-recovery`). - Separate field-level errors (fix this input) from surface-level errors (the whole action failed). - In a multi-step flow, anything already entered is prefilled or selectable later, never retyped (`rule/no-redundant-entry`). ## Permission and disabled - A permission-denied path is a designed state, not a crash: explain what the user lacks and how to request it. - A disabled control says why (tooltip, helper text, or adjacent message). A silently disabled button is a dead end. - Hide actions the user can never take; show ones they could take with different permissions, clearly gated. ## Optimistic updates - When showing a change before the server confirms, the failure state exists and preserves the user's input. - Optimistic UI without a rollback path is a happy-path shortcut, not a complete state (`ui-design` checks the built rollback under `async-optimistic-without-rollback`). ## Destructive state - Name the object, scope, and consequence before the user commits (`rule/name-object-scope-consequence`, `rule/destructive-names-action`). - Decide reversibility first, then the pattern (`rule/destructive-proportional`): reversible means act then offer undo, with no confirmation dialog; irreversible means one of review, check, or named confirmation (`rule/irreversible-action-safeguard`). - An undo toast is a courtesy, not the recovery path. Pair it with a place the object stays recoverable (Trash, Archive, history) or treat the action as irreversible (`rule/undo-only-when-honest`). - Design the in-progress and post-action states: pending, success with undo window, and failure. - A success screen for a consequential submission says what happened, gives a reference the user can keep, and says what happens next and when (GOV.UK confirmation pages). ## Expired and offline - A timer that can discard work warns before it fires and offers an extension, or the work survives it: a saved draft, a re-sendable code, a recoverable object (`rule/time-limit-adjustable`). A live auction or a security-mandated timeout is the exception, and says so. - Offline is a state, not an error: show what is cached, queue or block writes explicitly, and say which. A write that silently fails offline is data loss. - A degraded dependency (search down, payments slow) degrades one region, not the whole surface. ## Overlays - A modal does not open a second modal (`rule/no-nested-modals`). Resolve, sequence, or inline the second step. - Long content never pushes the confirm and cancel actions out of reach. Keeping the actions reachable is this skill's decision; whether the modal body scrolls correctly is `ui-design` Audit mode's rendered check. - Focus moves into the overlay on open, returns to the trigger on close, and Escape closes it. - A toast carries acknowledgement and undo, never a decision: anything that needs the user to choose is a dialog or inline. ## Resilience: extreme data, localization, viewport These states are decided here; whether the built UI renders them correctly is `ui-design` Audit mode's check (`layout-long-content-safety`, `dark-i18n-rtl-untested`). - Long strings, large numbers, zero, negative, and missing values, for every text region and every stat. - Localization headroom scales inversely with string length: per the W3C's cited IBM figures, English strings under 10 characters grow 200 to 300% in translation, 11 to 20 characters grow 180 to 200%, and only strings over 70 characters settle near 130%. A segmented control with three fixed-width English labels is the first thing to break; design it to wrap or stack. - RTL mirroring of direction-bearing layout (progress, back and forward, sliders) and vertical headroom for Thai, Arabic, and CJK scripts. - Compact and wide viewports for every materially changed state, not just populated.
-
-
SKILL.md 11.6 KB
--- name: product-design description: Specifies interaction choices, action scope, reversibility, recovery, and reachable states. Use when asked to "design the flow", "should delete be undoable", "choose the control", or "review this product decision". For visual implementation use ui-design; for motion use ui-animation; for wording use copywriting. --- # Product Design Decide what the interface should do, then route who builds and verifies it: pick the right interaction, make scope and consequence clear, cover reality beyond the happy path. - **IS:** the decision layer. From a brief, spec, mockup, intent, or existing UI: choose the interaction and control, name the object, scope, and consequence of each action, settle reversibility and the safeguard it implies, enumerate every reachable state, set resilience expectations, and require accessibility as task completion. It decides, then routes build, verification, and wording out. - **IS NOT:** - whether a feature deserves investment or fits the product: the external `product-judgment` skill from Brandwriter. - building or styling UI, visual direction, palettes, type: `ui-design`. - auditing the built result (rendered quality, a11y markup, keyboard, layout, performance, React or Next code-level UX with a ship verdict): `ui-design` Audit mode. - copy wording, persuasion, or AI-ism removal: `copywriting`. - motion, gesture physics, or deep typography: `ui-animation`, `typography-audit`. - whether an agentic feature earns trust: `ax-audit`. ## Routing boundary `product-design` owns action semantics, scope, reversibility, and contested state choices. `ui-design` builds and styles those states. `ui-animation` owns timing, gestures, and measured motion. A routine missing loading or error state stays with the UI build; a gesture replacing a control needs a product decision and an accessible alternative before its physics. ## Request modes Resolve one mode from the user's verb and artifact before acting, then load that mode's references. `references/rules.md` loads in **every** mode: every finding cites a rule ID from it, and you cannot conclude that no rule governs a decision without the registry in front of you. | Mode | Dispatch when the user asks for | Load (plus `references/rules.md`) | |------|--------------------------------|------| | **shape** (default) | "design the flow for", "what control here", "how should this work", "is this the right pattern", a brief with no settled UI | `references/product-judgment.md`, `references/surfaces.md` | | **spec** | "spec the right interaction", "define the expected states", judgment applied before or during a build | `references/product-judgment.md`, `references/surfaces.md`, `references/naming-and-copy.md`; route the build to `ui-design` | | **review** | "review this flow for product correctness", "what's wrong with this UX decision", "is this the right interaction" | `references/interface-quality.md` | | **action** | "what should this action affect", "should this be undoable", "do we need a confirm dialog", or reversibility is unsettled | `references/naming-and-copy.md`; route final wording to `copywriting` | | **harden** | "make this resilient", "what breaks here", error, permission, offline, expiry, and destructive paths | `references/surfaces.md`, `references/interface-quality.md`, `references/product-judgment.md` | **Review mode is about a flow, not an artifact.** "Audit this component", "check my UI", and "design QA this page" point at built markup and belong to `ui-design` Audit mode. This skill's review asks whether the decisions behind a flow are right, and stops at decision altitude. Modes chain: shape leads into spec; review leads into harden. When intent is ambiguous, use the narrowest mode the verb supports. A URL, screenshot, route, or component identifies scope; it does not authorize edits. `references/lint-patterns.md` has no mode: read it when deciding whether a standard belongs in the consuming project's linter or in this skill. `evals/evals.json` never loads during a user task; it is the regression set for anyone changing this skill. ## Workflow ```text Product design pass: - [ ] Step 1: Classify the request into one mode - [ ] Step 2: Locate authority (user constraints, project design system, AGENTS.md) - [ ] Step 3: Load rules.md plus that mode's reference files - [ ] Step 4: Write the internal brief (shape, spec, harden); stop and ask if job, outcome, or consequence is unfillable - [ ] Step 5: Name object, scope, consequence, and reversibility for each action in scope (spec, action, review) - [ ] Step 6: Enumerate reachable states and check coverage (shape, spec, harden) - [ ] Step 7: Emit output with a rule ID or labeled coverage gap per finding or decision; route follow-on work to siblings - [ ] Step 8: Check the decision contract and identify unresolved product decisions ``` Steps 5 and 6 are mode-scoped because their references are: a pure `action` pass has no state matrix to enumerate, and a `shape` pass has no built actions to name yet. Output length follows the work, not the template. A single settled decision is a short answer; drop the sections a pass did not need rather than filling them. ## Decision authority Conflict order, highest first: 1. The user's explicit goal and constraints. 2. Verified user and product evidence, and what the system actually does. 3. Project-canonical guidance: `AGENTS.md` or `CLAUDE.md`, the project's design system, routed sibling skills. 4. Sibling-skill ownership: route, do not duplicate. 5. This skill's standards (below). 6. General interface and platform conventions (WCAG 2.2, NN/g, Apple HIG, Material, GOV.UK), which `references/rules.md` cites per rule. When a request spans authorities, name the owning skill and hand off. ## Product design standards Five pillars, each naming its rule IDs in `references/rules.md` and the reference that details it. - **Right interaction.** Pick the control from the choice's shape; keep options visible and reversible; prefer inline disclosure over a modal; every gesture has a control alternative; choose the smallest coherent intervention. `rule/control-matches-cardinality`, `rule/navigation-vs-action`, `rule/inline-before-modal`, `rule/no-nested-modals`, `rule/gesture-has-control-alternative`, `rule/smallest-intervention`. Detail: `references/product-judgment.md`. - **Action naming and consequence.** Name the object, scope, and consequence; settle reversibility first, then the pattern; an irreversible action gets review, check, or named confirmation; undo appears only when honest. `rule/name-object-scope-consequence`, `rule/destructive-names-action`, `rule/destructive-proportional`, `rule/irreversible-action-safeguard`, `rule/undo-only-when-honest`, `rule/preserve-user-input`. Detail: `references/naming-and-copy.md`. - **State coverage.** Design every reachable state, not just the populated one: empty states name the object and a first action; errors explain and offer recovery; timers warn before they discard. `rule/cover-reachable-states`, `rule/empty-state-action`, `rule/error-states-recovery`, `rule/loading-stable-labels`, `rule/time-limit-adjustable`. Detail: `references/surfaces.md`. - **Resilience.** Overflow, extreme data, localization and RTL, offline, and network failure are designed states; every fetch lands in one. Shares `rule/cover-reachable-states`: it is the same requirement pointed at adverse inputs. Detail: `references/surfaces.md` > Resilience. Whether the built UI renders them is `ui-design` Audit mode's check. - **Accessibility as task completion.** Every control has a name; the primary flow completes by keyboard with visible focus; nothing already entered is retyped; authentication allows assistance; state and consequence are understandable, not just labeled. `rule/accessible-name-required`, `rule/keyboard-complete-flow`, `rule/no-custom-focus-bypass`, `rule/no-redundant-entry`, `rule/auth-allows-assistance`. Detail: `references/interface-quality.md`. Markup and target-size checks route to `ui-design` Audit mode. ## Review output In review and harden modes, lead with findings ordered by user impact (P0 to P3), each with location, verification status, rule ID, user consequence, and the smallest concrete fix with the skill that owns it. Keep findings at decision altitude; a line-level code or framework fix is `ui-design` Audit mode's output. Rubric and finding format: `references/interface-quality.md` > Severity rubric. ## Pass self-check Use these as the decision contract. Report unresolved decisions; omit a separate ceremony when the output already carries them: - Every finding and non-mechanical decision carries a rule ID that appears verbatim in `references/rules.md`, or an inline coverage gap labeled proposed. - The internal brief is present with job, desired outcome, and consequence filled, for shape, spec, and harden. - Every destructive or consequential action in scope has its reversibility stated and a matching pattern. - Follow-on work is routed by name (`ui-design`, `ui-animation`, `copywriting`), never done here. ## Gotchas - A confirmation dialog on a reversible action (archive, remove from list, unsubscribe) trains users to click through, so the one confirmation that matters, permanent delete, gets the same reflexive click. NN/g's "cry wolf" finding. Act and offer undo instead (`rule/destructive-proportional`). - An undo toast as the only recovery path: it vanishes in about five seconds, and the object is gone. Either the object stays recoverable (Trash, Archive) or the action is irreversible and needs a safeguard. Do not call it undo otherwise (`rule/undo-only-when-honest`, WCAG 2.2.1). - Swipe-to-delete or drag-to-reorder with no button or menu equivalent fails WCAG 2.5.1 and 2.5.7 outright and is undiscoverable to everyone else. Spec the alternative before routing the physics to `ui-animation` (`rule/gesture-has-control-alternative`). - A segmented control with three fixed-width English labels: strings under 10 characters grow 200 to 300% in translation (W3C), so "Day / Week / Month" becomes a wrapped or clipped mess in German. Decide the wrap or stack behavior in the spec. - Reusing the "No projects yet, Create project" empty state for a filtered-to-zero list. The user creates a duplicate because the item they searched for exists behind the filter. Three empties, three designs (`references/surfaces.md`). - A checkout or sign-up that asks again for something entered two steps earlier (billing address after shipping, email after account) fails WCAG 3.3.7 and is the step where mobile users leave (`rule/no-redundant-entry`). - Emitting a line-level fix (a prop, a hook, a `className`) instead of the decision. It arrives without the rendered check that would validate it, and the product decision it was supposed to carry goes unstated. Route it to `ui-design` Audit mode. - Citing a plausible-sounding rule ID that does not exist (`rule/clear-labels`). The citation resolves to nothing, so the finding cannot be deduped against a `ui-design` audit or traced to a rule. Record a coverage gap instead. ## Related skills - `ui-design`: visual direction and building the decided interaction in code; its Audit mode covers the built result, rendered quality and accessibility markup, with a ship verdict. - `copywriting`: exact wording for names, errors, and empty and loading copy; defines the shared copy rule IDs in its `references/ui-states.md`. - `ui-animation`: the passage between two states (timing, easing, springs, gesture physics). This skill settles whether a gesture replaces a control and what its alternative is; that skill builds the motion. - `ax-audit`: whether a built agentic feature earns trust; this skill decides what it should do first. - `typography-audit`: deep type.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.