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

231 lines
9.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: <SLUG>-interaction-design
description: 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.
---
# <PROJECT NAME> 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 | not supported> | <…> |
| Mouse | <…> | <…> |
| Keyboard | supported (always — a11y baseline) | full keyboard navigation required |
| Voice | <typically not supported in v1> | — |
| Switch / assistive | <…> | — |
**Primary**: <which> — 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 | drawer> | — |
| Multi-field create | <drawer | modal | full-page route> | — |
| Multi-field edit | <drawer | modal | full-page route> | usually same as create |
| Confirm destructive | modal | always — non-negotiable |
| Settings / configuration | full-page route | — |
| Top-level navigation | <sidebar | tab bar | header nav> | — |
| Detail-from-list | <full route | side panel | drawer> | — |
| Filtering / sorting | <inline controls | popover | drawer> | — |
| Search | <header search | command palette | dedicated page> | — |
## 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 | conditional> | <token> |
| List item enter / exit | <…> | <token> |
| Modal / drawer open / close | <…> | <token> |
| State changes (toggle, expand) | <…> | <token> |
| Loading → loaded transitions | <…> | <token> |
| 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 | < <px> | <…> |
| Tablet | <px> <px> | <…> |
| Desktop | ≥ <px> | <…> |
| (Large desktop) | ≥ <px> | 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**: <list>
- **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: <usually skeleton>
- Inline buttons: <usually spinner-in-button>
- Page-level: <skeleton or blocking>
- **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**: <see Optimistic updates below>
## Time formatting
- **Relative time** for events within: <threshold — e.g., < 7 days>
- Pattern: "<3 hours ago>", "<yesterday>", "<last Tuesday>"
- **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: <action classes>
- Pessimistic for: <action classes>
### 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)
<!-- Skip / remove this section if input model doesn't include touch. -->
- **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**: <pattern>
- **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
<!-- Anything skipped or deferred during the ui-system interview. -->
- <TBD: ...>