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>
This commit is contained in:
@@ -1,112 +1,230 @@
|
||||
---
|
||||
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, and keyboard policy. Load and apply whenever building UI behavior — modals, forms, navigation, transitions, gestures, error handling, async states, focus management. Pairs with <SLUG>-design-system.
|
||||
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).
|
||||
> 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.
|
||||
reused everywhere. For visual tokens (color, type, spacing), see the
|
||||
paired `<SLUG>-design-system` skill.
|
||||
|
||||
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 |
|
||||
|---|---|
|
||||
| Touch | <TBD: primary | supported | not supported> |
|
||||
| Mouse | <TBD> |
|
||||
| Keyboard | <TBD> |
|
||||
| Voice | <TBD: usually "not supported" in v1> |
|
||||
| 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.
|
||||
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 | <TBD> |
|
||||
| Multi-field create / edit | <drawer | modal — pick one> | <TBD> |
|
||||
| Confirm destructive | modal | always |
|
||||
| Settings / configuration | full-page route | — |
|
||||
| Top-level navigation | <sidebar | tab bar | header nav> | <TBD> |
|
||||
| Detail-from-list | <full route | side panel> | <TBD> |
|
||||
| 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
|
||||
- **Reduced motion**: respected via `prefers-reduced-motion` everywhere; fallbacks declared per pattern below
|
||||
- **When things animate**:
|
||||
- Page/route transitions: <yes/no, how>
|
||||
- List item enter/exit: <yes/no, how>
|
||||
- Modal/drawer open/close: <yes/no, how>
|
||||
- State changes (toggle, expand): <yes/no, how>
|
||||
- **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 | Primary? |
|
||||
| Breakpoint | Range | Purpose |
|
||||
|---|---|---|
|
||||
| Phone | < <px> | <TBD> |
|
||||
| Tablet | <px> – <px> | <TBD> |
|
||||
| Desktop | ≥ <px> | <TBD> |
|
||||
| Phone | < <px> | <…> |
|
||||
| Tablet | <px> – <px> | <…> |
|
||||
| Desktop | ≥ <px> | <…> |
|
||||
| (Large desktop) | ≥ <px> | optional |
|
||||
|
||||
**Primary design target**: <which one — "mobile-first", "desktop-first", "fluid">
|
||||
- **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 — often just English in v1>
|
||||
- **RTL support**: <yes | no | planned>
|
||||
- **String length budget**: assume +30% over English for German/French translations
|
||||
- **Pluralization**: <TBD: ICU MessageFormat / library / manual>
|
||||
- **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. No inventing on a per-screen basis.
|
||||
One declared posture per state, used everywhere. Per-screen variation
|
||||
is an exception that needs justification, not a default.
|
||||
|
||||
### Empty
|
||||
- **Visual**: <icon + heading + body + optional CTA>
|
||||
- **Visual**: <icon + heading + body + CTA | heading + body | heading only>
|
||||
- **Tone**: <encouraging | neutral | matter-of-fact>
|
||||
- **CTA**: <when present, what kind of action>
|
||||
- **CTA**: <present always | present when actionable | never>
|
||||
- **Copy length**: keep to 1–2 sentences; the state itself communicates
|
||||
|
||||
### Loading
|
||||
- **Default pattern**: <skeleton | spinner | blocking>
|
||||
- **When to use which**: <criteria — "skeleton for list/card containers, spinner for inline buttons, blocking only for explicit user-initiated actions">
|
||||
- **Threshold for showing loading at all**: <ms — usually 200–300ms; below that, just let it pop>
|
||||
- **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 200–300ms>
|
||||
|
||||
### Error
|
||||
- **Surface**: <inline | toast | dialog — by error class>
|
||||
- **Recovery**: <retry button | clear path forward | "contact support" only as last resort>
|
||||
- **Copy tone**: <plain language, name what happened, name what to do next>
|
||||
- **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**: <feature subset that works | banner only | "go online to continue">
|
||||
- **Sync semantics**: <when reconnected, what happens>
|
||||
- **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>
|
||||
- **Absolute time** otherwise, format: <pattern — e.g., "MMM d, yyyy h:mm a">
|
||||
- **Time zones**: <user-local | fixed (which?) | configurable>
|
||||
- **Date-only vs date+time**: <when each is shown>
|
||||
- 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; focus trap while open; restore focus on close
|
||||
- **Tab order**: declared per-flow as needed; focus visible always (per design-system)
|
||||
- **Forms**: `Enter` submits; `Esc` cancels destructive
|
||||
- **Lists**: <arrow-key nav? | not 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 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**: <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
|
||||
|
||||
- <TBD: anything the placeholder pass couldn't answer>
|
||||
<!-- Anything skipped or deferred during the ui-system interview. -->
|
||||
|
||||
- <TBD: ...>
|
||||
|
||||
Reference in New Issue
Block a user