Files
movq 92f005895c feat(composer): expand ui-system from placeholder to full interview
ui-system skill is no longer a placeholder. Full design-system and
interaction-design interviews with branching, defaults, batched
question clusters, and an 'accept default / skip' protocol so users
move through fast when they have taste and patient when they don't.

Design system interview covers: visual posture, color (with WCAG
contrast verification before writing), typography, spacing, radii,
shadows, density, visual motion, components, theming, and
accessibility tokens (focus ring, hit targets).

Interaction design interview covers: input model, state-surface
declarations per action class, motion posture and triggers,
breakpoints, i18n, four state postures (empty/loading/error/offline),
time formatting, keyboard policy, optimistic-update strategy with
rollback and conflict resolution, gestures, focus management,
notification patterns, selection, and drag-and-drop.

Reference banks for "make it look like Linear/Notion/Stripe/etc."
translate well-known products into starting tokens — user still
confirms each value, no silent invention.

Templates expanded to hold the full output:
- design-system/SKILL.md grew sections for accessibility tokens,
  density, dark-mode mapping, contrast verification, theming variants
- design-system/tokens.ts now exports color (light + dark), typography
  (family/size/weight/line-height/letter-spacing), spacing + density-
  aware padding tokens, radii, shadows, motion (durations + easings),
  z-index scale, breakpoints, hit-target minimums
- design-system/components.md gained anatomy/state/a11y coverage for
  10 primitives plus an "adding a new component" workflow and a
  "patterns to avoid" list (nested cards, color-only meaning, etc.)
- interaction-design/SKILL.md gained sections for optimistic updates,
  conflict resolution, gestures, focus management, notification
  patterns, selection/multi-select, and drag-and-drop

Hard rules: never invent on the user's behalf; <TBD> instead. Verify
contrast before writing color tokens. Always declare prefers-reduced-
motion as honored.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 21:10:36 -05:00

9.2 KiB
Raw Permalink Blame History

name, description
name description
<SLUG>-interaction-design Interaction design for the <PROJECT NAME> project. State surfaces (modal vs inline vs drawer vs full-page), motion philosophy, input modes (touch/mouse/keyboard), breakpoints, i18n posture, empty/loading/error/offline state postures, time formatting, keyboard policy, optimistic-update strategy, gesture handling, and focus management. Load and apply whenever building UI behavior — modals, forms, navigation, transitions, gestures, error handling, async states, focus management, or any decision about how the interface responds. Pairs with <SLUG>-design-system.

interaction design

Status: <draft | reviewed | locked> Generated by Composer's ui-system phase. Re-running that phase updates this skill (with confirmation on overwrite).

How to use this skill

When building UI behavior — anything beyond static styling — read this skill first. Don't invent new state-surface patterns, motion durations, or empty-state postures. They're declared once here and reused everywhere. For visual tokens (color, type, spacing), see the paired <SLUG>-design-system skill.

If a screen needs a pattern that isn't declared here, propose it in this skill before writing the code — not the other way around.

Input modes

Mode Status Notes
Touch <primary supported
Mouse <…> <…>
Keyboard supported (always — a11y baseline) full keyboard navigation required
Voice
Switch / assistive <…>

Primary: — design defaults assume this mode.

State surfaces

One pattern per action class. Used everywhere. If a screen needs a deviation, document it inline as an exception with a reason.

Action class Pattern Notes
Quick edit (single field) <inline edit popover
Multi-field create <drawer modal
Multi-field edit <drawer modal
Confirm destructive modal always — non-negotiable
Settings / configuration full-page route
Top-level navigation <sidebar tab bar
Detail-from-list <full route side panel
Filtering / sorting <inline controls popover
Search <header search command palette

Motion

  • Posture: <minimal | restrained | expressive>
  • Default duration / easing: see design-system tokens (motion.duration.default, motion.easing.standard)

Animation triggers

Trigger Animated? Duration / easing
Page / route transitions <yes no
List item enter / exit <…>
Modal / drawer open / close <…>
State changes (toggle, expand) <…>
Loading → loaded transitions <…>
Hover / focus state changes <…> <token — usually fast>

Reduced motion

prefers-reduced-motion: reduce is always honored. Fallback strategy:

  • Replace transitions with instant state changes.
  • Replace fades with instant show/hide.
  • Replace slides with crossfades or instant.
  • Keep hover/focus state changes (these are essential signals, not motion).

Breakpoints

Breakpoint Range Purpose
Phone < <…>
Tablet <…>
Desktop <…>
(Large desktop) optional
  • Primary design target: <mobile-first | desktop-first | fluid>
  • Fluid scale ranges (if used): <…>
  • See tokens.ts breakpoint for px values.

i18n

  • Locales at launch:
  • RTL support: <yes | no | planned for vN>
  • Pluralization: <ICU MessageFormat | library | manual>
  • String length budget: assume +30% over English for de/fr translations
  • Date / number formatting: Intl.DateTimeFormat / Intl.NumberFormat (locale-aware)
  • Locale switching mechanism: <…>

State postures

One declared posture per state, used everywhere. Per-screen variation is an exception that needs justification, not a default.

Empty

  • Visual: <icon + heading + body + CTA | heading + body | heading only>
  • Tone: <encouraging | neutral | matter-of-fact>
  • CTA: <present always | present when actionable | never>
  • Copy length: keep to 12 sentences; the state itself communicates

Loading

  • Default pattern: <skeleton | spinner | blocking>
  • By action class:
    • List / card containers:
    • Inline buttons:
    • Page-level:
  • Threshold for showing loading at all: <ms — usually 200300ms>

Error

  • Surface by class:
    • Recoverable inline (validation): inline beneath the field
    • Recoverable async (network): toast with retry
    • Unrecoverable (system): dialog
  • Recovery affordances: <retry | clear path forward | report>
  • Copy tone: plain language, name what happened, name what to do next
  • Copy length: 12 sentences max
  • Never show stack traces, error codes without explanation, or "An error occurred" without specifics

Offline

  • Behavior: <full subset works | banner only | "go online to continue">
  • Indicator: <persistent banner | transient toast | none>
  • Sync semantics: <queue + flush on reconnect | fail loudly | not in v1>
  • Conflict resolution on reconnect:

Time formatting

  • Relative time for events within: <threshold — e.g., < 7 days>
    • Pattern: "<3 hours ago>", "", ""
  • Absolute time otherwise:
    • Pattern: <Intl.DateTimeFormat locale-aware | explicit format>
    • Example: <e.g., "Apr 28, 2026 4:30 PM">
  • Date-only vs date+time: show time when it matters (events, logs); date-only for ages, anniversaries, milestones
  • Time zones: <user-local | fixed | configurable>
  • Tooltip / hover: relative-time displays should show absolute on hover

Keyboard

  • Global shortcuts: <list, or "none in v1">
  • Within-modal:
    • Esc closes (always)
    • Focus trapped while open
    • Focus restored to trigger element on close
  • Tab order: declared per-flow as relevant; focus visible always (per design-system)
  • Forms:
    • Enter submits (or Cmd+Enter for multi-line forms)
    • Esc cancels destructive actions only
  • Lists / menus:
    • Arrow-key navigation: <yes | no in v1>
    • Home / End: <yes | no>
    • Type-ahead select: <yes | no>

Optimistic updates & error recovery

  • Default posture: <optimistic with rollback | pessimistic | mixed>
  • Optimistic by default: most actions feel fast; rollback on failure
  • Pessimistic by default: destructive actions, money flows, anything irreversible
  • Mixed strategy (if applicable):
    • Optimistic for:
    • Pessimistic for:

Rollback strategy

  • UI on failure: <toast + revert | silent revert | dialog>
  • Retry affordance: <inline retry button | toast button | none>
  • Stale data detection: <ETag | timestamp | version>

Conflict resolution

  • Strategy: <last-write-wins | show conflict UI | append both | platform-specific>
  • User-visible signaling: <…>

Gestures (touch only)

  • Swipe actions on rows: <yes (which actions, which directions) | no>
  • Long-press menu: <yes | no>
  • Pull-to-refresh: <yes (where) | no>
  • Pinch-to-zoom: <yes (where — usually images, maps) | no>
  • Edge-swipe back navigation: <platform default | overridden>

Focus management

  • After modal close: restore focus to trigger element (always)
  • After route change: <heading focus | container focus | no change>
  • After form error: focus first error field (always)
  • After successful action that closes UI: restore to a sensible parent
  • On initial page load: <do not auto-focus | focus main heading | focus primary CTA>
  • Focus visibility: always visible per design-system tokens; no outline: none without a replacement

Notification patterns

  • Toasts: <use cases — confirmations, async results>
    • Position: <top-right | bottom-center | platform-default>
    • Duration: <ms — usually 40006000>
    • Dismissible: yes
    • Stacking: <max N | replace>
  • Inline notifications / banners: <use cases — status, warnings, persistent state>
  • Dialogs: <use cases — confirmation, error, blocking decisions>
  • Badge counts: <where shown, how cleared>

Selection & multi-select

  • Single select:
  • Multi-select:
    • Trigger: <long-press (touch), checkbox always visible, shift-click range, etc.>
    • Action bar: <sticky bottom | top | inline>
    • Bulk action limits: <none | N items max>
  • Select-all: <yes (where) | no>

Drag & drop

  • Use cases: <reordering | moving between lists | upload | none>
  • Affordance: <handle-only | row-anywhere | platform-default>
  • Touch support: <yes (long-press to lift) | desktop-only | none>
  • Live preview: <yes | no>

TBD on return

  • <TBD: ...>