@elsahafy/ux-mcp-server 2.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.
@@ -0,0 +1,469 @@
1
+ {
2
+ "name": "Animation & Motion Design",
3
+ "description": "Motion design principles, performance, and accessibility for UI animations",
4
+ "principles": {
5
+ "purpose_driven": {
6
+ "description": "Every animation should have a purpose",
7
+ "valid_purposes": [
8
+ "Direct attention to important elements",
9
+ "Provide feedback on user actions",
10
+ "Show relationships between elements",
11
+ "Smooth transitions between states",
12
+ "Communicate system status",
13
+ "Guide users through flows",
14
+ "Add personality and delight"
15
+ ],
16
+ "avoid": "Animation for decoration only"
17
+ },
18
+ "disney_12_principles": {
19
+ "description": "Classic animation principles applied to UI",
20
+ "relevant_to_ui": {
21
+ "squash_and_stretch": {
22
+ "principle": "Objects deform to show flexibility",
23
+ "ui_use": "Buttons that compress on click, elastic loading indicators",
24
+ "example": "Scale down slightly on press, bounce back"
25
+ },
26
+ "anticipation": {
27
+ "principle": "Prepare for main action",
28
+ "ui_use": "Slight move before big transition",
29
+ "example": "Pull back before sliding forward"
30
+ },
31
+ "staging": {
32
+ "principle": "Direct attention to what's important",
33
+ "ui_use": "Animate important elements first, others follow",
34
+ "example": "Modal backdrop fades in, then content slides in"
35
+ },
36
+ "follow_through": {
37
+ "principle": "Different parts move at different rates",
38
+ "ui_use": "Staggered list animations, momentum after main movement",
39
+ "example": "Card slides in, shadow follows with slight delay"
40
+ },
41
+ "ease_in_ease_out": {
42
+ "principle": "Gradual acceleration and deceleration",
43
+ "ui_use": "All UI animations (nothing moves at constant speed)",
44
+ "example": "cubic-bezier easing functions",
45
+ "critical": "Most important principle for UI"
46
+ },
47
+ "secondary_action": {
48
+ "principle": "Smaller actions support main action",
49
+ "ui_use": "Icon wobbles as notification appears",
50
+ "example": "Menu opens (main), items fade in sequentially (secondary)"
51
+ }
52
+ }
53
+ },
54
+ "material_motion": {
55
+ "description": "Google's motion design system",
56
+ "key_concepts": {
57
+ "responsive": "Animations react to user input",
58
+ "natural": "Inspired by real-world physics",
59
+ "aware": "Elements aware of each other and user",
60
+ "intentional": "Guide focus and hierarchy"
61
+ },
62
+ "duration": {
63
+ "mobile": "Shorter (200-300ms)",
64
+ "tablet": "Medium (250-400ms)",
65
+ "desktop": "Longer (300-500ms)",
66
+ "rationale": "Smaller screens = faster animations"
67
+ }
68
+ }
69
+ },
70
+ "timing": {
71
+ "durations": {
72
+ "instant": {
73
+ "duration": "0-100ms",
74
+ "use": "Immediate feedback (hover states, ripples)",
75
+ "note": "Feels instant to users"
76
+ },
77
+ "fast": {
78
+ "duration": "100-200ms",
79
+ "use": "Simple transitions (fades, simple slides)",
80
+ "examples": ["Tooltip appear", "Dropdown open", "Button hover"]
81
+ },
82
+ "medium": {
83
+ "duration": "200-500ms",
84
+ "use": "Most UI animations (default choice)",
85
+ "examples": ["Modal appear", "Page transition", "Card expand"]
86
+ },
87
+ "slow": {
88
+ "duration": "500ms-1s",
89
+ "use": "Complex transitions, large movements",
90
+ "examples": ["Full-screen transition", "Complex reveal"],
91
+ "warning": "Can feel sluggish if overused"
92
+ },
93
+ "very_slow": {
94
+ "duration": "> 1s",
95
+ "use": "Loading states, progress indicators",
96
+ "avoid": "Regular UI transitions (too slow)"
97
+ }
98
+ },
99
+ "golden_rule": "200-300ms for most UI animations",
100
+ "speed_perception": "Mobile feels faster with shorter durations",
101
+ "consider_motion_preference": "Reduce or disable for users with prefers-reduced-motion"
102
+ },
103
+ "easing": {
104
+ "description": "How animation accelerates/decelerates",
105
+ "types": {
106
+ "linear": {
107
+ "curve": "constant speed throughout",
108
+ "css": "ease: linear",
109
+ "use": "Color changes, opacity (rarely for movement)",
110
+ "avoid": "Feels robotic for movement"
111
+ },
112
+ "ease_in": {
113
+ "curve": "Slow start, fast end",
114
+ "css": "ease: ease-in or cubic-bezier(0.4, 0, 1, 1)",
115
+ "use": "Exit animations (leaving screen)",
116
+ "rationale": "Accelerates away from view"
117
+ },
118
+ "ease_out": {
119
+ "curve": "Fast start, slow end",
120
+ "css": "ease: ease-out or cubic-bezier(0, 0, 0.2, 1)",
121
+ "use": "Enter animations (appearing on screen)",
122
+ "rationale": "Decelerates into position",
123
+ "most_common": "Default for most UI animations"
124
+ },
125
+ "ease_in_out": {
126
+ "curve": "Slow start and end, fast middle",
127
+ "css": "ease: ease-in-out or cubic-bezier(0.4, 0, 0.2, 1)",
128
+ "use": "Moving within same screen",
129
+ "example": "Modal sliding from side to center"
130
+ },
131
+ "custom_cubic_bezier": {
132
+ "description": "Fine-tune easing curve",
133
+ "tool": "https://cubic-bezier.com",
134
+ "material_standard": "cubic-bezier(0.4, 0.0, 0.2, 1)",
135
+ "ios_standard": "cubic-bezier(0.25, 0.1, 0.25, 1)"
136
+ }
137
+ },
138
+ "recommendation": "Use ease-out for 90% of UI animations"
139
+ },
140
+ "animation_types": {
141
+ "micro_interactions": {
142
+ "description": "Small animations for user feedback",
143
+ "examples": {
144
+ "button_press": {
145
+ "animation": "Scale down slightly, then back",
146
+ "duration": "100-150ms",
147
+ "css": "transform: scale(0.95); transition: transform 100ms ease-out;"
148
+ },
149
+ "checkbox_check": {
150
+ "animation": "Checkmark draws in",
151
+ "duration": "200ms",
152
+ "technique": "SVG stroke animation or transform"
153
+ },
154
+ "toggle_switch": {
155
+ "animation": "Circle slides across track",
156
+ "duration": "200ms",
157
+ "easing": "ease-out"
158
+ },
159
+ "like_button": {
160
+ "animation": "Heart pops and changes color",
161
+ "duration": "300ms",
162
+ "sequence": "Scale up → bounce → settle"
163
+ }
164
+ },
165
+ "purpose": "Confirm action, provide feedback"
166
+ },
167
+ "loading_states": {
168
+ "spinner": {
169
+ "use": "Unknown duration (< 10 seconds expected)",
170
+ "animation": "Rotate infinitely",
171
+ "best_practice": "Show immediately if expected > 1 second"
172
+ },
173
+ "progress_bar": {
174
+ "use": "Known duration or progress",
175
+ "animation": "Width grows left to right",
176
+ "best_practice": "Update regularly, smooth transitions"
177
+ },
178
+ "skeleton_screen": {
179
+ "use": "Content loading (better than spinner)",
180
+ "animation": "Shimmer effect across placeholder",
181
+ "benefit": "Shows structure, feels faster"
182
+ },
183
+ "pulse": {
184
+ "use": "Loading placeholder",
185
+ "animation": "Opacity or background color pulse",
186
+ "duration": "1-2s infinite loop"
187
+ }
188
+ },
189
+ "page_transitions": {
190
+ "fade": {
191
+ "description": "Simplest transition",
192
+ "use": "Unrelated pages",
193
+ "duration": "200-300ms",
194
+ "css": "opacity: 0 → 1"
195
+ },
196
+ "slide": {
197
+ "description": "New page slides in",
198
+ "use": "Forward/back navigation",
199
+ "direction": "Left for forward, right for back",
200
+ "duration": "300-400ms"
201
+ },
202
+ "shared_element": {
203
+ "description": "Element morphs between pages",
204
+ "use": "Detail views (thumbnail → full image)",
205
+ "complexity": "High (requires careful coordination)",
206
+ "impact": "Strongest sense of continuity"
207
+ },
208
+ "cross_fade": {
209
+ "description": "Overlap old and new content",
210
+ "use": "Similar pages, content updates",
211
+ "duration": "300-400ms"
212
+ }
213
+ },
214
+ "modal_animations": {
215
+ "backdrop": {
216
+ "animation": "Fade in from transparent",
217
+ "duration": "200ms",
218
+ "easing": "ease-out"
219
+ },
220
+ "content": {
221
+ "options": [
222
+ "Scale from 0.9 to 1.0 + fade",
223
+ "Slide down from top",
224
+ "Slide up from bottom",
225
+ "Fade + slight upward movement"
226
+ ],
227
+ "duration": "250-300ms",
228
+ "timing": "Start after backdrop (100ms delay)"
229
+ },
230
+ "exit": {
231
+ "reverse": "Reverse entry animation",
232
+ "duration": "200ms (slightly faster than enter)",
233
+ "backdrop_timing": "Fade out after content starts"
234
+ }
235
+ },
236
+ "list_animations": {
237
+ "stagger": {
238
+ "description": "Items appear sequentially",
239
+ "delay": "50-100ms between items",
240
+ "use": "Initial load, new items added",
241
+ "limit": "First 10-15 items (rest instant)"
242
+ },
243
+ "reorder": {
244
+ "description": "Smooth position changes",
245
+ "duration": "300-400ms",
246
+ "easing": "ease-in-out",
247
+ "use": "Drag-and-drop, sorting"
248
+ },
249
+ "add_remove": {
250
+ "add": "Fade + scale in from 0.8",
251
+ "remove": "Fade + scale out to 0.8",
252
+ "duration": "200-250ms"
253
+ }
254
+ },
255
+ "scroll_animations": {
256
+ "parallax": {
257
+ "description": "Background moves slower than foreground",
258
+ "use": "Hero sections (sparingly)",
259
+ "performance": "Use transform for GPU acceleration",
260
+ "accessibility": "Disable for reduced-motion"
261
+ },
262
+ "reveal_on_scroll": {
263
+ "description": "Elements fade/slide in when scrolled into view",
264
+ "trigger": "When element is 10-20% visible",
265
+ "duration": "400-600ms",
266
+ "avoid": "Don't animate all elements (overwhelming)"
267
+ },
268
+ "sticky_header": {
269
+ "animation": "Shrink on scroll down",
270
+ "duration": "200ms",
271
+ "trigger": "After scrolling 50-100px"
272
+ }
273
+ }
274
+ },
275
+ "performance": {
276
+ "gpu_acceleration": {
277
+ "efficient_properties": [
278
+ "transform (translate, scale, rotate)",
279
+ "opacity"
280
+ ],
281
+ "avoid_animating": [
282
+ "width, height (triggers layout)",
283
+ "top, left, margin, padding (triggers layout)",
284
+ "background-position (slow repaint)",
285
+ "box-shadow (slow)"
286
+ ],
287
+ "trigger_gpu": "will-change: transform, opacity;",
288
+ "warning": "Don't overuse will-change (memory intensive)"
289
+ },
290
+ "60fps_target": {
291
+ "frame_budget": "16.67ms per frame",
292
+ "javascript": "Use requestAnimationFrame, not setInterval",
293
+ "css": "Prefer CSS animations for simple cases",
294
+ "avoid": "Animating too many elements simultaneously"
295
+ },
296
+ "best_practices": [
297
+ "Use transform and opacity only when possible",
298
+ "Apply will-change sparingly",
299
+ "Use requestAnimationFrame for JS animations",
300
+ "Reduce animation complexity on low-end devices",
301
+ "Debounce scroll/resize event handlers",
302
+ "Use CSS animations for simple loops",
303
+ "Use Web Animations API for complex JS control"
304
+ ],
305
+ "monitoring": [
306
+ "Chrome DevTools Performance tab",
307
+ "Check frame rate during animations",
308
+ "Watch for layout thrashing",
309
+ "Monitor memory usage with will-change"
310
+ ]
311
+ },
312
+ "accessibility": {
313
+ "prefers_reduced_motion": {
314
+ "media_query": "@media (prefers-reduced-motion: reduce) { /* disable/reduce animations */ }",
315
+ "requirement": "WCAG 2.1 Success Criterion 2.3.3",
316
+ "implementation": {
317
+ "disable": "Remove animations entirely",
318
+ "reduce": "Shorten duration, remove bounces/springs",
319
+ "crossfade": "Use simple fades instead of complex motions"
320
+ },
321
+ "javascript": "const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;",
322
+ "respect": "Always respect this preference"
323
+ },
324
+ "seizure_triggers": {
325
+ "avoid": [
326
+ "Flashing more than 3 times per second",
327
+ "Large flashing areas",
328
+ "High contrast flashing",
329
+ "Rapid motion across large screen areas"
330
+ ],
331
+ "wcag": "WCAG 2.1 Success Criterion 2.3.1 (Level A)"
332
+ },
333
+ "vestibular_disorders": {
334
+ "description": "Motion can cause dizziness, nausea in some users",
335
+ "reduce_risk": [
336
+ "Avoid excessive motion",
337
+ "Use subtle animations",
338
+ "Respect reduced-motion preference",
339
+ "Don't animate background/large areas",
340
+ "Avoid parallax effects for essential content"
341
+ ]
342
+ },
343
+ "focus_indicators": {
344
+ "requirement": "Animated focus indicators must remain visible",
345
+ "avoid": "Don't fade out focus rings",
346
+ "ok": "Pulsing or highlighting focus is acceptable"
347
+ }
348
+ },
349
+ "tools_and_libraries": {
350
+ "css": {
351
+ "transitions": "Simple state changes (hover, active)",
352
+ "animations": "Keyframe animations, loops",
353
+ "example": ".button {\n transition: transform 200ms ease-out;\n}\n.button:hover {\n transform: scale(1.05);\n}"
354
+ },
355
+ "javascript_libraries": [
356
+ {
357
+ "name": "GSAP (GreenSock)",
358
+ "use": "Complex, timeline-based animations",
359
+ "pros": ["Powerful", "Great performance", "Timeline control"],
360
+ "cons": ["Large bundle size"]
361
+ },
362
+ {
363
+ "name": "Framer Motion",
364
+ "use": "React animations",
365
+ "pros": ["React-friendly", "Declarative", "Shared layout animations"],
366
+ "cons": ["React only"]
367
+ },
368
+ {
369
+ "name": "Anime.js",
370
+ "use": "Lightweight general-purpose",
371
+ "pros": ["Small size", "Versatile"],
372
+ "cons": ["Less powerful than GSAP"]
373
+ },
374
+ {
375
+ "name": "Lottie",
376
+ "use": "Designer-created animations (After Effects)",
377
+ "pros": ["Complex animations from designers", "Cross-platform"],
378
+ "cons": ["Large file sizes possible"]
379
+ },
380
+ {
381
+ "name": "Web Animations API",
382
+ "use": "Native browser API",
383
+ "pros": ["No library needed", "Good performance"],
384
+ "cons": ["Verbose syntax", "Limited browser support (older IE)"]
385
+ }
386
+ ],
387
+ "design_tools": [
388
+ "After Effects (with Lottie plugin)",
389
+ "Figma (prototyping)",
390
+ "Principle",
391
+ "ProtoPie"
392
+ ]
393
+ },
394
+ "common_patterns": {
395
+ "button_states": {
396
+ "idle_to_hover": "transform: scale(1.05); duration: 150ms",
397
+ "hover_to_active": "transform: scale(0.95); duration: 100ms",
398
+ "loading": "Disable + show spinner, duration: instant"
399
+ },
400
+ "toast_notification": {
401
+ "enter": "Slide in from top/bottom + fade, 300ms",
402
+ "exit": "Fade out + slight slide, 200ms",
403
+ "auto_dismiss": "After 4-6 seconds"
404
+ },
405
+ "dropdown_menu": {
406
+ "enter": "Fade + scale from 0.95, origin: top, 200ms",
407
+ "exit": "Fade out, 150ms"
408
+ },
409
+ "accordion": {
410
+ "expand": "Height auto (use max-height trick), 300ms ease-out",
411
+ "collapse": "Height 0, 250ms ease-in"
412
+ },
413
+ "tabs": {
414
+ "indicator": "Slide smoothly to active tab, 250ms ease-out",
415
+ "content": "Cross-fade, 200ms"
416
+ }
417
+ },
418
+ "anti_patterns": [
419
+ {
420
+ "pattern": "Animations everywhere",
421
+ "problem": "Overwhelming, slows perceived performance",
422
+ "solution": "Animate only important interactions"
423
+ },
424
+ {
425
+ "pattern": "Very long durations (> 500ms)",
426
+ "problem": "Users wait, feels sluggish",
427
+ "solution": "Keep most animations 200-300ms"
428
+ },
429
+ {
430
+ "pattern": "Linear easing for movement",
431
+ "problem": "Feels robotic, unnatural",
432
+ "solution": "Use ease-out or ease-in-out"
433
+ },
434
+ {
435
+ "pattern": "Animating layout properties",
436
+ "problem": "Poor performance, jank",
437
+ "solution": "Use transform and opacity only"
438
+ },
439
+ {
440
+ "pattern": "Ignoring reduced-motion",
441
+ "problem": "Accessibility issue, can cause nausea",
442
+ "solution": "Always implement reduced-motion support"
443
+ },
444
+ {
445
+ "pattern": "Too many simultaneous animations",
446
+ "problem": "Visual chaos, performance issues",
447
+ "solution": "Stagger or sequence animations"
448
+ },
449
+ {
450
+ "pattern": "Inconsistent animation styles",
451
+ "problem": "Disjointed experience",
452
+ "solution": "Define animation system (durations, easings)"
453
+ }
454
+ ],
455
+ "checklist": [
456
+ "Every animation has a clear purpose",
457
+ "Durations are 200-300ms for most interactions",
458
+ "Using ease-out for enter animations",
459
+ "Animating transform and opacity (not layout properties)",
460
+ "Respecting prefers-reduced-motion",
461
+ "No flashing more than 3 times per second",
462
+ "Animations feel smooth at 60fps",
463
+ "Consistent timing across similar interactions",
464
+ "Loading states for operations > 1 second",
465
+ "Exit animations are slightly faster than enter",
466
+ "Focus indicators remain visible during animation",
467
+ "Works well on low-end devices"
468
+ ]
469
+ }
@@ -0,0 +1,212 @@
1
+ {
2
+ "name": "Dark Mode Best Practices",
3
+ "description": "Guidelines for implementing accessible and user-friendly dark mode",
4
+ "principles": {
5
+ "user_preference": {
6
+ "description": "Respect user's system preference and provide manual toggle",
7
+ "detection": {
8
+ "css": "@media (prefers-color-scheme: dark) { /* dark mode styles */ }",
9
+ "javascript": "window.matchMedia('(prefers-color-scheme: dark)').matches"
10
+ },
11
+ "best_practices": [
12
+ "Default to system preference",
13
+ "Provide manual toggle override",
14
+ "Persist user choice in localStorage",
15
+ "Sync across tabs/sessions",
16
+ "Show current mode in UI"
17
+ ]
18
+ },
19
+ "color_considerations": {
20
+ "backgrounds": {
21
+ "avoid_pure_black": {
22
+ "reason": "Causes eye strain, poor contrast on OLED",
23
+ "recommended": "#121212 to #1e1e1e instead of #000000"
24
+ },
25
+ "use_elevation": {
26
+ "description": "Lighter backgrounds for elevated surfaces",
27
+ "example": {
28
+ "base": "#121212",
29
+ "elevated": "#1e1e1e",
30
+ "cards": "#2a2a2a"
31
+ }
32
+ }
33
+ },
34
+ "text_colors": {
35
+ "primary": {
36
+ "light_on_dark": "#ffffff or rgba(255, 255, 255, 0.87)",
37
+ "contrast_ratio": "Maintain 4.5:1 minimum"
38
+ },
39
+ "secondary": {
40
+ "light_on_dark": "rgba(255, 255, 255, 0.60)",
41
+ "use_for": "Secondary text, labels"
42
+ },
43
+ "disabled": {
44
+ "light_on_dark": "rgba(255, 255, 255, 0.38)",
45
+ "use_for": "Disabled text, hints"
46
+ }
47
+ },
48
+ "color_saturation": {
49
+ "description": "Reduce saturation in dark mode",
50
+ "rationale": "Bright saturated colors cause eye strain on dark backgrounds",
51
+ "example": {
52
+ "light_mode_primary": "#2563eb (vibrant blue)",
53
+ "dark_mode_primary": "#60a5fa (desaturated blue)"
54
+ },
55
+ "adjustment": "Increase lightness by 20-30%, decrease saturation by 10-20%"
56
+ }
57
+ },
58
+ "contrast": {
59
+ "wcag_requirements": {
60
+ "normal_text": "4.5:1 contrast ratio minimum (WCAG AA)",
61
+ "large_text": "3:1 contrast ratio minimum",
62
+ "ui_components": "3:1 contrast ratio for borders, icons"
63
+ },
64
+ "dark_mode_challenges": [
65
+ "Pure white on pure black is too harsh (15:1+)",
66
+ "Consider slight tint to reduce harshness",
67
+ "Test with actual dark mode users",
68
+ "Some colors need more adjustment than others"
69
+ ]
70
+ }
71
+ },
72
+ "implementation": {
73
+ "css_variables": {
74
+ "description": "Use CSS custom properties for theme switching",
75
+ "example": ":root {\n /* Light mode (default) */\n --bg-primary: #ffffff;\n --bg-secondary: #f3f4f6;\n --text-primary: #111827;\n --text-secondary: #6b7280;\n --border: #e5e7eb;\n}\n\n[data-theme='dark'] {\n --bg-primary: #1e1e1e;\n --bg-secondary: #2a2a2a;\n --text-primary: #e5e7eb;\n --text-secondary: #9ca3af;\n --border: #374151;\n}\n\nbody {\n background: var(--bg-primary);\n color: var(--text-primary);\n}"
76
+ },
77
+ "javascript_toggle": {
78
+ "example": "// Toggle function\nfunction toggleDarkMode() {\n const html = document.documentElement;\n const currentTheme = html.getAttribute('data-theme');\n const newTheme = currentTheme === 'dark' ? 'light' : 'dark';\n \n html.setAttribute('data-theme', newTheme);\n localStorage.setItem('theme', newTheme);\n}\n\n// Initialize from localStorage or system preference\nfunction initTheme() {\n const saved = localStorage.getItem('theme');\n const system = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n const theme = saved || system;\n \n document.documentElement.setAttribute('data-theme', theme);\n}\n\n// Run on page load\ninitTheme();\n\n// Listen for system changes\nwindow.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {\n if (!localStorage.getItem('theme')) {\n document.documentElement.setAttribute('data-theme', e.matches ? 'dark' : 'light');\n }\n});"
79
+ },
80
+ "prevent_flash": {
81
+ "description": "Prevent white flash on page load",
82
+ "solution": "Inline theme script in <head> before CSS",
83
+ "example": "<script>\n (function() {\n const theme = localStorage.getItem('theme') ||\n (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');\n document.documentElement.setAttribute('data-theme', theme);\n })();\n</script>"
84
+ }
85
+ },
86
+ "component_adaptations": {
87
+ "images": {
88
+ "problem": "Photos/images may look washed out in dark mode",
89
+ "solutions": [
90
+ {
91
+ "name": "Reduce opacity",
92
+ "implementation": "[data-theme='dark'] img { opacity: 0.9; }"
93
+ },
94
+ {
95
+ "name": "Different images",
96
+ "implementation": "Use picture element with media query for dark mode"
97
+ },
98
+ {
99
+ "name": "CSS filter",
100
+ "implementation": "[data-theme='dark'] img { filter: brightness(0.9) contrast(1.1); }"
101
+ }
102
+ ]
103
+ },
104
+ "shadows": {
105
+ "light_mode": "box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);",
106
+ "dark_mode": "box-shadow: 0 4px 6px rgba(0, 0, 0, 0.5);",
107
+ "note": "Increase shadow opacity in dark mode for visibility"
108
+ },
109
+ "borders": {
110
+ "light_mode": "border: 1px solid #e5e7eb;",
111
+ "dark_mode": "border: 1px solid #374151;",
112
+ "alternative": "Use subtle backgrounds instead of borders"
113
+ },
114
+ "icons": {
115
+ "svg_approach": "Use currentColor for SVG fill/stroke",
116
+ "icon_libraries": "Choose icons that work in both modes",
117
+ "consideration": "Some icons may need different styles in dark mode"
118
+ }
119
+ },
120
+ "testing_checklist": [
121
+ "Test all text for sufficient contrast (4.5:1 min)",
122
+ "Check all UI component colors",
123
+ "Verify images don't look washed out",
124
+ "Test shadows are visible",
125
+ "Check form inputs are clearly visible",
126
+ "Verify focus indicators stand out",
127
+ "Test disabled states",
128
+ "Check error/success colors work",
129
+ "Verify charts and data visualizations",
130
+ "Test on OLED screens (blacks should be true black)",
131
+ "Check loading states and skeletons",
132
+ "Verify all interactive elements are visible"
133
+ ],
134
+ "common_mistakes": [
135
+ {
136
+ "mistake": "Using pure black (#000000)",
137
+ "problem": "Too harsh, poor for OLED displays",
138
+ "solution": "Use dark grays (#121212, #1e1e1e)"
139
+ },
140
+ {
141
+ "mistake": "Not adjusting color saturation",
142
+ "problem": "Vibrant colors cause eye strain on dark backgrounds",
143
+ "solution": "Desaturate and lighten colors by 20-30%"
144
+ },
145
+ {
146
+ "mistake": "Same shadows in both modes",
147
+ "problem": "Shadows invisible in dark mode",
148
+ "solution": "Increase opacity or use lighter shadows"
149
+ },
150
+ {
151
+ "mistake": "Forgetting form inputs",
152
+ "problem": "Inputs blend into background",
153
+ "solution": "Distinct background/border for inputs"
154
+ },
155
+ {
156
+ "mistake": "No toggle UI",
157
+ "problem": "Users can't manually switch",
158
+ "solution": "Provide visible theme toggle"
159
+ },
160
+ {
161
+ "mistake": "Flash of wrong theme on load",
162
+ "problem": "Jarring experience",
163
+ "solution": "Inline script in <head> to set theme before render"
164
+ }
165
+ ],
166
+ "accessibility": [
167
+ "Maintain WCAG AA contrast ratios (4.5:1 text, 3:1 UI)",
168
+ "Don't rely on color alone to convey information",
169
+ "Ensure focus indicators are visible in both modes",
170
+ "Test with screen readers",
171
+ "Provide toggle with accessible label",
172
+ "Announce theme change to screen readers",
173
+ "Support prefers-color-scheme media query",
174
+ "Respect prefers-contrast media query"
175
+ ],
176
+ "color_palette_example": {
177
+ "light_mode": {
178
+ "background": {
179
+ "primary": "#ffffff",
180
+ "secondary": "#f9fafb",
181
+ "tertiary": "#f3f4f6"
182
+ },
183
+ "text": {
184
+ "primary": "#111827",
185
+ "secondary": "#6b7280",
186
+ "tertiary": "#9ca3af"
187
+ },
188
+ "border": "#e5e7eb",
189
+ "primary": "#3b82f6",
190
+ "success": "#10b981",
191
+ "warning": "#f59e0b",
192
+ "error": "#ef4444"
193
+ },
194
+ "dark_mode": {
195
+ "background": {
196
+ "primary": "#1e1e1e",
197
+ "secondary": "#2a2a2a",
198
+ "tertiary": "#363636"
199
+ },
200
+ "text": {
201
+ "primary": "#e5e7eb",
202
+ "secondary": "#9ca3af",
203
+ "tertiary": "#6b7280"
204
+ },
205
+ "border": "#374151",
206
+ "primary": "#60a5fa",
207
+ "success": "#34d399",
208
+ "warning": "#fbbf24",
209
+ "error": "#f87171"
210
+ }
211
+ }
212
+ }