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>
9.2 KiB
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-systemphase. 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.tsbreakpointfor 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 1–2 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 200–300ms>
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: 1–2 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.DateTimeFormatlocale-aware | explicit format> - Example: <e.g., "Apr 28, 2026 4:30 PM">
- Pattern: <
- 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:
Esccloses (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:
Entersubmits (or Cmd+Enter for multi-line forms)Esccancels 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: nonewithout a replacement
Notification patterns
- Toasts: <use cases — confirmations, async results>
- Position: <top-right | bottom-center | platform-default>
- Duration: <ms — usually 4000–6000>
- 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: ...>