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:
Bernt
2026-07-02 08:58:29 +00:00
parent 1e40d384ca
commit 500d9c052b
3 changed files with 553 additions and 37 deletions
+91 -37
View File
@@ -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:**