@trishchuk/coolors-mcp 1.0.0 → 1.1.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 (140) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +20 -8
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +22 -8
  3. package/.github/pull_request_template.md +33 -8
  4. package/.github/workflows/ci.yml +107 -104
  5. package/.github/workflows/deploy-docs.yml +14 -11
  6. package/.github/workflows/release.yml +25 -23
  7. package/README.md +149 -15
  8. package/dist/bin/server.js +997 -256
  9. package/dist/bin/server.js.map +1 -1
  10. package/dist/{chunk-P3ARRKLS.js → chunk-HOMDMKUY.js} +3 -1
  11. package/dist/{chunk-P3ARRKLS.js.map → chunk-HOMDMKUY.js.map} +1 -1
  12. package/dist/{chunk-IQ7NN26V.js → chunk-LHW2ZTOU.js} +14 -2
  13. package/dist/chunk-LHW2ZTOU.js.map +1 -0
  14. package/dist/color/index.js +1 -1
  15. package/dist/coolors-mcp.d.ts +4 -4
  16. package/dist/coolors-mcp.js +1 -1
  17. package/docs/.vitepress/components/ClientGrid.vue +9 -3
  18. package/docs/.vitepress/components/CodeBlock.vue +51 -44
  19. package/docs/.vitepress/components/ConfigModal.vue +151 -67
  20. package/docs/.vitepress/components/DiagramModal.vue +186 -154
  21. package/docs/.vitepress/components/TroubleshootingModal.vue +101 -96
  22. package/docs/.vitepress/config.js +171 -141
  23. package/docs/.vitepress/theme/FundingLayout.vue +65 -54
  24. package/docs/.vitepress/theme/Layout.vue +21 -21
  25. package/docs/.vitepress/theme/components/AdBanner.vue +73 -52
  26. package/docs/.vitepress/theme/components/AdPlaceholder.vue +3 -3
  27. package/docs/.vitepress/theme/components/FundingEffects.vue +77 -53
  28. package/docs/.vitepress/theme/components/FundingHero.vue +78 -63
  29. package/docs/.vitepress/theme/components/SupportSection.vue +106 -89
  30. package/docs/.vitepress/theme/custom-app.css +19 -12
  31. package/docs/.vitepress/theme/custom.css +33 -25
  32. package/docs/.vitepress/theme/index.js +19 -16
  33. package/docs/concepts/accessibility.md +59 -47
  34. package/docs/concepts/color-spaces.md +28 -6
  35. package/docs/concepts/distance-metrics.md +45 -30
  36. package/docs/concepts/hct.md +30 -27
  37. package/docs/concepts/image-analysis.md +52 -21
  38. package/docs/concepts/material-design.md +43 -17
  39. package/docs/concepts/theme-matching.md +64 -40
  40. package/docs/examples/basic-colors.md +92 -108
  41. package/docs/examples/creating-themes.md +104 -108
  42. package/docs/examples/css-refactoring.md +33 -29
  43. package/docs/examples/image-extraction.md +145 -138
  44. package/docs/getting-started.md +45 -34
  45. package/docs/index.md +5 -1
  46. package/docs/installation.md +15 -1
  47. package/docs/tools/accessibility.md +74 -68
  48. package/docs/tools/image-extraction.md +62 -54
  49. package/docs/tools/theme-matching.md +45 -42
  50. package/eslint.config.ts +13 -0
  51. package/jsr.json +1 -1
  52. package/package.json +17 -13
  53. package/src/bin/server.ts +13 -1
  54. package/src/color/__tests__/extract-colors.test.ts +20 -30
  55. package/src/color/apca.ts +105 -0
  56. package/src/color/color-blindness.ts +109 -0
  57. package/src/coolors-mcp.ts +1 -1
  58. package/src/session.ts +10 -2
  59. package/src/theme/matcher.ts +1 -1
  60. package/src/theme/refactor.ts +1 -1
  61. package/src/theme/types.ts +3 -0
  62. package/src/tools/__tests__/cohesion.test.ts +97 -0
  63. package/src/tools/__tests__/color-blindness.test.ts +45 -0
  64. package/src/tools/__tests__/color-conversion.test.ts +38 -0
  65. package/src/tools/__tests__/contrast-checker.test.ts +56 -0
  66. package/src/tools/__tests__/palette-export.test.ts +54 -0
  67. package/src/tools/adjust-color.tool.ts +80 -0
  68. package/src/tools/cohesion.tools.ts +380 -0
  69. package/src/tools/color-blindness.tool.ts +168 -0
  70. package/src/tools/color-conversion.tool.ts +1 -1
  71. package/src/tools/contrast-checker.tool.ts +53 -14
  72. package/src/tools/dislike-analyzer.tool.ts +41 -54
  73. package/src/tools/image-extraction.tools.ts +62 -115
  74. package/src/tools/index.ts +15 -2
  75. package/src/tools/palette-export.tool.ts +174 -0
  76. package/src/tools/palette-with-locks.tool.ts +8 -6
  77. package/src/types.ts +2 -3
  78. package/tsconfig.json +12 -2
  79. package/vitest.config.js +1 -3
  80. package/.claude/settings.local.json +0 -39
  81. package/.env +0 -2
  82. package/.mcp.json +0 -12
  83. package/CLAUDE.md +0 -201
  84. package/DOCUMENTATION.md +0 -274
  85. package/GEMINI.md +0 -54
  86. package/demo/content_based_color.png +0 -0
  87. package/demo/music-player.html +0 -621
  88. package/demo/podcast-player.html +0 -903
  89. package/dist/chunk-IQ7NN26V.js.map +0 -1
  90. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +0 -93
  91. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js.map +0 -7
  92. package/docs/.vitepress/cache/deps/_metadata.json +0 -127
  93. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +0 -9
  94. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +0 -7
  95. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +0 -12683
  96. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js.map +0 -7
  97. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +0 -9719
  98. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js.map +0 -7
  99. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +0 -4710
  100. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +0 -7
  101. package/docs/.vitepress/cache/deps/cytoscape.js +0 -30278
  102. package/docs/.vitepress/cache/deps/cytoscape.js.map +0 -7
  103. package/docs/.vitepress/cache/deps/dayjs.js +0 -285
  104. package/docs/.vitepress/cache/deps/dayjs.js.map +0 -7
  105. package/docs/.vitepress/cache/deps/debug.js +0 -468
  106. package/docs/.vitepress/cache/deps/debug.js.map +0 -7
  107. package/docs/.vitepress/cache/deps/package.json +0 -3
  108. package/docs/.vitepress/cache/deps/prismjs.js +0 -1466
  109. package/docs/.vitepress/cache/deps/prismjs.js.map +0 -7
  110. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +0 -228
  111. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js.map +0 -7
  112. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +0 -142
  113. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js.map +0 -7
  114. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +0 -27
  115. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js.map +0 -7
  116. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +0 -65
  117. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js.map +0 -7
  118. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +0 -53
  119. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js.map +0 -7
  120. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +0 -73
  121. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js.map +0 -7
  122. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +0 -4507
  123. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +0 -7
  124. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +0 -584
  125. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +0 -7
  126. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +0 -1146
  127. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +0 -7
  128. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +0 -1667
  129. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +0 -7
  130. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +0 -1814
  131. package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +0 -7
  132. package/docs/.vitepress/cache/deps/vue.js +0 -344
  133. package/docs/.vitepress/cache/deps/vue.js.map +0 -7
  134. package/examples/theme-matching.md +0 -113
  135. package/mcp-config.json +0 -8
  136. package/note.md +0 -35
  137. package/research_results.md +0 -53
  138. package/src/tools/colors.ts +0 -31
  139. package/src/tools/registry.ts +0 -142
  140. package/src/tools/simple-tools.ts +0 -37
@@ -8,36 +8,36 @@ Check the contrast ratio between two colors and verify WCAG compliance.
8
8
 
9
9
  ### Parameters
10
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) |
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; // Contrast ratio (1-21)
23
- ratioString: string; // Formatted as "X.XX:1"
22
+ ratio: number; // Contrast ratio (1-21)
23
+ ratioString: string; // Formatted as "X.XX:1"
24
24
  passes: {
25
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
- };
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; // Passes AAA for normal text (7:1)
32
- large: boolean; // Passes AAA for large text (4.5:1)
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; // Relative luminance (0-1)
38
- background: number; // Relative luminance (0-1)
39
- };
40
- isLargeText: boolean; // Whether text qualifies as large
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" }, // Dark gray on white
117
- { fg: "#6366f1", bg: "#f3f4f6" }, // Blue on light gray
118
- { fg: "#ffffff", bg: "#dc2626" } // White on red
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 | 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 |
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: 'lightened' | 'darkened' | 'none';
167
- toneChange: number; // HCT tone difference
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 | 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) |
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 | 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) |
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
- | Context | AA Minimum | AAA Minimum |
436
- |---------|------------|-------------|
437
- | Normal text | 4.5:1 | 7:1 |
438
- | Large text | 3:1 | 4.5:1 |
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 | No requirement | No requirement |
442
+ | Logotypes | No requirement | No requirement |
441
443
 
442
444
  #### 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 |
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('Palette has accessibility issues:', validation.issues);
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 // Avoid excessive contrast
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: '#000000',
550
- background: '#ffffff',
551
- primary: '#0000ff'
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 | 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) |
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; // Hex color value
24
- rgb: [r, g, b]; // RGB values
25
- hct: { // HCT values
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; // Percentage of image (0-1)
31
- score: number; // UI suitability score (0-1)
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('canvas');
115
- const ctx = canvas.getContext('2d');
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('sharp');
131
+ const sharp = require("sharp");
131
132
 
132
133
  async function getPixelsFromImage(filepath) {
133
134
  const { data, info } = await sharp(filepath)
134
- .resize(300) // Resize for performance
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('photo.jpg');
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 | 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) |
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; // Selected source color
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; // Generated CSS variables
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 | Description | Best For |
272
- |---------|-------------|----------|
273
- | `tonalSpot` | Default, balanced | General use |
274
- | `fidelity` | Preserves source color | Brand-critical |
275
- | `vibrant` | Higher chroma | Playful, energetic |
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` | Minimal color | Professional |
278
- | `monochrome` | Single hue | Minimalist |
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 | Required | Description |
294
- |-----------|------|----------|-------------|
295
- | `color` | string | ✅ | Color to analyze (hex, rgb, hsl) |
296
- | `autoFix` | boolean | ❌ | Automatically return fixed version (default: true) |
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 | Type | Required | Description |
381
- |-----------|------|----------|-------------|
382
- | `colors` | string[] | ✅ | Array of colors to check |
383
- | `strategy` | string | ❌ | Fix strategy: shift, lighten, both (default: both) |
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: 'inside' })
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: 'vibrant' // Music apps often use vibrant themes
541
+ variant: "vibrant", // Music apps often use vibrant themes
538
542
  });
539
543
 
540
544
  // 3. Apply to UI
541
- applyTheme(theme.schemes.dark); // Music apps often use dark themes
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, // Logos typically have few colors
556
- minPopulation: 0.05 // Higher threshold for logos
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, // Reduce chroma
578
- tone: 95 // Very light
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