omnidesign 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/QUICKREF.md +150 -0
  3. package/README.md +576 -0
  4. package/bin/cli.js +390 -0
  5. package/bin/detect-ide.js +50 -0
  6. package/bin/install.js +8 -0
  7. package/logo.jpg +0 -0
  8. package/package.json +84 -0
  9. package/recipes/components/README.md +29 -0
  10. package/recipes/components/agent-card.md +314 -0
  11. package/recipes/components/ai-chat.md +252 -0
  12. package/recipes/components/bento-grid.md +186 -0
  13. package/recipes/components/code-block.md +503 -0
  14. package/recipes/components/file-upload.md +483 -0
  15. package/recipes/components/forms.md +238 -0
  16. package/recipes/components/hero-section.md +161 -0
  17. package/recipes/components/navbar.md +214 -0
  18. package/recipes/components/prompt-input.md +293 -0
  19. package/recipes/components/thinking-indicator.md +372 -0
  20. package/recipes/motion/README.md +3 -0
  21. package/recipes/motion/motion-system.md +437 -0
  22. package/recipes/patterns/README.md +3 -0
  23. package/skills/aider/omnidesign.md +67 -0
  24. package/skills/amp/SKILL.md +114 -0
  25. package/skills/antigravity/SKILL.md +114 -0
  26. package/skills/claude/omnidesign.md +111 -0
  27. package/skills/continue/omnidesign.yaml +29 -0
  28. package/skills/cursor/omnidesign.md +110 -0
  29. package/skills/kilo/SKILL.md +114 -0
  30. package/skills/opencode/omnidesign.md +110 -0
  31. package/skills/vscode/package.json +66 -0
  32. package/skills/zed/omnidesign.json +7 -0
  33. package/tokens/motion/README.md +3 -0
  34. package/tokens/primitives/README.md +3 -0
  35. package/tokens/primitives/color.json +219 -0
  36. package/tokens/primitives/motion.json +56 -0
  37. package/tokens/primitives/radii.json +37 -0
  38. package/tokens/primitives/shadows.json +34 -0
  39. package/tokens/primitives/spacing.json +67 -0
  40. package/tokens/primitives/typography.json +127 -0
  41. package/tokens/semantic/README.md +3 -0
  42. package/tokens/semantic/color.json +114 -0
  43. package/tokens/semantic/motion.json +44 -0
  44. package/tokens/semantic/radii.json +29 -0
  45. package/tokens/semantic/shadows.json +24 -0
  46. package/tokens/semantic/spacing.json +69 -0
  47. package/tokens/semantic/typography.json +118 -0
  48. package/tokens/shadows/README.md +3 -0
  49. package/tokens/themes/README.md +3 -0
  50. package/tokens/themes/berry.json +143 -0
  51. package/tokens/themes/brutalist.json +143 -0
  52. package/tokens/themes/coral.json +143 -0
  53. package/tokens/themes/corporate.json +143 -0
  54. package/tokens/themes/cream.json +143 -0
  55. package/tokens/themes/cyberpunk.json +143 -0
  56. package/tokens/themes/daylight.json +143 -0
  57. package/tokens/themes/deep-space.json +143 -0
  58. package/tokens/themes/forest.json +143 -0
  59. package/tokens/themes/graphite.json +143 -0
  60. package/tokens/themes/lavender.json +143 -0
  61. package/tokens/themes/midnight.json +143 -0
  62. package/tokens/themes/mint.json +143 -0
  63. package/tokens/themes/navy.json +143 -0
  64. package/tokens/themes/noir.json +143 -0
  65. package/tokens/themes/obsidian.json +143 -0
  66. package/tokens/themes/ocean.json +143 -0
  67. package/tokens/themes/paper.json +143 -0
  68. package/tokens/themes/ruby.json +143 -0
  69. package/tokens/themes/slate.json +143 -0
  70. package/tokens/themes/snow.json +143 -0
  71. package/tokens/themes/solar.json +143 -0
  72. package/tokens/themes/spring.json +143 -0
  73. package/tokens/themes/starry-night.json +143 -0
  74. package/tokens/themes/sunset.json +143 -0
  75. package/tokens/typography/FONT_GUIDE.md +381 -0
  76. package/tokens/typography/README.md +37 -0
  77. package/tokens/typography/font-collection.json +221 -0
@@ -0,0 +1,293 @@
1
+ # AI Prompt Input
2
+
3
+ Smart input component with prompt suggestions, templates, and autocomplete.
4
+
5
+ ## When to Use
6
+ - AI image generation interfaces (Midjourney, DALL-E)
7
+ - Prompt engineering tools
8
+ - AI writing assistants
9
+ - Command palettes with AI
10
+
11
+ ## Anatomy
12
+
13
+ ```
14
+ ┌─────────────────────────────────────────────────────────────┐
15
+ │ PromptInput │
16
+ │ ├─ PromptField (textarea with expanding height) │
17
+ │ ├─ PromptToolbar (template buttons, modifiers) │
18
+ │ ├─ SuggestionsDropdown (autocomplete, history) │
19
+ │ ├─ TokenCounter (remaining tokens / cost estimate) │
20
+ │ └─ PromptExamples (preset prompts below input) │
21
+ └─────────────────────────────────────────────────────────────┘
22
+ ```
23
+
24
+ ## Token Usage
25
+
26
+ ```css
27
+ /* Main Input */
28
+ .prompt-input {
29
+ background: var(--color-surface-raised);
30
+ border: 2px solid var(--color-border-default);
31
+ border-radius: var(--radius-xl);
32
+ padding: var(--spacing-md);
33
+ transition: border-color var(--duration-fast);
34
+ }
35
+
36
+ .prompt-input:focus-within {
37
+ border-color: var(--color-interactive-primary);
38
+ box-shadow: var(--shadow-focus);
39
+ }
40
+
41
+ /* Textarea */
42
+ .prompt-textarea {
43
+ background: transparent;
44
+ border: none;
45
+ color: var(--color-text-default);
46
+ font-family: var(--font-sans);
47
+ font-size: var(--font-size-base);
48
+ line-height: var(--line-height-relaxed);
49
+ resize: none;
50
+ min-height: 3rem;
51
+ max-height: 20rem;
52
+ }
53
+
54
+ /* Suggestions Dropdown */
55
+ .suggestions {
56
+ background: var(--color-surface-raised);
57
+ border: 1px solid var(--color-border-default);
58
+ border-radius: var(--radius-lg);
59
+ box-shadow: var(--shadow-dropdown);
60
+ max-height: 300px;
61
+ overflow-y: auto;
62
+ }
63
+
64
+ .suggestion-item {
65
+ padding: var(--spacing-sm) var(--spacing-md);
66
+ cursor: pointer;
67
+ }
68
+
69
+ .suggestion-item:hover,
70
+ .suggestion-item[aria-selected="true"] {
71
+ background: var(--color-surface-sunken);
72
+ }
73
+
74
+ /* Token Counter */
75
+ .token-counter {
76
+ font-family: var(--font-mono);
77
+ font-size: var(--font-size-xs);
78
+ color: var(--color-text-muted);
79
+ }
80
+
81
+ .token-counter.warning {
82
+ color: var(--color-status-warning);
83
+ }
84
+
85
+ .token-counter.error {
86
+ color: var(--color-status-error);
87
+ }
88
+
89
+ /* Modifier Tags */
90
+ .modifier-tag {
91
+ background: var(--color-surface-sunken);
92
+ border: 1px solid var(--color-border-default);
93
+ border-radius: var(--radius-full);
94
+ padding: var(--spacing-2xs) var(--spacing-sm);
95
+ font-size: var(--font-size-xs);
96
+ font-family: var(--font-mono);
97
+ cursor: pointer;
98
+ }
99
+
100
+ .modifier-tag:hover {
101
+ background: var(--color-interactive-primary);
102
+ color: var(--color-text-inverted);
103
+ border-color: var(--color-interactive-primary);
104
+ }
105
+ ```
106
+
107
+ ## State Matrix
108
+
109
+ | Element | Default | Focus | Hover | Active | Disabled |
110
+ |---------|---------|-------|-------|--------|----------|
111
+ | Input Container | border-default | border-primary + shadow-focus | - | - | opacity-50 |
112
+ | Suggestion | transparent | selected bg | sunken bg | - | - |
113
+ | Modifier Tag | sunken bg | - | primary bg | - | - |
114
+ | Token Counter | muted | - | - | - | - |
115
+ | Generate Button | primary | primary-hover | - | pressed | - |
116
+
117
+ ## Accessibility
118
+
119
+ ```html
120
+ <div role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-controls="suggestions-list">
121
+ <textarea
122
+ role="textbox"
123
+ aria-autocomplete="list"
124
+ aria-controls="suggestions-list"
125
+ aria-activedescendant=""
126
+ placeholder="Describe what you want to create..."
127
+ ></textarea>
128
+
129
+ <ul id="suggestions-list" role="listbox" aria-label="Prompt suggestions">
130
+ <li role="option" id="suggestion-1">A futuristic city...</li>
131
+ <li role="option" id="suggestion-2">A serene landscape...</li>
132
+ </ul>
133
+ </div>
134
+
135
+ <div aria-live="polite" aria-atomic="true" class="sr-only">
136
+ 50 tokens remaining
137
+ </div>
138
+ ```
139
+
140
+ ## Example: Image Generation Prompt
141
+
142
+ ```tsx
143
+ function ImagePromptInput({ onGenerate, maxTokens = 1000 }) {
144
+ const [prompt, setPrompt] = useState('');
145
+ const [tokens, setTokens] = useState(0);
146
+ const [showSuggestions, setShowSuggestions] = useState(false);
147
+
148
+ const modifiers = [
149
+ { label: '--ar 16:9', desc: 'Aspect ratio' },
150
+ { label: '--v 6', desc: 'Version 6' },
151
+ { label: '--style raw', desc: 'Raw style' },
152
+ { label: '--s 750', desc: 'Stylize' },
153
+ ];
154
+
155
+ return (
156
+ <div className="prompt-input-container">
157
+ <div className="prompt-input" onClick={() => textareaRef.current?.focus()}>
158
+ <textarea
159
+ ref={textareaRef}
160
+ value={prompt}
161
+ onChange={handleInputChange}
162
+ onFocus={() => setShowSuggestions(true)}
163
+ placeholder="A futuristic city at sunset, cyberpunk style, neon lights reflecting on wet streets..."
164
+ rows={3}
165
+ />
166
+
167
+ <div className="prompt-toolbar">
168
+ <div className="modifier-chips">
169
+ {modifiers.map(mod => (
170
+ <button
171
+ key={mod.label}
172
+ className="modifier-tag"
173
+ onClick={() => appendModifier(mod.label)}
174
+ title={mod.desc}
175
+ >
176
+ {mod.label}
177
+ </button>
178
+ ))}
179
+ </div>
180
+
181
+ <TokenCounter current={tokens} max={maxTokens} />
182
+ </div>
183
+ </div>
184
+
185
+ {showSuggestions && (
186
+ <SuggestionsDropdown
187
+ query={prompt}
188
+ onSelect={setPrompt}
189
+ onClose={() => setShowSuggestions(false)}
190
+ />
191
+ )}
192
+
193
+ <div className="prompt-examples">
194
+ <span className="label">Try:</span>
195
+ {EXAMPLE_PROMPTS.map(example => (
196
+ <button
197
+ key={example}
198
+ className="example-chip"
199
+ onClick={() => setPrompt(example)}
200
+ >
201
+ {example.slice(0, 40)}...
202
+ </button>
203
+ ))}
204
+ </div>
205
+
206
+ <button
207
+ className="generate-btn"
208
+ disabled={!prompt.trim() || tokens > maxTokens}
209
+ onClick={() => onGenerate(prompt)}
210
+ >
211
+ <SparklesIcon />
212
+ Generate Image
213
+ </button>
214
+ </div>
215
+ );
216
+ }
217
+
218
+ function TokenCounter({ current, max }) {
219
+ const percentage = (current / max) * 100;
220
+ const status = percentage > 90 ? 'error' : percentage > 70 ? 'warning' : '';
221
+
222
+ return (
223
+ <div className={`token-counter ${status}`}>
224
+ {current.toLocaleString()} / {max.toLocaleString()} tokens
225
+ {status === 'error' && ' (Limit exceeded)'}
226
+ </div>
227
+ );
228
+ }
229
+ ```
230
+
231
+ ## Example: Command Palette with AI
232
+
233
+ ```tsx
234
+ function AIPromptPalette({ isOpen, onClose, onExecute }) {
235
+ const [query, setQuery] = useState('');
236
+ const [suggestions, setSuggestions] = useState([]);
237
+
238
+ return (
239
+ <Modal isOpen={isOpen} onClose={onClose} className="prompt-palette">
240
+ <div className="palette-input">
241
+ <CommandIcon className="input-icon" />
242
+ <input
243
+ type="text"
244
+ value={query}
245
+ onChange={e => setQuery(e.target.value)}
246
+ placeholder="Ask AI to do something..."
247
+ autoFocus
248
+ />
249
+ <kbd className="shortcut">ESC</kbd>
250
+ </div>
251
+
252
+ <div className="palette-suggestions">
253
+ <section>
254
+ <header>AI Actions</header>
255
+ <SuggestionItem
256
+ icon={<GenerateIcon />}
257
+ title="Generate code"
258
+ subtitle="Create a React component"
259
+ onClick={() => onExecute('generate', query)}
260
+ />
261
+ <SuggestionItem
262
+ icon={<ExplainIcon />}
263
+ title="Explain this"
264
+ subtitle="Explain the selected code"
265
+ onClick={() => onExecute('explain', query)}
266
+ />
267
+ </section>
268
+
269
+ <section>
270
+ <header>Recent Prompts</header>
271
+ {recentPrompts.map(prompt => (
272
+ <SuggestionItem
273
+ key={prompt.id}
274
+ icon={<HistoryIcon />}
275
+ title={prompt.text}
276
+ onClick={() => onExecute('repeat', prompt.text)}
277
+ />
278
+ ))}
279
+ </section>
280
+ </div>
281
+ </Modal>
282
+ );
283
+ }
284
+ ```
285
+
286
+ ## Tokens Used
287
+
288
+ - **color**: surface-raised, surface-sunken, interactive-primary, text-default, text-inverted, text-muted, border-default, status-warning, status-error
289
+ - **spacing**: 2xs, sm, md
290
+ - **radii**: full, lg, xl
291
+ - **shadow**: focus, dropdown
292
+ - **typography**: font-sans, font-mono, size-xs, size-base
293
+ - **motion**: duration-fast
@@ -0,0 +1,372 @@
1
+ # Streaming/Thinking Indicator
2
+
3
+ Visual feedback for AI processing, streaming responses, and loading states.
4
+
5
+ ## When to Use
6
+ - AI is generating a response
7
+ - Processing user input
8
+ - Loading model outputs
9
+ - File upload/processing
10
+ - Multi-step AI workflows
11
+
12
+ ## Anatomy
13
+
14
+ ```
15
+ ┌─────────────────────────────────────────────────────────────┐
16
+ │ ThinkingIndicator │
17
+ │ ├─ Container (message bubble or inline) │
18
+ │ ├─ Avatar/Icon (AI avatar or status icon) │
19
+ │ ├─ Animation (dots, wave, pulse, shimmer) │
20
+ │ ├─ Status Text (optional: "Thinking...", "Processing") │
21
+ │ └─ Cancel Action (optional: stop generation) │
22
+ └─────────────────────────────────────────────────────────────┘
23
+ ```
24
+
25
+ ## Token Usage
26
+
27
+ ```css
28
+ /* Base Container */
29
+ .thinking-indicator {
30
+ display: flex;
31
+ align-items: center;
32
+ gap: var(--spacing-sm);
33
+ padding: var(--spacing-md);
34
+ color: var(--color-text-muted);
35
+ font-size: var(--font-size-sm);
36
+ }
37
+
38
+ /* Message Bubble Style */
39
+ .thinking-bubble {
40
+ background: var(--color-surface-raised);
41
+ border: 1px solid var(--color-border-default);
42
+ border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) var(--radius-sm);
43
+ padding: var(--spacing-card-padding);
44
+ max-width: 80%;
45
+ }
46
+
47
+ /* Inline Style */
48
+ .thinking-inline {
49
+ display: inline-flex;
50
+ align-items: center;
51
+ gap: var(--spacing-xs);
52
+ margin-left: var(--spacing-xs);
53
+ }
54
+
55
+ /* Dots Animation */
56
+ .thinking-dots {
57
+ display: flex;
58
+ gap: 4px;
59
+ }
60
+
61
+ .thinking-dots span {
62
+ width: 8px;
63
+ height: 8px;
64
+ background: var(--color-interactive-primary);
65
+ border-radius: var(--radius-full);
66
+ animation: bounce 1.4s ease-in-out infinite both;
67
+ }
68
+
69
+ .thinking-dots span:nth-child(1) { animation-delay: -0.32s; }
70
+ .thinking-dots span:nth-child(2) { animation-delay: -0.16s; }
71
+ .thinking-dots span:nth-child(3) { animation-delay: 0s; }
72
+
73
+ @keyframes bounce {
74
+ 0%, 80%, 100% { transform: scale(0); }
75
+ 40% { transform: scale(1); }
76
+ }
77
+
78
+ /* Wave Animation */
79
+ .thinking-wave {
80
+ display: flex;
81
+ align-items: center;
82
+ gap: 3px;
83
+ height: 20px;
84
+ }
85
+
86
+ .thinking-wave span {
87
+ width: 3px;
88
+ background: var(--color-interactive-primary);
89
+ border-radius: var(--radius-full);
90
+ animation: wave 1.2s ease-in-out infinite;
91
+ }
92
+
93
+ .thinking-wave span:nth-child(1) { height: 8px; animation-delay: -0.4s; }
94
+ .thinking-wave span:nth-child(2) { height: 12px; animation-delay: -0.3s; }
95
+ .thinking-wave span:nth-child(3) { height: 16px; animation-delay: -0.2s; }
96
+ .thinking-wave span:nth-child(4) { height: 12px; animation-delay: -0.1s; }
97
+ .thinking-wave span:nth-child(5) { height: 8px; animation-delay: 0s; }
98
+
99
+ @keyframes wave {
100
+ 0%, 100% { transform: scaleY(0.5); }
101
+ 50% { transform: scaleY(1); }
102
+ }
103
+
104
+ /* Pulse Ring */
105
+ .thinking-pulse {
106
+ position: relative;
107
+ width: 40px;
108
+ height: 40px;
109
+ }
110
+
111
+ .thinking-pulse::before,
112
+ .thinking-pulse::after {
113
+ content: '';
114
+ position: absolute;
115
+ inset: 0;
116
+ border-radius: var(--radius-full);
117
+ background: var(--color-interactive-primary);
118
+ opacity: 0.6;
119
+ animation: pulse-ring 2s cubic-bezier(0, 0.2, 0.8, 1) infinite;
120
+ }
121
+
122
+ .thinking-pulse::after {
123
+ animation-delay: 1s;
124
+ }
125
+
126
+ @keyframes pulse-ring {
127
+ 0% { transform: scale(0.8); opacity: 1; }
128
+ 100% { transform: scale(2); opacity: 0; }
129
+ }
130
+
131
+ /* Shimmer Effect */
132
+ .thinking-shimmer {
133
+ background: linear-gradient(
134
+ 90deg,
135
+ var(--color-surface-sunken) 25%,
136
+ var(--color-surface-raised) 50%,
137
+ var(--color-surface-sunken) 75%
138
+ );
139
+ background-size: 200% 100%;
140
+ border-radius: var(--radius-md);
141
+ animation: shimmer 1.5s infinite;
142
+ }
143
+
144
+ @keyframes shimmer {
145
+ 0% { background-position: 200% 0; }
146
+ 100% { background-position: -200% 0; }
147
+ }
148
+
149
+ /* Progress Steps */
150
+ .progress-steps {
151
+ display: flex;
152
+ gap: var(--spacing-sm);
153
+ }
154
+
155
+ .progress-step {
156
+ display: flex;
157
+ align-items: center;
158
+ gap: var(--spacing-xs);
159
+ padding: var(--spacing-xs) var(--spacing-sm);
160
+ border-radius: var(--radius-full);
161
+ font-size: var(--font-size-xs);
162
+ background: var(--color-surface-sunken);
163
+ color: var(--color-text-muted);
164
+ transition: all var(--duration-fast);
165
+ }
166
+
167
+ .progress-step.active {
168
+ background: rgba(37, 99, 235, 0.15);
169
+ color: var(--color-interactive-primary);
170
+ }
171
+
172
+ .progress-step.completed {
173
+ background: rgba(34, 197, 94, 0.15);
174
+ color: #22C55E;
175
+ }
176
+
177
+ .progress-step-icon {
178
+ width: 16px;
179
+ height: 16px;
180
+ }
181
+
182
+ /* Cancel Button */
183
+ .cancel-btn {
184
+ display: flex;
185
+ align-items: center;
186
+ gap: var(--spacing-xs);
187
+ padding: var(--spacing-xs) var(--spacing-sm);
188
+ background: var(--color-surface-sunken);
189
+ border: 1px solid var(--color-border-default);
190
+ border-radius: var(--radius-md);
191
+ font-size: var(--font-size-xs);
192
+ color: var(--color-text-muted);
193
+ cursor: pointer;
194
+ transition: all var(--duration-fast);
195
+ }
196
+
197
+ .cancel-btn:hover {
198
+ background: rgba(239, 68, 68, 0.1);
199
+ border-color: rgba(239, 68, 68, 0.3);
200
+ color: var(--color-status-error);
201
+ }
202
+ ```
203
+
204
+ ## State Matrix
205
+
206
+ | Element | Default | Active | Completed | Error |
207
+ |---------|---------|--------|-----------|-------|
208
+ | Dots | bounce animation | - | fade out | - |
209
+ | Wave | wave animation | - | fade out | - |
210
+ | Pulse | pulse-ring | - | - | - |
211
+ | Progress Step | muted | primary bg | green | red |
212
+ | Cancel Button | ghost | hover red | - | - |
213
+
214
+ ## Accessibility
215
+
216
+ ```html
217
+ <!-- Screen reader announcements -->
218
+ <div aria-live="polite" aria-atomic="true" class="sr-only">
219
+ Assistant is thinking
220
+ </div>
221
+
222
+ <div role="status" aria-label="AI is processing your request">
223
+ <div class="thinking-dots" aria-hidden="true">
224
+ <span></span><span></span><span></span>
225
+ </div>
226
+ <span class="sr-only">Thinking</span>
227
+ </div>
228
+
229
+ <!-- Progress with steps -->
230
+ <div role="progressbar" aria-valuemin="0" aria-valuemax="3" aria-valuenow="2" aria-label="Processing steps">
231
+ <div class="progress-steps">
232
+ <div class="progress-step completed" aria-label="Step 1: Analyzing request, completed">
233
+ <CheckIcon /> Analyzing
234
+ </div>
235
+ <div class="progress-step active" aria-label="Step 2: Generating response, in progress">
236
+ <Spinner /> Generating
237
+ </div>
238
+ <div class="progress-step" aria-label="Step 3: Formatting output, pending">
239
+ Formatting
240
+ </div>
241
+ </div>
242
+ </div>
243
+ ```
244
+
245
+ ## Example: Chat Thinking State
246
+
247
+ ```tsx
248
+ function ChatThinking({ onCancel }) {
249
+ return (
250
+ <article className="thinking-bubble" aria-live="polite">
251
+ <div className="thinking-indicator">
252
+ <AIAvatar className="avatar-small" />
253
+
254
+ <div className="thinking-dots" aria-hidden="true">
255
+ <span></span>
256
+ <span></span>
257
+ <span></span>
258
+ </div>
259
+
260
+ <span className="sr-only">Assistant is thinking</span>
261
+
262
+ {onCancel && (
263
+ <button
264
+ className="cancel-btn"
265
+ onClick={onCancel}
266
+ aria-label="Stop generating"
267
+ >
268
+ <StopIcon />
269
+ Stop
270
+ </button>
271
+ )}
272
+ </div>
273
+ </article>
274
+ );
275
+ }
276
+ ```
277
+
278
+ ## Example: Multi-Step Processing
279
+
280
+ ```tsx
281
+ function ProcessingSteps({ steps, currentStep }) {
282
+ return (
283
+ <div className="processing-indicator">
284
+ <div className="progress-steps">
285
+ {steps.map((step, index) => {
286
+ const isCompleted = index < currentStep;
287
+ const isActive = index === currentStep;
288
+
289
+ return (
290
+ <div
291
+ key={step.id}
292
+ className={`progress-step ${isActive ? 'active' : ''} ${isCompleted ? 'completed' : ''}`}
293
+ aria-current={isActive ? 'step' : undefined}
294
+ >
295
+ {isCompleted ? (
296
+ <CheckIcon className="progress-step-icon" />
297
+ ) : isActive ? (
298
+ <Spinner className="progress-step-icon" />
299
+ ) : (
300
+ <span className="step-number">{index + 1}</span>
301
+ )}
302
+ <span>{step.label}</span>
303
+ </div>
304
+ );
305
+ })}
306
+ </div>
307
+
308
+ {currentStep < steps.length && (
309
+ <p className="current-step-description">
310
+ {steps[currentStep].description}
311
+ </p>
312
+ )}
313
+ </div>
314
+ );
315
+ }
316
+
317
+ // Usage
318
+ const steps = [
319
+ { id: 'analyze', label: 'Analyzing', description: 'Understanding your request...' },
320
+ { id: 'search', label: 'Searching', description: 'Finding relevant information...' },
321
+ { id: 'generate', label: 'Generating', description: 'Creating your response...' },
322
+ ];
323
+
324
+ <ProcessingSteps steps={steps} currentStep={1} />
325
+ ```
326
+
327
+ ## Example: Inline Typing Indicator
328
+
329
+ ```tsx
330
+ function InlineThinking() {
331
+ return (
332
+ <span className="thinking-inline" role="status" aria-label="AI is typing">
333
+ <span className="thinking-wave" aria-hidden="true">
334
+ <span></span>
335
+ <span></span>
336
+ <span></span>
337
+ <span></span>
338
+ <span></span>
339
+ </span>
340
+ </span>
341
+ );
342
+ }
343
+ ```
344
+
345
+ ## Example: Skeleton Loading for AI
346
+
347
+ ```tsx
348
+ function MessageSkeleton() {
349
+ return (
350
+ <div className="message-skeleton" aria-busy="true" aria-label="Loading message">
351
+ <div className="skeleton-header">
352
+ <div className="thinking-shimmer avatar-skeleton"></div>
353
+ <div className="thinking-shimmer name-skeleton"></div>
354
+ </div>
355
+
356
+ <div className="skeleton-content">
357
+ <div className="thinking-shimmer line-skeleton" style={{ width: '90%' }}></div>
358
+ <div className="thinking-shimmer line-skeleton" style={{ width: '75%' }}></div>
359
+ <div className="thinking-shimmer line-skeleton" style={{ width: '60%' }}></div>
360
+ </div>
361
+ </div>
362
+ );
363
+ }
364
+ ```
365
+
366
+ ## Tokens Used
367
+
368
+ - **color**: surface-raised, surface-sunken, interactive-primary, text-muted, status-error, status-success
369
+ - **spacing**: xs, sm, md, card-padding
370
+ - **radii**: full, md, lg
371
+ - **typography**: size-xs, size-sm
372
+ - **motion**: duration-fast
@@ -0,0 +1,3 @@
1
+ # Motion
2
+
3
+ Animation pattern recipes and implementation guides. These document common motion patterns like page transitions and micro-interactions.