@trishchuk/coolors-mcp 1.0.0 → 1.0.1
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 +2 -6
- package/.github/ISSUE_TEMPLATE/bug_report.md +20 -8
- package/.github/ISSUE_TEMPLATE/feature_request.md +22 -8
- package/.github/pull_request_template.md +33 -8
- package/.github/workflows/ci.yml +97 -97
- package/.github/workflows/deploy-docs.yml +9 -9
- package/.github/workflows/release.yml +15 -15
- package/README.md +26 -1
- package/TOOLS_UK.md +233 -0
- package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +30 -12
- package/docs/.vitepress/cache/deps/_metadata.json +1 -1
- package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -6
- package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +2543 -1612
- package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +3508 -2529
- package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +1902 -1003
- package/docs/.vitepress/cache/deps/cytoscape.js +13303 -7347
- package/docs/.vitepress/cache/deps/dayjs.js +494 -272
- package/docs/.vitepress/cache/deps/debug.js +82 -38
- package/docs/.vitepress/cache/deps/prismjs.js +444 -272
- package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +80 -73
- package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +93 -62
- package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +13 -13
- package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +34 -27
- package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +20 -17
- package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +75 -41
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +2005 -1438
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +2 -2
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +566 -229
- package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +382 -270
- package/docs/.vitepress/cache/deps/vitepress___minisearch.js +334 -125
- package/docs/.vitepress/cache/deps/vue.js +2 -2
- package/docs/.vitepress/components/ClientGrid.vue +9 -3
- package/docs/.vitepress/components/CodeBlock.vue +51 -44
- package/docs/.vitepress/components/ConfigModal.vue +151 -67
- package/docs/.vitepress/components/DiagramModal.vue +186 -154
- package/docs/.vitepress/components/TroubleshootingModal.vue +101 -96
- package/docs/.vitepress/config.js +171 -141
- package/docs/.vitepress/theme/FundingLayout.vue +65 -54
- package/docs/.vitepress/theme/Layout.vue +21 -21
- package/docs/.vitepress/theme/components/AdBanner.vue +73 -52
- package/docs/.vitepress/theme/components/AdPlaceholder.vue +3 -3
- package/docs/.vitepress/theme/components/FundingEffects.vue +77 -53
- package/docs/.vitepress/theme/components/FundingHero.vue +78 -63
- package/docs/.vitepress/theme/components/SupportSection.vue +106 -89
- package/docs/.vitepress/theme/custom-app.css +19 -12
- package/docs/.vitepress/theme/custom.css +33 -25
- package/docs/.vitepress/theme/index.js +19 -16
- package/docs/concepts/accessibility.md +59 -47
- package/docs/concepts/color-spaces.md +28 -6
- package/docs/concepts/distance-metrics.md +45 -30
- package/docs/concepts/hct.md +30 -27
- package/docs/concepts/image-analysis.md +52 -21
- package/docs/concepts/material-design.md +43 -17
- package/docs/concepts/theme-matching.md +64 -40
- package/docs/examples/basic-colors.md +92 -108
- package/docs/examples/creating-themes.md +104 -108
- package/docs/examples/css-refactoring.md +33 -29
- package/docs/examples/image-extraction.md +145 -138
- package/docs/getting-started.md +45 -34
- package/docs/index.md +5 -1
- package/docs/installation.md +15 -1
- package/docs/tools/accessibility.md +74 -68
- package/docs/tools/image-extraction.md +62 -54
- package/docs/tools/theme-matching.md +45 -42
- package/note.md +1 -2
- package/package.json +2 -2
|
@@ -8,36 +8,36 @@ Check the contrast ratio between two colors and verify WCAG compliance.
|
|
|
8
8
|
|
|
9
9
|
### Parameters
|
|
10
10
|
|
|
11
|
-
| Parameter
|
|
12
|
-
|
|
13
|
-
| `foreground` | string | ✅
|
|
14
|
-
| `background` | string | ✅
|
|
15
|
-
| `fontSize`
|
|
16
|
-
| `fontWeight` | number | ❌
|
|
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
17
|
|
|
18
18
|
### Returns
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
21
|
{
|
|
22
|
-
ratio: number;
|
|
23
|
-
ratioString: string;
|
|
22
|
+
ratio: number; // Contrast ratio (1-21)
|
|
23
|
+
ratioString: string; // Formatted as "X.XX:1"
|
|
24
24
|
passes: {
|
|
25
25
|
AA: {
|
|
26
|
-
normal: boolean;
|
|
27
|
-
large: boolean;
|
|
28
|
-
nonText: boolean;
|
|
29
|
-
}
|
|
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
30
|
AAA: {
|
|
31
|
-
normal: boolean;
|
|
32
|
-
large: boolean;
|
|
31
|
+
normal: boolean; // Passes AAA for normal text (7:1)
|
|
32
|
+
large: boolean; // Passes AAA for large text (4.5:1)
|
|
33
33
|
}
|
|
34
|
-
}
|
|
34
|
+
}
|
|
35
35
|
recommendation: string; // Human-readable recommendation
|
|
36
36
|
luminance: {
|
|
37
|
-
foreground: number;
|
|
38
|
-
background: number;
|
|
39
|
-
}
|
|
40
|
-
isLargeText: boolean;
|
|
37
|
+
foreground: number; // Relative luminance (0-1)
|
|
38
|
+
background: number; // Relative luminance (0-1)
|
|
39
|
+
}
|
|
40
|
+
isLargeText: boolean; // Whether text qualifies as large
|
|
41
41
|
}
|
|
42
42
|
```
|
|
43
43
|
|
|
@@ -113,9 +113,9 @@ Check the contrast ratio between two colors and verify WCAG compliance.
|
|
|
113
113
|
```javascript
|
|
114
114
|
// Test color pairs
|
|
115
115
|
const pairs = [
|
|
116
|
-
{ fg: "#1f2937", bg: "#ffffff" },
|
|
117
|
-
{ fg: "#6366f1", bg: "#f3f4f6" },
|
|
118
|
-
{ fg: "#ffffff", bg: "#dc2626" }
|
|
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
119
|
];
|
|
120
120
|
|
|
121
121
|
for (const pair of pairs) {
|
|
@@ -127,6 +127,7 @@ for (const pair of pairs) {
|
|
|
127
127
|
### Large Text Definition
|
|
128
128
|
|
|
129
129
|
Text is considered "large" when:
|
|
130
|
+
|
|
130
131
|
- Font size ≥ 18pt (24px)
|
|
131
132
|
- Font size ≥ 14pt (18.67px) AND bold (weight ≥ 700)
|
|
132
133
|
|
|
@@ -143,12 +144,12 @@ Automatically adjust a color to meet contrast requirements.
|
|
|
143
144
|
|
|
144
145
|
### Parameters
|
|
145
146
|
|
|
146
|
-
| Parameter
|
|
147
|
-
|
|
148
|
-
| `foreground`
|
|
149
|
-
| `background`
|
|
150
|
-
| `targetRatio`
|
|
151
|
-
| `preferLighter` | boolean | ❌
|
|
147
|
+
| Parameter | Type | Required | Description |
|
|
148
|
+
| --------------- | ------- | -------- | -------------------------------- |
|
|
149
|
+
| `foreground` | string | ✅ | Color to adjust |
|
|
150
|
+
| `background` | string | ✅ | Background color |
|
|
151
|
+
| `targetRatio` | number | ✅ | Minimum contrast ratio needed |
|
|
152
|
+
| `preferLighter` | boolean | ❌ | Prefer lightening over darkening |
|
|
152
153
|
|
|
153
154
|
### Returns
|
|
154
155
|
|
|
@@ -157,14 +158,14 @@ Automatically adjust a color to meet contrast requirements.
|
|
|
157
158
|
original: {
|
|
158
159
|
color: string;
|
|
159
160
|
ratio: number;
|
|
160
|
-
}
|
|
161
|
+
}
|
|
161
162
|
adjusted: {
|
|
162
163
|
color: string;
|
|
163
164
|
ratio: number;
|
|
164
|
-
}
|
|
165
|
+
}
|
|
165
166
|
adjustmentMade: boolean;
|
|
166
|
-
adjustmentType:
|
|
167
|
-
toneChange: number;
|
|
167
|
+
adjustmentType: "lightened" | "darkened" | "none";
|
|
168
|
+
toneChange: number; // HCT tone difference
|
|
168
169
|
}
|
|
169
170
|
```
|
|
170
171
|
|
|
@@ -241,12 +242,12 @@ Generate accessible color pairs for different UI contexts.
|
|
|
241
242
|
|
|
242
243
|
### Parameters
|
|
243
244
|
|
|
244
|
-
| Parameter
|
|
245
|
-
|
|
246
|
-
| `baseColor`
|
|
247
|
-
| `count`
|
|
248
|
-
| `contrastLevels` | string[] | ❌
|
|
249
|
-
| `contexts`
|
|
245
|
+
| Parameter | Type | Required | Description |
|
|
246
|
+
| ---------------- | -------- | -------- | ------------------------------------------------ |
|
|
247
|
+
| `baseColor` | string | ✅ | Starting color |
|
|
248
|
+
| `count` | number | ❌ | Number of pairs to generate (default: 5) |
|
|
249
|
+
| `contrastLevels` | string[] | ❌ | Required levels: AA, AAA (default: ['AA']) |
|
|
250
|
+
| `contexts` | string[] | ❌ | UI contexts: text, button, border (default: all) |
|
|
250
251
|
|
|
251
252
|
### Returns
|
|
252
253
|
|
|
@@ -328,11 +329,11 @@ Check all color combinations in a palette for accessibility.
|
|
|
328
329
|
|
|
329
330
|
### Parameters
|
|
330
331
|
|
|
331
|
-
| Parameter
|
|
332
|
-
|
|
333
|
-
| `palette`
|
|
334
|
-
| `level`
|
|
335
|
-
| `includeReport` | boolean | ❌
|
|
332
|
+
| Parameter | Type | Required | Description |
|
|
333
|
+
| --------------- | ------- | -------- | ----------------------------------------- |
|
|
334
|
+
| `palette` | object | ✅ | Color palette with role names and values |
|
|
335
|
+
| `level` | string | ❌ | WCAG level to test: AA, AAA (default: AA) |
|
|
336
|
+
| `includeReport` | boolean | ❌ | Generate detailed report (default: true) |
|
|
336
337
|
|
|
337
338
|
### Returns
|
|
338
339
|
|
|
@@ -432,19 +433,21 @@ Check all color combinations in a palette for accessibility.
|
|
|
432
433
|
### Contrast Requirements
|
|
433
434
|
|
|
434
435
|
#### Text Content
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
|
438
|
-
|
|
|
436
|
+
|
|
437
|
+
| Context | AA Minimum | AAA Minimum |
|
|
438
|
+
| --------------- | -------------- | -------------- |
|
|
439
|
+
| Normal text | 4.5:1 | 7:1 |
|
|
440
|
+
| Large text | 3:1 | 4.5:1 |
|
|
439
441
|
| Incidental text | No requirement | No requirement |
|
|
440
|
-
| Logotypes
|
|
442
|
+
| Logotypes | No requirement | No requirement |
|
|
441
443
|
|
|
442
444
|
#### Non-Text Content
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
|
446
|
-
|
|
|
447
|
-
|
|
|
445
|
+
|
|
446
|
+
| Context | AA Minimum | Notes |
|
|
447
|
+
| ------------- | -------------- | ------------------ |
|
|
448
|
+
| UI components | 3:1 | Active components |
|
|
449
|
+
| Graphics | 3:1 | Essential graphics |
|
|
450
|
+
| Decorative | No requirement | Purely decorative |
|
|
448
451
|
|
|
449
452
|
### Testing Strategy
|
|
450
453
|
|
|
@@ -454,7 +457,7 @@ async function testAccessibility(theme) {
|
|
|
454
457
|
// 1. Check individual pairs
|
|
455
458
|
const criticalPairs = [
|
|
456
459
|
{ fg: theme.text, bg: theme.background },
|
|
457
|
-
{ fg: theme.primary, bg: theme.surface }
|
|
460
|
+
{ fg: theme.primary, bg: theme.surface },
|
|
458
461
|
];
|
|
459
462
|
|
|
460
463
|
for (const pair of criticalPairs) {
|
|
@@ -467,7 +470,7 @@ async function testAccessibility(theme) {
|
|
|
467
470
|
// 2. Validate entire palette
|
|
468
471
|
const validation = await validatePalette(theme);
|
|
469
472
|
if (!validation.valid) {
|
|
470
|
-
console.error(
|
|
473
|
+
console.error("Palette has accessibility issues:", validation.issues);
|
|
471
474
|
}
|
|
472
475
|
|
|
473
476
|
// 3. Generate report
|
|
@@ -486,14 +489,14 @@ async function fixAccessibility(theme) {
|
|
|
486
489
|
fixed.text = await ensureContrast({
|
|
487
490
|
foreground: theme.text,
|
|
488
491
|
background: theme.background,
|
|
489
|
-
targetRatio: 4.5
|
|
492
|
+
targetRatio: 4.5,
|
|
490
493
|
});
|
|
491
494
|
|
|
492
495
|
// Ensure buttons are accessible
|
|
493
496
|
fixed.buttonText = await ensureContrast({
|
|
494
497
|
foreground: theme.buttonText,
|
|
495
498
|
background: theme.buttonBg,
|
|
496
|
-
targetRatio: 4.5
|
|
499
|
+
targetRatio: 4.5,
|
|
497
500
|
});
|
|
498
501
|
|
|
499
502
|
return fixed;
|
|
@@ -512,17 +515,17 @@ function validateDarkMode(darkTheme) {
|
|
|
512
515
|
{
|
|
513
516
|
fg: darkTheme.text,
|
|
514
517
|
bg: darkTheme.background,
|
|
515
|
-
min: 4.5
|
|
518
|
+
min: 4.5,
|
|
516
519
|
},
|
|
517
520
|
// But not too harsh (avoid pure white on black)
|
|
518
521
|
{
|
|
519
522
|
fg: darkTheme.text,
|
|
520
523
|
bg: darkTheme.background,
|
|
521
|
-
max: 18
|
|
522
|
-
}
|
|
524
|
+
max: 18, // Avoid excessive contrast
|
|
525
|
+
},
|
|
523
526
|
];
|
|
524
527
|
|
|
525
|
-
return checks.every(check => {
|
|
528
|
+
return checks.every((check) => {
|
|
526
529
|
const ratio = getContrast(check.fg, check.bg);
|
|
527
530
|
return ratio >= (check.min || 0) && ratio <= (check.max || 21);
|
|
528
531
|
});
|
|
@@ -546,10 +549,10 @@ function generateContrastLevels(baseTheme) {
|
|
|
546
549
|
|
|
547
550
|
// Maximum - For accessibility needs
|
|
548
551
|
maximum: {
|
|
549
|
-
text:
|
|
550
|
-
background:
|
|
551
|
-
primary:
|
|
552
|
-
}
|
|
552
|
+
text: "#000000",
|
|
553
|
+
background: "#ffffff",
|
|
554
|
+
primary: "#0000ff",
|
|
555
|
+
},
|
|
553
556
|
};
|
|
554
557
|
}
|
|
555
558
|
```
|
|
@@ -570,12 +573,12 @@ function validateFormColors(formTheme) {
|
|
|
570
573
|
focusRing: { min: 3.0, against: formTheme.inputBg },
|
|
571
574
|
|
|
572
575
|
// Placeholder text (relaxed requirement)
|
|
573
|
-
placeholder: { min: 3.0, against: formTheme.inputBg }
|
|
576
|
+
placeholder: { min: 3.0, against: formTheme.inputBg },
|
|
574
577
|
};
|
|
575
578
|
|
|
576
579
|
return Object.entries(requirements).map(([element, req]) => ({
|
|
577
580
|
element,
|
|
578
|
-
passes: checkContrast(formTheme[element], req.against).ratio >= req.min
|
|
581
|
+
passes: checkContrast(formTheme[element], req.against).ratio >= req.min,
|
|
579
582
|
}));
|
|
580
583
|
}
|
|
581
584
|
```
|
|
@@ -586,6 +589,7 @@ function validateFormColors(formTheme) {
|
|
|
586
589
|
|
|
587
590
|
**Problem**: Colors don't meet minimum contrast
|
|
588
591
|
**Solution**:
|
|
592
|
+
|
|
589
593
|
- Use `ensure_contrast` to auto-adjust
|
|
590
594
|
- Increase tone difference between colors
|
|
591
595
|
- Consider different color roles
|
|
@@ -594,6 +598,7 @@ function validateFormColors(formTheme) {
|
|
|
594
598
|
|
|
595
599
|
**Problem**: Maximum contrast (21:1) is too harsh
|
|
596
600
|
**Solution**:
|
|
601
|
+
|
|
597
602
|
- Use off-white (#fafafa) instead of pure white
|
|
598
603
|
- Use very dark gray (#0a0a0a) instead of pure black
|
|
599
604
|
- Aim for 12-15:1 for comfortable reading
|
|
@@ -602,6 +607,7 @@ function validateFormColors(formTheme) {
|
|
|
602
607
|
|
|
603
608
|
**Problem**: Adjusted colors lose brand identity
|
|
604
609
|
**Solution**:
|
|
610
|
+
|
|
605
611
|
- Adjust the background instead of foreground
|
|
606
612
|
- Use borders or icons to supplement color
|
|
607
613
|
- Provide high-contrast mode as option
|
|
@@ -611,4 +617,4 @@ function validateFormColors(formTheme) {
|
|
|
611
617
|
- [Accessibility Concepts](../concepts/accessibility.md) - WCAG standards explained
|
|
612
618
|
- [HCT System](../concepts/hct.md) - Tone-based contrast
|
|
613
619
|
- [Color Operations](./color-operations.md) - Color manipulation
|
|
614
|
-
- [Material Design Tools](./material-design.md) - Accessible themes
|
|
620
|
+
- [Material Design Tools](./material-design.md) - Accessible themes
|
|
@@ -8,27 +8,28 @@ Extract dominant colors from an image using Google's Celebi quantization algorit
|
|
|
8
8
|
|
|
9
9
|
### Parameters
|
|
10
10
|
|
|
11
|
-
| Parameter
|
|
12
|
-
|
|
13
|
-
| `imageData`
|
|
14
|
-
| `maxColors`
|
|
15
|
-
| `minPopulation` | number
|
|
16
|
-
| `targetChroma`
|
|
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
17
|
|
|
18
18
|
### Returns
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
21
|
{
|
|
22
22
|
colors: Array<{
|
|
23
|
-
hex: string;
|
|
24
|
-
rgb: [r, g, b];
|
|
25
|
-
hct: {
|
|
23
|
+
hex: string; // Hex color value
|
|
24
|
+
rgb: [r, g, b]; // RGB values
|
|
25
|
+
hct: {
|
|
26
|
+
// HCT values
|
|
26
27
|
hue: number;
|
|
27
28
|
chroma: number;
|
|
28
29
|
tone: number;
|
|
29
30
|
};
|
|
30
|
-
population: number;
|
|
31
|
-
score: number;
|
|
31
|
+
population: number; // Percentage of image (0-1)
|
|
32
|
+
score: number; // UI suitability score (0-1)
|
|
32
33
|
}>;
|
|
33
34
|
metadata: {
|
|
34
35
|
totalPixels: number;
|
|
@@ -111,8 +112,8 @@ Extract dominant colors from an image using Google's Celebi quantization algorit
|
|
|
111
112
|
#### From Canvas (Browser)
|
|
112
113
|
|
|
113
114
|
```javascript
|
|
114
|
-
const canvas = document.getElementById(
|
|
115
|
-
const ctx = canvas.getContext(
|
|
115
|
+
const canvas = document.getElementById("canvas");
|
|
116
|
+
const ctx = canvas.getContext("2d");
|
|
116
117
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
117
118
|
|
|
118
119
|
// Convert to flat array
|
|
@@ -120,25 +121,25 @@ const pixels = Array.from(imageData.data);
|
|
|
120
121
|
|
|
121
122
|
// Extract colors
|
|
122
123
|
const result = await extractColors({
|
|
123
|
-
imageData: pixels
|
|
124
|
+
imageData: pixels,
|
|
124
125
|
});
|
|
125
126
|
```
|
|
126
127
|
|
|
127
128
|
#### From Image File (Node.js)
|
|
128
129
|
|
|
129
130
|
```javascript
|
|
130
|
-
const sharp = require(
|
|
131
|
+
const sharp = require("sharp");
|
|
131
132
|
|
|
132
133
|
async function getPixelsFromImage(filepath) {
|
|
133
134
|
const { data, info } = await sharp(filepath)
|
|
134
|
-
.resize(300)
|
|
135
|
+
.resize(300) // Resize for performance
|
|
135
136
|
.raw()
|
|
136
137
|
.toBuffer({ resolveWithObject: true });
|
|
137
138
|
|
|
138
139
|
return Array.from(data);
|
|
139
140
|
}
|
|
140
141
|
|
|
141
|
-
const pixels = await getPixelsFromImage(
|
|
142
|
+
const pixels = await getPixelsFromImage("photo.jpg");
|
|
142
143
|
```
|
|
143
144
|
|
|
144
145
|
### Use Cases
|
|
@@ -154,18 +155,18 @@ Generate a complete Material Design 3 theme from an image.
|
|
|
154
155
|
|
|
155
156
|
### Parameters
|
|
156
157
|
|
|
157
|
-
| Parameter
|
|
158
|
-
|
|
159
|
-
| `imageData`
|
|
160
|
-
| `variant`
|
|
161
|
-
| `contrastLevel`
|
|
162
|
-
| `sourceColorIndex` | number
|
|
158
|
+
| Parameter | Type | Required | Description |
|
|
159
|
+
| ------------------ | -------- | -------- | ---------------------------------------------------------------------------- |
|
|
160
|
+
| `imageData` | number[] | ✅ | RGBA pixel array |
|
|
161
|
+
| `variant` | string | ❌ | Theme variant: tonalSpot, fidelity, vibrant, expressive, neutral, monochrome |
|
|
162
|
+
| `contrastLevel` | number | ❌ | Contrast level: 0 (default), 0.5 (medium), 1.0 (high) |
|
|
163
|
+
| `sourceColorIndex` | number | ❌ | Which extracted color to use as source (default: 0) |
|
|
163
164
|
|
|
164
165
|
### Returns
|
|
165
166
|
|
|
166
167
|
```typescript
|
|
167
168
|
{
|
|
168
|
-
sourceColor: string;
|
|
169
|
+
sourceColor: string; // Selected source color
|
|
169
170
|
extractedColors: Array<{
|
|
170
171
|
hex: string;
|
|
171
172
|
score: number;
|
|
@@ -178,19 +179,19 @@ Generate a complete Material Design 3 theme from an image.
|
|
|
178
179
|
primaryContainer: string;
|
|
179
180
|
onPrimaryContainer: string;
|
|
180
181
|
// ... all Material Design color roles
|
|
181
|
-
}
|
|
182
|
+
}
|
|
182
183
|
dark: {
|
|
183
184
|
// ... dark theme colors
|
|
184
185
|
}
|
|
185
|
-
}
|
|
186
|
+
}
|
|
186
187
|
palettes: {
|
|
187
188
|
primary: object;
|
|
188
189
|
secondary: object;
|
|
189
190
|
tertiary: object;
|
|
190
191
|
neutral: object;
|
|
191
192
|
error: object;
|
|
192
|
-
}
|
|
193
|
-
css: string;
|
|
193
|
+
}
|
|
194
|
+
css: string; // Generated CSS variables
|
|
194
195
|
}
|
|
195
196
|
```
|
|
196
197
|
|
|
@@ -268,14 +269,14 @@ Generate a complete Material Design 3 theme from an image.
|
|
|
268
269
|
|
|
269
270
|
### Theme Variants
|
|
270
271
|
|
|
271
|
-
| Variant
|
|
272
|
-
|
|
273
|
-
| `tonalSpot`
|
|
274
|
-
| `fidelity`
|
|
275
|
-
| `vibrant`
|
|
272
|
+
| Variant | Description | Best For |
|
|
273
|
+
| ------------ | ----------------------- | ------------------ |
|
|
274
|
+
| `tonalSpot` | Default, balanced | General use |
|
|
275
|
+
| `fidelity` | Preserves source color | Brand-critical |
|
|
276
|
+
| `vibrant` | Higher chroma | Playful, energetic |
|
|
276
277
|
| `expressive` | Unexpected combinations | Creative, artistic |
|
|
277
|
-
| `neutral`
|
|
278
|
-
| `monochrome` | Single hue
|
|
278
|
+
| `neutral` | Minimal color | Professional |
|
|
279
|
+
| `monochrome` | Single hue | Minimalist |
|
|
279
280
|
|
|
280
281
|
### Use Cases
|
|
281
282
|
|
|
@@ -290,10 +291,10 @@ Check if a color falls in the universally disliked "bile zone" and get a fixed v
|
|
|
290
291
|
|
|
291
292
|
### Parameters
|
|
292
293
|
|
|
293
|
-
| Parameter | Type
|
|
294
|
-
|
|
295
|
-
| `color`
|
|
296
|
-
| `autoFix` | boolean | ❌
|
|
294
|
+
| Parameter | Type | Required | Description |
|
|
295
|
+
| --------- | ------- | -------- | -------------------------------------------------- |
|
|
296
|
+
| `color` | string | ✅ | Color to analyze (hex, rgb, hsl) |
|
|
297
|
+
| `autoFix` | boolean | ❌ | Automatically return fixed version (default: true) |
|
|
297
298
|
|
|
298
299
|
### Returns
|
|
299
300
|
|
|
@@ -358,6 +359,7 @@ Check if a color falls in the universally disliked "bile zone" and get a fixed v
|
|
|
358
359
|
### The Dislike Zone
|
|
359
360
|
|
|
360
361
|
Colors are universally disliked when they have:
|
|
362
|
+
|
|
361
363
|
- **Hue**: 50-120° (yellow-green range)
|
|
362
364
|
- **Chroma**: 20-50 (moderate saturation)
|
|
363
365
|
- **Tone**: 20-50 (dark to medium)
|
|
@@ -377,10 +379,10 @@ Analyze and fix multiple colors, returning only liked versions.
|
|
|
377
379
|
|
|
378
380
|
### Parameters
|
|
379
381
|
|
|
380
|
-
| Parameter
|
|
381
|
-
|
|
382
|
-
| `colors`
|
|
383
|
-
| `strategy` | string
|
|
382
|
+
| Parameter | Type | Required | Description |
|
|
383
|
+
| ---------- | -------- | -------- | -------------------------------------------------- |
|
|
384
|
+
| `colors` | string[] | ✅ | Array of colors to check |
|
|
385
|
+
| `strategy` | string | ❌ | Fix strategy: shift, lighten, both (default: both) |
|
|
384
386
|
|
|
385
387
|
### Returns
|
|
386
388
|
|
|
@@ -466,6 +468,7 @@ Analyze and fix multiple colors, returning only liked versions.
|
|
|
466
468
|
### Image Preparation
|
|
467
469
|
|
|
468
470
|
#### Optimal Size
|
|
471
|
+
|
|
469
472
|
- Resize images to 200-500px width
|
|
470
473
|
- Larger images don't improve accuracy
|
|
471
474
|
- Smaller images process faster
|
|
@@ -473,11 +476,12 @@ Analyze and fix multiple colors, returning only liked versions.
|
|
|
473
476
|
```javascript
|
|
474
477
|
// Resize before extraction
|
|
475
478
|
const resized = await sharp(image)
|
|
476
|
-
.resize(300, null, { fit:
|
|
479
|
+
.resize(300, null, { fit: "inside" })
|
|
477
480
|
.toBuffer();
|
|
478
481
|
```
|
|
479
482
|
|
|
480
483
|
#### Image Quality
|
|
484
|
+
|
|
481
485
|
- Use uncompressed or lightly compressed images
|
|
482
486
|
- Avoid heavily filtered images
|
|
483
487
|
- Ensure good color representation
|
|
@@ -505,19 +509,19 @@ function getCachedColors(imageHash) {
|
|
|
505
509
|
```javascript
|
|
506
510
|
// Process multiple images efficiently
|
|
507
511
|
const images = [img1, img2, img3];
|
|
508
|
-
const results = await Promise.all(
|
|
509
|
-
images.map(img => extractColors(img))
|
|
510
|
-
);
|
|
512
|
+
const results = await Promise.all(images.map((img) => extractColors(img)));
|
|
511
513
|
```
|
|
512
514
|
|
|
513
515
|
### Color Selection
|
|
514
516
|
|
|
515
517
|
#### For UI Themes
|
|
518
|
+
|
|
516
519
|
- Prefer colors with chroma 40-60
|
|
517
520
|
- Avoid very dark or very light colors
|
|
518
521
|
- Check for accessibility
|
|
519
522
|
|
|
520
523
|
#### For Artistic Palettes
|
|
524
|
+
|
|
521
525
|
- Include wider chroma range
|
|
522
526
|
- Keep accent colors
|
|
523
527
|
- Preserve unique hues
|
|
@@ -534,11 +538,11 @@ async function themeFromAlbumArt(artworkUrl) {
|
|
|
534
538
|
// 2. Generate theme
|
|
535
539
|
const theme = await generateThemeFromImage({
|
|
536
540
|
imageData: pixels,
|
|
537
|
-
variant:
|
|
541
|
+
variant: "vibrant", // Music apps often use vibrant themes
|
|
538
542
|
});
|
|
539
543
|
|
|
540
544
|
// 3. Apply to UI
|
|
541
|
-
applyTheme(theme.schemes.dark);
|
|
545
|
+
applyTheme(theme.schemes.dark); // Music apps often use dark themes
|
|
542
546
|
}
|
|
543
547
|
```
|
|
544
548
|
|
|
@@ -552,8 +556,8 @@ async function extractBrandColors(logoPath) {
|
|
|
552
556
|
// 2. Extract colors
|
|
553
557
|
const extracted = await extractColors({
|
|
554
558
|
imageData: pixels,
|
|
555
|
-
maxColors: 3,
|
|
556
|
-
minPopulation: 0.05
|
|
559
|
+
maxColors: 3, // Logos typically have few colors
|
|
560
|
+
minPopulation: 0.05, // Higher threshold for logos
|
|
557
561
|
});
|
|
558
562
|
|
|
559
563
|
// 3. Fix any disliked colors
|
|
@@ -574,8 +578,8 @@ async function adaptiveBackground(imageUrl) {
|
|
|
574
578
|
// 2. Create subtle background
|
|
575
579
|
const background = {
|
|
576
580
|
...dominant.hct,
|
|
577
|
-
chroma: dominant.hct.chroma * 0.3,
|
|
578
|
-
tone: 95
|
|
581
|
+
chroma: dominant.hct.chroma * 0.3, // Reduce chroma
|
|
582
|
+
tone: 95, // Very light
|
|
579
583
|
};
|
|
580
584
|
|
|
581
585
|
return hctToHex(background);
|
|
@@ -588,6 +592,7 @@ async function adaptiveBackground(imageUrl) {
|
|
|
588
592
|
|
|
589
593
|
**Problem**: Empty result from extraction
|
|
590
594
|
**Solution**:
|
|
595
|
+
|
|
591
596
|
- Check image data format (must be RGBA)
|
|
592
597
|
- Verify pixel array is not empty
|
|
593
598
|
- Lower minPopulation threshold
|
|
@@ -596,6 +601,7 @@ async function adaptiveBackground(imageUrl) {
|
|
|
596
601
|
|
|
597
602
|
**Problem**: Extracted colors don't represent image well
|
|
598
603
|
**Solution**:
|
|
604
|
+
|
|
599
605
|
- Increase maxColors
|
|
600
606
|
- Adjust targetChroma for different types
|
|
601
607
|
- Try different quantization settings
|
|
@@ -604,6 +610,7 @@ async function adaptiveBackground(imageUrl) {
|
|
|
604
610
|
|
|
605
611
|
**Problem**: Extracted colors are unpleasant
|
|
606
612
|
**Solution**:
|
|
613
|
+
|
|
607
614
|
- Use `fix_disliked_colors_batch`
|
|
608
615
|
- Adjust extraction to avoid bile zone
|
|
609
616
|
- Post-process results
|
|
@@ -612,6 +619,7 @@ async function adaptiveBackground(imageUrl) {
|
|
|
612
619
|
|
|
613
620
|
**Problem**: Slow extraction for large images
|
|
614
621
|
**Solution**:
|
|
622
|
+
|
|
615
623
|
- Resize images before extraction
|
|
616
624
|
- Use sampling (process every nth pixel)
|
|
617
625
|
- Cache results for repeated images
|
|
@@ -621,4 +629,4 @@ async function adaptiveBackground(imageUrl) {
|
|
|
621
629
|
- [Image Analysis Concepts](../concepts/image-analysis.md) - How extraction works
|
|
622
630
|
- [Material Design Tools](./material-design.md) - Theme generation
|
|
623
631
|
- [Color Operations](./color-operations.md) - Color manipulation
|
|
624
|
-
- [Image Extraction Examples](../examples/image-extraction.md) - Practical examples
|
|
632
|
+
- [Image Extraction Examples](../examples/image-extraction.md) - Practical examples
|