docs: AI Design Principles + Button RFC + Release Definition
- Motion System v1:
- Renamed duration tokens from time-based (fast/slow) to intention-based
(instant, interaction, transition, navigation, layout, context-change,
attention, background)
- Updated all component motion tables to use intention-based tokens
- Rationale: AI reasons about purpose, not milliseconds
- Button gold standard (chapter 8.3.1):
- Added RFC-level sections: Cognitive Purpose, When to use/NOT use,
User Expectation, Interaction Contract, Failure Behaviour,
Accessibility Contract, AI Contract
- Sets the bar for all future component specifications
- AI_DESIGN_PRINCIPLES.md (v1.0, LOCKED):
- Core principle: AI must be a design system citizen
- Before-action rules: read hierarchy, check existing, apply New Component Rule
- Token rules: no hardcoded values, semantic first, lifecycle, deterministic
- Component rules: inheritance first, use template, document anti-patterns
- Motion rules: intention-based duration, reduced motion, no decorative animation
- Accessibility rules: WCAG 2.1 AA, no ARIA without purpose
- AI Contract for Button: when to choose Button vs Link vs Icon Button
- RELEASE_DEFINITION.md:
- Defines Landvex Design System v1.0 release gates
- Foundation, Tokens, Foundations, Components (Tier 1/2/3),
Validation, Production
- Current progress: ~55%
- Next milestones: Grid+Elevation, Input/Select/Card, Brand Palette
Rationale: AI rules before components (AI will write components).
Intention-based motion tokens for better AI reasoning. Button as RFC
sets the standard. Release definition creates clear target.
This commit is contained in:
@@ -533,15 +533,26 @@ Dedicated palette for geospatial visualization. Defined by **layer**, not indivi
|
||||
- Multiple animations must not conflict
|
||||
- Motion must respect `prefers-reduced-motion`
|
||||
|
||||
### 5.2 Duration Scale
|
||||
### 5.2 Duration Tokens (Intention-Based)
|
||||
|
||||
| Token | Value | Usage |
|
||||
|-------|-------|-------|
|
||||
| `duration-instant` | 0ms | No animation |
|
||||
| `duration-fast` | 100ms | Hover states, focus rings |
|
||||
| `duration-normal` | 200ms | Standard transitions |
|
||||
| `duration-slow` | 300ms | Page transitions, drawers |
|
||||
| `duration-slower` | 500ms | Complex animations, modals |
|
||||
Tokens are named by **intention**, not duration. AI and developers reason about purpose, not milliseconds.
|
||||
|
||||
| Token | Value | Intention | Usage |
|
||||
|-------|-------|-----------|-------|
|
||||
| `duration-instant` | 0ms | No perceived time | State changes that must feel immediate |
|
||||
| `duration-interaction` | 100ms | Micro-feedback | Hover, focus, press, toggle |
|
||||
| `duration-transition` | 200ms | Element state change | Appear, disappear, expand, collapse |
|
||||
| `duration-navigation` | 300ms | View change | Page transition, drawer, modal |
|
||||
| `duration-layout` | 400ms | Structural shift | Sidebar expand, grid reorder |
|
||||
| `duration-context-change` | 500ms | Major context switch | Full-screen overlay, wizard step |
|
||||
| `duration-attention` | 600ms | Draw attention | Toast, alert, notification |
|
||||
| `duration-background` | 1000ms | Ambient, non-blocking | Skeleton shimmer, progress sweep |
|
||||
|
||||
**Mapping to traditional terms:**
|
||||
- `duration-interaction` ≈ "fast"
|
||||
- `duration-transition` ≈ "normal"
|
||||
- `duration-navigation` ≈ "slow"
|
||||
- `duration-context-change` ≈ "slower"
|
||||
|
||||
### 5.3 Easing Functions
|
||||
|
||||
@@ -559,36 +570,36 @@ Dedicated palette for geospatial visualization. Defined by **layer**, not indivi
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Hover | Background color shift | 100ms | ease-out |
|
||||
| Press | Scale to 0.98 | 50ms | ease-in |
|
||||
| Release | Scale to 1.0 | 100ms | ease-out |
|
||||
| Loading | Spinner rotation | 1s | linear infinite |
|
||||
| Disabled | Opacity to 0.5 | 100ms | ease-in-out |
|
||||
| Hover | Background color shift | `duration-interaction` | ease-out |
|
||||
| Press | Scale to 0.98 | `duration-instant` | ease-in |
|
||||
| Release | Scale to 1.0 | `duration-interaction` | ease-out |
|
||||
| Loading | Spinner rotation | `duration-background` | linear infinite |
|
||||
| Disabled | Opacity to 0.5 | `duration-interaction` | ease-in-out |
|
||||
|
||||
#### 5.4.2 Modal
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Open | Fade in + scale from 0.95 | 300ms | ease-out |
|
||||
| Close | Fade out + scale to 0.95 | 200ms | ease-in |
|
||||
| Backdrop | Fade to 50% opacity | 300ms | ease-in-out |
|
||||
| Open | Fade in + scale from 0.95 | `duration-navigation` | ease-out |
|
||||
| Close | Fade out + scale to 0.95 | `duration-transition` | ease-in |
|
||||
| Backdrop | Fade to 50% opacity | `duration-navigation` | ease-in-out |
|
||||
|
||||
#### 5.4.3 Drawer
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Open | Slide from edge | 300ms | ease-out |
|
||||
| Close | Slide to edge | 200ms | ease-in |
|
||||
| Backdrop | Fade to 50% opacity | 300ms | ease-in-out |
|
||||
| Open | Slide from edge | `duration-navigation` | ease-out |
|
||||
| Close | Slide to edge | `duration-transition` | ease-in |
|
||||
| Backdrop | Fade to 50% opacity | `duration-navigation` | ease-in-out |
|
||||
|
||||
#### 5.4.4 Map Transitions
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Pan | None (instant) | 0ms | — |
|
||||
| Zoom | Smooth interpolation | 300ms | ease-in-out |
|
||||
| Layer toggle | Cross-fade | 200ms | ease-in-out |
|
||||
| Feature select | Highlight pulse | 300ms | ease-out |
|
||||
| Pan | None (instant) | `duration-instant` | — |
|
||||
| Zoom | Smooth interpolation | `duration-navigation` | ease-in-out |
|
||||
| Layer toggle | Cross-fade | `duration-transition` | ease-in-out |
|
||||
| Feature select | Highlight pulse | `duration-navigation` | ease-out |
|
||||
|
||||
**Rule:** Map panning is never animated. Users need instant feedback on drag.
|
||||
|
||||
@@ -596,16 +607,16 @@ Dedicated palette for geospatial visualization. Defined by **layer**, not indivi
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Loading | Shimmer sweep | 1.5s | ease-in-out infinite |
|
||||
| Complete | Fade to content | 200ms | ease-out |
|
||||
| Loading | Shimmer sweep | `duration-background` | ease-in-out infinite |
|
||||
| Complete | Fade to content | `duration-transition` | ease-out |
|
||||
|
||||
#### 5.4.6 Progress
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Indeterminate | Sweep | 1s | linear infinite |
|
||||
| Determinate | Width growth | 300ms | ease-out |
|
||||
| Complete | Checkmark draw | 200ms | ease-out |
|
||||
| Indeterminate | Sweep | `duration-background` | linear infinite |
|
||||
| Determinate | Width growth | `duration-navigation` | ease-out |
|
||||
| Complete | Checkmark draw | `duration-transition` | ease-out |
|
||||
|
||||
### 5.5 Reduced Motion
|
||||
|
||||
@@ -631,9 +642,9 @@ When `prefers-reduced-motion: reduce` is active:
|
||||
|
||||
| Type | Animation | Duration | Purpose |
|
||||
|------|-----------|----------|---------|
|
||||
| Error | Subtle shake (4px, 3 cycles) | 300ms | Indicate invalid input |
|
||||
| Success | Checkmark draw + fade | 400ms | Confirm completion |
|
||||
| Warning | Pulse border color | 2s | Draw attention without alarm |
|
||||
| Error | Subtle shake (4px, 3 cycles) | `duration-navigation` | Indicate invalid input |
|
||||
| Success | Checkmark draw + fade | `duration-layout` | Confirm completion |
|
||||
| Warning | Pulse border color | `duration-attention` | Draw attention without alarm |
|
||||
|
||||
---
|
||||
|
||||
@@ -766,9 +777,52 @@ Only then may a new component be defined.
|
||||
|
||||
### 8.3.1 Button
|
||||
|
||||
**Purpose:** Trigger primary user actions. The most used interactive element.
|
||||
**Cognitive Purpose:** Button exists to trigger actions that modify state or advance workflow. It is the primary interface between user intent and system response.
|
||||
|
||||
**Design Goal:** Immediately recognizable, consistently responsive, accessible without thought.
|
||||
**When to use:**
|
||||
- Primary user action (submit, confirm, save)
|
||||
- Form submission
|
||||
- Dialog confirmation
|
||||
- Action that requires explicit user commitment
|
||||
|
||||
**When NOT to use:**
|
||||
- Navigation (use Link)
|
||||
- Toggling state (use Switch)
|
||||
- Selecting from options (use Select)
|
||||
- Secondary information reveal (use Accordion)
|
||||
|
||||
**User Expectation:**
|
||||
- Button is clickable
|
||||
- Button responds immediately to press
|
||||
- Button indicates if action is in progress
|
||||
- Button indicates if action is unavailable
|
||||
|
||||
**Interaction Contract:**
|
||||
- Click → Action executes
|
||||
- Hover → Visual feedback (but action does not execute)
|
||||
- Focus → Keyboard can activate
|
||||
- Loading → Action is in progress, further clicks ignored
|
||||
- Disabled → Action is unavailable, reason explained elsewhere
|
||||
|
||||
**Failure Behaviour:**
|
||||
- If action fails: Button returns to default state, error shown elsewhere (not on button)
|
||||
- If network fails: Button remains in loading state until timeout, then error
|
||||
- If validation fails: Button remains enabled, form shows errors
|
||||
|
||||
**Accessibility Contract:**
|
||||
- Screen reader announces button role and label
|
||||
- Focus is visible and logical
|
||||
- Disabled state is communicated
|
||||
- Loading state is communicated
|
||||
|
||||
**AI Contract:**
|
||||
- AI chooses Button for primary actions
|
||||
- AI chooses Link for navigation
|
||||
- AI chooses Icon Button for toolbar actions
|
||||
- AI chooses Split Button for primary + secondary options
|
||||
- AI never uses Button for navigation
|
||||
|
||||
---
|
||||
|
||||
**Token Dependencies:**
|
||||
- `button-primary-bg` → `brand-500`
|
||||
@@ -809,10 +863,10 @@ Only then may a new component be defined.
|
||||
| State | Visual | Motion |
|
||||
|-------|--------|--------|
|
||||
| Default | As variant | None |
|
||||
| Hover | Darken 10% | Background shift 100ms ease-out |
|
||||
| Focus | 2px ring `border-focus` | Ring appear 100ms ease-out |
|
||||
| Pressed | Scale 0.98 | Scale 50ms ease-in |
|
||||
| Loading | Spinner replaces text | Spinner 1s linear infinite |
|
||||
| Hover | Darken 10% | Background shift `duration-interaction` ease-out |
|
||||
| Focus | 2px ring `border-focus` | Ring appear `duration-interaction` ease-out |
|
||||
| Pressed | Scale 0.98 | Scale `duration-instant` ease-in |
|
||||
| Loading | Spinner replaces text | Spinner `duration-background` linear infinite |
|
||||
| Disabled | Opacity 0.5, no pointer | None |
|
||||
|
||||
**Keyboard:**
|
||||
|
||||
Reference in New Issue
Block a user