@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.
- package/.claude/settings.local.json +39 -0
- package/.env +2 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +73 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +71 -0
- package/.github/pull_request_template.md +97 -0
- package/.github/workflows/ci.yml +127 -0
- package/.github/workflows/deploy-docs.yml +56 -0
- package/.github/workflows/release.yml +99 -0
- package/.mcp.json +12 -0
- package/.prettierignore +1 -0
- package/CLAUDE.md +201 -0
- package/DOCUMENTATION.md +274 -0
- package/GEMINI.md +54 -0
- package/LICENSE +21 -0
- package/README.md +401 -0
- package/demo/content_based_color.png +0 -0
- package/demo/music-player.html +621 -0
- package/demo/podcast-player.html +903 -0
- package/dist/bin/coolors-mcp.d.ts +1 -0
- package/dist/bin/coolors-mcp.js +154 -0
- package/dist/bin/coolors-mcp.js.map +1 -0
- package/dist/bin/server.d.ts +1 -0
- package/dist/bin/server.js +3292 -0
- package/dist/bin/server.js.map +1 -0
- package/dist/chunk-IQ7NN26V.js +114 -0
- package/dist/chunk-IQ7NN26V.js.map +1 -0
- package/dist/chunk-P3ARRKLS.js +1214 -0
- package/dist/chunk-P3ARRKLS.js.map +1 -0
- package/dist/color/index.d.ts +716 -0
- package/dist/color/index.js +153 -0
- package/dist/color/index.js.map +1 -0
- package/dist/coolors-mcp.d.ts +136 -0
- package/dist/coolors-mcp.js +7 -0
- package/dist/coolors-mcp.js.map +1 -0
- package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
- package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
- package/docs/.vitepress/cache/deps/_metadata.json +127 -0
- package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
- package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
- package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +12683 -0
- package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js.map +7 -0
- package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +9719 -0
- package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js.map +7 -0
- package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
- package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
- package/docs/.vitepress/cache/deps/cytoscape.js +30278 -0
- package/docs/.vitepress/cache/deps/cytoscape.js.map +7 -0
- package/docs/.vitepress/cache/deps/dayjs.js +285 -0
- package/docs/.vitepress/cache/deps/dayjs.js.map +7 -0
- package/docs/.vitepress/cache/deps/debug.js +468 -0
- package/docs/.vitepress/cache/deps/debug.js.map +7 -0
- package/docs/.vitepress/cache/deps/package.json +3 -0
- package/docs/.vitepress/cache/deps/prismjs.js +1466 -0
- package/docs/.vitepress/cache/deps/prismjs.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +228 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +142 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +27 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +65 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +53 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +73 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1146 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
- package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___minisearch.js +1814 -0
- package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
- package/docs/.vitepress/cache/deps/vue.js +344 -0
- package/docs/.vitepress/cache/deps/vue.js.map +7 -0
- package/docs/.vitepress/components/ClientGrid.vue +125 -0
- package/docs/.vitepress/components/CodeBlock.vue +231 -0
- package/docs/.vitepress/components/ConfigModal.vue +477 -0
- package/docs/.vitepress/components/DiagramModal.vue +528 -0
- package/docs/.vitepress/components/TroubleshootingModal.vue +472 -0
- package/docs/.vitepress/config.js +162 -0
- package/docs/.vitepress/theme/FundingLayout.vue +251 -0
- package/docs/.vitepress/theme/Layout.vue +134 -0
- package/docs/.vitepress/theme/components/AdBanner.vue +317 -0
- package/docs/.vitepress/theme/components/AdPlaceholder.vue +78 -0
- package/docs/.vitepress/theme/components/FundingEffects.vue +322 -0
- package/docs/.vitepress/theme/components/FundingHero.vue +345 -0
- package/docs/.vitepress/theme/components/SupportSection.vue +511 -0
- package/docs/.vitepress/theme/custom-app.css +339 -0
- package/docs/.vitepress/theme/custom.css +699 -0
- package/docs/.vitepress/theme/index.js +25 -0
- package/docs/README.md +198 -0
- package/docs/concepts/accessibility.md +473 -0
- package/docs/concepts/color-spaces.md +222 -0
- package/docs/concepts/distance-metrics.md +384 -0
- package/docs/concepts/hct.md +261 -0
- package/docs/concepts/image-analysis.md +396 -0
- package/docs/concepts/material-design.md +306 -0
- package/docs/concepts/theme-matching.md +399 -0
- package/docs/examples/basic-colors.md +490 -0
- package/docs/examples/creating-themes.md +898 -0
- package/docs/examples/css-refactoring.md +824 -0
- package/docs/examples/image-extraction.md +882 -0
- package/docs/getting-started.md +366 -0
- package/docs/index.md +190 -0
- package/docs/installation.md +157 -0
- package/docs/tools/README.md +234 -0
- package/docs/tools/accessibility.md +614 -0
- package/docs/tools/color-operations.md +374 -0
- package/docs/tools/image-extraction.md +624 -0
- package/docs/tools/material-design.md +347 -0
- package/docs/tools/theme-matching.md +552 -0
- package/eslint.config.ts +14 -0
- package/examples/theme-matching.md +113 -0
- package/jsr.json +7 -0
- package/mcp-config.json +8 -0
- package/note.md +35 -0
- package/package.json +122 -0
- package/research_results.md +53 -0
- package/src/bin/coolors-mcp.ts +194 -0
- package/src/bin/server.ts +61 -0
- package/src/color/__tests__/conversions-argb.test.ts +198 -0
- package/src/color/__tests__/extract-colors.test.ts +360 -0
- package/src/color/__tests__/image-utils.test.ts +242 -0
- package/src/color/__tests__/reference-colors.test.ts +278 -0
- package/src/color/__tests__/round-trip.test.ts +197 -0
- package/src/color/conversions.test.ts +402 -0
- package/src/color/conversions.ts +393 -0
- package/src/color/dislike/__tests__/dislike-analyzer.test.ts +248 -0
- package/src/color/dislike/dislike-analyzer.ts +114 -0
- package/src/color/extract-colors.ts +228 -0
- package/src/color/hct/__tests__/hct-class.test.ts +232 -0
- package/src/color/hct/harmonization.ts +204 -0
- package/src/color/hct/hct-class.ts +109 -0
- package/src/color/hct/hct-solver.ts +168 -0
- package/src/color/hct/index.ts +39 -0
- package/src/color/hct/tonal-palette.ts +211 -0
- package/src/color/hct/types.ts +88 -0
- package/src/color/image-utils.ts +79 -0
- package/src/color/index.ts +87 -0
- package/src/color/material-theme.ts +157 -0
- package/src/color/metrics.test.ts +276 -0
- package/src/color/metrics.ts +281 -0
- package/src/color/quantize/__tests__/quantizer_celebi.test.ts +195 -0
- package/src/color/quantize/lab_point_provider.ts +55 -0
- package/src/color/quantize/point_provider.ts +27 -0
- package/src/color/quantize/quantizer_celebi.ts +51 -0
- package/src/color/quantize/quantizer_celebi_test.ts +71 -0
- package/src/color/quantize/quantizer_map.ts +47 -0
- package/src/color/quantize/quantizer_wsmeans.ts +232 -0
- package/src/color/quantize/quantizer_wu.ts +472 -0
- package/src/color/score/__tests__/score.test.ts +224 -0
- package/src/color/score/score.ts +175 -0
- package/src/color/types.ts +151 -0
- package/src/color/utils/color_utils.ts +292 -0
- package/src/color/utils/math_utils.ts +145 -0
- package/src/color/utils.test.ts +403 -0
- package/src/color/utils.ts +315 -0
- package/src/constants.ts +5 -0
- package/src/coolors-mcp.ts +37 -0
- package/src/examples/addition.ts +333 -0
- package/src/examples/color-demo.ts +125 -0
- package/src/examples/custom-logger.ts +201 -0
- package/src/examples/oauth-server.ts +113 -0
- package/src/examples/session-context.ts +269 -0
- package/src/session.ts +116 -0
- package/src/theme/__tests__/matcher.test.ts +180 -0
- package/src/theme/__tests__/parser.test.ts +148 -0
- package/src/theme/__tests__/refactor.test.ts +224 -0
- package/src/theme/index.ts +34 -0
- package/src/theme/matcher.ts +395 -0
- package/src/theme/parser.ts +392 -0
- package/src/theme/refactor.ts +360 -0
- package/src/theme/types.ts +152 -0
- package/src/tools/__tests__/gradient-generator.test.ts +206 -0
- package/src/tools/__tests__/palette-with-locks.test.ts +109 -0
- package/src/tools/color-conversion.tool.ts +54 -0
- package/src/tools/color-distance.tool.ts +41 -0
- package/src/tools/colors.ts +31 -0
- package/src/tools/contrast-checker.tool.ts +37 -0
- package/src/tools/dislike-analyzer.tool.ts +247 -0
- package/src/tools/gradient-generator.tool.ts +250 -0
- package/src/tools/image-extraction.tools.ts +289 -0
- package/src/tools/index.ts +39 -0
- package/src/tools/material-theme.tools.ts +250 -0
- package/src/tools/palette-generator.tool.ts +135 -0
- package/src/tools/palette-with-locks.tool.ts +221 -0
- package/src/tools/registry.ts +142 -0
- package/src/tools/simple-tools.ts +37 -0
- package/src/tools/theme-matching.tools.ts +334 -0
- package/src/types.ts +182 -0
- package/src/utils.ts +22 -0
- package/tsconfig.json +8 -0
- 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
|