@whykusanagi/corrupted-theme 0.1.1 → 0.1.3

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 (52) hide show
  1. package/CHANGELOG.md +253 -0
  2. package/README.md +97 -7
  3. package/docs/CAPABILITIES.md +209 -0
  4. package/docs/CHARACTER_LEVEL_CORRUPTION.md +264 -0
  5. package/docs/COMPONENTS_REFERENCE.md +295 -8
  6. package/docs/CORRUPTION_PHRASES.md +529 -0
  7. package/docs/FUTURE_WORK.md +189 -0
  8. package/docs/IMPLEMENTATION_VALIDATION.md +401 -0
  9. package/docs/LLM_PROVIDERS.md +345 -0
  10. package/docs/PERSONALITY.md +128 -0
  11. package/docs/ROADMAP.md +266 -0
  12. package/docs/ROUTING.md +324 -0
  13. package/docs/STYLE_GUIDE.md +605 -0
  14. package/docs/brand/BRAND_OVERVIEW.md +413 -0
  15. package/docs/brand/COLOR_SYSTEM.md +583 -0
  16. package/docs/brand/DESIGN_TOKENS.md +1009 -0
  17. package/docs/brand/TRANSLATION_FAILURE_AESTHETIC.md +525 -0
  18. package/docs/brand/TYPOGRAPHY.md +624 -0
  19. package/docs/components/ANIMATION_GUIDELINES.md +901 -0
  20. package/docs/components/COMPONENT_LIBRARY.md +1061 -0
  21. package/docs/components/GLASSMORPHISM.md +602 -0
  22. package/docs/components/INTERACTIVE_STATES.md +766 -0
  23. package/docs/governance/CONTRIBUTION_GUIDELINES.md +593 -0
  24. package/docs/governance/DESIGN_SYSTEM_GOVERNANCE.md +451 -0
  25. package/docs/governance/VERSION_MANAGEMENT.md +447 -0
  26. package/docs/governance/VERSION_REFERENCES.md +229 -0
  27. package/docs/platforms/CLI_IMPLEMENTATION.md +1025 -0
  28. package/docs/platforms/COMPONENT_MAPPING.md +579 -0
  29. package/docs/platforms/NPM_PACKAGE.md +854 -0
  30. package/docs/platforms/WEB_IMPLEMENTATION.md +1221 -0
  31. package/docs/standards/ACCESSIBILITY.md +715 -0
  32. package/docs/standards/ANTI_PATTERNS.md +554 -0
  33. package/docs/standards/SPACING_SYSTEM.md +549 -0
  34. package/examples/assets/celeste-avatar.png +0 -0
  35. package/examples/button.html +22 -10
  36. package/examples/card.html +22 -9
  37. package/examples/extensions-showcase.html +716 -0
  38. package/examples/form.html +22 -9
  39. package/examples/index.html +619 -396
  40. package/examples/layout.html +22 -8
  41. package/examples/nikke-team-builder.html +23 -9
  42. package/examples/showcase-complete.html +884 -28
  43. package/examples/showcase.html +21 -8
  44. package/package.json +14 -5
  45. package/src/css/components.css +676 -0
  46. package/src/css/extensions.css +933 -0
  47. package/src/css/theme.css +6 -74
  48. package/src/css/typography.css +5 -0
  49. package/src/lib/character-corruption.js +563 -0
  50. package/src/lib/components.js +283 -0
  51. package/src/lib/countdown-widget.js +609 -0
  52. package/src/lib/gallery.js +481 -0
@@ -0,0 +1,901 @@
1
+ # Animation Guidelines
2
+
3
+ > **Celeste Brand System** | Component Documentation
4
+ > **Document**: Animation Guidelines
5
+ > **Version**: 1.0.0
6
+ > **Last Updated**: 2025-12-13
7
+
8
+ ---
9
+
10
+ ## Table of Contents
11
+
12
+ 1. [Overview](#overview)
13
+ 2. [Core Principles](#core-principles)
14
+ 3. [Timing System](#timing-system)
15
+ 4. [Easing Functions](#easing-functions)
16
+ 5. [Animation Types](#animation-types)
17
+ 6. [Corruption Animations](#corruption-animations)
18
+ 7. [CLI Terminal Animations](#cli-terminal-animations)
19
+ 8. [Performance Guidelines](#performance-guidelines)
20
+ 9. [Accessibility](#accessibility)
21
+ 10. [Implementation Examples](#implementation-examples)
22
+
23
+ ---
24
+
25
+ ## Overview
26
+
27
+ Animation brings the Celeste brand to life while maintaining the **translation-failure corruption aesthetic**. All animations must balance premium polish with glitching imperfection, creating an authentic corrupted AI experience.
28
+
29
+ ### Animation Philosophy
30
+
31
+ - **Purposeful**: Every animation serves a functional or branding purpose
32
+ - **Performant**: 60fps minimum, GPU-accelerated when possible
33
+ - **Accessible**: Respects `prefers-reduced-motion` user preference
34
+ - **Corrupted**: Subtle glitches enhance brand identity without disrupting UX
35
+ - **Consistent**: Same timing/easing across platforms (web + CLI)
36
+
37
+ ---
38
+
39
+ ## Core Principles
40
+
41
+ ### 1. Speed Hierarchy
42
+
43
+ Animations must feel **fast but not rushed**, with three distinct speed tiers:
44
+
45
+ | Tier | Duration | Use Case | Example |
46
+ |------|----------|----------|---------|
47
+ | **Micro** | 150ms | Immediate feedback | Button hover, focus ring appearance |
48
+ | **Standard** | 300ms | Primary transitions | Card expansion, modal open/close |
49
+ | **Slow** | 500ms | Complex changes | Page transitions, layout shifts |
50
+
51
+ ### 2. Natural Motion
52
+
53
+ - **Ease-in-out** is the default easing (feels natural)
54
+ - **Avoid linear** easing (feels robotic except for loaders)
55
+ - **Custom curves** for brand-specific animations (corruption glitch, bounce)
56
+
57
+ ### 3. Layered Timing
58
+
59
+ When animating multiple properties, **stagger timing** to create depth:
60
+
61
+ ```css
62
+ /* Good: Staggered properties feel polished */
63
+ .card {
64
+ transition:
65
+ transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), /* Bounce first */
66
+ box-shadow 0.3s ease-out 0.05s, /* Shadow follows */
67
+ border-color 0.3s ease-out 0.1s; /* Border last */
68
+ }
69
+
70
+ /* Bad: Simultaneous properties feel flat */
71
+ .card {
72
+ transition: all 0.3s ease; /* Don't use 'all' */
73
+ }
74
+ ```
75
+
76
+ ### 4. Directional Consistency
77
+
78
+ - **Entrances**: Fade in + slide from direction of origin (300ms)
79
+ - **Exits**: Fade out + slide toward destination (200ms, 33% faster)
80
+ - **Exits are faster** than entrances (user already made decision)
81
+
82
+ ---
83
+
84
+ ## Timing System
85
+
86
+ ### Duration Scale
87
+
88
+ All durations are based on **multiples of 50ms** for consistency:
89
+
90
+ ```css
91
+ /* CSS Custom Properties */
92
+ :root {
93
+ /* Micro-interactions */
94
+ --duration-instant: 100ms; /* Hover color changes */
95
+ --duration-fast: 150ms; /* Focus indicators, tooltips */
96
+ --duration-quick: 200ms; /* Dropdown open, badge appear */
97
+
98
+ /* Standard transitions */
99
+ --duration-normal: 300ms; /* Modal open, card expand */
100
+ --duration-moderate: 400ms; /* Sidebar slide, toast enter */
101
+
102
+ /* Complex transitions */
103
+ --duration-slow: 500ms; /* Page transitions */
104
+ --duration-slower: 700ms; /* Full layout shifts */
105
+ --duration-slowest: 1000ms; /* Loading screens only */
106
+ }
107
+ ```
108
+
109
+ ### When to Use Each Duration
110
+
111
+ #### 100ms (Instant)
112
+ - Color changes on hover
113
+ - Background tint changes
114
+ - Icon color shifts
115
+
116
+ #### 150ms (Fast) ⭐ Default for micro-interactions
117
+ - Button hover states
118
+ - Focus ring appearance
119
+ - Small scale changes (1.0 → 1.05)
120
+ - Border color changes
121
+
122
+ #### 200ms (Quick)
123
+ - Dropdown menu open
124
+ - Tooltip appearance
125
+ - Badge/chip animations
126
+ - Small element exits
127
+
128
+ #### 300ms (Normal) ⭐ Default for standard transitions
129
+ - Modal/dialog open
130
+ - Card expansion
131
+ - Accordion open/close
132
+ - Tab switching
133
+ - Form field validation feedback
134
+
135
+ #### 400ms (Moderate)
136
+ - Sidebar slide in/out
137
+ - Toast notification enter
138
+ - Complex hover effects (multiple properties)
139
+ - Menu navigation transitions
140
+
141
+ #### 500ms (Slow)
142
+ - Page route transitions
143
+ - Full-screen overlay enter
144
+ - Large layout shifts
145
+ - Dashboard section transitions
146
+
147
+ #### 700ms+ (Slower)
148
+ - **Use sparingly** - Reserved for:
149
+ - Initial page load animations
150
+ - Loading screen transitions
151
+ - Full application state changes
152
+
153
+ ---
154
+
155
+ ## Easing Functions
156
+
157
+ ### Standard Easing Curves
158
+
159
+ ```css
160
+ :root {
161
+ /* Default easing (natural motion) */
162
+ --ease-default: ease; /* Browser default */
163
+ --ease-in-out: cubic-bezier(0.42, 0, 0.58, 1); /* Symmetric */
164
+
165
+ /* Directional easing */
166
+ --ease-in: cubic-bezier(0.42, 0, 1, 1); /* Starts slow */
167
+ --ease-out: cubic-bezier(0, 0, 0.58, 1); /* Ends slow */
168
+
169
+ /* Custom easing (brand-specific) */
170
+ --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1); /* Overshoot bounce */
171
+ --ease-snappy: cubic-bezier(0.16, 1, 0.3, 1); /* Fast start, smooth end */
172
+ --ease-glitch: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* Corrupted motion */
173
+ --ease-smooth: cubic-bezier(0.25, 0.1, 0.25, 1); /* Material Design */
174
+ }
175
+ ```
176
+
177
+ ### Easing Selection Guide
178
+
179
+ | Easing | Use Case | Visual Effect |
180
+ |--------|----------|---------------|
181
+ | `ease` | **Default** - Most transitions | Natural acceleration/deceleration |
182
+ | `ease-in-out` | Symmetric motion | Smooth start and end |
183
+ | `ease-out` | **Recommended for entrances** | Elements settle into place |
184
+ | `ease-in` | **Recommended for exits** | Elements accelerate away |
185
+ | `cubic-bezier(0.34, 1.56, 0.64, 1)` | **Bounce effect** (brand signature) | Playful overshoot (buttons, cards) |
186
+ | `cubic-bezier(0.68, -0.55, 0.27, 1.55)` | **Glitch effect** (corruption) | Erratic, corrupted motion |
187
+ | `linear` | Loading spinners, progress bars | Constant speed (no acceleration) |
188
+
189
+ ### When to Use Custom Easing
190
+
191
+ **Bounce (`--ease-bounce`)** - Signature Celeste animation:
192
+ - Button clicks (scale 1.0 → 0.98 → 1.0)
193
+ - Card hover interactions
194
+ - Badge/chip appearances
195
+ - Success state confirmations
196
+
197
+ **Glitch (`--ease-glitch`)** - Corruption aesthetic:
198
+ - Text scramble/corruption effects
199
+ - Error state transitions
200
+ - Eye flicker animations
201
+ - Translation-failure text changes
202
+
203
+ ---
204
+
205
+ ## Animation Types
206
+
207
+ ### 1. Transitions (Default)
208
+
209
+ Use CSS `transition` for simple state changes:
210
+
211
+ ```css
212
+ .btn {
213
+ /* Properties to animate | duration | easing | delay */
214
+ transition:
215
+ background-color 0.15s ease-out,
216
+ border-color 0.15s ease-out,
217
+ transform 0.15s cubic-bezier(0.34, 1.56, 0.64, 1),
218
+ box-shadow 0.2s ease-out 0.05s; /* Delayed shadow */
219
+ }
220
+
221
+ .btn:hover {
222
+ background-color: var(--color-accent-light);
223
+ border-color: rgba(217, 79, 144, 0.5);
224
+ transform: scale(1.05);
225
+ box-shadow: 0 0 20px rgba(217, 79, 144, 0.4);
226
+ }
227
+ ```
228
+
229
+ ### 2. Keyframe Animations
230
+
231
+ Use `@keyframes` for complex, looping, or multi-step animations:
232
+
233
+ ```css
234
+ /* Spinner (loading indicator) */
235
+ @keyframes spin {
236
+ from { transform: rotate(0deg); }
237
+ to { transform: rotate(360deg); }
238
+ }
239
+
240
+ .spinner {
241
+ animation: spin 1s linear infinite; /* Linear for constant rotation */
242
+ }
243
+
244
+ /* Pulse (attention-grabbing) */
245
+ @keyframes pulse {
246
+ 0%, 100% { opacity: 1; }
247
+ 50% { opacity: 0.5; }
248
+ }
249
+
250
+ .loading-badge {
251
+ animation: pulse 1.5s ease-in-out infinite;
252
+ }
253
+
254
+ /* Bounce in (entrance animation) */
255
+ @keyframes bounceIn {
256
+ 0% {
257
+ opacity: 0;
258
+ transform: scale(0.3) translateY(-20px);
259
+ }
260
+ 50% {
261
+ transform: scale(1.05); /* Overshoot */
262
+ }
263
+ 70% {
264
+ transform: scale(0.95); /* Settle */
265
+ }
266
+ 100% {
267
+ opacity: 1;
268
+ transform: scale(1) translateY(0);
269
+ }
270
+ }
271
+
272
+ .card-enter {
273
+ animation: bounceIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
274
+ }
275
+ ```
276
+
277
+ ### 3. Transform Animations
278
+
279
+ **CRITICAL**: Only animate GPU-accelerated properties for 60fps performance:
280
+
281
+ ✅ **Animate these** (GPU-accelerated):
282
+ - `transform: translate()` - Move elements
283
+ - `transform: scale()` - Size changes
284
+ - `transform: rotate()` - Rotation
285
+ - `opacity` - Fade in/out
286
+
287
+ ❌ **Never animate these** (CPU-bound, causes reflow):
288
+ - `width`, `height` - Use `scale()` instead
289
+ - `top`, `left`, `margin` - Use `translate()` instead
290
+ - `padding` - Pre-render different states
291
+ - `background-position` - Use `transform` on pseudo-element
292
+
293
+ ```css
294
+ /* Good: GPU-accelerated */
295
+ .card {
296
+ transition: transform 0.3s ease-out;
297
+ }
298
+ .card:hover {
299
+ transform: scale(1.02) translateY(-4px);
300
+ }
301
+
302
+ /* Bad: Causes reflow */
303
+ .card {
304
+ transition: width 0.3s ease-out, margin-top 0.3s ease-out;
305
+ }
306
+ .card:hover {
307
+ width: 320px;
308
+ margin-top: -4px;
309
+ }
310
+ ```
311
+
312
+ ---
313
+
314
+ ## Corruption Animations
315
+
316
+ ### Philosophy
317
+
318
+ Corruption animations are the **signature Celeste brand element**. They must:
319
+ - Be **subtle** (25-40% intensity) to maintain readability
320
+ - **Enhance, not disrupt** the user experience
321
+ - Follow the **translation-failure aesthetic** (character-level mixing, NOT leet speak)
322
+
323
+ ### Intensity Guidelines
324
+
325
+ | Intensity | Corruption % | Use Case |
326
+ |-----------|--------------|----------|
327
+ | **Minimal** | 15-20% | Body text, critical information |
328
+ | **Low** | 25-30% | Headers, non-critical labels |
329
+ | **Medium** | 35-40% | Decorative text, brand elements |
330
+ | **High** | 45-50% | Easter eggs, loading screens |
331
+ | **Extreme** | 50%+ | ⚠️ **Never use** - unreadable |
332
+
333
+ ### Text Corruption Animation
334
+
335
+ Character-level corruption with Japanese character mixing:
336
+
337
+ ```css
338
+ @keyframes textCorrupt {
339
+ 0%, 100% {
340
+ opacity: 1;
341
+ }
342
+ 10% {
343
+ opacity: 0.8;
344
+ transform: translateX(1px);
345
+ }
346
+ 20% {
347
+ opacity: 1;
348
+ transform: translateX(-1px);
349
+ }
350
+ 30% {
351
+ opacity: 0.9;
352
+ transform: translateX(0);
353
+ }
354
+ }
355
+
356
+ .corrupted-text {
357
+ animation: textCorrupt 3s ease-in-out infinite;
358
+ /* JavaScript handles character replacement */
359
+ }
360
+ ```
361
+
362
+ **JavaScript Implementation** (character-level mixing):
363
+
364
+ ```javascript
365
+ function corruptText(text, intensity = 0.3) {
366
+ const japaneseChars = ['ア', 'イ', 'ウ', '使', '統', '計', 'ー', 'ル'];
367
+
368
+ return text.split('').map((char, i) => {
369
+ if (Math.random() < intensity && /[a-zA-Z]/.test(char)) {
370
+ return japaneseChars[Math.floor(Math.random() * japaneseChars.length)];
371
+ }
372
+ return char;
373
+ }).join('');
374
+ }
375
+
376
+ // Example: "USAGE ANALYTICS" → "US使AGE ANア統LYTICS" (30% corruption)
377
+ ```
378
+
379
+ ### Flicker Animation (Eyes)
380
+
381
+ The signature "eye flicker" animation from CLI dashboard:
382
+
383
+ ```css
384
+ @keyframes flicker {
385
+ 0%, 100% { opacity: 1; }
386
+ 45% { opacity: 1; }
387
+ 50% { opacity: 0.3; } /* Brief blink */
388
+ 55% { opacity: 1; }
389
+ 60% { opacity: 0.5; } /* Double blink */
390
+ 65% { opacity: 1; }
391
+ }
392
+
393
+ .eye-icon {
394
+ animation: flicker 4s ease-in-out infinite;
395
+ animation-delay: calc(var(--flicker-seed) * 1s); /* Randomize timing */
396
+ }
397
+ ```
398
+
399
+ ### Glitch Effect (Advanced)
400
+
401
+ Multi-layer glitch effect for error states or brand moments:
402
+
403
+ ```css
404
+ @keyframes glitch {
405
+ 0% {
406
+ transform: translate(0);
407
+ opacity: 1;
408
+ }
409
+ 20% {
410
+ transform: translate(-2px, 2px);
411
+ opacity: 0.8;
412
+ }
413
+ 40% {
414
+ transform: translate(2px, -2px);
415
+ opacity: 0.9;
416
+ }
417
+ 60% {
418
+ transform: translate(-1px, -1px);
419
+ opacity: 0.85;
420
+ }
421
+ 80% {
422
+ transform: translate(1px, 1px);
423
+ opacity: 0.95;
424
+ }
425
+ 100% {
426
+ transform: translate(0);
427
+ opacity: 1;
428
+ }
429
+ }
430
+
431
+ .glitch-text {
432
+ position: relative;
433
+ animation: glitch 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
434
+ }
435
+
436
+ /* Optional: RGB split effect */
437
+ .glitch-text::before,
438
+ .glitch-text::after {
439
+ content: attr(data-text);
440
+ position: absolute;
441
+ top: 0;
442
+ left: 0;
443
+ opacity: 0.8;
444
+ }
445
+
446
+ .glitch-text::before {
447
+ animation: glitch 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
448
+ color: #d94f90; /* Pink channel */
449
+ z-index: -1;
450
+ }
451
+
452
+ .glitch-text::after {
453
+ animation: glitch 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55) 0.05s;
454
+ color: #8b5cf6; /* Purple channel */
455
+ z-index: -2;
456
+ }
457
+ ```
458
+
459
+ ### Loading Spinner (Corrupted)
460
+
461
+ ```css
462
+ @keyframes spinCorrupt {
463
+ 0% { transform: rotate(0deg); }
464
+ 25% { transform: rotate(90deg) scale(1.1); } /* Stutter */
465
+ 26% { transform: rotate(85deg) scale(1.0); } /* Correction */
466
+ 50% { transform: rotate(180deg); }
467
+ 75% { transform: rotate(270deg) scale(0.9); } /* Stutter */
468
+ 76% { transform: rotate(275deg) scale(1.0); } /* Correction */
469
+ 100% { transform: rotate(360deg); }
470
+ }
471
+
472
+ .spinner-corrupted {
473
+ animation: spinCorrupt 1.2s cubic-bezier(0.68, -0.55, 0.27, 1.55) infinite;
474
+ }
475
+ ```
476
+
477
+ ---
478
+
479
+ ## CLI Terminal Animations
480
+
481
+ ### Terminal Constraints
482
+
483
+ - **Refresh Rate**: Most terminals refresh at 60Hz (16.67ms per frame)
484
+ - **Character-Based**: Can't use sub-character positioning
485
+ - **Color Limitations**: 256-color palette (not full RGB)
486
+ - **No Blur/Shadow**: CSS effects unavailable
487
+
488
+ ### Animation Techniques
489
+
490
+ #### 1. Frame-Based Animation (Spinner)
491
+
492
+ ```go
493
+ // Rotating spinner frames
494
+ var spinnerFrames = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
495
+
496
+ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
497
+ switch msg := msg.(type) {
498
+ case tickMsg:
499
+ m.spinnerFrame = (m.spinnerFrame + 1) % len(spinnerFrames)
500
+ return m, tick(150 * time.Millisecond) // 150ms per frame
501
+ }
502
+ }
503
+ ```
504
+
505
+ #### 2. Progress Bar Animation
506
+
507
+ ```go
508
+ // Block character progress (smooth with unicode)
509
+ var progressChars = []string{"█", "▓", "▒", "░"}
510
+
511
+ func renderProgress(percent float64) string {
512
+ filled := int(percent * 40) // 40 char width
513
+ bar := strings.Repeat("█", filled)
514
+ bar += strings.Repeat("░", 40-filled)
515
+ return bar
516
+ }
517
+ ```
518
+
519
+ #### 3. Text Fade (ANSI Color Gradients)
520
+
521
+ ```go
522
+ // Fade text by reducing color intensity
523
+ var fadeColors = []string{
524
+ "\033[38;5;205m", // Full pink (100%)
525
+ "\033[38;5;204m", // Lighter (80%)
526
+ "\033[38;5;203m", // Lighter (60%)
527
+ "\033[38;5;202m", // Lighter (40%)
528
+ "\033[38;5;201m", // Lighter (20%)
529
+ }
530
+
531
+ func fadeText(text string, frame int) string {
532
+ color := fadeColors[frame % len(fadeColors)]
533
+ return color + text + "\033[0m"
534
+ }
535
+ ```
536
+
537
+ #### 4. Corruption Intensity Animation
538
+
539
+ ```go
540
+ // Gradually increase corruption intensity
541
+ func animateCorruption(text string, tick int) string {
542
+ intensity := 0.15 + (float64(tick % 100) / 100.0 * 0.25) // 15-40%
543
+ return CorruptTextJapanese(text, intensity)
544
+ }
545
+ ```
546
+
547
+ ### CLI Animation Timing
548
+
549
+ Match web timing where possible for cross-platform consistency:
550
+
551
+ | Animation | Web | CLI | Implementation |
552
+ |-----------|-----|-----|----------------|
553
+ | **Spinner** | 150ms/frame | 150ms/frame | Frame-based rotation |
554
+ | **Progress bar** | 300ms/update | 300ms/update | Block character fill |
555
+ | **Text fade** | 150ms transition | 150ms/step | ANSI color change |
556
+ | **Corruption flicker** | 3s cycle | 3s cycle | Character replacement |
557
+
558
+ ---
559
+
560
+ ## Performance Guidelines
561
+
562
+ ### Rule 1: Animate Only GPU Properties
563
+
564
+ ✅ **Safe** (60fps on all devices):
565
+ - `transform` (translate, rotate, scale)
566
+ - `opacity`
567
+
568
+ ⚠️ **Caution** (may drop frames on mobile):
569
+ - `backdrop-filter` (blur) - use sparingly
570
+ - `box-shadow` - pre-render or use pseudo-elements
571
+
572
+ ❌ **Never** (causes jank):
573
+ - `width`, `height`, `top`, `left`, `margin`, `padding`
574
+ - `background-position` (use transform on ::before instead)
575
+
576
+ ### Rule 2: Limit Concurrent Animations
577
+
578
+ - **Maximum 3-5 animated elements** visible at once
579
+ - **Pause animations** for off-screen elements (`Intersection Observer`)
580
+ - **Reduce motion** on low-powered devices
581
+
582
+ ```javascript
583
+ // Pause animations for off-screen elements
584
+ const observer = new IntersectionObserver((entries) => {
585
+ entries.forEach(entry => {
586
+ if (entry.isIntersecting) {
587
+ entry.target.style.animationPlayState = 'running';
588
+ } else {
589
+ entry.target.style.animationPlayState = 'paused';
590
+ }
591
+ });
592
+ });
593
+
594
+ document.querySelectorAll('.animated').forEach(el => observer.observe(el));
595
+ ```
596
+
597
+ ### Rule 3: Use `will-change` Sparingly
598
+
599
+ ```css
600
+ /* Good: Apply will-change only during animation */
601
+ .card:hover {
602
+ will-change: transform; /* Browser optimizes during hover */
603
+ }
604
+
605
+ .card {
606
+ will-change: auto; /* Remove optimization when done */
607
+ }
608
+
609
+ /* Bad: Always on (wastes memory) */
610
+ .card {
611
+ will-change: transform, opacity, box-shadow; /* Too many properties */
612
+ }
613
+ ```
614
+
615
+ ---
616
+
617
+ ## Accessibility
618
+
619
+ ### 1. Respect `prefers-reduced-motion`
620
+
621
+ **CRITICAL**: All animations must respect user preference:
622
+
623
+ ```css
624
+ /* Default: Full animations */
625
+ .card {
626
+ transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
627
+ }
628
+
629
+ /* Reduced motion: Instant transitions */
630
+ @media (prefers-reduced-motion: reduce) {
631
+ .card {
632
+ transition: transform 0.01s linear; /* Near-instant */
633
+ }
634
+
635
+ /* Disable decorative animations entirely */
636
+ .corrupted-text,
637
+ .flicker,
638
+ .glitch-effect {
639
+ animation: none;
640
+ }
641
+ }
642
+ ```
643
+
644
+ ### 2. Never Animate Critical Content
645
+
646
+ - **Error messages**: Appear instantly (no delay/animation)
647
+ - **Form validation**: Immediate feedback (<100ms)
648
+ - **Focus indicators**: Instant appearance (accessibility requirement)
649
+ - **Loading states**: Show within 100ms (perceived performance)
650
+
651
+ ### 3. Provide Skip Options
652
+
653
+ For long animations (>1s), provide skip button:
654
+
655
+ ```html
656
+ <div class="loading-screen">
657
+ <div class="animation">...</div>
658
+ <button class="skip-btn">Skip animation</button>
659
+ </div>
660
+ ```
661
+
662
+ ---
663
+
664
+ ## Implementation Examples
665
+
666
+ ### Example 1: Animated Button (Complete)
667
+
668
+ ```css
669
+ .btn {
670
+ /* Base styles */
671
+ background: rgba(217, 79, 144, 0.2);
672
+ border: 1px solid rgba(217, 79, 144, 0.3);
673
+ color: #ffffff;
674
+ padding: 0.75rem 1.5rem;
675
+ border-radius: 8px;
676
+ cursor: pointer;
677
+
678
+ /* Animations */
679
+ transition:
680
+ background-color 0.15s ease-out,
681
+ border-color 0.15s ease-out,
682
+ transform 0.15s cubic-bezier(0.34, 1.56, 0.64, 1),
683
+ box-shadow 0.2s ease-out 0.05s;
684
+ }
685
+
686
+ .btn:hover {
687
+ background: rgba(217, 79, 144, 0.3);
688
+ border-color: rgba(217, 79, 144, 0.5);
689
+ transform: scale(1.05);
690
+ box-shadow: 0 0 20px rgba(217, 79, 144, 0.4);
691
+ }
692
+
693
+ .btn:active {
694
+ transform: scale(0.98);
695
+ transition-duration: 0.1s; /* Faster on click */
696
+ }
697
+
698
+ /* Accessibility */
699
+ @media (prefers-reduced-motion: reduce) {
700
+ .btn {
701
+ transition: background-color 0.01s linear, border-color 0.01s linear;
702
+ }
703
+ }
704
+ ```
705
+
706
+ ### Example 2: Modal Enter/Exit
707
+
708
+ ```css
709
+ /* Modal backdrop */
710
+ .modal-backdrop {
711
+ opacity: 0;
712
+ animation: fadeIn 0.3s ease-out forwards;
713
+ }
714
+
715
+ @keyframes fadeIn {
716
+ to { opacity: 1; }
717
+ }
718
+
719
+ /* Modal content */
720
+ .modal {
721
+ opacity: 0;
722
+ transform: scale(0.9) translateY(-20px);
723
+ animation: modalEnter 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
724
+ }
725
+
726
+ @keyframes modalEnter {
727
+ to {
728
+ opacity: 1;
729
+ transform: scale(1) translateY(0);
730
+ }
731
+ }
732
+
733
+ /* Exit animation (triggered by JS class) */
734
+ .modal.exiting {
735
+ animation: modalExit 0.2s ease-in forwards;
736
+ }
737
+
738
+ @keyframes modalExit {
739
+ to {
740
+ opacity: 0;
741
+ transform: scale(0.95) translateY(10px);
742
+ }
743
+ }
744
+ ```
745
+
746
+ ### Example 3: Corrupted Loading Spinner (CLI + Web)
747
+
748
+ **Web**:
749
+ ```css
750
+ .spinner-corrupted {
751
+ width: 40px;
752
+ height: 40px;
753
+ border: 3px solid rgba(217, 79, 144, 0.2);
754
+ border-top-color: #d94f90;
755
+ border-radius: 50%;
756
+ animation: spinCorrupt 1.2s cubic-bezier(0.68, -0.55, 0.27, 1.55) infinite;
757
+ }
758
+
759
+ @keyframes spinCorrupt {
760
+ 0% { transform: rotate(0deg); }
761
+ 25% { transform: rotate(90deg) scale(1.1); }
762
+ 26% { transform: rotate(85deg); }
763
+ 50% { transform: rotate(180deg); }
764
+ 75% { transform: rotate(270deg) scale(0.9); }
765
+ 76% { transform: rotate(275deg); }
766
+ 100% { transform: rotate(360deg); }
767
+ }
768
+ ```
769
+
770
+ **CLI (Go)**:
771
+ ```go
772
+ var spinnerFrames = []string{
773
+ "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏",
774
+ }
775
+
776
+ func (m Model) View() string {
777
+ frame := spinnerFrames[m.tick % len(spinnerFrames)]
778
+ color := lipgloss.Color("#d94f90")
779
+
780
+ // Add random stutter (corruption)
781
+ if m.tick % 4 == 0 && rand.Float64() < 0.15 {
782
+ frame = spinnerFrames[(m.tick-1) % len(spinnerFrames)] // Repeat frame
783
+ }
784
+
785
+ return lipgloss.NewStyle().Foreground(color).Render(frame)
786
+ }
787
+ ```
788
+
789
+ ---
790
+
791
+ ## Anti-Patterns
792
+
793
+ ### ❌ Don't: Use `transition: all`
794
+
795
+ ```css
796
+ /* Bad: Animates everything (slow, unintentional animations) */
797
+ .card {
798
+ transition: all 0.3s ease;
799
+ }
800
+
801
+ /* Good: Specify properties explicitly */
802
+ .card {
803
+ transition: transform 0.3s ease, opacity 0.3s ease;
804
+ }
805
+ ```
806
+
807
+ ### ❌ Don't: Animate Layout Properties
808
+
809
+ ```css
810
+ /* Bad: Causes reflow */
811
+ .card:hover {
812
+ width: 320px;
813
+ margin-top: -10px;
814
+ }
815
+
816
+ /* Good: Use transform */
817
+ .card:hover {
818
+ transform: scale(1.1) translateY(-10px);
819
+ }
820
+ ```
821
+
822
+ ### ❌ Don't: Over-Animate
823
+
824
+ ```css
825
+ /* Bad: Too many concurrent animations (overwhelming) */
826
+ .card {
827
+ animation: pulse 1s infinite, shake 0.5s infinite, glow 2s infinite;
828
+ }
829
+
830
+ /* Good: One primary animation */
831
+ .card {
832
+ animation: pulse 2s ease-in-out infinite;
833
+ }
834
+ ```
835
+
836
+ ### ❌ Don't: Ignore Reduced Motion
837
+
838
+ ```css
839
+ /* Bad: Forces animation on all users */
840
+ .element {
841
+ animation: spin 1s infinite; /* Can cause nausea */
842
+ }
843
+
844
+ /* Good: Respects user preference */
845
+ @media (prefers-reduced-motion: no-preference) {
846
+ .element {
847
+ animation: spin 1s infinite;
848
+ }
849
+ }
850
+ ```
851
+
852
+ ---
853
+
854
+ ## Quick Reference
855
+
856
+ ### Animation Decision Tree
857
+
858
+ ```
859
+ Need animation?
860
+ ├─ Immediate feedback (<100ms)? → Use transition with 100-150ms
861
+ ├─ State change? → Use transition with 150-300ms
862
+ ├─ Complex multi-step? → Use @keyframes
863
+ ├─ Loading indicator? → Use linear animation (constant speed)
864
+ ├─ Decorative/branding? → Use cubic-bezier with reduced-motion fallback
865
+ └─ Layout change? → Use transform (never width/height/margin)
866
+ ```
867
+
868
+ ### Common Durations Cheat Sheet
869
+
870
+ ```css
871
+ /* Copy-paste ready */
872
+ --fast: 150ms; /* Hover, focus */
873
+ --normal: 300ms; /* Modal, card */
874
+ --slow: 500ms; /* Page transition */
875
+ ```
876
+
877
+ ### Common Easings Cheat Sheet
878
+
879
+ ```css
880
+ /* Copy-paste ready */
881
+ --ease-default: ease; /* General use */
882
+ --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1); /* Buttons, cards */
883
+ --ease-glitch: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* Corruption */
884
+ ```
885
+
886
+ ---
887
+
888
+ ## Related Documentation
889
+
890
+ - [INTERACTIVE_STATES.md](./INTERACTIVE_STATES.md) - State-specific animation timings
891
+ - [GLASSMORPHISM.md](./GLASSMORPHISM.md) - Performance notes for backdrop-filter
892
+ - [COLOR_SYSTEM.md](../brand/COLOR_SYSTEM.md) - Color values for animations
893
+ - [TYPOGRAPHY.md](../brand/TYPOGRAPHY.md) - Text animation considerations
894
+ - [TRANSLATION_FAILURE_AESTHETIC.md](../brand/TRANSLATION_FAILURE_AESTHETIC.md) - Corruption guidelines
895
+
896
+ ---
897
+
898
+ **Last Updated**: 2025-12-13
899
+ **Version**: 1.0.0
900
+ **Maintainer**: Celeste Brand System
901
+ **Status**: ✅ Phase 2 Complete