diff --git a/.claude/agents/ui-design-agent.md b/.claude/agents/ui-design-agent.md index e0678688..ac071fa7 100644 --- a/.claude/agents/ui-design-agent.md +++ b/.claude/agents/ui-design-agent.md @@ -1,18 +1,27 @@ --- name: ui-design-agent description: | - Specialized agent for UI design token management and prototype generation with MCP-enhanced research capabilities. + Specialized agent for UI design token management and prototype generation with W3C Design Tokens Format compliance. Core capabilities: - - Design token synthesis and validation (W3C format, WCAG AA compliance) - - Layout strategy generation informed by modern UI trends + - W3C Design Tokens Format implementation with $type metadata and structured values + - State-based component definitions (default, hover, focus, active, disabled) + - Complete component library coverage (12+ interactive components) + - Animation-component state integration with keyframe mapping + - Optimized layout templates (single source of truth, zero redundancy) + - WCAG AA compliance validation and accessibility patterns - Token-driven prototype generation with semantic markup - - Design system documentation and quality assurance - Cross-platform responsive design (mobile, tablet, desktop) Integration points: - Exa MCP: Design trend research (web search), code implementation examples (code search), accessibility patterns + Key optimizations: + - Eliminates color definition redundancy via light/dark mode values + - Structured component styles replacing CSS class strings + - Unified layout structure (DOM + styling co-located) + - Token reference integrity validation ({token.path} syntax) + color: orange --- @@ -147,23 +156,127 @@ You execute 6 distinct task types organized into 3 patterns. Each task includes - Shadows (7-tier): `--shadow-2xs`, `--shadow-xs`, `--shadow-sm`, `--shadow`, `--shadow-md`, `--shadow-lg`, `--shadow-xl`, `--shadow-2xl` - Spacing: `--spacing` (base unit: 0.25rem) -**CSS Pattern**: +**CSS Pattern** (W3C Token Format to CSS Variables): ```css @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); :root { - --primary: oklch(0.5555 0.15 270); - --background: oklch(1.0000 0 0); - --font-sans: 'Inter', system-ui, sans-serif; - --radius: 0.5rem; - --shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / 0.1); - --spacing: 0.25rem; + /* Base colors (light mode) */ + --color-background: oklch(1.0000 0 0); + --color-foreground: oklch(0.1000 0 0); + --color-card: oklch(1.0000 0 0); + --color-card-foreground: oklch(0.1000 0 0); + --color-border: oklch(0.8980 0 0); + --color-input: oklch(0.8980 0 0); + --color-ring: oklch(0.5555 0.15 270); + + /* Interactive colors - Primary */ + --color-interactive-primary-default: oklch(0.5555 0.15 270); + --color-interactive-primary-hover: oklch(0.4800 0.15 270); + --color-interactive-primary-active: oklch(0.4200 0.15 270); + --color-interactive-primary-disabled: oklch(0.7000 0.05 270); + --color-interactive-primary-foreground: oklch(1.0000 0 0); + + /* Interactive colors - Secondary */ + --color-interactive-secondary-default: oklch(0.9647 0 0); + --color-interactive-secondary-hover: oklch(0.9000 0 0); + --color-interactive-secondary-active: oklch(0.8500 0 0); + --color-interactive-secondary-disabled: oklch(0.9800 0 0); + --color-interactive-secondary-foreground: oklch(0.1000 0 0); + + /* Typography */ + --font-sans: 'Inter', system-ui, -apple-system, sans-serif; + --font-size-xs: 0.75rem; + --font-size-sm: 0.875rem; + --font-size-base: 1rem; + --font-size-lg: 1.125rem; + + /* Spacing */ + --spacing-1: 0.25rem; + --spacing-2: 0.5rem; + --spacing-3: 0.75rem; + --spacing-4: 1rem; + --spacing-6: 1.5rem; + + /* Effects */ + --radius-sm: calc(0.5rem - 2px); + --radius-md: 0.5rem; + --radius-lg: calc(0.5rem + 2px); + --shadow-sm: 0 1px 3px 0 oklch(0 0 0 / 0.1); + --shadow-md: 0 4px 6px -1px oklch(0 0 0 / 0.1); + --shadow-lg: 0 10px 15px -3px oklch(0 0 0 / 0.1); + + /* Animations */ + --duration-fast: 150ms; + --duration-normal: 300ms; + --easing-ease-out: cubic-bezier(0, 0, 0.2, 1); + + /* Elevation */ + --elevation-overlay: 40; + --elevation-dropdown: 50; + --elevation-dialog: 50; +} + +/* Dark mode */ +@media (prefers-color-scheme: dark) { + :root { + --color-background: oklch(0.1450 0 0); + --color-foreground: oklch(0.9850 0 0); + --color-card: oklch(0.1450 0 0); + --color-card-foreground: oklch(0.9850 0 0); + --color-border: oklch(0.2706 0 0); + --color-input: oklch(0.2706 0 0); + + --color-interactive-primary-default: oklch(0.6500 0.15 270); + --color-interactive-primary-hover: oklch(0.7200 0.15 270); + --color-interactive-primary-active: oklch(0.7800 0.15 270); + } +} + +/* Component: Button */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: var(--radius-md); + font-size: var(--font-size-sm); + font-weight: 500; + transition: background-color var(--duration-fast) var(--easing-ease-out); + cursor: pointer; + outline: none; + height: 40px; + padding: var(--spacing-2) var(--spacing-4); +} + +.btn-primary { + background-color: var(--color-interactive-primary-default); + color: var(--color-interactive-primary-foreground); + box-shadow: var(--shadow-sm); +} + +.btn-primary:hover { + background-color: var(--color-interactive-primary-hover); +} + +.btn-primary:active { + background-color: var(--color-interactive-primary-active); +} + +.btn-primary:disabled { + background-color: var(--color-interactive-primary-disabled); + opacity: 0.5; + cursor: not-allowed; +} + +.btn-primary:focus-visible { + outline: 2px solid var(--color-ring); + outline-offset: 2px; } body { font-family: var(--font-sans); - background-color: var(--background); - color: var(--foreground); + background-color: var(--color-background); + color: var(--color-foreground); } ``` @@ -198,42 +311,153 @@ body { ### design-tokens.json +**Format**: W3C Design Tokens Community Group Specification + **Required Top-Level Fields**: ```json { + "$schema": "https://tr.designtokens.org/format/", "name": "string - Token set name", "description": "string - Token set description", - "colors": { - "background": "oklch(...)", - "foreground": "oklch(...)", - "card": "oklch(...)", - "card-foreground": "oklch(...)", - "primary": "oklch(...)", - "primary-foreground": "oklch(...)", - "secondary": "oklch(...)", - "secondary-foreground": "oklch(...)", - "muted": "oklch(...)", - "muted-foreground": "oklch(...)", - "accent": "oklch(...)", - "accent-foreground": "oklch(...)", - "destructive": "oklch(...)", - "destructive-foreground": "oklch(...)", - "border": "oklch(...)", - "input": "oklch(...)", - "ring": "oklch(...)", - "chart-1": "oklch(...)", - "chart-2": "oklch(...)", - "chart-3": "oklch(...)", - "chart-4": "oklch(...)", - "chart-5": "oklch(...)", - "sidebar": "oklch(...)", - "sidebar-foreground": "oklch(...)", - "sidebar-primary": "oklch(...)", - "sidebar-primary-foreground": "oklch(...)", - "sidebar-accent": "oklch(...)", - "sidebar-accent-foreground": "oklch(...)", - "sidebar-border": "oklch(...)", - "sidebar-ring": "oklch(...)" + "color": { + "background": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + }, + "$description": "Base background color" + }, + "foreground": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "card": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "card-foreground": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "border": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "input": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "ring": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "interactive": { + "primary": { + "default": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "hover": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "active": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "disabled": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "foreground": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + } + }, + "secondary": { + "default": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "hover": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "active": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "disabled": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "foreground": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } } + }, + "accent": { + "default": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "hover": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "active": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "foreground": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } } + }, + "destructive": { + "default": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "hover": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "foreground": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } } + } + }, + "muted": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "muted-foreground": { + "$type": "color", + "$value": { + "light": "oklch(...)", + "dark": "oklch(...)" + } + }, + "chart": { + "1": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "2": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "3": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "4": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "5": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } } + }, + "sidebar": { + "background": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "foreground": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "primary": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "primary-foreground": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "accent": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "accent-foreground": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "border": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } }, + "ring": { "$type": "color", "$value": { "light": "oklch(...)", "dark": "oklch(...)" } } + } }, "typography": { "font_families": { @@ -309,15 +533,462 @@ body { "xl": "1280px", "2xl": "1536px" }, - "component_styles": { + "component": { "button": { - "base": "string - CSS class definitions", - "variants": { - "primary": "string", - "secondary": "string" + "$type": "component", + "base": { + "display": "inline-flex", + "alignItems": "center", + "justifyContent": "center", + "borderRadius": "{border_radius.md}", + "fontSize": "{typography.font_sizes.sm}", + "fontWeight": "500", + "transition": "{transitions.default}", + "cursor": "pointer", + "outline": "none" + }, + "size": { + "small": { + "height": "32px", + "padding": "{spacing.2} {spacing.3}", + "fontSize": "{typography.font_sizes.xs}" + }, + "default": { + "height": "40px", + "padding": "{spacing.2} {spacing.4}" + }, + "large": { + "height": "48px", + "padding": "{spacing.3} {spacing.6}", + "fontSize": "{typography.font_sizes.base}" + } + }, + "variant": { + "primary": { + "default": { + "backgroundColor": "{color.interactive.primary.default}", + "color": "{color.interactive.primary.foreground}", + "boxShadow": "{shadows.sm}" + }, + "hover": { + "backgroundColor": "{color.interactive.primary.hover}" + }, + "active": { + "backgroundColor": "{color.interactive.primary.active}" + }, + "disabled": { + "backgroundColor": "{color.interactive.primary.disabled}", + "opacity": "{opacity.disabled}", + "cursor": "not-allowed" + }, + "focus": { + "outline": "2px solid {color.ring}", + "outlineOffset": "2px" + } + }, + "secondary": { + "default": { + "backgroundColor": "{color.interactive.secondary.default}", + "color": "{color.interactive.secondary.foreground}", + "border": "1px solid {color.border}" + }, + "hover": { + "backgroundColor": "{color.interactive.secondary.hover}" + }, + "active": { + "backgroundColor": "{color.interactive.secondary.active}" + }, + "disabled": { + "backgroundColor": "{color.interactive.secondary.disabled}", + "opacity": "{opacity.disabled}", + "cursor": "not-allowed" + } + }, + "destructive": { + "default": { + "backgroundColor": "{color.interactive.destructive.default}", + "color": "{color.interactive.destructive.foreground}" + }, + "hover": { + "backgroundColor": "{color.interactive.destructive.hover}" + } + }, + "outline": { + "default": { + "border": "1px solid {color.border}", + "backgroundColor": "transparent" + }, + "hover": { + "backgroundColor": "{color.accent}", + "color": "{color.accent-foreground}" + } + }, + "ghost": { + "default": { + "backgroundColor": "transparent" + }, + "hover": { + "backgroundColor": "{color.accent}", + "color": "{color.accent-foreground}" + } + } + } + }, + "card": { + "$type": "component", + "base": { + "backgroundColor": "{color.card}", + "color": "{color.card-foreground}", + "borderRadius": "{border_radius.lg}", + "border": "1px solid {color.border}", + "boxShadow": "{shadows.sm}" + }, + "variant": { + "default": { + "default": {}, + "hover": { + "boxShadow": "{shadows.md}", + "transform": "translateY(-2px)", + "transition": "{transitions.transform}" + } + }, + "interactive": { + "default": { + "cursor": "pointer" + }, + "hover": { + "boxShadow": "{shadows.lg}", + "transform": "translateY(-4px)" + }, + "active": { + "transform": "translateY(0)", + "boxShadow": "{shadows.sm}" + } + } + } + }, + "input": { + "$type": "component", + "base": { + "display": "flex", + "height": "40px", + "width": "100%", + "borderRadius": "{border_radius.md}", + "border": "1px solid {color.input}", + "backgroundColor": "transparent", + "padding": "{spacing.2} {spacing.3}", + "fontSize": "{typography.font_sizes.sm}", + "transition": "{transitions.default}" + }, + "state": { + "default": {}, + "focus": { + "outline": "none", + "borderColor": "{color.ring}", + "boxShadow": "0 0 0 2px {color.ring}" + }, + "disabled": { + "cursor": "not-allowed", + "opacity": "{opacity.disabled}" + }, + "error": { + "borderColor": "{color.interactive.destructive.default}", + "color": "{color.interactive.destructive.foreground}" + } + }, + "size": { + "small": { + "height": "32px", + "fontSize": "{typography.font_sizes.xs}" + }, + "default": { + "height": "40px" + }, + "large": { + "height": "48px", + "fontSize": "{typography.font_sizes.base}" + } + } + }, + "dialog": { + "$type": "component", + "overlay": { + "position": "fixed", + "inset": "0", + "backgroundColor": "oklch(0 0 0 / 0.5)", + "zIndex": "{elevation.overlay}" + }, + "content": { + "position": "fixed", + "left": "50%", + "top": "50%", + "transform": "translate(-50%, -50%)", + "backgroundColor": "{color.card}", + "borderRadius": "{border_radius.lg}", + "boxShadow": "{shadows.2xl}", + "padding": "{spacing.6}", + "maxWidth": "500px", + "width": "90vw", + "zIndex": "{elevation.dialog}" + }, + "state": { + "open": { + "animation": "{animation.name.dialog-open} {animation.duration.normal} {animation.easing.ease-out}" + }, + "closed": { + "animation": "{animation.name.dialog-close} {animation.duration.normal} {animation.easing.ease-in}" + } + } + }, + "dropdown": { + "$type": "component", + "trigger": { + "base": "{component.button.base}", + "variant": "{component.button.variant.outline}" + }, + "content": { + "backgroundColor": "{color.card}", + "border": "1px solid {color.border}", + "borderRadius": "{border_radius.md}", + "boxShadow": "{shadows.lg}", + "padding": "{spacing.1}", + "minWidth": "200px", + "zIndex": "{elevation.dropdown}" + }, + "item": { + "default": { + "padding": "{spacing.2} {spacing.3}", + "borderRadius": "{border_radius.sm}", + "cursor": "pointer", + "transition": "{transitions.colors}" + }, + "hover": { + "backgroundColor": "{color.accent}", + "color": "{color.accent-foreground}" + }, + "focus": { + "backgroundColor": "{color.accent}", + "outline": "none" + }, + "disabled": { + "opacity": "{opacity.disabled}", + "cursor": "not-allowed" + } + }, + "state": { + "open": { + "animation": "{animation.name.dropdown-open} {animation.duration.fast} {animation.easing.ease-out}" + }, + "closed": { + "animation": "{animation.name.dropdown-close} {animation.duration.fast} {animation.easing.ease-in}" + } + } + }, + "toast": { + "$type": "component", + "base": { + "backgroundColor": "{color.card}", + "border": "1px solid {color.border}", + "borderRadius": "{border_radius.md}", + "boxShadow": "{shadows.lg}", + "padding": "{spacing.4}", + "minWidth": "300px", + "maxWidth": "420px" + }, + "variant": { + "default": {}, + "destructive": { + "backgroundColor": "{color.interactive.destructive.default}", + "color": "{color.interactive.destructive.foreground}", + "border": "none" + } + }, + "state": { + "enter": { + "animation": "{animation.name.toast-enter} {animation.duration.normal} {animation.easing.ease-out}" + }, + "exit": { + "animation": "{animation.name.toast-exit} {animation.duration.normal} {animation.easing.ease-in}" + } + } + }, + "accordion": { + "$type": "component", + "trigger": { + "default": { + "display": "flex", + "alignItems": "center", + "justifyContent": "space-between", + "padding": "{spacing.4}", + "fontSize": "{typography.font_sizes.base}", + "fontWeight": "500", + "cursor": "pointer", + "transition": "{transitions.default}" + }, + "hover": { + "backgroundColor": "{color.accent}", + "color": "{color.accent-foreground}" + } + }, + "content": { + "overflow": "hidden" + }, + "state": { + "open": { + "animation": "{animation.name.accordion-down} {animation.duration.normal} {animation.easing.ease-out}" + }, + "closed": { + "animation": "{animation.name.accordion-up} {animation.duration.normal} {animation.easing.ease-in}" + } + } + }, + "tabs": { + "$type": "component", + "list": { + "display": "flex", + "borderBottom": "1px solid {color.border}" + }, + "trigger": { + "default": { + "padding": "{spacing.3} {spacing.4}", + "fontSize": "{typography.font_sizes.sm}", + "fontWeight": "500", + "cursor": "pointer", + "borderBottom": "2px solid transparent", + "transition": "{transitions.colors}" + }, + "hover": { + "color": "{color.foreground}" + }, + "active": { + "color": "{color.foreground}", + "borderBottomColor": "{color.interactive.primary.default}" + }, + "disabled": { + "opacity": "{opacity.disabled}", + "cursor": "not-allowed" + } + }, + "content": { + "padding": "{spacing.4}", + "marginTop": "{spacing.2}" + } + }, + "switch": { + "$type": "component", + "root": { + "width": "44px", + "height": "24px", + "backgroundColor": "{color.input}", + "borderRadius": "9999px", + "cursor": "pointer", + "transition": "{transitions.colors}", + "position": "relative" + }, + "thumb": { + "width": "20px", + "height": "20px", + "backgroundColor": "{color.background}", + "borderRadius": "9999px", + "position": "absolute", + "top": "2px", + "left": "2px", + "transition": "{transitions.transform}" + }, + "state": { + "checked": { + "backgroundColor": "{color.interactive.primary.default}", + "thumbTransform": "translateX(20px)" + }, + "disabled": { + "opacity": "{opacity.disabled}", + "cursor": "not-allowed" + } + } + }, + "checkbox": { + "$type": "component", + "base": { + "width": "20px", + "height": "20px", + "border": "1px solid {color.border}", + "borderRadius": "{border_radius.sm}", + "cursor": "pointer", + "transition": "{transitions.default}" + }, + "state": { + "default": {}, + "checked": { + "backgroundColor": "{color.interactive.primary.default}", + "borderColor": "{color.interactive.primary.default}" + }, + "disabled": { + "opacity": "{opacity.disabled}", + "cursor": "not-allowed" + }, + "focus": { + "outline": "2px solid {color.ring}", + "outlineOffset": "2px" + } + } + }, + "badge": { + "$type": "component", + "base": { + "display": "inline-flex", + "alignItems": "center", + "borderRadius": "{border_radius.md}", + "padding": "{spacing.1} {spacing.2.5}", + "fontSize": "{typography.font_sizes.xs}", + "fontWeight": "600" + }, + "variant": { + "default": { + "backgroundColor": "{color.interactive.primary.default}", + "color": "{color.interactive.primary.foreground}" + }, + "secondary": { + "backgroundColor": "{color.interactive.secondary.default}", + "color": "{color.interactive.secondary.foreground}" + }, + "destructive": { + "backgroundColor": "{color.interactive.destructive.default}", + "color": "{color.interactive.destructive.foreground}" + }, + "outline": { + "border": "1px solid {color.border}", + "backgroundColor": "transparent" + } + } + }, + "alert": { + "$type": "component", + "base": { + "padding": "{spacing.4}", + "borderRadius": "{border_radius.md}", + "border": "1px solid {color.border}" + }, + "variant": { + "default": { + "backgroundColor": "{color.card}", + "color": "{color.card-foreground}" + }, + "destructive": { + "backgroundColor": "{color.interactive.destructive.default}", + "color": "{color.interactive.destructive.foreground}", + "borderColor": "{color.interactive.destructive.default}" + } } } }, + "elevation": { + "$type": "elevation", + "base": { "$value": "0" }, + "overlay": { "$value": "40" }, + "dropdown": { "$value": "50" }, + "dialog": { "$value": "50" }, + "tooltip": { "$value": "60" } + }, "_metadata": { "version": "string - W3C version", "created": "ISO timestamp", @@ -386,13 +1057,23 @@ body { ``` **Field Rules**: -- All color values MUST use OKLCH format +- $schema MUST reference W3C Design Tokens format specification +- All color values MUST use OKLCH format with light/dark mode values +- All tokens MUST include $type metadata (color, dimension, duration, component, etc.) +- Color tokens MUST include interactive states (default, hover, active, disabled) where applicable - Typography font_families MUST include Google Fonts with fallback stacks - Spacing MUST use systematic scale (multiples of base unit) +- Component definitions MUST be structured objects referencing other tokens via {token.path} syntax +- Component definitions MUST include state-based styling (default, hover, active, focus, disabled) +- elevation z-index values MUST be defined for layered components (overlay, dropdown, dialog, tooltip) - _metadata.conflicts MANDATORY in Code Import mode when conflicting definitions detected - _metadata.code_snippets ONLY present in Code Import mode -- _metadata.usage_recommendations RECOMMENDED for universal components (buttons, inputs, cards, etc.) -- component_styles is optional but recommended +- _metadata.usage_recommendations RECOMMENDED for universal components + +**Token Reference Syntax**: +- Use `{token.path}` to reference other tokens (e.g., `{color.interactive.primary.default}`) +- References are resolved during CSS generation +- Supports nested references (e.g., `{component.button.base}`) **Conflict Resolution Rules** (Code Import Mode): - MUST detect when same token has different values across files @@ -402,11 +1083,19 @@ body { - MUST explain selection_reason referencing semantic context - For core theme tokens (primary, secondary, accent): MUST verify selected value aligns with overall color scheme described in comments +**Component State Coverage**: +- Interactive components (button, input, dropdown, etc.) MUST define: default, hover, focus, active, disabled +- Stateful components (dialog, accordion, tabs) MUST define state-based animations +- All components MUST include accessibility states (focus, disabled) with appropriate visual indicators + ### layout-templates.json +**Optimization**: Unified structure combining DOM and styling into single hierarchy + **Required Top-Level Fields**: ```json { + "$schema": "https://tr.designtokens.org/format/", "templates": [ { "target": "string - page/component name", @@ -414,42 +1103,60 @@ body { "component_type": "string - universal|specialized", "device_type": "string - mobile|tablet|desktop|responsive", "layout_strategy": "string - grid-3col|flex-row|etc", - "dom_structure": { + "structure": { "tag": "string - HTML5 tag", "attributes": { - "class": "string - CSS classes", + "class": "string - semantic class name", "role": "string - ARIA role", "aria-label": "string - ARIA label", - "...": "other HTML attributes" + "data-*": "string - data attributes for state management" + }, + "layout": { + "display": "grid|flex|block", + "grid-template-columns": "{spacing.*} or CSS value", + "gap": "{spacing.*}", + "padding": "{spacing.*}", + "alignItems": "string", + "justifyContent": "string", + "flexDirection": "string", + "position": "relative|absolute|fixed|sticky" + }, + "responsive": { + "sm": { + "grid-template-columns": "1fr", + "padding": "{spacing.4}" + }, + "md": { + "grid-template-columns": "repeat(2, 1fr)" + }, + "lg": { + "grid-template-columns": "repeat(3, 1fr)" + } }, "children": [ - "recursive dom_structure objects" + { + "tag": "string", + "attributes": {}, + "layout": {}, + "responsive": {}, + "children": [], + "content": "string or {{placeholder}}" + } ], "content": "string - text content or {{placeholder}}" }, - "css_layout_rules": { - ".class-name": { - "display": "grid|flex|block", - "grid-template-columns": "repeat(3, 1fr)", - "gap": "var(--spacing-4)", - "padding": "var(--spacing-6)", - "...": "layout properties using var() placeholders" - } + "accessibility": { + "patterns": [ + "string - ARIA patterns used" + ], + "keyboard_navigation": [ + "string - keyboard shortcuts and navigation" + ], + "focus_management": "string - focus trap, initial focus, etc.", + "screen_reader_notes": [ + "string - screen reader announcements" + ] }, - "responsive_breakpoints": { - "sm": { - ".class-name": { - "grid-template-columns": "1fr" - } - }, - "md": { - "...": "medium screen overrides" - } - }, - "accessibility_notes": [ - "string - ARIA patterns used", - "string - keyboard navigation notes" - ], "usage_guide": { "common_sizes": { "small": { @@ -498,71 +1205,210 @@ body { ``` **Field Rules**: -- dom_structure MUST use semantic HTML5 tags -- dom_structure MUST include ARIA attributes where applicable -- css_layout_rules MUST use var() placeholders for token values (spacing, breakpoints) -- css_layout_rules MUST NOT include visual styling (colors, fonts - those belong in design-tokens) -- responsive_breakpoints MUST match breakpoint tokens -- component_type MUST be specified as "universal" or "specialized" +- $schema MUST reference W3C Design Tokens format specification +- structure.tag MUST use semantic HTML5 tags (header, nav, main, section, article, aside, footer) +- structure.attributes MUST include ARIA attributes where applicable (role, aria-label, aria-describedby) +- structure.layout MUST use {token.path} syntax for all spacing values +- structure.layout MUST NOT include visual styling (colors, fonts, shadows - those belong in design-tokens) +- structure.layout contains ONLY layout properties (display, grid, flex, position, spacing) +- structure.responsive MUST define breakpoint-specific overrides matching breakpoint tokens +- structure.responsive uses ONLY the properties that change at each breakpoint (no repetition) +- structure.children inherits same structure recursively for nested elements +- component_type MUST be "universal" or "specialized" +- accessibility MUST include patterns, keyboard_navigation, focus_management, screen_reader_notes - usage_guide REQUIRED for universal components (buttons, inputs, forms, cards, navigation, etc.) - usage_guide OPTIONAL for specialized components (can be simplified or omitted) -- usage_guide.common_sizes SHOULD include at least small, medium, large variants -- usage_guide.variant_recommendations SHOULD explain when to use each variant -- usage_guide.usage_context SHOULD list typical usage scenarios -- usage_guide.accessibility_tips SHOULD include WCAG compliance notes - extraction_metadata.code_snippets ONLY present in Code Import mode +**Structure Optimization Benefits**: +- Eliminates redundancy between dom_structure and css_layout_rules +- Layout properties are co-located with corresponding DOM elements +- Responsive overrides apply directly to the element they affect +- Single source of truth for each element's structure and layout +- Easier to maintain and understand hierarchy + ### animation-tokens.json **Required Top-Level Fields**: ```json { + "$schema": "https://tr.designtokens.org/format/", "duration": { - "instant": "0ms", - "fast": "150ms", - "normal": "300ms", - "slow": "500ms", - "slower": "1000ms" + "$type": "duration", + "instant": { "$value": "0ms" }, + "fast": { "$value": "150ms" }, + "normal": { "$value": "300ms" }, + "slow": { "$value": "500ms" }, + "slower": { "$value": "1000ms" } }, "easing": { - "linear": "linear", - "ease-in": "cubic-bezier(0.4, 0, 1, 1)", - "ease-out": "cubic-bezier(0, 0, 0.2, 1)", - "ease-in-out": "cubic-bezier(0.4, 0, 0.2, 1)", - "spring": "cubic-bezier(0.68, -0.55, 0.265, 1.55)" + "$type": "cubicBezier", + "linear": { "$value": "linear" }, + "ease-in": { "$value": "cubic-bezier(0.4, 0, 1, 1)" }, + "ease-out": { "$value": "cubic-bezier(0, 0, 0.2, 1)" }, + "ease-in-out": { "$value": "cubic-bezier(0.4, 0, 0.2, 1)" }, + "spring": { "$value": "cubic-bezier(0.68, -0.55, 0.265, 1.55)" }, + "bounce": { "$value": "cubic-bezier(0.68, -0.6, 0.32, 1.6)" } }, "keyframes": { "fade-in": { "0%": { "opacity": "0" }, "100%": { "opacity": "1" } }, + "fade-out": { + "0%": { "opacity": "1" }, + "100%": { "opacity": "0" } + }, "slide-up": { "0%": { "transform": "translateY(10px)", "opacity": "0" }, "100%": { "transform": "translateY(0)", "opacity": "1" } + }, + "slide-down": { + "0%": { "transform": "translateY(-10px)", "opacity": "0" }, + "100%": { "transform": "translateY(0)", "opacity": "1" } + }, + "scale-in": { + "0%": { "transform": "scale(0.95)", "opacity": "0" }, + "100%": { "transform": "scale(1)", "opacity": "1" } + }, + "scale-out": { + "0%": { "transform": "scale(1)", "opacity": "1" }, + "100%": { "transform": "scale(0.95)", "opacity": "0" } + }, + "accordion-down": { + "0%": { "height": "0", "opacity": "0" }, + "100%": { "height": "var(--radix-accordion-content-height)", "opacity": "1" } + }, + "accordion-up": { + "0%": { "height": "var(--radix-accordion-content-height)", "opacity": "1" }, + "100%": { "height": "0", "opacity": "0" } + }, + "dialog-open": { + "0%": { "transform": "translate(-50%, -48%) scale(0.96)", "opacity": "0" }, + "100%": { "transform": "translate(-50%, -50%) scale(1)", "opacity": "1" } + }, + "dialog-close": { + "0%": { "transform": "translate(-50%, -50%) scale(1)", "opacity": "1" }, + "100%": { "transform": "translate(-50%, -48%) scale(0.96)", "opacity": "0" } + }, + "dropdown-open": { + "0%": { "transform": "scale(0.95) translateY(-4px)", "opacity": "0" }, + "100%": { "transform": "scale(1) translateY(0)", "opacity": "1" } + }, + "dropdown-close": { + "0%": { "transform": "scale(1) translateY(0)", "opacity": "1" }, + "100%": { "transform": "scale(0.95) translateY(-4px)", "opacity": "0" } + }, + "toast-enter": { + "0%": { "transform": "translateX(100%)", "opacity": "0" }, + "100%": { "transform": "translateX(0)", "opacity": "1" } + }, + "toast-exit": { + "0%": { "transform": "translateX(0)", "opacity": "1" }, + "100%": { "transform": "translateX(100%)", "opacity": "0" } + }, + "spin": { + "0%": { "transform": "rotate(0deg)" }, + "100%": { "transform": "rotate(360deg)" } + }, + "pulse": { + "0%, 100%": { "opacity": "1" }, + "50%": { "opacity": "0.5" } } }, "interactions": { "button-hover": { "property": "background-color, transform", - "duration": "var(--duration-fast)", - "easing": "var(--easing-ease-out)" + "duration": "{duration.fast}", + "easing": "{easing.ease-out}" + }, + "button-active": { + "property": "transform", + "duration": "{duration.instant}", + "easing": "{easing.ease-in}" }, "card-hover": { "property": "box-shadow, transform", - "duration": "var(--duration-normal)", - "easing": "var(--easing-ease-in-out)" + "duration": "{duration.normal}", + "easing": "{easing.ease-in-out}" + }, + "input-focus": { + "property": "border-color, box-shadow", + "duration": "{duration.fast}", + "easing": "{easing.ease-out}" + }, + "dropdown-toggle": { + "property": "opacity, transform", + "duration": "{duration.fast}", + "easing": "{easing.ease-out}" + }, + "accordion-toggle": { + "property": "height, opacity", + "duration": "{duration.normal}", + "easing": "{easing.ease-in-out}" + }, + "dialog-toggle": { + "property": "opacity, transform", + "duration": "{duration.normal}", + "easing": "{easing.spring}" + }, + "tabs-switch": { + "property": "color, border-color", + "duration": "{duration.fast}", + "easing": "{easing.ease-in-out}" } }, "transitions": { - "default": "all var(--duration-normal) var(--easing-ease-in-out)", - "colors": "color var(--duration-fast) var(--easing-linear), background-color var(--duration-fast) var(--easing-linear)", - "transform": "transform var(--duration-normal) var(--easing-spring)" + "default": { + "$value": "all {duration.normal} {easing.ease-in-out}" + }, + "colors": { + "$value": "color {duration.fast} {easing.linear}, background-color {duration.fast} {easing.linear}" + }, + "transform": { + "$value": "transform {duration.normal} {easing.spring}" + }, + "opacity": { + "$value": "opacity {duration.fast} {easing.linear}" + }, + "all-smooth": { + "$value": "all {duration.slow} {easing.ease-in-out}" + } + }, + "component_animations": { + "button": { + "hover": { "animation": "none", "transition": "{interactions.button-hover}" }, + "active": { "animation": "none", "transition": "{interactions.button-active}" } + }, + "card": { + "hover": { "animation": "none", "transition": "{interactions.card-hover}" } + }, + "input": { + "focus": { "animation": "none", "transition": "{interactions.input-focus}" } + }, + "dialog": { + "open": { "animation": "dialog-open {duration.normal} {easing.spring}" }, + "close": { "animation": "dialog-close {duration.normal} {easing.ease-in}" } + }, + "dropdown": { + "open": { "animation": "dropdown-open {duration.fast} {easing.ease-out}" }, + "close": { "animation": "dropdown-close {duration.fast} {easing.ease-in}" } + }, + "toast": { + "enter": { "animation": "toast-enter {duration.normal} {easing.ease-out}" }, + "exit": { "animation": "toast-exit {duration.normal} {easing.ease-in}" } + }, + "accordion": { + "open": { "animation": "accordion-down {duration.normal} {easing.ease-out}" }, + "close": { "animation": "accordion-up {duration.normal} {easing.ease-in}" } + } }, "accessibility": { "prefers_reduced_motion": { "duration": "0ms", "keyframes": {}, - "note": "Disable animations when user prefers reduced motion" + "note": "Disable animations when user prefers reduced motion", + "css_rule": "@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } }" } }, "_metadata": { @@ -584,13 +1430,23 @@ body { ``` **Field Rules**: -- duration values MUST use ms units -- easing MUST use standard CSS easing keywords or cubic-bezier() -- keyframes MUST use percentage-based keyframe syntax -- interactions MUST reference duration and easing using var() placeholders -- accessibility.prefers_reduced_motion MUST be included +- $schema MUST reference W3C Design Tokens format specification +- All duration values MUST use $value wrapper with ms units +- All easing values MUST use $value wrapper with standard CSS easing or cubic-bezier() +- keyframes MUST define complete component state animations (open/close, enter/exit) +- interactions MUST reference duration and easing using {token.path} syntax +- component_animations MUST map component states to specific keyframes and transitions +- component_animations MUST be defined for all interactive and stateful components +- transitions MUST use $value wrapper for complete transition definitions +- accessibility.prefers_reduced_motion MUST be included with CSS media query rule - _metadata.code_snippets ONLY present in Code Import mode +**Animation-Component Integration**: +- Each component in design-tokens.json component section MUST have corresponding entry in component_animations +- State-based animations (dialog.open, accordion.close) MUST use keyframe animations +- Interaction animations (button.hover, input.focus) MUST use transitions +- All animation references use {token.path} syntax for consistency + **Common Metadata Rules** (All Files): - `source` field values: `code-import` (from source code) | `explore` (from visual references) | `text` (from prompts) - `code_snippets` array ONLY present when source = `code-import` @@ -676,11 +1532,47 @@ mcp__exa__get_code_context_exa( ### Validation Checks -**Design Token Completeness**: ✅ All required categories | ✅ Semantic naming | ✅ OKLCH colors | ✅ Font fallback stacks | ✅ Systematic spacing +**W3C Format Compliance**: +- ✅ $schema field present in all token files +- ✅ All tokens use $type metadata +- ✅ All color tokens use $value with light/dark modes +- ✅ All duration/easing tokens use $value wrapper -**Accessibility**: ✅ WCAG AA contrast ratios | ✅ Heading hierarchy | ✅ Landmark roles | ✅ ARIA attributes | ✅ Keyboard navigation +**Design Token Completeness**: +- ✅ All required color categories defined (background, foreground, card, border, input, ring) +- ✅ Interactive color states defined (default, hover, active, disabled) for primary, secondary, accent, destructive +- ✅ Component definitions for all UI elements (button, card, input, dialog, dropdown, toast, accordion, tabs, switch, checkbox, badge, alert) +- ✅ Elevation z-index values defined for layered components +- ✅ OKLCH color format for all color values +- ✅ Font fallback stacks for all typography families +- ✅ Systematic spacing scale (multiples of base unit) -**CSS Token Usage**: ✅ Extract all var() references | ✅ Verify all exist in design-tokens.json | ✅ Flag hardcoded values | ✅ 100% token coverage +**Component State Coverage**: +- ✅ Interactive components define: default, hover, focus, active, disabled states +- ✅ Stateful components define state-based animations +- ✅ All components reference tokens via {token.path} syntax (no hardcoded values) +- ✅ Component animations map to keyframes in animation-tokens.json + +**Accessibility**: +- ✅ WCAG AA contrast ratios (4.5:1 text, 3:1 UI components) +- ✅ Semantic HTML5 tags (header, nav, main, section, article) +- ✅ Heading hierarchy (h1-h6 proper nesting) +- ✅ Landmark roles and ARIA attributes +- ✅ Keyboard navigation support +- ✅ Focus states with visible indicators (outline, ring) +- ✅ prefers-reduced-motion media query in animation-tokens.json + +**Token Reference Integrity**: +- ✅ All {token.path} references resolve to defined tokens +- ✅ No circular references in token definitions +- ✅ Nested references properly resolved (e.g., component referencing other component) +- ✅ No hardcoded values in component definitions + +**Layout Structure Optimization**: +- ✅ No redundancy between structure and styling +- ✅ Layout properties co-located with DOM elements +- ✅ Responsive overrides define only changed properties +- ✅ Single source of truth for each element ### Error Recovery @@ -694,11 +1586,17 @@ mcp__exa__get_code_context_exa( ### ALWAYS +**W3C Format Compliance**: ✅ Include $schema in all token files | ✅ Use $type metadata for all tokens | ✅ Use $value wrapper for color (light/dark), duration, easing | ✅ Validate token structure against W3C spec + **Pattern Recognition**: ✅ Identify pattern from [TASK_TYPE_IDENTIFIER] first | ✅ Apply pattern-specific execution rules | ✅ Follow autonomy level **File Writing** (PRIMARY): ✅ Use Write() tool immediately after generation | ✅ Write incrementally (one variant/target at a time) | ✅ Verify each operation | ✅ Use EXACT paths from prompt -**Quality Standards**: ✅ WCAG AA, OKLCH, semantic naming | ✅ Google Fonts with fallbacks | ✅ Mobile-first responsive | ✅ Semantic HTML5 + ARIA | ✅ MCP research (Pattern 1 & Pattern 2 Explore mode) | ✅ Record code snippets (Code Import mode) +**Component State Coverage**: ✅ Define all interaction states (default, hover, focus, active, disabled) | ✅ Map component animations to keyframes | ✅ Use {token.path} syntax for all references | ✅ Validate token reference integrity + +**Quality Standards**: ✅ WCAG AA (4.5:1 text, 3:1 UI) | ✅ OKLCH color format | ✅ Semantic naming | ✅ Google Fonts with fallbacks | ✅ Mobile-first responsive | ✅ Semantic HTML5 + ARIA | ✅ MCP research (Pattern 1 & Pattern 2 Explore mode) | ✅ Record code snippets (Code Import mode) + +**Structure Optimization**: ✅ Co-locate DOM and layout properties (layout-templates.json) | ✅ Eliminate redundancy (no duplicate definitions) | ✅ Single source of truth for each element | ✅ Responsive overrides define only changed properties **Target Independence**: ✅ Process EXACTLY ONE target per task | ✅ Keep standalone and reusable | ✅ Verify no cross-contamination @@ -708,4 +1606,10 @@ mcp__exa__get_code_context_exa( **Task Execution**: ❌ Mix multiple targets | ❌ Make design decisions in Pattern 3 | ❌ Skip pattern identification | ❌ Interact with user | ❌ Return MCP research as files -**Quality Violations**: ❌ Hardcoded values instead of tokens | ❌ Non-OKLCH colors | ❌ Skip WCAG validation | ❌ Omit Google Fonts imports | ❌ Incomplete systems +**Format Violations**: ❌ Omit $schema field | ❌ Omit $type metadata | ❌ Use raw values instead of $value wrapper | ❌ Use var() instead of {token.path} in JSON + +**Component Violations**: ❌ Use CSS class strings instead of structured objects | ❌ Omit component states (hover, focus, disabled) | ❌ Hardcoded values instead of token references | ❌ Missing animation mappings for stateful components + +**Quality Violations**: ❌ Non-OKLCH colors | ❌ Skip WCAG validation | ❌ Omit Google Fonts imports | ❌ Duplicate definitions (redundancy) | ❌ Incomplete component library + +**Structure Violations**: ❌ Separate dom_structure and css_layout_rules | ❌ Repeat unchanged properties in responsive overrides | ❌ Include visual styling in layout definitions | ❌ Create circular token references