@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,624 @@
1
+ # Image Extraction Tools
2
+
3
+ Tools for extracting colors from images and generating themes based on image content.
4
+
5
+ ## extract_image_colors
6
+
7
+ Extract dominant colors from an image using Google's Celebi quantization algorithm.
8
+
9
+ ### Parameters
10
+
11
+ | Parameter | Type | Required | Description |
12
+ |-----------|------|----------|-------------|
13
+ | `imageData` | number[] | ✅ | RGBA pixel array (flat array of values 0-255) |
14
+ | `maxColors` | number | ❌ | Maximum colors to extract (default: 5, max: 128) |
15
+ | `minPopulation` | number | ❌ | Minimum pixel percentage for color (default: 0.01) |
16
+ | `targetChroma` | number | ❌ | Preferred chroma for UI colors (default: 48) |
17
+
18
+ ### Returns
19
+
20
+ ```typescript
21
+ {
22
+ colors: Array<{
23
+ hex: string; // Hex color value
24
+ rgb: [r, g, b]; // RGB values
25
+ hct: { // HCT values
26
+ hue: number;
27
+ chroma: number;
28
+ tone: number;
29
+ };
30
+ population: number; // Percentage of image (0-1)
31
+ score: number; // UI suitability score (0-1)
32
+ }>;
33
+ metadata: {
34
+ totalPixels: number;
35
+ uniqueColors: number;
36
+ processingTime: number;
37
+ }
38
+ }
39
+ ```
40
+
41
+ ### Examples
42
+
43
+ #### Basic Color Extraction
44
+
45
+ ```javascript
46
+ // Extract top 5 colors from image
47
+ {
48
+ "name": "extract_image_colors",
49
+ "arguments": {
50
+ "imageData": [/* RGBA pixel array */],
51
+ "maxColors": 5
52
+ }
53
+ }
54
+
55
+ // Response
56
+ {
57
+ "colors": [
58
+ {
59
+ "hex": "#6366f1",
60
+ "rgb": [99, 102, 241],
61
+ "hct": { "hue": 265.8, "chroma": 87.2, "tone": 47.9 },
62
+ "population": 0.23,
63
+ "score": 0.89
64
+ },
65
+ {
66
+ "hex": "#ec4899",
67
+ "rgb": [236, 72, 153],
68
+ "population": 0.15,
69
+ "score": 0.76
70
+ }
71
+ // ... more colors
72
+ ],
73
+ "metadata": {
74
+ "totalPixels": 90000,
75
+ "uniqueColors": 1247,
76
+ "processingTime": 145
77
+ }
78
+ }
79
+ ```
80
+
81
+ #### Extract More Colors
82
+
83
+ ```javascript
84
+ // Get detailed color palette
85
+ {
86
+ "name": "extract_image_colors",
87
+ "arguments": {
88
+ "imageData": [/* pixels */],
89
+ "maxColors": 12,
90
+ "minPopulation": 0.005 // Include colors with 0.5% coverage
91
+ }
92
+ }
93
+ ```
94
+
95
+ #### UI-Optimized Extraction
96
+
97
+ ```javascript
98
+ // Extract colors suitable for UI
99
+ {
100
+ "name": "extract_image_colors",
101
+ "arguments": {
102
+ "imageData": [/* pixels */],
103
+ "maxColors": 5,
104
+ "targetChroma": 48 // Prefer moderate chroma for UI
105
+ }
106
+ }
107
+ ```
108
+
109
+ ### Image Data Preparation
110
+
111
+ #### From Canvas (Browser)
112
+
113
+ ```javascript
114
+ const canvas = document.getElementById('canvas');
115
+ const ctx = canvas.getContext('2d');
116
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
117
+
118
+ // Convert to flat array
119
+ const pixels = Array.from(imageData.data);
120
+
121
+ // Extract colors
122
+ const result = await extractColors({
123
+ imageData: pixels
124
+ });
125
+ ```
126
+
127
+ #### From Image File (Node.js)
128
+
129
+ ```javascript
130
+ const sharp = require('sharp');
131
+
132
+ async function getPixelsFromImage(filepath) {
133
+ const { data, info } = await sharp(filepath)
134
+ .resize(300) // Resize for performance
135
+ .raw()
136
+ .toBuffer({ resolveWithObject: true });
137
+
138
+ return Array.from(data);
139
+ }
140
+
141
+ const pixels = await getPixelsFromImage('photo.jpg');
142
+ ```
143
+
144
+ ### Use Cases
145
+
146
+ - Extracting brand colors from logos
147
+ - Creating themes from album artwork
148
+ - Analyzing color usage in designs
149
+ - Generating palettes from photos
150
+
151
+ ## generate_theme_from_image
152
+
153
+ Generate a complete Material Design 3 theme from an image.
154
+
155
+ ### Parameters
156
+
157
+ | Parameter | Type | Required | Description |
158
+ |-----------|------|----------|-------------|
159
+ | `imageData` | number[] | ✅ | RGBA pixel array |
160
+ | `variant` | string | ❌ | Theme variant: tonalSpot, fidelity, vibrant, expressive, neutral, monochrome |
161
+ | `contrastLevel` | number | ❌ | Contrast level: 0 (default), 0.5 (medium), 1.0 (high) |
162
+ | `sourceColorIndex` | number | ❌ | Which extracted color to use as source (default: 0) |
163
+
164
+ ### Returns
165
+
166
+ ```typescript
167
+ {
168
+ sourceColor: string; // Selected source color
169
+ extractedColors: Array<{
170
+ hex: string;
171
+ score: number;
172
+ selected: boolean;
173
+ }>;
174
+ schemes: {
175
+ light: {
176
+ primary: string;
177
+ onPrimary: string;
178
+ primaryContainer: string;
179
+ onPrimaryContainer: string;
180
+ // ... all Material Design color roles
181
+ };
182
+ dark: {
183
+ // ... dark theme colors
184
+ }
185
+ };
186
+ palettes: {
187
+ primary: object;
188
+ secondary: object;
189
+ tertiary: object;
190
+ neutral: object;
191
+ error: object;
192
+ };
193
+ css: string; // Generated CSS variables
194
+ }
195
+ ```
196
+
197
+ ### Examples
198
+
199
+ #### Basic Theme Generation
200
+
201
+ ```javascript
202
+ // Generate theme from image
203
+ {
204
+ "name": "generate_theme_from_image",
205
+ "arguments": {
206
+ "imageData": [/* RGBA pixels */]
207
+ }
208
+ }
209
+
210
+ // Response includes complete theme
211
+ {
212
+ "sourceColor": "#6366f1",
213
+ "schemes": {
214
+ "light": {
215
+ "primary": "#5256c9",
216
+ "onPrimary": "#ffffff",
217
+ "primaryContainer": "#e0e0ff",
218
+ "onPrimaryContainer": "#070764"
219
+ // ... more colors
220
+ },
221
+ "dark": {
222
+ "primary": "#bfc1ff",
223
+ "onPrimary": "#212599",
224
+ "primaryContainer": "#393cb0",
225
+ "onPrimaryContainer": "#e0e0ff"
226
+ // ... more colors
227
+ }
228
+ }
229
+ }
230
+ ```
231
+
232
+ #### With Specific Variant
233
+
234
+ ```javascript
235
+ // Generate vibrant theme
236
+ {
237
+ "name": "generate_theme_from_image",
238
+ "arguments": {
239
+ "imageData": [/* pixels */],
240
+ "variant": "vibrant",
241
+ "contrastLevel": 0.5 // Medium contrast
242
+ }
243
+ }
244
+ ```
245
+
246
+ #### Choose Different Source Color
247
+
248
+ ```javascript
249
+ // Use second extracted color as source
250
+ {
251
+ "name": "generate_theme_from_image",
252
+ "arguments": {
253
+ "imageData": [/* pixels */],
254
+ "sourceColorIndex": 1 // Use second color
255
+ }
256
+ }
257
+
258
+ // Shows which color was selected
259
+ {
260
+ "extractedColors": [
261
+ { "hex": "#6366f1", "score": 0.89, "selected": false },
262
+ { "hex": "#ec4899", "score": 0.76, "selected": true }, // Used
263
+ { "hex": "#10b981", "score": 0.71, "selected": false }
264
+ ],
265
+ "sourceColor": "#ec4899"
266
+ }
267
+ ```
268
+
269
+ ### Theme Variants
270
+
271
+ | Variant | Description | Best For |
272
+ |---------|-------------|----------|
273
+ | `tonalSpot` | Default, balanced | General use |
274
+ | `fidelity` | Preserves source color | Brand-critical |
275
+ | `vibrant` | Higher chroma | Playful, energetic |
276
+ | `expressive` | Unexpected combinations | Creative, artistic |
277
+ | `neutral` | Minimal color | Professional |
278
+ | `monochrome` | Single hue | Minimalist |
279
+
280
+ ### Use Cases
281
+
282
+ - Dynamic theming from user photos
283
+ - Content-aware UI adaptation
284
+ - Brand extraction from logos
285
+ - Seasonal theme generation
286
+
287
+ ## analyze_color_likability
288
+
289
+ Check if a color falls in the universally disliked "bile zone" and get a fixed version.
290
+
291
+ ### Parameters
292
+
293
+ | Parameter | Type | Required | Description |
294
+ |-----------|------|----------|-------------|
295
+ | `color` | string | ✅ | Color to analyze (hex, rgb, hsl) |
296
+ | `autoFix` | boolean | ❌ | Automatically return fixed version (default: true) |
297
+
298
+ ### Returns
299
+
300
+ ```typescript
301
+ {
302
+ original: string; // Input color
303
+ isDisliked: boolean; // Falls in dislike zone
304
+ reason?: string; // Why it's disliked
305
+ fixed?: string; // Improved version
306
+ adjustments?: {
307
+ hueShift: number; // Degrees shifted
308
+ toneIncrease: number; // Tone adjustment
309
+ }
310
+ }
311
+ ```
312
+
313
+ ### Examples
314
+
315
+ #### Check Color Likability
316
+
317
+ ```javascript
318
+ // Check if color is disliked
319
+ {
320
+ "name": "analyze_color_likability",
321
+ "arguments": {
322
+ "color": "#6b7c3a" // Dark yellow-green
323
+ }
324
+ }
325
+
326
+ // Response
327
+ {
328
+ "original": "#6b7c3a",
329
+ "isDisliked": true,
330
+ "reason": "Falls in 'bile zone' - dark yellow-green associated with biological waste",
331
+ "fixed": "#7c8b4a", // Shifted and lightened
332
+ "adjustments": {
333
+ "hueShift": 15,
334
+ "toneIncrease": 10
335
+ }
336
+ }
337
+ ```
338
+
339
+ #### Check Without Auto-Fix
340
+
341
+ ```javascript
342
+ {
343
+ "name": "analyze_color_likability",
344
+ "arguments": {
345
+ "color": "#6b7c3a",
346
+ "autoFix": false
347
+ }
348
+ }
349
+
350
+ // Just reports the issue
351
+ {
352
+ "original": "#6b7c3a",
353
+ "isDisliked": true,
354
+ "reason": "Falls in 'bile zone'"
355
+ }
356
+ ```
357
+
358
+ ### The Dislike Zone
359
+
360
+ Colors are universally disliked when they have:
361
+ - **Hue**: 50-120° (yellow-green range)
362
+ - **Chroma**: 20-50 (moderate saturation)
363
+ - **Tone**: 20-50 (dark to medium)
364
+
365
+ These colors resemble biological waste and are instinctively avoided.
366
+
367
+ ### Use Cases
368
+
369
+ - Validating color choices
370
+ - Improving generated palettes
371
+ - Fixing extracted colors
372
+ - Ensuring pleasant UI colors
373
+
374
+ ## fix_disliked_colors_batch
375
+
376
+ Analyze and fix multiple colors, returning only liked versions.
377
+
378
+ ### Parameters
379
+
380
+ | Parameter | Type | Required | Description |
381
+ |-----------|------|----------|-------------|
382
+ | `colors` | string[] | ✅ | Array of colors to check |
383
+ | `strategy` | string | ❌ | Fix strategy: shift, lighten, both (default: both) |
384
+
385
+ ### Returns
386
+
387
+ ```typescript
388
+ {
389
+ results: Array<{
390
+ original: string;
391
+ isDisliked: boolean;
392
+ fixed?: string;
393
+ kept: boolean; // Whether original or fixed was kept
394
+ }>;
395
+ summary: {
396
+ total: number;
397
+ disliked: number;
398
+ fixed: number;
399
+ unchanged: number;
400
+ };
401
+ fixedColors: string[]; // Final list of all liked colors
402
+ }
403
+ ```
404
+
405
+ ### Examples
406
+
407
+ #### Fix Multiple Colors
408
+
409
+ ```javascript
410
+ {
411
+ "name": "fix_disliked_colors_batch",
412
+ "arguments": {
413
+ "colors": ["#6b7c3a", "#6366f1", "#5c6b2f", "#ec4899"]
414
+ }
415
+ }
416
+
417
+ // Response
418
+ {
419
+ "results": [
420
+ { "original": "#6b7c3a", "isDisliked": true, "fixed": "#7c8b4a", "kept": false },
421
+ { "original": "#6366f1", "isDisliked": false, "kept": true },
422
+ { "original": "#5c6b2f", "isDisliked": true, "fixed": "#6b7a3e", "kept": false },
423
+ { "original": "#ec4899", "isDisliked": false, "kept": true }
424
+ ],
425
+ "summary": {
426
+ "total": 4,
427
+ "disliked": 2,
428
+ "fixed": 2,
429
+ "unchanged": 2
430
+ },
431
+ "fixedColors": ["#7c8b4a", "#6366f1", "#6b7a3e", "#ec4899"]
432
+ }
433
+ ```
434
+
435
+ #### Different Fix Strategies
436
+
437
+ ```javascript
438
+ // Only shift hue, don't lighten
439
+ {
440
+ "name": "fix_disliked_colors_batch",
441
+ "arguments": {
442
+ "colors": ["#6b7c3a", "#5c6b2f"],
443
+ "strategy": "shift" // Only hue adjustment
444
+ }
445
+ }
446
+
447
+ // Only lighten, don't shift
448
+ {
449
+ "name": "fix_disliked_colors_batch",
450
+ "arguments": {
451
+ "colors": ["#6b7c3a", "#5c6b2f"],
452
+ "strategy": "lighten" // Only tone adjustment
453
+ }
454
+ }
455
+ ```
456
+
457
+ ### Use Cases
458
+
459
+ - Cleaning up extracted color palettes
460
+ - Validating theme colors
461
+ - Ensuring pleasant color schemes
462
+ - Batch color improvement
463
+
464
+ ## Best Practices
465
+
466
+ ### Image Preparation
467
+
468
+ #### Optimal Size
469
+ - Resize images to 200-500px width
470
+ - Larger images don't improve accuracy
471
+ - Smaller images process faster
472
+
473
+ ```javascript
474
+ // Resize before extraction
475
+ const resized = await sharp(image)
476
+ .resize(300, null, { fit: 'inside' })
477
+ .toBuffer();
478
+ ```
479
+
480
+ #### Image Quality
481
+ - Use uncompressed or lightly compressed images
482
+ - Avoid heavily filtered images
483
+ - Ensure good color representation
484
+
485
+ ### Performance Optimization
486
+
487
+ #### Caching Results
488
+
489
+ ```javascript
490
+ const cache = new Map();
491
+
492
+ function getCachedColors(imageHash) {
493
+ if (cache.has(imageHash)) {
494
+ return cache.get(imageHash);
495
+ }
496
+
497
+ const colors = extractColors(image);
498
+ cache.set(imageHash, colors);
499
+ return colors;
500
+ }
501
+ ```
502
+
503
+ #### Batch Processing
504
+
505
+ ```javascript
506
+ // Process multiple images efficiently
507
+ const images = [img1, img2, img3];
508
+ const results = await Promise.all(
509
+ images.map(img => extractColors(img))
510
+ );
511
+ ```
512
+
513
+ ### Color Selection
514
+
515
+ #### For UI Themes
516
+ - Prefer colors with chroma 40-60
517
+ - Avoid very dark or very light colors
518
+ - Check for accessibility
519
+
520
+ #### For Artistic Palettes
521
+ - Include wider chroma range
522
+ - Keep accent colors
523
+ - Preserve unique hues
524
+
525
+ ## Common Patterns
526
+
527
+ ### Album Art Theming
528
+
529
+ ```javascript
530
+ async function themeFromAlbumArt(artworkUrl) {
531
+ // 1. Load and prepare image
532
+ const pixels = await loadImage(artworkUrl);
533
+
534
+ // 2. Generate theme
535
+ const theme = await generateThemeFromImage({
536
+ imageData: pixels,
537
+ variant: 'vibrant' // Music apps often use vibrant themes
538
+ });
539
+
540
+ // 3. Apply to UI
541
+ applyTheme(theme.schemes.dark); // Music apps often use dark themes
542
+ }
543
+ ```
544
+
545
+ ### Logo Color Extraction
546
+
547
+ ```javascript
548
+ async function extractBrandColors(logoPath) {
549
+ // 1. Load logo
550
+ const pixels = await loadLogo(logoPath);
551
+
552
+ // 2. Extract colors
553
+ const extracted = await extractColors({
554
+ imageData: pixels,
555
+ maxColors: 3, // Logos typically have few colors
556
+ minPopulation: 0.05 // Higher threshold for logos
557
+ });
558
+
559
+ // 3. Fix any disliked colors
560
+ const fixed = await fixDislikedColors(extracted.colors);
561
+
562
+ return fixed;
563
+ }
564
+ ```
565
+
566
+ ### Dynamic Background
567
+
568
+ ```javascript
569
+ async function adaptiveBackground(imageUrl) {
570
+ // 1. Extract dominant color
571
+ const colors = await extractColors(imageUrl);
572
+ const dominant = colors[0];
573
+
574
+ // 2. Create subtle background
575
+ const background = {
576
+ ...dominant.hct,
577
+ chroma: dominant.hct.chroma * 0.3, // Reduce chroma
578
+ tone: 95 // Very light
579
+ };
580
+
581
+ return hctToHex(background);
582
+ }
583
+ ```
584
+
585
+ ## Troubleshooting
586
+
587
+ ### No Colors Extracted
588
+
589
+ **Problem**: Empty result from extraction
590
+ **Solution**:
591
+ - Check image data format (must be RGBA)
592
+ - Verify pixel array is not empty
593
+ - Lower minPopulation threshold
594
+
595
+ ### Poor Color Selection
596
+
597
+ **Problem**: Extracted colors don't represent image well
598
+ **Solution**:
599
+ - Increase maxColors
600
+ - Adjust targetChroma for different types
601
+ - Try different quantization settings
602
+
603
+ ### Disliked Colors in Results
604
+
605
+ **Problem**: Extracted colors are unpleasant
606
+ **Solution**:
607
+ - Use `fix_disliked_colors_batch`
608
+ - Adjust extraction to avoid bile zone
609
+ - Post-process results
610
+
611
+ ### Performance Issues
612
+
613
+ **Problem**: Slow extraction for large images
614
+ **Solution**:
615
+ - Resize images before extraction
616
+ - Use sampling (process every nth pixel)
617
+ - Cache results for repeated images
618
+
619
+ ## See Also
620
+
621
+ - [Image Analysis Concepts](../concepts/image-analysis.md) - How extraction works
622
+ - [Material Design Tools](./material-design.md) - Theme generation
623
+ - [Color Operations](./color-operations.md) - Color manipulation
624
+ - [Image Extraction Examples](../examples/image-extraction.md) - Practical examples