@trishchuk/coolors-mcp 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 (197) hide show
  1. package/.claude/settings.local.json +39 -0
  2. package/.env +2 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +73 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +71 -0
  5. package/.github/pull_request_template.md +97 -0
  6. package/.github/workflows/ci.yml +127 -0
  7. package/.github/workflows/deploy-docs.yml +56 -0
  8. package/.github/workflows/release.yml +99 -0
  9. package/.mcp.json +12 -0
  10. package/.prettierignore +1 -0
  11. package/CLAUDE.md +201 -0
  12. package/DOCUMENTATION.md +274 -0
  13. package/GEMINI.md +54 -0
  14. package/LICENSE +21 -0
  15. package/README.md +401 -0
  16. package/demo/content_based_color.png +0 -0
  17. package/demo/music-player.html +621 -0
  18. package/demo/podcast-player.html +903 -0
  19. package/dist/bin/coolors-mcp.d.ts +1 -0
  20. package/dist/bin/coolors-mcp.js +154 -0
  21. package/dist/bin/coolors-mcp.js.map +1 -0
  22. package/dist/bin/server.d.ts +1 -0
  23. package/dist/bin/server.js +3292 -0
  24. package/dist/bin/server.js.map +1 -0
  25. package/dist/chunk-IQ7NN26V.js +114 -0
  26. package/dist/chunk-IQ7NN26V.js.map +1 -0
  27. package/dist/chunk-P3ARRKLS.js +1214 -0
  28. package/dist/chunk-P3ARRKLS.js.map +1 -0
  29. package/dist/color/index.d.ts +716 -0
  30. package/dist/color/index.js +153 -0
  31. package/dist/color/index.js.map +1 -0
  32. package/dist/coolors-mcp.d.ts +136 -0
  33. package/dist/coolors-mcp.js +7 -0
  34. package/dist/coolors-mcp.js.map +1 -0
  35. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
  36. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
  37. package/docs/.vitepress/cache/deps/_metadata.json +127 -0
  38. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
  39. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
  40. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +12683 -0
  41. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js.map +7 -0
  42. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +9719 -0
  43. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js.map +7 -0
  44. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
  45. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
  46. package/docs/.vitepress/cache/deps/cytoscape.js +30278 -0
  47. package/docs/.vitepress/cache/deps/cytoscape.js.map +7 -0
  48. package/docs/.vitepress/cache/deps/dayjs.js +285 -0
  49. package/docs/.vitepress/cache/deps/dayjs.js.map +7 -0
  50. package/docs/.vitepress/cache/deps/debug.js +468 -0
  51. package/docs/.vitepress/cache/deps/debug.js.map +7 -0
  52. package/docs/.vitepress/cache/deps/package.json +3 -0
  53. package/docs/.vitepress/cache/deps/prismjs.js +1466 -0
  54. package/docs/.vitepress/cache/deps/prismjs.js.map +7 -0
  55. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +228 -0
  56. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js.map +7 -0
  57. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +142 -0
  58. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js.map +7 -0
  59. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +27 -0
  60. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js.map +7 -0
  61. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +65 -0
  62. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js.map +7 -0
  63. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +53 -0
  64. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js.map +7 -0
  65. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +73 -0
  66. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js.map +7 -0
  67. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
  68. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  69. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
  70. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  71. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1146 -0
  72. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  73. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
  74. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  75. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +1814 -0
  76. package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  77. package/docs/.vitepress/cache/deps/vue.js +344 -0
  78. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  79. package/docs/.vitepress/components/ClientGrid.vue +125 -0
  80. package/docs/.vitepress/components/CodeBlock.vue +231 -0
  81. package/docs/.vitepress/components/ConfigModal.vue +477 -0
  82. package/docs/.vitepress/components/DiagramModal.vue +528 -0
  83. package/docs/.vitepress/components/TroubleshootingModal.vue +472 -0
  84. package/docs/.vitepress/config.js +162 -0
  85. package/docs/.vitepress/theme/FundingLayout.vue +251 -0
  86. package/docs/.vitepress/theme/Layout.vue +134 -0
  87. package/docs/.vitepress/theme/components/AdBanner.vue +317 -0
  88. package/docs/.vitepress/theme/components/AdPlaceholder.vue +78 -0
  89. package/docs/.vitepress/theme/components/FundingEffects.vue +322 -0
  90. package/docs/.vitepress/theme/components/FundingHero.vue +345 -0
  91. package/docs/.vitepress/theme/components/SupportSection.vue +511 -0
  92. package/docs/.vitepress/theme/custom-app.css +339 -0
  93. package/docs/.vitepress/theme/custom.css +699 -0
  94. package/docs/.vitepress/theme/index.js +25 -0
  95. package/docs/README.md +198 -0
  96. package/docs/concepts/accessibility.md +473 -0
  97. package/docs/concepts/color-spaces.md +222 -0
  98. package/docs/concepts/distance-metrics.md +384 -0
  99. package/docs/concepts/hct.md +261 -0
  100. package/docs/concepts/image-analysis.md +396 -0
  101. package/docs/concepts/material-design.md +306 -0
  102. package/docs/concepts/theme-matching.md +399 -0
  103. package/docs/examples/basic-colors.md +490 -0
  104. package/docs/examples/creating-themes.md +898 -0
  105. package/docs/examples/css-refactoring.md +824 -0
  106. package/docs/examples/image-extraction.md +882 -0
  107. package/docs/getting-started.md +366 -0
  108. package/docs/index.md +190 -0
  109. package/docs/installation.md +157 -0
  110. package/docs/tools/README.md +234 -0
  111. package/docs/tools/accessibility.md +614 -0
  112. package/docs/tools/color-operations.md +374 -0
  113. package/docs/tools/image-extraction.md +624 -0
  114. package/docs/tools/material-design.md +347 -0
  115. package/docs/tools/theme-matching.md +552 -0
  116. package/eslint.config.ts +14 -0
  117. package/examples/theme-matching.md +113 -0
  118. package/jsr.json +7 -0
  119. package/mcp-config.json +8 -0
  120. package/note.md +35 -0
  121. package/package.json +122 -0
  122. package/research_results.md +53 -0
  123. package/src/bin/coolors-mcp.ts +194 -0
  124. package/src/bin/server.ts +61 -0
  125. package/src/color/__tests__/conversions-argb.test.ts +198 -0
  126. package/src/color/__tests__/extract-colors.test.ts +360 -0
  127. package/src/color/__tests__/image-utils.test.ts +242 -0
  128. package/src/color/__tests__/reference-colors.test.ts +278 -0
  129. package/src/color/__tests__/round-trip.test.ts +197 -0
  130. package/src/color/conversions.test.ts +402 -0
  131. package/src/color/conversions.ts +393 -0
  132. package/src/color/dislike/__tests__/dislike-analyzer.test.ts +248 -0
  133. package/src/color/dislike/dislike-analyzer.ts +114 -0
  134. package/src/color/extract-colors.ts +228 -0
  135. package/src/color/hct/__tests__/hct-class.test.ts +232 -0
  136. package/src/color/hct/harmonization.ts +204 -0
  137. package/src/color/hct/hct-class.ts +109 -0
  138. package/src/color/hct/hct-solver.ts +168 -0
  139. package/src/color/hct/index.ts +39 -0
  140. package/src/color/hct/tonal-palette.ts +211 -0
  141. package/src/color/hct/types.ts +88 -0
  142. package/src/color/image-utils.ts +79 -0
  143. package/src/color/index.ts +87 -0
  144. package/src/color/material-theme.ts +157 -0
  145. package/src/color/metrics.test.ts +276 -0
  146. package/src/color/metrics.ts +281 -0
  147. package/src/color/quantize/__tests__/quantizer_celebi.test.ts +195 -0
  148. package/src/color/quantize/lab_point_provider.ts +55 -0
  149. package/src/color/quantize/point_provider.ts +27 -0
  150. package/src/color/quantize/quantizer_celebi.ts +51 -0
  151. package/src/color/quantize/quantizer_celebi_test.ts +71 -0
  152. package/src/color/quantize/quantizer_map.ts +47 -0
  153. package/src/color/quantize/quantizer_wsmeans.ts +232 -0
  154. package/src/color/quantize/quantizer_wu.ts +472 -0
  155. package/src/color/score/__tests__/score.test.ts +224 -0
  156. package/src/color/score/score.ts +175 -0
  157. package/src/color/types.ts +151 -0
  158. package/src/color/utils/color_utils.ts +292 -0
  159. package/src/color/utils/math_utils.ts +145 -0
  160. package/src/color/utils.test.ts +403 -0
  161. package/src/color/utils.ts +315 -0
  162. package/src/constants.ts +5 -0
  163. package/src/coolors-mcp.ts +37 -0
  164. package/src/examples/addition.ts +333 -0
  165. package/src/examples/color-demo.ts +125 -0
  166. package/src/examples/custom-logger.ts +201 -0
  167. package/src/examples/oauth-server.ts +113 -0
  168. package/src/examples/session-context.ts +269 -0
  169. package/src/session.ts +116 -0
  170. package/src/theme/__tests__/matcher.test.ts +180 -0
  171. package/src/theme/__tests__/parser.test.ts +148 -0
  172. package/src/theme/__tests__/refactor.test.ts +224 -0
  173. package/src/theme/index.ts +34 -0
  174. package/src/theme/matcher.ts +395 -0
  175. package/src/theme/parser.ts +392 -0
  176. package/src/theme/refactor.ts +360 -0
  177. package/src/theme/types.ts +152 -0
  178. package/src/tools/__tests__/gradient-generator.test.ts +206 -0
  179. package/src/tools/__tests__/palette-with-locks.test.ts +109 -0
  180. package/src/tools/color-conversion.tool.ts +54 -0
  181. package/src/tools/color-distance.tool.ts +41 -0
  182. package/src/tools/colors.ts +31 -0
  183. package/src/tools/contrast-checker.tool.ts +37 -0
  184. package/src/tools/dislike-analyzer.tool.ts +247 -0
  185. package/src/tools/gradient-generator.tool.ts +250 -0
  186. package/src/tools/image-extraction.tools.ts +289 -0
  187. package/src/tools/index.ts +39 -0
  188. package/src/tools/material-theme.tools.ts +250 -0
  189. package/src/tools/palette-generator.tool.ts +135 -0
  190. package/src/tools/palette-with-locks.tool.ts +221 -0
  191. package/src/tools/registry.ts +142 -0
  192. package/src/tools/simple-tools.ts +37 -0
  193. package/src/tools/theme-matching.tools.ts +334 -0
  194. package/src/types.ts +182 -0
  195. package/src/utils.ts +22 -0
  196. package/tsconfig.json +8 -0
  197. package/vitest.config.js +15 -0
@@ -0,0 +1,614 @@
1
+ # Accessibility Tools
2
+
3
+ Tools for ensuring color choices meet WCAG accessibility standards.
4
+
5
+ ## check_contrast
6
+
7
+ Check the contrast ratio between two colors and verify WCAG compliance.
8
+
9
+ ### Parameters
10
+
11
+ | Parameter | Type | Required | Description |
12
+ |-----------|------|----------|-------------|
13
+ | `foreground` | string | ✅ | Foreground/text color (hex, rgb, hsl) |
14
+ | `background` | string | ✅ | Background color (hex, rgb, hsl) |
15
+ | `fontSize` | number | ❌ | Font size in pixels (for determining large text) |
16
+ | `fontWeight` | number | ❌ | Font weight (for determining bold text) |
17
+
18
+ ### Returns
19
+
20
+ ```typescript
21
+ {
22
+ ratio: number; // Contrast ratio (1-21)
23
+ ratioString: string; // Formatted as "X.XX:1"
24
+ passes: {
25
+ AA: {
26
+ normal: boolean; // Passes AA for normal text (4.5:1)
27
+ large: boolean; // Passes AA for large text (3:1)
28
+ nonText: boolean; // Passes AA for UI elements (3:1)
29
+ };
30
+ AAA: {
31
+ normal: boolean; // Passes AAA for normal text (7:1)
32
+ large: boolean; // Passes AAA for large text (4.5:1)
33
+ }
34
+ };
35
+ recommendation: string; // Human-readable recommendation
36
+ luminance: {
37
+ foreground: number; // Relative luminance (0-1)
38
+ background: number; // Relative luminance (0-1)
39
+ };
40
+ isLargeText: boolean; // Whether text qualifies as large
41
+ }
42
+ ```
43
+
44
+ ### Examples
45
+
46
+ #### Basic Contrast Check
47
+
48
+ ```javascript
49
+ // Check black text on white background
50
+ {
51
+ "name": "check_contrast",
52
+ "arguments": {
53
+ "foreground": "#000000",
54
+ "background": "#ffffff"
55
+ }
56
+ }
57
+
58
+ // Response
59
+ {
60
+ "ratio": 21,
61
+ "ratioString": "21:1",
62
+ "passes": {
63
+ "AA": {
64
+ "normal": true,
65
+ "large": true,
66
+ "nonText": true
67
+ },
68
+ "AAA": {
69
+ "normal": true,
70
+ "large": true
71
+ }
72
+ },
73
+ "recommendation": "Excellent contrast - passes all WCAG standards",
74
+ "luminance": {
75
+ "foreground": 0,
76
+ "background": 1
77
+ }
78
+ }
79
+ ```
80
+
81
+ #### With Font Size Context
82
+
83
+ ```javascript
84
+ // Check specific text size
85
+ {
86
+ "name": "check_contrast",
87
+ "arguments": {
88
+ "foreground": "#6366f1",
89
+ "background": "#ffffff",
90
+ "fontSize": 24, // 24px = large text
91
+ "fontWeight": 400
92
+ }
93
+ }
94
+
95
+ // Response
96
+ {
97
+ "ratio": 3.03,
98
+ "ratioString": "3.03:1",
99
+ "passes": {
100
+ "AA": {
101
+ "normal": false, // Needs 4.5:1
102
+ "large": true, // Passes 3:1 for large
103
+ "nonText": true
104
+ }
105
+ },
106
+ "isLargeText": true,
107
+ "recommendation": "Passes AA for large text only. Consider darker foreground for normal text."
108
+ }
109
+ ```
110
+
111
+ #### Check Multiple Combinations
112
+
113
+ ```javascript
114
+ // Test color pairs
115
+ const pairs = [
116
+ { fg: "#1f2937", bg: "#ffffff" }, // Dark gray on white
117
+ { fg: "#6366f1", bg: "#f3f4f6" }, // Blue on light gray
118
+ { fg: "#ffffff", bg: "#dc2626" } // White on red
119
+ ];
120
+
121
+ for (const pair of pairs) {
122
+ const result = await checkContrast(pair.fg, pair.bg);
123
+ console.log(`${pair.fg} on ${pair.bg}: ${result.ratioString}`);
124
+ }
125
+ ```
126
+
127
+ ### Large Text Definition
128
+
129
+ Text is considered "large" when:
130
+ - Font size ≥ 18pt (24px)
131
+ - Font size ≥ 14pt (18.67px) AND bold (weight ≥ 700)
132
+
133
+ ### Use Cases
134
+
135
+ - Validating text/background combinations
136
+ - Ensuring button accessibility
137
+ - Checking form field contrast
138
+ - Verifying icon visibility
139
+
140
+ ## ensure_contrast
141
+
142
+ Automatically adjust a color to meet contrast requirements.
143
+
144
+ ### Parameters
145
+
146
+ | Parameter | Type | Required | Description |
147
+ |-----------|------|----------|-------------|
148
+ | `foreground` | string | ✅ | Color to adjust |
149
+ | `background` | string | ✅ | Background color |
150
+ | `targetRatio` | number | ✅ | Minimum contrast ratio needed |
151
+ | `preferLighter` | boolean | ❌ | Prefer lightening over darkening |
152
+
153
+ ### Returns
154
+
155
+ ```typescript
156
+ {
157
+ original: {
158
+ color: string;
159
+ ratio: number;
160
+ };
161
+ adjusted: {
162
+ color: string;
163
+ ratio: number;
164
+ };
165
+ adjustmentMade: boolean;
166
+ adjustmentType: 'lightened' | 'darkened' | 'none';
167
+ toneChange: number; // HCT tone difference
168
+ }
169
+ ```
170
+
171
+ ### Examples
172
+
173
+ #### Ensure AA Compliance
174
+
175
+ ```javascript
176
+ // Make color accessible
177
+ {
178
+ "name": "ensure_contrast",
179
+ "arguments": {
180
+ "foreground": "#8b92f0", // Light blue
181
+ "background": "#ffffff",
182
+ "targetRatio": 4.5 // AA for normal text
183
+ }
184
+ }
185
+
186
+ // Response
187
+ {
188
+ "original": {
189
+ "color": "#8b92f0",
190
+ "ratio": 2.8
191
+ },
192
+ "adjusted": {
193
+ "color": "#5256c9", // Darkened
194
+ "ratio": 4.51
195
+ },
196
+ "adjustmentMade": true,
197
+ "adjustmentType": "darkened",
198
+ "toneChange": -15
199
+ }
200
+ ```
201
+
202
+ #### Ensure AAA Compliance
203
+
204
+ ```javascript
205
+ // Maximize readability
206
+ {
207
+ "name": "ensure_contrast",
208
+ "arguments": {
209
+ "foreground": "#6366f1",
210
+ "background": "#ffffff",
211
+ "targetRatio": 7 // AAA standard
212
+ }
213
+ }
214
+ ```
215
+
216
+ #### Prefer Lighter Adjustment
217
+
218
+ ```javascript
219
+ // For dark backgrounds, prefer lightening
220
+ {
221
+ "name": "ensure_contrast",
222
+ "arguments": {
223
+ "foreground": "#6366f1",
224
+ "background": "#1f2937", // Dark background
225
+ "targetRatio": 4.5,
226
+ "preferLighter": true // Lighten the foreground
227
+ }
228
+ }
229
+ ```
230
+
231
+ ### Use Cases
232
+
233
+ - Auto-fixing inaccessible colors
234
+ - Creating accessible variations
235
+ - Generating readable text colors
236
+ - Building high-contrast modes
237
+
238
+ ## get_accessible_pairs
239
+
240
+ Generate accessible color pairs for different UI contexts.
241
+
242
+ ### Parameters
243
+
244
+ | Parameter | Type | Required | Description |
245
+ |-----------|------|----------|-------------|
246
+ | `baseColor` | string | ✅ | Starting color |
247
+ | `count` | number | ❌ | Number of pairs to generate (default: 5) |
248
+ | `contrastLevels` | string[] | ❌ | Required levels: AA, AAA (default: ['AA']) |
249
+ | `contexts` | string[] | ❌ | UI contexts: text, button, border (default: all) |
250
+
251
+ ### Returns
252
+
253
+ ```typescript
254
+ {
255
+ baseColor: string;
256
+ pairs: Array<{
257
+ foreground: string;
258
+ background: string;
259
+ contrast: number;
260
+ passes: object;
261
+ context: string;
262
+ recommendation: string;
263
+ }>;
264
+ }
265
+ ```
266
+
267
+ ### Examples
268
+
269
+ #### Generate Text Color Pairs
270
+
271
+ ```javascript
272
+ // Get accessible text colors
273
+ {
274
+ "name": "get_accessible_pairs",
275
+ "arguments": {
276
+ "baseColor": "#6366f1",
277
+ "count": 5,
278
+ "contexts": ["text"]
279
+ }
280
+ }
281
+
282
+ // Returns various accessible combinations
283
+ {
284
+ "pairs": [
285
+ {
286
+ "foreground": "#6366f1",
287
+ "background": "#ffffff",
288
+ "contrast": 3.03,
289
+ "context": "text",
290
+ "recommendation": "Use for large text only"
291
+ },
292
+ {
293
+ "foreground": "#ffffff",
294
+ "background": "#6366f1",
295
+ "contrast": 3.03,
296
+ "context": "text",
297
+ "recommendation": "Inverted - use for buttons"
298
+ }
299
+ // ... more pairs
300
+ ]
301
+ }
302
+ ```
303
+
304
+ #### Generate AAA Pairs
305
+
306
+ ```javascript
307
+ // Maximum accessibility
308
+ {
309
+ "name": "get_accessible_pairs",
310
+ "arguments": {
311
+ "baseColor": "#6366f1",
312
+ "contrastLevels": ["AAA"],
313
+ "contexts": ["text", "button"]
314
+ }
315
+ }
316
+ ```
317
+
318
+ ### Use Cases
319
+
320
+ - Building accessible color systems
321
+ - Creating theme variations
322
+ - Generating style guides
323
+ - Testing color combinations
324
+
325
+ ## validate_palette_accessibility
326
+
327
+ Check all color combinations in a palette for accessibility.
328
+
329
+ ### Parameters
330
+
331
+ | Parameter | Type | Required | Description |
332
+ |-----------|------|----------|-------------|
333
+ | `palette` | object | ✅ | Color palette with role names and values |
334
+ | `level` | string | ❌ | WCAG level to test: AA, AAA (default: AA) |
335
+ | `includeReport` | boolean | ❌ | Generate detailed report (default: true) |
336
+
337
+ ### Returns
338
+
339
+ ```typescript
340
+ {
341
+ valid: boolean; // All combinations pass
342
+ totalCombinations: number;
343
+ passingCombinations: number;
344
+ failingCombinations: number;
345
+ issues: Array<{
346
+ foreground: string;
347
+ foregroundRole: string;
348
+ background: string;
349
+ backgroundRole: string;
350
+ ratio: number;
351
+ required: number;
352
+ suggestion: string;
353
+ }>;
354
+ report?: {
355
+ byRole: object; // Issues grouped by role
356
+ summary: string; // Human-readable summary
357
+ recommendations: string[];
358
+ }
359
+ }
360
+ ```
361
+
362
+ ### Examples
363
+
364
+ #### Validate Material Theme
365
+
366
+ ```javascript
367
+ // Check Material Design theme
368
+ {
369
+ "name": "validate_palette_accessibility",
370
+ "arguments": {
371
+ "palette": {
372
+ "primary": "#6366f1",
373
+ "onPrimary": "#ffffff",
374
+ "primaryContainer": "#e0e0ff",
375
+ "onPrimaryContainer": "#070764",
376
+ "surface": "#fffbff",
377
+ "onSurface": "#1b1b1f"
378
+ },
379
+ "level": "AA"
380
+ }
381
+ }
382
+
383
+ // Response shows any issues
384
+ {
385
+ "valid": false,
386
+ "totalCombinations": 6,
387
+ "passingCombinations": 5,
388
+ "failingCombinations": 1,
389
+ "issues": [
390
+ {
391
+ "foreground": "#6366f1",
392
+ "foregroundRole": "primary",
393
+ "background": "#e0e0ff",
394
+ "backgroundRole": "primaryContainer",
395
+ "ratio": 2.1,
396
+ "required": 4.5,
397
+ "suggestion": "Darken primary or lighten primaryContainer"
398
+ }
399
+ ]
400
+ }
401
+ ```
402
+
403
+ #### Validate Custom Palette
404
+
405
+ ```javascript
406
+ // Check brand colors
407
+ {
408
+ "name": "validate_palette_accessibility",
409
+ "arguments": {
410
+ "palette": {
411
+ "brand": "#FF5722",
412
+ "text": "#212121",
413
+ "background": "#FFFFFF",
414
+ "accent": "#00BCD4",
415
+ "muted": "#9E9E9E"
416
+ },
417
+ "level": "AAA",
418
+ "includeReport": true
419
+ }
420
+ }
421
+ ```
422
+
423
+ ### Use Cases
424
+
425
+ - Validating design systems
426
+ - Testing theme accessibility
427
+ - Generating accessibility reports
428
+ - Finding problem combinations
429
+
430
+ ## Best Practices
431
+
432
+ ### Contrast Requirements
433
+
434
+ #### Text Content
435
+ | Context | AA Minimum | AAA Minimum |
436
+ |---------|------------|-------------|
437
+ | Normal text | 4.5:1 | 7:1 |
438
+ | Large text | 3:1 | 4.5:1 |
439
+ | Incidental text | No requirement | No requirement |
440
+ | Logotypes | No requirement | No requirement |
441
+
442
+ #### Non-Text Content
443
+ | Context | AA Minimum | Notes |
444
+ |---------|------------|-------|
445
+ | UI components | 3:1 | Active components |
446
+ | Graphics | 3:1 | Essential graphics |
447
+ | Decorative | No requirement | Purely decorative |
448
+
449
+ ### Testing Strategy
450
+
451
+ ```javascript
452
+ // Comprehensive testing
453
+ async function testAccessibility(theme) {
454
+ // 1. Check individual pairs
455
+ const criticalPairs = [
456
+ { fg: theme.text, bg: theme.background },
457
+ { fg: theme.primary, bg: theme.surface }
458
+ ];
459
+
460
+ for (const pair of criticalPairs) {
461
+ const result = await checkContrast(pair.fg, pair.bg);
462
+ if (result.ratio < 4.5) {
463
+ console.warn(`Low contrast: ${pair.fg} on ${pair.bg}`);
464
+ }
465
+ }
466
+
467
+ // 2. Validate entire palette
468
+ const validation = await validatePalette(theme);
469
+ if (!validation.valid) {
470
+ console.error('Palette has accessibility issues:', validation.issues);
471
+ }
472
+
473
+ // 3. Generate report
474
+ return validation.report;
475
+ }
476
+ ```
477
+
478
+ ### Automatic Fixing
479
+
480
+ ```javascript
481
+ // Fix accessibility issues automatically
482
+ async function fixAccessibility(theme) {
483
+ const fixed = { ...theme };
484
+
485
+ // Ensure all text meets AA
486
+ fixed.text = await ensureContrast({
487
+ foreground: theme.text,
488
+ background: theme.background,
489
+ targetRatio: 4.5
490
+ });
491
+
492
+ // Ensure buttons are accessible
493
+ fixed.buttonText = await ensureContrast({
494
+ foreground: theme.buttonText,
495
+ background: theme.buttonBg,
496
+ targetRatio: 4.5
497
+ });
498
+
499
+ return fixed;
500
+ }
501
+ ```
502
+
503
+ ## Common Patterns
504
+
505
+ ### Dark Mode Accessibility
506
+
507
+ ```javascript
508
+ // Ensure dark mode meets standards
509
+ function validateDarkMode(darkTheme) {
510
+ const checks = [
511
+ // Primary text should be readable
512
+ {
513
+ fg: darkTheme.text,
514
+ bg: darkTheme.background,
515
+ min: 4.5
516
+ },
517
+ // But not too harsh (avoid pure white on black)
518
+ {
519
+ fg: darkTheme.text,
520
+ bg: darkTheme.background,
521
+ max: 18 // Avoid excessive contrast
522
+ }
523
+ ];
524
+
525
+ return checks.every(check => {
526
+ const ratio = getContrast(check.fg, check.bg);
527
+ return ratio >= (check.min || 0) && ratio <= (check.max || 21);
528
+ });
529
+ }
530
+ ```
531
+
532
+ ### Progressive Enhancement
533
+
534
+ ```javascript
535
+ // Provide multiple contrast levels
536
+ function generateContrastLevels(baseTheme) {
537
+ return {
538
+ // Default - AA compliance
539
+ default: baseTheme,
540
+
541
+ // Medium - Enhanced readability
542
+ medium: adjustContrast(baseTheme, 1.2),
543
+
544
+ // High - AAA compliance
545
+ high: adjustContrast(baseTheme, 1.5),
546
+
547
+ // Maximum - For accessibility needs
548
+ maximum: {
549
+ text: '#000000',
550
+ background: '#ffffff',
551
+ primary: '#0000ff'
552
+ }
553
+ };
554
+ }
555
+ ```
556
+
557
+ ### Form Validation
558
+
559
+ ```javascript
560
+ // Ensure form fields are accessible
561
+ function validateFormColors(formTheme) {
562
+ const requirements = {
563
+ // Input fields need clear boundaries
564
+ inputBorder: { min: 3.0, against: formTheme.inputBg },
565
+
566
+ // Error text must be readable
567
+ errorText: { min: 4.5, against: formTheme.background },
568
+
569
+ // Focus indicators must be visible
570
+ focusRing: { min: 3.0, against: formTheme.inputBg },
571
+
572
+ // Placeholder text (relaxed requirement)
573
+ placeholder: { min: 3.0, against: formTheme.inputBg }
574
+ };
575
+
576
+ return Object.entries(requirements).map(([element, req]) => ({
577
+ element,
578
+ passes: checkContrast(formTheme[element], req.against).ratio >= req.min
579
+ }));
580
+ }
581
+ ```
582
+
583
+ ## Troubleshooting
584
+
585
+ ### Low Contrast Issues
586
+
587
+ **Problem**: Colors don't meet minimum contrast
588
+ **Solution**:
589
+ - Use `ensure_contrast` to auto-adjust
590
+ - Increase tone difference between colors
591
+ - Consider different color roles
592
+
593
+ ### Harsh Contrast
594
+
595
+ **Problem**: Maximum contrast (21:1) is too harsh
596
+ **Solution**:
597
+ - Use off-white (#fafafa) instead of pure white
598
+ - Use very dark gray (#0a0a0a) instead of pure black
599
+ - Aim for 12-15:1 for comfortable reading
600
+
601
+ ### Color Meaning Lost
602
+
603
+ **Problem**: Adjusted colors lose brand identity
604
+ **Solution**:
605
+ - Adjust the background instead of foreground
606
+ - Use borders or icons to supplement color
607
+ - Provide high-contrast mode as option
608
+
609
+ ## See Also
610
+
611
+ - [Accessibility Concepts](../concepts/accessibility.md) - WCAG standards explained
612
+ - [HCT System](../concepts/hct.md) - Tone-based contrast
613
+ - [Color Operations](./color-operations.md) - Color manipulation
614
+ - [Material Design Tools](./material-design.md) - Accessible themes