@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,1214 @@
1
+ // src/color/types.ts
2
+ var ColorFormat = /* @__PURE__ */ ((ColorFormat2) => {
3
+ ColorFormat2["HEX"] = "hex";
4
+ ColorFormat2["HSL"] = "hsl";
5
+ ColorFormat2["HSV"] = "hsv";
6
+ ColorFormat2["LAB"] = "lab";
7
+ ColorFormat2["RGB"] = "rgb";
8
+ ColorFormat2["XYZ"] = "xyz";
9
+ return ColorFormat2;
10
+ })(ColorFormat || {});
11
+ var ColorConstants = {
12
+ /**
13
+ * D65 illuminant reference white point
14
+ */
15
+ D65: {
16
+ X: 95.047,
17
+ Y: 100,
18
+ Z: 108.883
19
+ },
20
+ /**
21
+ * Epsilon for LAB conversion
22
+ */
23
+ EPSILON: 8856e-6,
24
+ /**
25
+ * Kappa for LAB conversion
26
+ */
27
+ KAPPA: 903.3
28
+ };
29
+
30
+ // src/color/conversions.ts
31
+ function argbToRgb(argb) {
32
+ const r = argb >> 16 & 255;
33
+ const g = argb >> 8 & 255;
34
+ const b = argb & 255;
35
+ return { b, g, r };
36
+ }
37
+ function hexToRgb(hex) {
38
+ const cleanHex = hex.replace("#", "");
39
+ const fullHex = cleanHex.length === 3 ? cleanHex.split("").map((c) => c + c).join("") : cleanHex;
40
+ const num = parseInt(fullHex, 16);
41
+ return {
42
+ b: num & 255,
43
+ g: num >> 8 & 255,
44
+ r: num >> 16 & 255
45
+ };
46
+ }
47
+ function hslToRgb(hsl) {
48
+ const h = hsl.h / 360;
49
+ const s = hsl.s / 100;
50
+ const l = hsl.l / 100;
51
+ let b, g, r;
52
+ if (s === 0) {
53
+ r = g = b = l;
54
+ } else {
55
+ const hue2rgb = (p2, q2, t) => {
56
+ if (t < 0) t += 1;
57
+ if (t > 1) t -= 1;
58
+ if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
59
+ if (t < 1 / 2) return q2;
60
+ if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
61
+ return p2;
62
+ };
63
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
64
+ const p = 2 * l - q;
65
+ r = hue2rgb(p, q, h + 1 / 3);
66
+ g = hue2rgb(p, q, h);
67
+ b = hue2rgb(p, q, h - 1 / 3);
68
+ }
69
+ return {
70
+ b: Math.round(b * 255),
71
+ g: Math.round(g * 255),
72
+ r: Math.round(r * 255)
73
+ };
74
+ }
75
+ function hsvToRgb(hsv) {
76
+ const h = hsv.h / 360;
77
+ const s = hsv.s / 100;
78
+ const v = hsv.v / 100;
79
+ const i = Math.floor(h * 6);
80
+ const f = h * 6 - i;
81
+ const p = v * (1 - s);
82
+ const q = v * (1 - f * s);
83
+ const t = v * (1 - (1 - f) * s);
84
+ let b, g, r;
85
+ switch (i % 6) {
86
+ case 0:
87
+ r = v;
88
+ g = t;
89
+ b = p;
90
+ break;
91
+ case 1:
92
+ r = q;
93
+ g = v;
94
+ b = p;
95
+ break;
96
+ case 2:
97
+ r = p;
98
+ g = v;
99
+ b = t;
100
+ break;
101
+ case 3:
102
+ r = p;
103
+ g = q;
104
+ b = v;
105
+ break;
106
+ case 4:
107
+ r = t;
108
+ g = p;
109
+ b = v;
110
+ break;
111
+ case 5:
112
+ r = v;
113
+ g = p;
114
+ b = q;
115
+ break;
116
+ default:
117
+ r = 0;
118
+ g = 0;
119
+ b = 0;
120
+ }
121
+ return {
122
+ b: Math.round(b * 255),
123
+ g: Math.round(g * 255),
124
+ r: Math.round(r * 255)
125
+ };
126
+ }
127
+ function labToRgb(lab) {
128
+ return xyzToRgb(labToXyz(lab));
129
+ }
130
+ function labToXyz(lab) {
131
+ const { D65, EPSILON, KAPPA } = ColorConstants;
132
+ const fy = (lab.l + 16) / 116;
133
+ const fx = lab.a / 500 + fy;
134
+ const fz = fy - lab.b / 200;
135
+ const x3 = Math.pow(fx, 3);
136
+ const y3 = Math.pow(fy, 3);
137
+ const z3 = Math.pow(fz, 3);
138
+ const x = x3 > EPSILON ? x3 : (116 * fx - 16) / KAPPA;
139
+ const y = lab.l > KAPPA * EPSILON ? y3 : lab.l / KAPPA;
140
+ const z = z3 > EPSILON ? z3 : (116 * fz - 16) / KAPPA;
141
+ return {
142
+ x: x * D65.X,
143
+ y: y * D65.Y,
144
+ z: z * D65.Z
145
+ };
146
+ }
147
+ function parseColor(color) {
148
+ const trimmed = color.trim().toLowerCase();
149
+ if (trimmed.startsWith("#")) {
150
+ try {
151
+ return hexToRgb(trimmed);
152
+ } catch {
153
+ return null;
154
+ }
155
+ }
156
+ const rgbMatch = trimmed.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)/);
157
+ if (rgbMatch) {
158
+ return {
159
+ b: parseInt(rgbMatch[3], 10),
160
+ g: parseInt(rgbMatch[2], 10),
161
+ r: parseInt(rgbMatch[1], 10)
162
+ };
163
+ }
164
+ const hslMatch = trimmed.match(/^hsla?\((\d+),\s*(\d+)%,\s*(\d+)%/);
165
+ if (hslMatch) {
166
+ return hslToRgb({
167
+ h: parseInt(hslMatch[1], 10),
168
+ l: parseInt(hslMatch[3], 10),
169
+ s: parseInt(hslMatch[2], 10)
170
+ });
171
+ }
172
+ return null;
173
+ }
174
+ function rgbToArgb(rgb) {
175
+ const r = Math.round(Math.max(0, Math.min(255, rgb.r)));
176
+ const g = Math.round(Math.max(0, Math.min(255, rgb.g)));
177
+ const b = Math.round(Math.max(0, Math.min(255, rgb.b)));
178
+ return (255 << 24 | r << 16 | g << 8 | b) >>> 0;
179
+ }
180
+ function rgbToHex(rgb) {
181
+ const toHex = (n) => {
182
+ const hex = Math.round(Math.max(0, Math.min(255, n))).toString(16);
183
+ return hex.length === 1 ? "0" + hex : hex;
184
+ };
185
+ return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
186
+ }
187
+ function rgbToHsl(rgb) {
188
+ const r = rgb.r / 255;
189
+ const g = rgb.g / 255;
190
+ const b = rgb.b / 255;
191
+ const max = Math.max(r, g, b);
192
+ const min = Math.min(r, g, b);
193
+ const diff = max - min;
194
+ let h = 0;
195
+ let s = 0;
196
+ const l = (max + min) / 2;
197
+ if (diff !== 0) {
198
+ s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min);
199
+ switch (max) {
200
+ case b:
201
+ h = ((r - g) / diff + 4) / 6;
202
+ break;
203
+ case g:
204
+ h = ((b - r) / diff + 2) / 6;
205
+ break;
206
+ case r:
207
+ h = ((g - b) / diff + (g < b ? 6 : 0)) / 6;
208
+ break;
209
+ }
210
+ }
211
+ return {
212
+ h: Math.round(h * 360),
213
+ l: Math.round(l * 100),
214
+ s: Math.round(s * 100)
215
+ };
216
+ }
217
+ function rgbToHsv(rgb) {
218
+ const r = rgb.r / 255;
219
+ const g = rgb.g / 255;
220
+ const b = rgb.b / 255;
221
+ const max = Math.max(r, g, b);
222
+ const min = Math.min(r, g, b);
223
+ const diff = max - min;
224
+ let h = 0;
225
+ const s = max === 0 ? 0 : diff / max;
226
+ const v = max;
227
+ if (diff !== 0) {
228
+ switch (max) {
229
+ case b:
230
+ h = ((r - g) / diff + 4) / 6;
231
+ break;
232
+ case g:
233
+ h = ((b - r) / diff + 2) / 6;
234
+ break;
235
+ case r:
236
+ h = ((g - b) / diff + (g < b ? 6 : 0)) / 6;
237
+ break;
238
+ }
239
+ }
240
+ return {
241
+ h: Math.round(h * 360),
242
+ s: Math.round(s * 100),
243
+ v: Math.round(v * 100)
244
+ };
245
+ }
246
+ function rgbToLab(rgb) {
247
+ return xyzToLab(rgbToXyz(rgb));
248
+ }
249
+ function rgbToXyz(rgb) {
250
+ let r = rgb.r / 255;
251
+ let g = rgb.g / 255;
252
+ let b = rgb.b / 255;
253
+ r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
254
+ g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
255
+ b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
256
+ r *= 100;
257
+ g *= 100;
258
+ b *= 100;
259
+ return {
260
+ x: r * 0.4124564 + g * 0.3575761 + b * 0.1804375,
261
+ y: r * 0.2126729 + g * 0.7151522 + b * 0.072175,
262
+ z: r * 0.0193339 + g * 0.119192 + b * 0.9503041
263
+ };
264
+ }
265
+ function xyzToLab(xyz) {
266
+ const { D65, EPSILON, KAPPA } = ColorConstants;
267
+ const x = xyz.x / D65.X;
268
+ const y = xyz.y / D65.Y;
269
+ const z = xyz.z / D65.Z;
270
+ const fx = x > EPSILON ? Math.cbrt(x) : (KAPPA * x + 16) / 116;
271
+ const fy = y > EPSILON ? Math.cbrt(y) : (KAPPA * y + 16) / 116;
272
+ const fz = z > EPSILON ? Math.cbrt(z) : (KAPPA * z + 16) / 116;
273
+ return {
274
+ a: 500 * (fx - fy),
275
+ b: 200 * (fy - fz),
276
+ l: 116 * fy - 16
277
+ };
278
+ }
279
+ function xyzToRgb(xyz) {
280
+ const x = xyz.x / 100;
281
+ const y = xyz.y / 100;
282
+ const z = xyz.z / 100;
283
+ let r = x * 3.2404542 + y * -1.5371385 + z * -0.4985314;
284
+ let g = x * -0.969266 + y * 1.8760108 + z * 0.041556;
285
+ let b = x * 0.0556434 + y * -0.2040259 + z * 1.0572252;
286
+ r = r > 31308e-7 ? 1.055 * Math.pow(r, 1 / 2.4) - 0.055 : 12.92 * r;
287
+ g = g > 31308e-7 ? 1.055 * Math.pow(g, 1 / 2.4) - 0.055 : 12.92 * g;
288
+ b = b > 31308e-7 ? 1.055 * Math.pow(b, 1 / 2.4) - 0.055 : 12.92 * b;
289
+ return {
290
+ b: Math.round(Math.max(0, Math.min(255, b * 255))),
291
+ g: Math.round(Math.max(0, Math.min(255, g * 255))),
292
+ r: Math.round(Math.max(0, Math.min(255, r * 255)))
293
+ };
294
+ }
295
+
296
+ // src/color/hct/hct-solver.ts
297
+ function hct(hue, chroma, tone) {
298
+ return {
299
+ c: Math.max(0, chroma),
300
+ h: sanitizeDegrees(hue),
301
+ t: Math.max(0, Math.min(100, tone))
302
+ };
303
+ }
304
+ function hctToRgb(hct2) {
305
+ const hue = sanitizeDegrees(hct2.h);
306
+ const chroma = Math.max(0, hct2.c);
307
+ const tone = Math.max(0, Math.min(100, hct2.t));
308
+ if (chroma < 1e-4 || tone < 0.5 || tone > 99.5) {
309
+ const gray2 = tone / 100 * 255;
310
+ return { b: gray2, g: gray2, r: gray2 };
311
+ }
312
+ const lstar = tone;
313
+ let bestRgb = null;
314
+ let low = 0;
315
+ let high = chroma;
316
+ const epsilon = 0.01;
317
+ while (high - low > epsilon) {
318
+ const mid = (low + high) / 2;
319
+ const a = mid * Math.cos(hue * Math.PI / 180);
320
+ const b = mid * Math.sin(hue * Math.PI / 180);
321
+ const xyz = labToXyz({ a, b, l: lstar });
322
+ const rgb = xyzToRgb(xyz);
323
+ if (isInGamut(rgb)) {
324
+ bestRgb = rgb;
325
+ low = mid;
326
+ } else {
327
+ high = mid;
328
+ }
329
+ }
330
+ if (bestRgb) {
331
+ return clampRgb(bestRgb);
332
+ }
333
+ for (let c = chroma; c >= 0; c -= 1) {
334
+ const a = c * Math.cos(hue * Math.PI / 180);
335
+ const b = c * Math.sin(hue * Math.PI / 180);
336
+ const xyz = labToXyz({ a, b, l: lstar });
337
+ const rgb = xyzToRgb(xyz);
338
+ if (isInGamut(rgb)) {
339
+ return clampRgb(rgb);
340
+ }
341
+ }
342
+ const gray = tone / 100 * 255;
343
+ return { b: gray, g: gray, r: gray };
344
+ }
345
+ function maxChroma(hue, tone) {
346
+ if (tone <= 0 || tone >= 100) return 0;
347
+ const hueCycle = hue % 360 / 360;
348
+ const redBoost = Math.sin(hueCycle * Math.PI * 2) * 0.2 + 1;
349
+ const toneFactor = Math.sin(tone / 100 * Math.PI);
350
+ return toneFactor * 120 * redBoost;
351
+ }
352
+ function rgbToHct(rgb) {
353
+ const xyz = rgbToXyz(rgb);
354
+ const lab = xyzToLab(xyz);
355
+ const tone = lab.l;
356
+ const chroma = Math.sqrt(lab.a * lab.a + lab.b * lab.b);
357
+ let hue = Math.atan2(lab.b, lab.a) * 180 / Math.PI;
358
+ if (hue < 0) {
359
+ hue += 360;
360
+ }
361
+ return {
362
+ c: chroma,
363
+ h: sanitizeDegrees(hue),
364
+ t: tone
365
+ };
366
+ }
367
+ function clampRgb(rgb) {
368
+ return {
369
+ b: Math.round(Math.max(0, Math.min(255, rgb.b))),
370
+ g: Math.round(Math.max(0, Math.min(255, rgb.g))),
371
+ r: Math.round(Math.max(0, Math.min(255, rgb.r)))
372
+ };
373
+ }
374
+ function isInGamut(rgb) {
375
+ return rgb.r >= 0 && rgb.r <= 255 && rgb.g >= 0 && rgb.g <= 255 && rgb.b >= 0 && rgb.b <= 255;
376
+ }
377
+ function sanitizeDegrees(degrees) {
378
+ return (degrees % 360 + 360) % 360;
379
+ }
380
+
381
+ // src/color/hct/hct-class.ts
382
+ var Hct = class _Hct {
383
+ get chroma() {
384
+ return this._chroma;
385
+ }
386
+ /**
387
+ * Set the chroma of this color. Chroma may decrease because chroma has a
388
+ * different maximum for any given hue and tone.
389
+ * @param newChroma 0 <= newChroma < ?
390
+ */
391
+ set chroma(newChroma) {
392
+ const rgb = hctToRgb({ c: newChroma, h: this._hue, t: this._tone });
393
+ this._argb = rgbToArgb(rgb);
394
+ const hct2 = rgbToHct(rgb);
395
+ this._hue = hct2.h;
396
+ this._chroma = hct2.c;
397
+ this._tone = hct2.t;
398
+ }
399
+ get hue() {
400
+ return this._hue;
401
+ }
402
+ /**
403
+ * Set the hue of this color. Chroma may decrease because chroma has a
404
+ * different maximum for any given hue and tone.
405
+ * @param newHue 0 <= newHue < 360; invalid values are corrected.
406
+ */
407
+ set hue(newHue) {
408
+ const rgb = hctToRgb({ c: this._chroma, h: newHue, t: this._tone });
409
+ this._argb = rgbToArgb(rgb);
410
+ const hct2 = rgbToHct(rgb);
411
+ this._hue = hct2.h;
412
+ this._chroma = hct2.c;
413
+ this._tone = hct2.t;
414
+ }
415
+ get tone() {
416
+ return this._tone;
417
+ }
418
+ /**
419
+ * Set the tone of this color. Chroma may decrease because chroma has a
420
+ * different maximum for any given hue and tone.
421
+ * @param newTone 0 <= newTone <= 100; invalid values are corrected.
422
+ */
423
+ set tone(newTone) {
424
+ const rgb = hctToRgb({ c: this._chroma, h: this._hue, t: newTone });
425
+ this._argb = rgbToArgb(rgb);
426
+ const hct2 = rgbToHct(rgb);
427
+ this._hue = hct2.h;
428
+ this._chroma = hct2.c;
429
+ this._tone = hct2.t;
430
+ }
431
+ _argb;
432
+ _chroma;
433
+ _hue;
434
+ _tone;
435
+ constructor(argb) {
436
+ this._argb = argb;
437
+ const rgb = argbToRgb(argb);
438
+ const hct2 = rgbToHct(rgb);
439
+ this._hue = hct2.h;
440
+ this._chroma = hct2.c;
441
+ this._tone = hct2.t;
442
+ }
443
+ /**
444
+ * Create an HCT color from hue, chroma, and tone.
445
+ * @param hue 0 <= hue < 360; invalid values are corrected.
446
+ * @param chroma 0 <= chroma < ?; Chroma may decrease because chroma has a
447
+ * different maximum for any given hue and tone.
448
+ * @param tone 0 <= tone <= 100; invalid values are corrected.
449
+ * @return HCT representation of a color in default viewing conditions.
450
+ */
451
+ static from(hue, chroma, tone) {
452
+ const rgb = hctToRgb({ c: chroma, h: hue, t: tone });
453
+ const argb = rgbToArgb(rgb);
454
+ return new _Hct(argb);
455
+ }
456
+ /**
457
+ * Create an HCT color from a color.
458
+ * @param argb ARGB representation of a color.
459
+ * @return HCT representation of a color in default viewing conditions
460
+ */
461
+ static fromInt(argb) {
462
+ return new _Hct(argb);
463
+ }
464
+ /**
465
+ * @return ARGB representation of an HCT color.
466
+ */
467
+ toInt() {
468
+ return this._argb;
469
+ }
470
+ };
471
+
472
+ // src/color/dislike/dislike-analyzer.ts
473
+ var DislikeAnalyzer = class _DislikeAnalyzer {
474
+ /**
475
+ * Analyze a batch of colors and return statistics
476
+ * @param colors Array of HCT colors
477
+ * @return Statistics about disliked colors
478
+ */
479
+ static analyzeBatch(colors) {
480
+ const dislikedIndices = [];
481
+ colors.forEach((color, index) => {
482
+ if (_DislikeAnalyzer.isDisliked(color)) {
483
+ dislikedIndices.push(index);
484
+ }
485
+ });
486
+ return {
487
+ disliked: dislikedIndices.length,
488
+ dislikedIndices,
489
+ percentage: dislikedIndices.length / colors.length * 100,
490
+ total: colors.length
491
+ };
492
+ }
493
+ /**
494
+ * Fix all disliked colors in a batch
495
+ * @param colors Array of HCT colors
496
+ * @return Array with disliked colors fixed
497
+ */
498
+ static fixBatch(colors) {
499
+ return colors.map((color) => _DislikeAnalyzer.fixIfDisliked(color));
500
+ }
501
+ /**
502
+ * If a color is disliked, lighten it to make it likable.
503
+ *
504
+ * @param hct A color to be judged.
505
+ * @return A new color if the original color is disliked, or the original
506
+ * color if it is acceptable.
507
+ */
508
+ static fixIfDisliked(hct2) {
509
+ if (_DislikeAnalyzer.isDisliked(hct2)) {
510
+ return Hct.from(hct2.hue, hct2.chroma, 70);
511
+ }
512
+ return hct2;
513
+ }
514
+ /**
515
+ * Fix a hex color if it's disliked
516
+ * @param hex Hex color string
517
+ * @return Fixed hex color or original if not disliked
518
+ */
519
+ static fixIfDislikedHex(hex) {
520
+ const argb = parseInt(hex.replace("#", ""), 16) | 4278190080;
521
+ const hct2 = Hct.fromInt(argb);
522
+ const fixed = _DislikeAnalyzer.fixIfDisliked(hct2);
523
+ if (fixed === hct2) {
524
+ return hex;
525
+ }
526
+ const fixedArgb = fixed.toInt();
527
+ const r = fixedArgb >> 16 & 255;
528
+ const g = fixedArgb >> 8 & 255;
529
+ const b = fixedArgb & 255;
530
+ return "#" + [r, g, b].map((x) => x.toString(16).padStart(2, "0")).join("");
531
+ }
532
+ /**
533
+ * Returns true if a color is disliked.
534
+ *
535
+ * @param hct A color to be judged.
536
+ * @return Whether the color is disliked.
537
+ *
538
+ * Disliked is defined as a dark yellow-green that is not neutral.
539
+ * Specifically: hue 90-111°, chroma > 16, tone < 65
540
+ */
541
+ static isDisliked(hct2) {
542
+ const huePasses = Math.round(hct2.hue) >= 90 && Math.round(hct2.hue) <= 111;
543
+ const chromaPasses = Math.round(hct2.chroma) > 16;
544
+ const tonePasses = Math.round(hct2.tone) < 65;
545
+ return huePasses && chromaPasses && tonePasses;
546
+ }
547
+ /**
548
+ * Check if a color is in the "bile zone" - universally disliked colors
549
+ * @param hex Hex color string
550
+ * @return Whether the color is disliked
551
+ */
552
+ static isDislikedHex(hex) {
553
+ const hct2 = Hct.fromInt(parseInt(hex.replace("#", ""), 16) | 4278190080);
554
+ return _DislikeAnalyzer.isDisliked(hct2);
555
+ }
556
+ };
557
+
558
+ // src/color/hct/harmonization.ts
559
+ function adjustTemperature(color, amount) {
560
+ const hctColor = rgbToHct(color);
561
+ const isWarm = hctColor.h <= 60 || hctColor.h >= 300;
562
+ let newHue;
563
+ if (amount > 0) {
564
+ newHue = isWarm ? circularInterpolate(hctColor.h, 30, Math.min(amount, 1)) : circularInterpolate(hctColor.h, 30, Math.min(amount * 2, 1));
565
+ } else {
566
+ newHue = !isWarm ? circularInterpolate(hctColor.h, 210, Math.min(-amount, 1)) : circularInterpolate(hctColor.h, 210, Math.min(-amount * 2, 1));
567
+ }
568
+ return hctToRgb(hct(newHue, hctColor.c, hctColor.t));
569
+ }
570
+ function analogous(color, angle = 30, count = 2) {
571
+ const hctColor = rgbToHct(color);
572
+ const colors = [];
573
+ for (let i = 1; i <= count; i++) {
574
+ colors.push(
575
+ hctToRgb(
576
+ hct(
577
+ sanitizeDegreesDouble(hctColor.h + angle * i),
578
+ hctColor.c,
579
+ hctColor.t
580
+ )
581
+ )
582
+ );
583
+ colors.push(
584
+ hctToRgb(
585
+ hct(
586
+ sanitizeDegreesDouble(hctColor.h - angle * i),
587
+ hctColor.c,
588
+ hctColor.t
589
+ )
590
+ )
591
+ );
592
+ }
593
+ return colors;
594
+ }
595
+ function blend(from, to, amount) {
596
+ const fromHct = rgbToHct(from);
597
+ const toHct = rgbToHct(to);
598
+ const h = circularInterpolate(fromHct.h, toHct.h, amount);
599
+ const c = fromHct.c + (toHct.c - fromHct.c) * amount;
600
+ const t = fromHct.t + (toHct.t - fromHct.t) * amount;
601
+ return hctToRgb(hct(h, c, t));
602
+ }
603
+ function doubleComplementary(color1, color2) {
604
+ const hct1 = rgbToHct(color1);
605
+ const hct2 = rgbToHct(color2);
606
+ return [
607
+ color1,
608
+ color2,
609
+ hctToRgb(hct((hct1.h + 180) % 360, hct1.c, hct1.t)),
610
+ hctToRgb(hct((hct2.h + 180) % 360, hct2.c, hct2.t))
611
+ ];
612
+ }
613
+ function gradient(from, to, steps) {
614
+ const colors = [];
615
+ for (let i = 0; i < steps; i++) {
616
+ const amount = i / (steps - 1);
617
+ colors.push(blend(from, to, amount));
618
+ }
619
+ return colors;
620
+ }
621
+ function harmonize(design, source, factor = 0.5) {
622
+ const fromHct = rgbToHct(design);
623
+ const toHct = rgbToHct(source);
624
+ const diffDegrees = differenceDegrees(fromHct.h, toHct.h);
625
+ const rotationDegrees = Math.min(diffDegrees * factor, 15);
626
+ const outputHue = sanitizeDegreesDouble(
627
+ fromHct.h + rotationDegrees * rotationDirection(fromHct.h, toHct.h)
628
+ );
629
+ return hctToRgb(hct(outputHue, fromHct.c, fromHct.t));
630
+ }
631
+ function splitComplementary(color, angle = 30) {
632
+ const hctColor = rgbToHct(color);
633
+ const complement = (hctColor.h + 180) % 360;
634
+ return [
635
+ color,
636
+ hctToRgb(
637
+ hct(sanitizeDegreesDouble(complement - angle), hctColor.c, hctColor.t)
638
+ ),
639
+ hctToRgb(
640
+ hct(sanitizeDegreesDouble(complement + angle), hctColor.c, hctColor.t)
641
+ )
642
+ ];
643
+ }
644
+ function tetradic(color) {
645
+ const hctColor = rgbToHct(color);
646
+ return [
647
+ color,
648
+ hctToRgb(hct((hctColor.h + 90) % 360, hctColor.c, hctColor.t)),
649
+ hctToRgb(hct((hctColor.h + 180) % 360, hctColor.c, hctColor.t)),
650
+ hctToRgb(hct((hctColor.h + 270) % 360, hctColor.c, hctColor.t))
651
+ ];
652
+ }
653
+ function circularInterpolate(from, to, amount) {
654
+ const difference = to - from;
655
+ const distance = Math.abs(difference);
656
+ if (distance > 180) {
657
+ if (difference > 0) {
658
+ from += 360;
659
+ } else {
660
+ to += 360;
661
+ }
662
+ }
663
+ return sanitizeDegreesDouble(from + (to - from) * amount);
664
+ }
665
+ function differenceDegrees(a, b) {
666
+ return Math.abs((a - b + 180) % 360 - 180);
667
+ }
668
+ function rotationDirection(from, to) {
669
+ const difference = to - from;
670
+ const normalized = (difference + 180) % 360 - 180;
671
+ return normalized >= 0 ? 1 : -1;
672
+ }
673
+ function sanitizeDegreesDouble(degrees) {
674
+ return (degrees % 360 + 360) % 360;
675
+ }
676
+
677
+ // src/color/hct/tonal-palette.ts
678
+ var MATERIAL_TONES = [
679
+ 0,
680
+ 10,
681
+ 20,
682
+ 30,
683
+ 40,
684
+ 50,
685
+ 60,
686
+ 70,
687
+ 80,
688
+ 90,
689
+ 95,
690
+ 99,
691
+ 100
692
+ ];
693
+ var EXTENDED_TONES = [
694
+ 0,
695
+ 5,
696
+ 10,
697
+ 15,
698
+ 20,
699
+ 25,
700
+ 30,
701
+ 35,
702
+ 40,
703
+ 45,
704
+ 50,
705
+ 55,
706
+ 60,
707
+ 65,
708
+ 70,
709
+ 75,
710
+ 80,
711
+ 85,
712
+ 90,
713
+ 92,
714
+ 94,
715
+ 96,
716
+ 98,
717
+ 99,
718
+ 100
719
+ ];
720
+ var TonalPalette = class _TonalPalette {
721
+ constructor(hue, chroma) {
722
+ this.hue = hue;
723
+ this.chroma = chroma;
724
+ }
725
+ /**
726
+ * Get extended tones for more options
727
+ */
728
+ get extendedTones() {
729
+ const tones = {};
730
+ for (const t of EXTENDED_TONES) {
731
+ tones[t] = this.tone(t);
732
+ }
733
+ return tones;
734
+ }
735
+ /**
736
+ * Get all Material 3 standard tones
737
+ */
738
+ get materialTones() {
739
+ const tones = {};
740
+ for (const t of MATERIAL_TONES) {
741
+ tones[t] = this.tone(t);
742
+ }
743
+ return tones;
744
+ }
745
+ cache = /* @__PURE__ */ new Map();
746
+ /**
747
+ * Create a tonal palette from an HCT color
748
+ */
749
+ static fromHct(color) {
750
+ return new _TonalPalette(color.h, color.c);
751
+ }
752
+ /**
753
+ * Create a tonal palette from an RGB color
754
+ */
755
+ static fromRgb(rgb) {
756
+ const hctColor = rgbToHct(rgb);
757
+ return new _TonalPalette(hctColor.h, hctColor.c);
758
+ }
759
+ /**
760
+ * Get the color at a specific tone
761
+ */
762
+ tone(tone) {
763
+ if (this.cache.has(tone)) {
764
+ return this.cache.get(tone);
765
+ }
766
+ const color = hctToRgb(hct(this.hue, this.chroma, tone));
767
+ this.cache.set(tone, color);
768
+ return color;
769
+ }
770
+ };
771
+ function analogousPalette(source, count = 5, hueShift = 30) {
772
+ const sourceHct = rgbToHct(source);
773
+ const palettes = [];
774
+ const startHue = sourceHct.h - hueShift * Math.floor(count / 2);
775
+ for (let i = 0; i < count; i++) {
776
+ const hue = (startHue + i * hueShift + 360) % 360;
777
+ palettes.push(new TonalPalette(hue, sourceHct.c));
778
+ }
779
+ return palettes;
780
+ }
781
+ function complementaryPalette(source) {
782
+ const sourceHct = rgbToHct(source);
783
+ return [
784
+ new TonalPalette(sourceHct.h, sourceHct.c),
785
+ new TonalPalette((sourceHct.h + 180) % 360, sourceHct.c)
786
+ ];
787
+ }
788
+ function corePaletteFromRgb(source) {
789
+ const sourceHct = rgbToHct(source);
790
+ const primary = new TonalPalette(sourceHct.h, Math.max(48, sourceHct.c));
791
+ const secondary = new TonalPalette(
792
+ sourceHct.h,
793
+ Math.max(16, sourceHct.c / 3)
794
+ );
795
+ const tertiary = new TonalPalette(
796
+ (sourceHct.h + 60) % 360,
797
+ Math.max(24, sourceHct.c / 2)
798
+ );
799
+ const error = new TonalPalette(25, 84);
800
+ const neutral = new TonalPalette(sourceHct.h, Math.min(4, sourceHct.c / 12));
801
+ const neutralVariant = new TonalPalette(
802
+ sourceHct.h,
803
+ Math.min(8, sourceHct.c / 6)
804
+ );
805
+ return {
806
+ error,
807
+ neutral,
808
+ neutralVariant,
809
+ primary,
810
+ secondary,
811
+ tertiary
812
+ };
813
+ }
814
+ function monochromaticPalette(source, tones = MATERIAL_TONES) {
815
+ const palette = TonalPalette.fromRgb(source);
816
+ return tones.map((t) => palette.tone(t));
817
+ }
818
+ function triadicPalette(source) {
819
+ const sourceHct = rgbToHct(source);
820
+ return [
821
+ new TonalPalette(sourceHct.h, sourceHct.c),
822
+ new TonalPalette((sourceHct.h + 120) % 360, sourceHct.c),
823
+ new TonalPalette((sourceHct.h + 240) % 360, sourceHct.c)
824
+ ];
825
+ }
826
+
827
+ // src/color/hct/types.ts
828
+ var STANDARD_CONDITIONS = {
829
+ aw: 29.98,
830
+ c: 0.69,
831
+ fl: 0.388,
832
+ flRoot: 0.789,
833
+ n: 0.184,
834
+ nbb: 1.017,
835
+ nc: 1,
836
+ ncb: 1.017,
837
+ rgbD: [1.021, 0.986, 0.934],
838
+ z: 1.909
839
+ };
840
+
841
+ // src/color/metrics.ts
842
+ function areColorsSimilar(color1, color2, threshold = 2.3) {
843
+ const distance = colorDistance(color1, color2, { metric: "deltaE2000" });
844
+ return distance <= threshold;
845
+ }
846
+ function colorDistance(color1, color2, options) {
847
+ const metric = options?.metric ?? "deltaE2000";
848
+ switch (metric) {
849
+ case "deltaE76": {
850
+ const lab1 = rgbToLab(color1);
851
+ const lab2 = rgbToLab(color2);
852
+ return deltaE76(lab1, lab2);
853
+ }
854
+ case "deltaE94": {
855
+ const lab1 = rgbToLab(color1);
856
+ const lab2 = rgbToLab(color2);
857
+ return deltaE94(lab1, lab2, options?.deltaE94);
858
+ }
859
+ case "euclidean":
860
+ return euclideanDistance(color1, color2);
861
+ case "weighted":
862
+ return weightedRgbDistance(color1, color2, options?.weights);
863
+ case "deltaE2000":
864
+ default: {
865
+ const lab1 = rgbToLab(color1);
866
+ const lab2 = rgbToLab(color2);
867
+ return deltaE2000(lab1, lab2);
868
+ }
869
+ }
870
+ }
871
+ function deltaE2000(lab1, lab2) {
872
+ const deg2rad = (deg) => deg * (Math.PI / 180);
873
+ const rad2deg = (rad) => rad * (180 / Math.PI);
874
+ const kL = 1;
875
+ const kC = 1;
876
+ const kH = 1;
877
+ const C1 = Math.sqrt(lab1.a * lab1.a + lab1.b * lab1.b);
878
+ const C2 = Math.sqrt(lab2.a * lab2.a + lab2.b * lab2.b);
879
+ const Cbar = (C1 + C2) / 2;
880
+ const G = 0.5 * (1 - Math.sqrt(Math.pow(Cbar, 7) / (Math.pow(Cbar, 7) + Math.pow(25, 7))));
881
+ const a1p = lab1.a * (1 + G);
882
+ const a2p = lab2.a * (1 + G);
883
+ const C1p = Math.sqrt(a1p * a1p + lab1.b * lab1.b);
884
+ const C2p = Math.sqrt(a2p * a2p + lab2.b * lab2.b);
885
+ let h1p = Math.atan2(lab1.b, a1p);
886
+ let h2p = Math.atan2(lab2.b, a2p);
887
+ if (h1p < 0) h1p += 2 * Math.PI;
888
+ if (h2p < 0) h2p += 2 * Math.PI;
889
+ h1p = rad2deg(h1p);
890
+ h2p = rad2deg(h2p);
891
+ const dLp = lab2.l - lab1.l;
892
+ const dCp = C2p - C1p;
893
+ let dhp = h2p - h1p;
894
+ if (dhp > 180) dhp -= 360;
895
+ if (dhp < -180) dhp += 360;
896
+ const dHp = 2 * Math.sqrt(C1p * C2p) * Math.sin(deg2rad(dhp) / 2);
897
+ const Lbar = (lab1.l + lab2.l) / 2;
898
+ const Cpbar = (C1p + C2p) / 2;
899
+ let hpbar = (h1p + h2p) / 2;
900
+ if (Math.abs(h1p - h2p) > 180) {
901
+ if (h1p + h2p < 360) {
902
+ hpbar += 180;
903
+ } else {
904
+ hpbar -= 180;
905
+ }
906
+ }
907
+ const T = 1 - 0.17 * Math.cos(deg2rad(hpbar - 30)) + 0.24 * Math.cos(deg2rad(2 * hpbar)) + 0.32 * Math.cos(deg2rad(3 * hpbar + 6)) - 0.2 * Math.cos(deg2rad(4 * hpbar - 63));
908
+ const dTheta = 30 * Math.exp(-Math.pow((hpbar - 275) / 25, 2));
909
+ const RC = 2 * Math.sqrt(Math.pow(Cpbar, 7) / (Math.pow(Cpbar, 7) + Math.pow(25, 7)));
910
+ const RT = -RC * Math.sin(2 * deg2rad(dTheta));
911
+ const SL = 1 + 0.015 * Math.pow(Lbar - 50, 2) / Math.sqrt(20 + Math.pow(Lbar - 50, 2));
912
+ const SC = 1 + 0.045 * Cpbar;
913
+ const SH = 1 + 0.015 * Cpbar * T;
914
+ const dLpKlSl = dLp / (kL * SL);
915
+ const dCpKcSc = dCp / (kC * SC);
916
+ const dHpKhSh = dHp / (kH * SH);
917
+ return Math.sqrt(
918
+ dLpKlSl * dLpKlSl + dCpKcSc * dCpKcSc + dHpKhSh * dHpKhSh + RT * dCpKcSc * dHpKhSh
919
+ );
920
+ }
921
+ function deltaE76(lab1, lab2) {
922
+ const dL = lab1.l - lab2.l;
923
+ const da = lab1.a - lab2.a;
924
+ const db = lab1.b - lab2.b;
925
+ return Math.sqrt(dL * dL + da * da + db * db);
926
+ }
927
+ function deltaE94(lab1, lab2, options) {
928
+ const kL = options?.kL ?? 1;
929
+ const kC = options?.kC ?? 1;
930
+ const kH = options?.kH ?? 1;
931
+ const dL = lab1.l - lab2.l;
932
+ const da = lab1.a - lab2.a;
933
+ const db = lab1.b - lab2.b;
934
+ const C1 = Math.sqrt(lab1.a * lab1.a + lab1.b * lab1.b);
935
+ const C2 = Math.sqrt(lab2.a * lab2.a + lab2.b * lab2.b);
936
+ const dC = C1 - C2;
937
+ const dH2 = da * da + db * db - dC * dC;
938
+ const dH = dH2 > 0 ? Math.sqrt(dH2) : 0;
939
+ const SL = 1;
940
+ const SC = 1 + 0.045 * C1;
941
+ const SH = 1 + 0.015 * C1;
942
+ const dLKlSl = dL / (kL * SL);
943
+ const dCKcSc = dC / (kC * SC);
944
+ const dHKhSh = dH / (kH * SH);
945
+ return Math.sqrt(dLKlSl * dLKlSl + dCKcSc * dCKcSc + dHKhSh * dHKhSh);
946
+ }
947
+ function euclideanDistance(color1, color2) {
948
+ const dr = color1.r - color2.r;
949
+ const dg = color1.g - color2.g;
950
+ const db = color1.b - color2.b;
951
+ return Math.sqrt(dr * dr + dg * dg + db * db);
952
+ }
953
+ function findMostDifferentColor(baseColor, colors, options) {
954
+ if (colors.length === 0) return null;
955
+ let maxDistance = -Infinity;
956
+ let mostDifferent = colors[0];
957
+ for (const color of colors) {
958
+ const distance = colorDistance(baseColor, color, options);
959
+ if (distance > maxDistance) {
960
+ maxDistance = distance;
961
+ mostDifferent = color;
962
+ }
963
+ }
964
+ return mostDifferent;
965
+ }
966
+ function findMostSimilarColor(baseColor, colors, options) {
967
+ if (colors.length === 0) return null;
968
+ let minDistance = Infinity;
969
+ let mostSimilar = colors[0];
970
+ for (const color of colors) {
971
+ const distance = colorDistance(baseColor, color, options);
972
+ if (distance < minDistance) {
973
+ minDistance = distance;
974
+ mostSimilar = color;
975
+ }
976
+ }
977
+ return mostSimilar;
978
+ }
979
+ function weightedRgbDistance(color1, color2, weights) {
980
+ const wr = weights?.r ?? 0.3;
981
+ const wg = weights?.g ?? 0.59;
982
+ const wb = weights?.b ?? 0.11;
983
+ const dr = (color1.r - color2.r) * wr;
984
+ const dg = (color1.g - color2.g) * wg;
985
+ const db = (color1.b - color2.b) * wb;
986
+ return Math.sqrt(dr * dr + dg * dg + db * db);
987
+ }
988
+
989
+ // src/color/utils.ts
990
+ function clampHsl(hsl) {
991
+ return {
992
+ h: clamp(hsl.h, 0, 360),
993
+ l: clamp(hsl.l, 0, 100),
994
+ s: clamp(hsl.s, 0, 100)
995
+ };
996
+ }
997
+ function clampHsv(hsv) {
998
+ return {
999
+ h: clamp(hsv.h, 0, 360),
1000
+ s: clamp(hsv.s, 0, 100),
1001
+ v: clamp(hsv.v, 0, 100)
1002
+ };
1003
+ }
1004
+ function clampRgb2(rgb) {
1005
+ return {
1006
+ b: clamp(rgb.b, 0, 255),
1007
+ g: clamp(rgb.g, 0, 255),
1008
+ r: clamp(rgb.r, 0, 255)
1009
+ };
1010
+ }
1011
+ function darken(rgb, amount) {
1012
+ const hsl = rgbToHsl(rgb);
1013
+ hsl.l = clamp(hsl.l - amount, 0, 100);
1014
+ return parseColor(formatHsl(hsl)) || rgb;
1015
+ }
1016
+ function desaturate(rgb, amount) {
1017
+ const hsl = rgbToHsl(rgb);
1018
+ hsl.s = clamp(hsl.s - amount, 0, 100);
1019
+ return parseColor(formatHsl(hsl)) || rgb;
1020
+ }
1021
+ function formatColor(rgb, format = "hex") {
1022
+ switch (format) {
1023
+ case "hex":
1024
+ return rgbToHex(rgb);
1025
+ case "hsl":
1026
+ return formatHsl(rgbToHsl(rgb));
1027
+ case "hsv": {
1028
+ const hsv = rgbToHsv(rgb);
1029
+ return `hsv(${hsv.h}, ${hsv.s}%, ${hsv.v}%)`;
1030
+ }
1031
+ case "rgb":
1032
+ return formatRgb(rgb);
1033
+ default:
1034
+ return rgbToHex(rgb);
1035
+ }
1036
+ }
1037
+ function formatHsl(hsl, alpha) {
1038
+ if (alpha !== void 0) {
1039
+ return `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${alpha})`;
1040
+ }
1041
+ return `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;
1042
+ }
1043
+ function formatRgb(rgb, alpha) {
1044
+ if (alpha !== void 0) {
1045
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`;
1046
+ }
1047
+ return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
1048
+ }
1049
+ function getComplementary(rgb) {
1050
+ const hsl = rgbToHsl(rgb);
1051
+ hsl.h = (hsl.h + 180) % 360;
1052
+ return parseColor(formatHsl(hsl)) || rgb;
1053
+ }
1054
+ function getContrastRatio(color1, color2) {
1055
+ const lum1 = getLuminance(color1);
1056
+ const lum2 = getLuminance(color2);
1057
+ const lighter = Math.max(lum1, lum2);
1058
+ const darker = Math.min(lum1, lum2);
1059
+ return (lighter + 0.05) / (darker + 0.05);
1060
+ }
1061
+ function getLuminance(rgb) {
1062
+ const rsRGB = rgb.r / 255;
1063
+ const gsRGB = rgb.g / 255;
1064
+ const bsRGB = rgb.b / 255;
1065
+ const r = rsRGB <= 0.03928 ? rsRGB / 12.92 : Math.pow((rsRGB + 0.055) / 1.055, 2.4);
1066
+ const g = gsRGB <= 0.03928 ? gsRGB / 12.92 : Math.pow((gsRGB + 0.055) / 1.055, 2.4);
1067
+ const b = bsRGB <= 0.03928 ? bsRGB / 12.92 : Math.pow((bsRGB + 0.055) / 1.055, 2.4);
1068
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
1069
+ }
1070
+ function invertColor(rgb) {
1071
+ return {
1072
+ b: 255 - rgb.b,
1073
+ g: 255 - rgb.g,
1074
+ r: 255 - rgb.r
1075
+ };
1076
+ }
1077
+ function isDark(rgb, threshold = 0.5) {
1078
+ return getLuminance(rgb) < threshold;
1079
+ }
1080
+ function isLight(rgb, threshold = 0.5) {
1081
+ return getLuminance(rgb) >= threshold;
1082
+ }
1083
+ function isValidHex(hex) {
1084
+ const cleanHex = hex.replace("#", "");
1085
+ return /^[0-9A-Fa-f]{3}$|^[0-9A-Fa-f]{6}$/.test(cleanHex);
1086
+ }
1087
+ function isValidHsl(hsl) {
1088
+ return hsl.h >= 0 && hsl.h <= 360 && hsl.s >= 0 && hsl.s <= 100 && hsl.l >= 0 && hsl.l <= 100;
1089
+ }
1090
+ function isValidHsv(hsv) {
1091
+ return hsv.h >= 0 && hsv.h <= 360 && hsv.s >= 0 && hsv.s <= 100 && hsv.v >= 0 && hsv.v <= 100;
1092
+ }
1093
+ function isValidRgb(rgb) {
1094
+ return rgb.r >= 0 && rgb.r <= 255 && rgb.g >= 0 && rgb.g <= 255 && rgb.b >= 0 && rgb.b <= 255;
1095
+ }
1096
+ function lighten(rgb, amount) {
1097
+ const hsl = rgbToHsl(rgb);
1098
+ hsl.l = clamp(hsl.l + amount, 0, 100);
1099
+ return parseColor(formatHsl(hsl)) || rgb;
1100
+ }
1101
+ function meetsContrastAA(color1, color2, largeText = false) {
1102
+ const ratio = getContrastRatio(color1, color2);
1103
+ return largeText ? ratio >= 3 : ratio >= 4.5;
1104
+ }
1105
+ function meetsContrastAAA(color1, color2, largeText = false) {
1106
+ const ratio = getContrastRatio(color1, color2);
1107
+ return largeText ? ratio >= 4.5 : ratio >= 7;
1108
+ }
1109
+ function mixColors(color1, color2, weight = 0.5) {
1110
+ const w = clamp(weight, 0, 1);
1111
+ const w2 = 1 - w;
1112
+ return {
1113
+ b: Math.round(color1.b * w + color2.b * w2),
1114
+ g: Math.round(color1.g * w + color2.g * w2),
1115
+ r: Math.round(color1.r * w + color2.r * w2)
1116
+ };
1117
+ }
1118
+ function randomColor() {
1119
+ return {
1120
+ b: Math.floor(Math.random() * 256),
1121
+ g: Math.floor(Math.random() * 256),
1122
+ r: Math.floor(Math.random() * 256)
1123
+ };
1124
+ }
1125
+ function saturate(rgb, amount) {
1126
+ const hsl = rgbToHsl(rgb);
1127
+ hsl.s = clamp(hsl.s + amount, 0, 100);
1128
+ return parseColor(formatHsl(hsl)) || rgb;
1129
+ }
1130
+ function toGrayscale(rgb) {
1131
+ const gray = Math.round(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b);
1132
+ return { b: gray, g: gray, r: gray };
1133
+ }
1134
+ function clamp(value, min, max) {
1135
+ return Math.max(min, Math.min(max, value));
1136
+ }
1137
+
1138
+ export {
1139
+ ColorFormat,
1140
+ ColorConstants,
1141
+ argbToRgb,
1142
+ hexToRgb,
1143
+ hslToRgb,
1144
+ hsvToRgb,
1145
+ labToRgb,
1146
+ labToXyz,
1147
+ parseColor,
1148
+ rgbToArgb,
1149
+ rgbToHex,
1150
+ rgbToHsl,
1151
+ rgbToHsv,
1152
+ rgbToLab,
1153
+ rgbToXyz,
1154
+ xyzToLab,
1155
+ xyzToRgb,
1156
+ hct,
1157
+ hctToRgb,
1158
+ maxChroma,
1159
+ rgbToHct,
1160
+ Hct,
1161
+ DislikeAnalyzer,
1162
+ adjustTemperature,
1163
+ analogous,
1164
+ blend,
1165
+ doubleComplementary,
1166
+ gradient,
1167
+ harmonize,
1168
+ splitComplementary,
1169
+ tetradic,
1170
+ MATERIAL_TONES,
1171
+ EXTENDED_TONES,
1172
+ TonalPalette,
1173
+ analogousPalette,
1174
+ complementaryPalette,
1175
+ corePaletteFromRgb,
1176
+ monochromaticPalette,
1177
+ triadicPalette,
1178
+ STANDARD_CONDITIONS,
1179
+ areColorsSimilar,
1180
+ colorDistance,
1181
+ deltaE2000,
1182
+ deltaE76,
1183
+ deltaE94,
1184
+ euclideanDistance,
1185
+ findMostDifferentColor,
1186
+ findMostSimilarColor,
1187
+ weightedRgbDistance,
1188
+ clampHsl,
1189
+ clampHsv,
1190
+ clampRgb2 as clampRgb,
1191
+ darken,
1192
+ desaturate,
1193
+ formatColor,
1194
+ formatHsl,
1195
+ formatRgb,
1196
+ getComplementary,
1197
+ getContrastRatio,
1198
+ getLuminance,
1199
+ invertColor,
1200
+ isDark,
1201
+ isLight,
1202
+ isValidHex,
1203
+ isValidHsl,
1204
+ isValidHsv,
1205
+ isValidRgb,
1206
+ lighten,
1207
+ meetsContrastAA,
1208
+ meetsContrastAAA,
1209
+ mixColors,
1210
+ randomColor,
1211
+ saturate,
1212
+ toGrayscale
1213
+ };
1214
+ //# sourceMappingURL=chunk-P3ARRKLS.js.map