chromonym 3.5.0 → 3.5.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.
Files changed (38) hide show
  1. package/README.md +11 -5
  2. package/dist/conversions/hex.d.ts.map +1 -1
  3. package/dist/conversions/hsl.d.ts.map +1 -1
  4. package/dist/conversions/hsv.d.ts.map +1 -1
  5. package/dist/conversions/pantone.d.ts.map +1 -1
  6. package/dist/conversions/rgb.d.ts.map +1 -1
  7. package/dist/convert.d.ts.map +1 -1
  8. package/dist/defineColorPalette.d.ts.map +1 -1
  9. package/dist/detectFormat.d.ts.map +1 -1
  10. package/dist/identify.d.ts.map +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/indexing.d.ts.map +1 -1
  13. package/dist/math/clamp.d.ts.map +1 -1
  14. package/dist/math/colorSpace.d.ts.map +1 -1
  15. package/dist/math/deltaE.d.ts.map +1 -1
  16. package/dist/math/editDistance.d.ts.map +1 -1
  17. package/dist/math/euclideanDistance.d.ts.map +1 -1
  18. package/dist/math/hueSector.d.ts.map +1 -1
  19. package/dist/palettes/crayola.d.ts.map +1 -1
  20. package/dist/palettes/fs595b.d.ts.map +1 -1
  21. package/dist/palettes/fs595c.d.ts.map +1 -1
  22. package/dist/palettes/isccNbs.d.ts.map +1 -1
  23. package/dist/palettes/nbs.d.ts.map +1 -1
  24. package/dist/palettes/ncs.d.ts.map +1 -1
  25. package/dist/palettes/normalize.d.ts.map +1 -1
  26. package/dist/palettes/ntc.d.ts.map +1 -1
  27. package/dist/palettes/pantone.d.ts.map +1 -1
  28. package/dist/palettes/pokemon.d.ts.map +1 -1
  29. package/dist/palettes/ral.d.ts.map +1 -1
  30. package/dist/palettes/resene.d.ts.map +1 -1
  31. package/dist/palettes/tailwind.d.ts.map +1 -1
  32. package/dist/palettes/web.d.ts.map +1 -1
  33. package/dist/palettes/werner.d.ts.map +1 -1
  34. package/dist/palettes/x11.d.ts.map +1 -1
  35. package/dist/palettes/xkcd.d.ts.map +1 -1
  36. package/dist/resolve.d.ts.map +1 -1
  37. package/dist/types.d.ts.map +1 -1
  38. package/package.json +21 -18
package/README.md CHANGED
@@ -21,7 +21,7 @@
21
21
  <code>identify</code> &nbsp;•&nbsp; <code>resolve</code> &nbsp;•&nbsp; <code>convert</code>
22
22
  </p>
23
23
 
24
- **The last color-naming library you'll ever need.** One API — `identify`, `resolve`, `convert` — works against any palette you throw at it. Ships twelve palettes out of the box (CSS, X11, Pantone, Crayola, NTC, XKCD, Resene, NCS, ISCC-NBS, NBS, FS 595 B, FS 595 C); bring your own (brand colors, paint chips, game factions, chart themes) with full TypeScript inference and zero registration. Six distance metrics — from fast Euclidean to industry-standard CIEDE2000 and OKLAB. Tree-shakes to the bone — you only pay for palettes you import.
24
+ **The last color-naming library you'll ever need.** Give it any hex, RGB, HSL, or HSV value and get back the nearest named color; give it a color name and get back the value. One API — `identify`, `resolve`, `convert` — works against any palette you throw at it. Ships sixteen palettes out of the box (CSS, X11, Pantone, Crayola, NTC, XKCD, RAL, Tailwind, Resene, NCS, ISCC-NBS, NBS, FS 595 B, FS 595 C, Werner, Pokémon); bring your own (brand colors, paint chips, game factions, chart themes) with full TypeScript inference and zero registration. Six distance metrics — from fast Euclidean to industry-standard CIEDE2000 and OKLAB. Tree-shakes to the bone — you only pay for palettes you import.
25
25
 
26
26
  <sub>*chromonym* (n.): a name for a color; *chroma* + *-onym*. Also the library.</sub>
27
27
 
@@ -74,7 +74,7 @@ convert('#e4002b', { palette: pantone, format: 'NAME' }) // '185 C' (exact mat
74
74
  convert('acme red', { palette: brand, format: 'RGB' }) // 'rgb(255, 42, 59)'
75
75
  ```
76
76
 
77
- The identification machinery is palette-agnostic — RAL, HKS, NCS, Munsell, or a bespoke in-house set are the same amount of work (a small file each, or a single object literal). PRs welcome; meanwhile, BYO lets you ship today.
77
+ The identification machinery is palette-agnostic — HKS, Munsell, or a bespoke in-house set are the same amount of work (a small file each, or a single object literal). PRs welcome; meanwhile, BYO lets you ship today.
78
78
 
79
79
  ## Install
80
80
 
@@ -296,7 +296,7 @@ Unparseable values are dropped with a `console.warn` naming the palette, the off
296
296
 
297
297
  If you prefer zero runtime and already have hex-only values, the `as const satisfies Palette<'A' | 'B' | ...>` pattern still works — list the key union once in the generic and it narrows identically.
298
298
 
299
- ### The twelve we ship
299
+ ### The sixteen we ship
300
300
 
301
301
  | Name | Entries | Source |
302
302
  |---|---|---|
@@ -312,6 +312,10 @@ If you prefer zero runtime and already have hex-only values, the `as const satis
312
312
  | `nbs` | 267 | Second digitization of the same 1955 standard; different sRGB (matches 1955 chip book; covers the 7 blocks `isccNbs` leaves as gaps) |
313
313
  | `resene` | 1378 | Resene Paints (NZ) catalog; te reo Māori and NZ place-names in the naming |
314
314
  | `ncs` | 1950 | Natural Colour System (Sweden) — perceptual, structured notation (`2030-R80B`), not NCS-licensed |
315
+ | `ral` | 216 | RAL Classic, the European industrial coatings standard (community sRGB values; not a licensed RAL product) |
316
+ | `tailwind` | 242 | Tailwind CSS v4 default theme (22 families × 11 shades, computed from the OKLCH spec) |
317
+ | `werner` | 110 | Werner's Nomenclature of Colours (1821, Patrick Syme; the field reference Darwin carried aboard the Beagle) |
318
+ | `pokemon` | 18 | Pokémon type-badge colors (community approximations; not an official asset set) |
315
319
 
316
320
  Importable directly, or via subpath exports for stricter tree-shaking:
317
321
 
@@ -454,7 +458,7 @@ const tryConvert = (input: ColorInput, opts = {}) => {
454
458
 
455
459
  **Install size and bundle size are not the same number.** Install size is what lands in your `node_modules/` after `npm install`; bundle size is what ships to your users after tree-shaking, minification, and gzip. For chromonym the gap is roughly two orders of magnitude.
456
460
 
457
- The published tarball is **~2.5 MB unpacked / ~557 kB gzipped** because it carries twelve palettes and ~9000 named-color entries; that's the install-size figure `packagephobia` reports. Your **production bundle** pays only for what you actually import, measured with `esbuild --minify`:
461
+ The published tarball is **~2.7 MB unpacked / ~600 kB gzipped** because it carries sixteen palettes and ~9500 named-color entries; that's the install-size figure `packagephobia` reports. Your **production bundle** pays only for what you actually import, measured with `esbuild --minify`:
458
462
 
459
463
  | Import | min | gzip |
460
464
  |---|---|---|
@@ -484,7 +488,7 @@ Re-exported from the root barrel — `import type { ... } from 'chromonym'`:
484
488
  ```sh
485
489
  bun install
486
490
  bun run lint # biome
487
- bun run typecheck # tsgo (native-preview)
491
+ bun run typecheck # tsc (TypeScript 7, native)
488
492
  bun test
489
493
  bun run build
490
494
  ```
@@ -501,6 +505,8 @@ chromonym deliberately limits its scope to color *naming* (resolving and identif
501
505
 
502
506
  MIT © [the-simian](https://github.com/the-simian)
503
507
 
508
+ <sub>Looking for this package and landed here another way? Common misspellings: *chromanym*, *chromonim*. The package name is **chromonym**.</sub>
509
+
504
510
  <p align="center"><sub>Crafted with care by <a href="https://simiancraft.com">Simiancraft</a>.</sub></p>
505
511
 
506
512
  <p align="center"><sub>Pantone® and Crayola® are trademarks of their respective owners; Chromonym is not affiliated. Palette values are community approximations. Demo typeface <a href="https://www.dafont.com/bauhaus-modern.font">Bauhaus Modern</a> © Nils Kähler. Full attributions: <a href="./NOTICE.md">NOTICE.md</a>.</sub></p>
@@ -1 +1 @@
1
- {"version":3,"file":"hex.d.ts","sourceRoot":"","sources":["../../src/conversions/hex.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAElD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAsB7C;AAMD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAE9C","sourcesContent":["import { HEX_RE } from '../detectFormat.js';\nimport { clamp } from '../math/clamp.js';\nimport type { HexColor, Rgba } from '../types.js';\n\n/**\n * Parse a hex color string into the canonical Rgba representation.\n * Accepts 3-digit (`#rgb`), 6-digit (`#rrggbb`), and 8-digit (`#rrggbbaa`).\n * Throws on any other input shape.\n */\nexport function hexToRgba(hex: HexColor): Rgba {\n const match = HEX_RE.exec(hex);\n const body = match?.[1];\n if (!body) throw new Error(`Invalid hex color: ${hex}`);\n\n if (body.length === 3) {\n const r = body.charAt(0);\n const g = body.charAt(1);\n const b = body.charAt(2);\n return {\n r: parseInt(r + r, 16),\n g: parseInt(g + g, 16),\n b: parseInt(b + b, 16),\n a: 1,\n };\n }\n\n const r = parseInt(body.slice(0, 2), 16);\n const g = parseInt(body.slice(2, 4), 16);\n const b = parseInt(body.slice(4, 6), 16);\n const a = body.length === 8 ? parseInt(body.slice(6, 8), 16) / 255 : 1;\n return { r, g, b, a };\n}\n\nfunction channelToHex(n: number): string {\n return clamp(Math.round(n), 0, 255).toString(16).padStart(2, '0');\n}\n\n/**\n * Emit a 6-digit lowercase hex string. Alpha is dropped; out-of-range\n * channel values are clamped to 0..255; fractional values are rounded.\n */\nexport function rgbaToHex(rgba: Rgba): HexColor {\n return `#${channelToHex(rgba.r)}${channelToHex(rgba.g)}${channelToHex(rgba.b)}` as HexColor;\n}\n"]}
1
+ {"version":3,"file":"hex.d.ts","sourceRoot":"","sources":["../../src/conversions/hex.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAElD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAsB7C;AAMD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAE9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"hsl.d.ts","sourceRoot":"","sources":["../../src/conversions/hsl.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAK7D;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAqC/C;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAyB/C","sourcesContent":["import { requireFinite } from '../math/clamp.js';\nimport { hueSectorToPrime } from '../math/hueSector.js';\nimport type { HslInput, HslString, Rgba } from '../types.js';\n\nconst HSL_RE =\n /^hsl\\s*\\(\\s*(-?\\d+(?:\\.\\d+)?)\\s*,\\s*(-?\\d+(?:\\.\\d+)?)%?\\s*,\\s*(-?\\d+(?:\\.\\d+)?)%?\\s*\\)$/i;\n\n/**\n * Parse HSL input (string or object) into canonical Rgba.\n * Hue wraps modulo 360; saturation and lightness are 0..100 percent.\n */\nexport function hslToRgba(input: HslInput): Rgba {\n let h: number;\n let s: number;\n let l: number;\n\n if (typeof input === 'string') {\n const match = HSL_RE.exec(input);\n if (!match) throw new Error(`Invalid hsl string: ${input}`);\n h = Number(match[1]);\n s = Number(match[2]);\n l = Number(match[3]);\n } else {\n h = requireFinite(input.h, 'h');\n s = requireFinite(input.s, 's');\n l = requireFinite(input.l, 'l');\n }\n\n const saturation = s / 100;\n const lightness = l / 100;\n\n if (saturation === 0) {\n const gray = Math.round(lightness * 255);\n return { r: gray, g: gray, b: gray, a: 1 };\n }\n\n const chroma = (1 - Math.abs(2 * lightness - 1)) * saturation;\n const hueSector = (((h % 360) + 360) % 360) / 60;\n const secondary = chroma * (1 - Math.abs((hueSector % 2) - 1));\n const lightnessOffset = lightness - chroma / 2;\n\n const [rPrime, gPrime, bPrime] = hueSectorToPrime(hueSector, chroma, secondary);\n return {\n r: Math.round((rPrime + lightnessOffset) * 255),\n g: Math.round((gPrime + lightnessOffset) * 255),\n b: Math.round((bPrime + lightnessOffset) * 255),\n a: 1,\n };\n}\n\n/**\n * Emit an `hsl(h, s%, l%)` string from Rgba. Alpha is dropped; all\n * three components are rounded to whole numbers.\n */\nexport function rgbaToHsl(rgba: Rgba): HslString {\n const rNorm = rgba.r / 255;\n const gNorm = rgba.g / 255;\n const bNorm = rgba.b / 255;\n const max = Math.max(rNorm, gNorm, bNorm);\n const min = Math.min(rNorm, gNorm, bNorm);\n const lightness = (max + min) / 2;\n\n if (max === min) {\n return `hsl(0, 0%, ${Math.round(lightness * 100)}%)` as HslString;\n }\n\n const delta = max - min;\n const saturation = lightness > 0.5 ? delta / (2 - max - min) : delta / (max + min);\n let hue: number;\n if (max === rNorm) {\n hue = (gNorm - bNorm) / delta + (gNorm < bNorm ? 6 : 0);\n } else if (max === gNorm) {\n hue = (bNorm - rNorm) / delta + 2;\n } else {\n hue = (rNorm - gNorm) / delta + 4;\n }\n hue *= 60;\n\n return `hsl(${Math.round(hue)}, ${Math.round(saturation * 100)}%, ${Math.round(lightness * 100)}%)`;\n}\n"]}
1
+ {"version":3,"file":"hsl.d.ts","sourceRoot":"","sources":["../../src/conversions/hsl.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAK7D;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAqC/C;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAyB/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"hsv.d.ts","sourceRoot":"","sources":["../../src/conversions/hsv.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAK7D;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CA+B/C;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAuB/C","sourcesContent":["import { requireFinite } from '../math/clamp.js';\nimport { hueSectorToPrime } from '../math/hueSector.js';\nimport type { HsvInput, HsvString, Rgba } from '../types.js';\n\nconst HSV_RE =\n /^hsv\\s*\\(\\s*(-?\\d+(?:\\.\\d+)?)\\s*,\\s*(-?\\d+(?:\\.\\d+)?)%?\\s*,\\s*(-?\\d+(?:\\.\\d+)?)%?\\s*\\)$/i;\n\n/**\n * Parse HSV input (string or object) into canonical Rgba.\n * Hue wraps modulo 360; saturation and value are 0..100 percent.\n */\nexport function hsvToRgba(input: HsvInput): Rgba {\n let h: number;\n let s: number;\n let v: number;\n\n if (typeof input === 'string') {\n const match = HSV_RE.exec(input);\n if (!match) throw new Error(`Invalid hsv string: ${input}`);\n h = Number(match[1]);\n s = Number(match[2]);\n v = Number(match[3]);\n } else {\n h = requireFinite(input.h, 'h');\n s = requireFinite(input.s, 's');\n v = requireFinite(input.v, 'v');\n }\n\n const saturation = s / 100;\n const value = v / 100;\n const chroma = value * saturation;\n const hueSector = (((h % 360) + 360) % 360) / 60;\n const secondary = chroma * (1 - Math.abs((hueSector % 2) - 1));\n const valueOffset = value - chroma;\n\n const [rPrime, gPrime, bPrime] = hueSectorToPrime(hueSector, chroma, secondary);\n return {\n r: Math.round((rPrime + valueOffset) * 255),\n g: Math.round((gPrime + valueOffset) * 255),\n b: Math.round((bPrime + valueOffset) * 255),\n a: 1,\n };\n}\n\n/**\n * Emit an `hsv(h, s%, v%)` string from Rgba. Alpha is dropped; all\n * three components are rounded to whole numbers.\n */\nexport function rgbaToHsv(rgba: Rgba): HsvString {\n const rNorm = rgba.r / 255;\n const gNorm = rgba.g / 255;\n const bNorm = rgba.b / 255;\n const max = Math.max(rNorm, gNorm, bNorm);\n const min = Math.min(rNorm, gNorm, bNorm);\n const delta = max - min;\n const value = max;\n const saturation = max === 0 ? 0 : delta / max;\n\n let hue = 0;\n if (delta !== 0) {\n if (max === rNorm) {\n hue = (gNorm - bNorm) / delta + (gNorm < bNorm ? 6 : 0);\n } else if (max === gNorm) {\n hue = (bNorm - rNorm) / delta + 2;\n } else {\n hue = (rNorm - gNorm) / delta + 4;\n }\n hue *= 60;\n }\n\n return `hsv(${Math.round(hue)}, ${Math.round(saturation * 100)}%, ${Math.round(value * 100)}%)`;\n}\n"]}
1
+ {"version":3,"file":"hsv.d.ts","sourceRoot":"","sources":["../../src/conversions/hsv.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAK7D;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CA+B/C;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAuB/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"pantone.d.ts","sourceRoot":"","sources":["../../src/conversions/pantone.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,gBAAgB,EAAW,MAAM,wBAAwB,CAAC;AACxE,OAAO,KAAK,EAAY,IAAI,EAAE,MAAM,aAAa,CAAC;AAGlD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAKhD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,gBAAgB,CAE1D","sourcesContent":["import { getNameIndex, nearest } from '../indexing.js';\nimport { type PantoneColorName, pantone } from '../palettes/pantone.js';\nimport type { HexColor, Rgba } from '../types.js';\nimport { hexToRgba } from './hex.js';\n\n/**\n * Resolve a Pantone code to Rgba.\n * Accepts any casing, spacing, and common prefixes (\"PMS\", \"Pantone\")\n * since non-alphanumeric characters are stripped before lookup.\n * Throws on unknown codes.\n */\nexport function pantoneToRgba(code: string): Rgba {\n const canonical = getNameIndex(pantone).get(pantone.normalize(code));\n if (canonical === undefined) throw new Error(`Unknown Pantone code: ${code}`);\n const hex = pantone.colors[canonical as keyof typeof pantone.colors];\n return hexToRgba(hex as HexColor);\n}\n\n/**\n * Find the nearest Pantone Coated code to the given Rgba. Uses the\n * `pantone` palette's own `defaultMetric` (ΔE*00 / CIEDE2000) — the\n * industry-standard perceptual metric, since Pantone values cluster densely\n * in the saturated blue/purple region where sRGB Euclidean distance gives\n * visually wrong answers.\n * Alpha is ignored. Always returns a code.\n */\nexport function rgbaToPantone(rgba: Rgba): PantoneColorName {\n return nearest(rgba, pantone, pantone.defaultMetric) as PantoneColorName;\n}\n"]}
1
+ {"version":3,"file":"pantone.d.ts","sourceRoot":"","sources":["../../src/conversions/pantone.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,gBAAgB,EAAW,MAAM,wBAAwB,CAAC;AACxE,OAAO,KAAK,EAAY,IAAI,EAAE,MAAM,aAAa,CAAC;AAGlD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAKhD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,gBAAgB,CAE1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"rgb.d.ts","sourceRoot":"","sources":["../../src/conversions/rgb.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAa,SAAS,EAAE,MAAM,aAAa,CAAC;AAgBnF;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,CA+B3D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAK/C","sourcesContent":["import { clamp, requireFinite } from '../math/clamp.js';\nimport type { Rgba, RgbaInput, RgbInput, RgbObject, RgbString } from '../types.js';\n\n// Alpha group split into two unambiguous alternatives to avoid polynomial\n// backtracking (CodeQL js/polynomial-redos) on malformed inputs like\n// `rgb(9,9,9,99...9`.\nconst RGB_RE =\n /^rgba?\\s*\\(\\s*(-?\\d+(?:\\.\\d+)?)\\s*,\\s*(-?\\d+(?:\\.\\d+)?)\\s*,\\s*(-?\\d+(?:\\.\\d+)?)\\s*(?:,\\s*(\\d+(?:\\.\\d+)?|\\.\\d+)\\s*)?\\)$/i;\n\nfunction sanitizeChannel(n: unknown, label: string): number {\n return clamp(requireFinite(n, label), 0, 255);\n}\n\nfunction sanitizeAlpha(n: unknown): number {\n return clamp(requireFinite(n, 'alpha'), 0, 1);\n}\n\n/**\n * Normalize any RGB/RGBA input shape (string, tuple, or object) into\n * the canonical Rgba representation. Alpha defaults to 1 when absent.\n * Rejects non-finite numeric inputs; clamps r/g/b to [0,255] and a to [0,1].\n * Throws on malformed strings. String parsing is linear-time; no polynomial\n * backtracking on pathological input. Leading-dot alpha (e.g. `.5`) is\n * accepted per the CSS Color spec.\n *\n * @example\n * rgbToRgba('rgba(255, 0, 0, .5)');\n * // => { r: 255, g: 0, b: 0, a: 0.5 }\n */\nexport function rgbToRgba(input: RgbInput | RgbaInput): Rgba {\n if (Array.isArray(input)) {\n const rawA = input.length === 4 ? input[3] : 1;\n return {\n r: sanitizeChannel(input[0], 'r'),\n g: sanitizeChannel(input[1], 'g'),\n b: sanitizeChannel(input[2], 'b'),\n a: sanitizeAlpha(rawA),\n };\n }\n\n if (typeof input === 'string') {\n const match = RGB_RE.exec(input);\n if (!match) throw new Error(`Invalid rgb(a) string: ${input}`);\n return {\n r: sanitizeChannel(Number(match[1]), 'r'),\n g: sanitizeChannel(Number(match[2]), 'g'),\n b: sanitizeChannel(Number(match[3]), 'b'),\n a: sanitizeAlpha(match[4] !== undefined ? Number(match[4]) : 1),\n };\n }\n\n // Object form — TypeScript's Array.isArray narrowing doesn't exclude\n // readonly tuple types from the union, so cast after the guards.\n const obj = input as RgbObject | Rgba;\n return {\n r: sanitizeChannel(obj.r, 'r'),\n g: sanitizeChannel(obj.g, 'g'),\n b: sanitizeChannel(obj.b, 'b'),\n a: sanitizeAlpha('a' in obj ? obj.a : 1),\n };\n}\n\n/**\n * Emit an `rgb(r, g, b)` string. Alpha is dropped; values are\n * already-clamped by rgbToRgba, but we re-clamp defensively for direct\n * Rgba-object callers who bypass the input normalizer.\n */\nexport function rgbaToRgb(rgba: Rgba): RgbString {\n const r = clamp(Math.round(rgba.r), 0, 255);\n const g = clamp(Math.round(rgba.g), 0, 255);\n const b = clamp(Math.round(rgba.b), 0, 255);\n return `rgb(${r}, ${g}, ${b})` as RgbString;\n}\n"]}
1
+ {"version":3,"file":"rgb.d.ts","sourceRoot":"","sources":["../../src/conversions/rgb.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAa,SAAS,EAAE,MAAM,aAAa,CAAC;AAgBnF;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,CA+B3D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAK/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,cAAc,EAAgB,MAAM,mBAAmB,CAAC;AAEtE,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,UAAU,EAIV,OAAO,EACP,UAAU,EACV,IAAI,EAGL,MAAM,YAAY,CAAC;AAYpB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,cAAc,GAAG,IAAI,CAgB5E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAE,WAAmB,GAAG,UAAU,CAqB5E;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,OAAO,IAAI;IAClD;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,OAAO,IAAI;IACrD;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAGF,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,wBAAwB,GAAG,UAAU,CAAC;AAGxF,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EACvC,KAAK,EAAE,UAAU,GAAG,MAAM,EAC1B,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC1B,UAAU,CAAC,CAAC,CAAC,CAAC;AAGjB,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EACvC,KAAK,EAAE,UAAU,GAAG,MAAM,EAC1B,IAAI,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAC7B,UAAU,CAAC","sourcesContent":["import { hexToRgba, rgbaToHex } from './conversions/hex.js';\nimport { hslToRgba, rgbaToHsl } from './conversions/hsl.js';\nimport { hsvToRgba, rgbaToHsv } from './conversions/hsv.js';\nimport { rgbaToRgb, rgbToRgba } from './conversions/rgb.js';\nimport { type DetectedFormat, detectFormat } from './detectFormat.js';\nimport { getNameIndex, getReverseNameIndex } from './indexing.js';\nimport type {\n ColorFormat,\n ColorInput,\n ColorValue,\n HexColor,\n HslInput,\n HsvInput,\n Palette,\n PaletteKey,\n Rgba,\n RgbaInput,\n RgbInput,\n} from './types.js';\n\nfunction safeStringify(x: unknown): string {\n if (x === undefined) return 'undefined';\n try {\n const s = JSON.stringify(x);\n return s === undefined ? String(x) : s;\n } catch {\n return Object.prototype.toString.call(x);\n }\n}\n\n/**\n * Normalize any recognized color input to canonical `Rgba`.\n * Pass `knownFormat` when the caller has already run `detectFormat` to skip\n * the redundant detection. Throws on `UNKNOWN` input.\n *\n * Palette names (Pantone codes, BYO keys) are not accepted here; they\n * require palette data to parse. Use `convert(name, { palette })` or\n * `resolve(name, { palette })` at the higher level.\n *\n * @example\n * toRgba('#ff0000'); // { r: 255, g: 0, b: 0, a: 1 }\n * toRgba('rgb(255, 0, 0)'); // { r: 255, g: 0, b: 0, a: 1 }\n * toRgba([255, 0, 0]); // { r: 255, g: 0, b: 0, a: 1 }\n * toRgba({ h: 0, s: 100, l: 50 }); // { r: 255, g: 0, b: 0, a: 1 }\n */\nexport function toRgba(input: ColorInput, knownFormat?: DetectedFormat): Rgba {\n const format = knownFormat ?? detectFormat(input);\n switch (format) {\n case 'HEX':\n return hexToRgba(input as HexColor);\n case 'RGB':\n return rgbToRgba(input as RgbInput);\n case 'RGBA':\n return rgbToRgba(input as RgbaInput);\n case 'HSL':\n return hslToRgba(input as HslInput);\n case 'HSV':\n return hsvToRgba(input as HsvInput);\n default:\n throw new Error(`Unrecognized color input: ${safeStringify(input)}`);\n }\n}\n\n/**\n * Emit a canonical `Rgba` in the target structural format. Palette-independent.\n *\n * For palette-key output (e.g. nearest Pantone code, brand name), use\n * `convert(rgba, { format: 'NAME', palette })`; or `identify` for fuzzy,\n * `rgbaToPantone` for the low-level Pantone-only path.\n *\n * @example\n * fromRgba({ r: 255, g: 0, b: 0, a: 1 }); // '#ff0000'\n * fromRgba({ r: 255, g: 0, b: 0, a: 1 }, 'HSL'); // 'hsl(0, 100%, 50%)'\n * fromRgba({ r: 255, g: 0, b: 0, a: 0.5 }, 'RGB'); // 'rgb(255, 0, 0)' (alpha dropped)\n */\nexport function fromRgba(rgba: Rgba, format: ColorFormat = 'HEX'): ColorValue {\n switch (format) {\n case 'HEX':\n return rgbaToHex(rgba);\n case 'RGB':\n return rgbaToRgb(rgba);\n case 'RGBA':\n return rgba;\n case 'HSL':\n return rgbaToHsl(rgba);\n case 'HSV':\n return rgbaToHsv(rgba);\n default: {\n // Runtime safety for JS callers bypassing the ColorFormat union.\n const hint =\n format === ('PANTONE' as unknown)\n ? ` — use convert(rgba, { palette: pantone, format: 'NAME' }) or rgbaToPantone from 'chromonym/conversions/pantone'`\n : '';\n throw new Error(`Unsupported format: ${safeStringify(format)}${hint}`);\n }\n }\n}\n\n/**\n * Detect the input color format, normalize to Rgba, and emit the result\n * in the requested output format.\n *\n * Without a `palette` option, `convert` is strictly structural —\n * HEX ↔ RGB ↔ RGBA ↔ HSL ↔ HSV, no palette data ever touched, tree-shakes\n * to the bone.\n *\n * With a `palette` option, `convert` understands the palette's naming\n * scheme both ways:\n * - Input can be a palette name (`'185 C'`, `'Acme Red'`) — parsed via\n * `palette.normalize` and looked up in `palette.colors`.\n * - Output can be `format: 'NAME'` — the exact canonical key from\n * `palette.colors`, throws if the color isn't a pixel-exact match (use\n * `identify` for nearest-match).\n *\n * The palette data comes from the caller's own import, so tree-shaking\n * is preserved: callers who don't pass `palette` never pull a palette.\n *\n * Throws on unrecognized input (parser-flavored — `identify`/`resolve`\n * are the `null`-returning alternatives).\n */\n\n/**\n * Options for the structural (palette-free) variant of {@link convert}.\n * Use when you only need to translate between HEX / RGB / RGBA / HSL / HSV.\n *\n * @example\n * convert('#ff0000', { format: 'HSL' }); // 'hsl(0, 100%, 50%)'\n */\nexport type ConvertStructuralOptions = {\n /**\n * Target output format. Defaults to `'HEX'`.\n */\n readonly format?: ColorFormat;\n};\n\n/**\n * Options for {@link convert} when reverse-looking-up a palette name\n * from an exact color value. Generic so the return narrows to the\n * palette's literal-key union.\n *\n * Throws at runtime if the input isn't a pixel-exact match in the\n * palette; use `identify` for nearest-match semantics.\n *\n * @example\n * convert('#e4002b', { palette: pantone, format: 'NAME' }); // '185 C'\n * convert('#663399', { palette: web, format: 'NAME' }); // 'rebeccapurple'\n */\nexport type ConvertNameOptions<P extends Palette> = {\n /**\n * Palette to reverse-look-up against. Required when `format` is `'NAME'`.\n */\n readonly palette: P;\n /**\n * Output discriminator. `'NAME'` returns the palette's canonical key\n * for the input color.\n */\n readonly format: 'NAME';\n};\n\n/**\n * Options for {@link convert} when a palette is provided but the output\n * is a structural format (HEX / RGB / HSL / HSV). Unlocks palette-name\n * *input*: the `input` may be `'185 C'`, `'Acme Red'`, etc., which is\n * resolved through `palette.normalize` before conversion.\n *\n * @example\n * convert('185 C', { palette: pantone }); // '#e4002b'\n * convert('185 C', { palette: pantone, format: 'HSL' }); // 'hsl(349, 100%, 45%)'\n */\nexport type ConvertPaletteOptions<P extends Palette> = {\n /**\n * Palette used to parse name-shaped inputs.\n */\n readonly palette: P;\n /**\n * Target output format. Defaults to `'HEX'`.\n */\n readonly format?: ColorFormat;\n};\n\n// Overload 1: no palette — structural only. Input is strictly ColorInput.\nexport function convert(input: ColorInput, opts?: ConvertStructuralOptions): ColorValue;\n\n// Overload 2: palette present, format 'NAME' — returns a palette key.\nexport function convert<P extends Palette>(\n input: ColorInput | string,\n opts: ConvertNameOptions<P>,\n): PaletteKey<P>;\n\n// Overload 3: palette present, structural format — returns ColorValue.\nexport function convert<P extends Palette>(\n input: ColorInput | string,\n opts: ConvertPaletteOptions<P>,\n): ColorValue;\n\n// Implementation\nexport function convert(\n input: ColorInput | string,\n opts: { format?: ColorFormat | 'NAME'; palette?: Palette } = {},\n): ColorValue | string {\n const { format = 'HEX', palette } = opts;\n\n // --- Parse input → Rgba ---\n // Structural detection first; palette lookup only as a fallback. This\n // way `convert('#ff0000', { palette: brand })` always means \"parse hex,\"\n // even if the brand palette happens to have a key that normalizes to\n // \"ff0000\".\n const detected = detectFormat(input as ColorInput);\n let rgba: Rgba;\n if (detected !== 'UNKNOWN') {\n rgba = toRgba(input as ColorInput, detected);\n } else if (palette !== undefined && typeof input === 'string') {\n const canonical = getNameIndex(palette).get(palette.normalize(input));\n if (canonical === undefined) {\n throw new Error(\n `Unrecognized color input: ${safeStringify(input)} (not structural, and not found in palette '${palette.name}')`,\n );\n }\n const hex = (palette.colors as Record<string, HexColor>)[canonical];\n if (hex === undefined) {\n throw new Error(`Unrecognized color input: ${safeStringify(input)}`);\n }\n rgba = hexToRgba(hex);\n } else {\n throw new Error(`Unrecognized color input: ${safeStringify(input)}`);\n }\n\n // --- Emit ---\n if (format === 'NAME') {\n if (palette === undefined) {\n throw new Error(`convert(_, { format: 'NAME' }) requires a 'palette' option`);\n }\n // Palette colors are alpha = 1 by construction; a partially-transparent\n // input isn't \"that named color\" in the strict-convert sense. Reject\n // here rather than silently drop alpha during the reverse lookup.\n if (rgba.a !== 1) {\n throw new Error(\n `format: 'NAME' requires fully-opaque input (a === 1). Got a=${rgba.a}. ` +\n `Strip alpha first or use identify() for fuzzy matching.`,\n );\n }\n const hex = rgbaToHex(rgba).toLowerCase();\n const name = getReverseNameIndex(palette).get(hex);\n if (name === undefined) {\n throw new Error(\n `No exact match for ${hex} in palette '${palette.name}'. Use identify() for nearest-match semantics.`,\n );\n }\n return name;\n }\n return fromRgba(rgba, format);\n}\n"]}
1
+ {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,cAAc,EAAgB,MAAM,mBAAmB,CAAC;AAEtE,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,UAAU,EAIV,OAAO,EACP,UAAU,EACV,IAAI,EAGL,MAAM,YAAY,CAAC;AAYpB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,cAAc,GAAG,IAAI,CAgB5E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAE,WAAmB,GAAG,UAAU,CAqB5E;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,OAAO,IAAI;IAClD;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,OAAO,IAAI;IACrD;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAGF,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,wBAAwB,GAAG,UAAU,CAAC;AAGxF,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EACvC,KAAK,EAAE,UAAU,GAAG,MAAM,EAC1B,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC1B,UAAU,CAAC,CAAC,CAAC,CAAC;AAGjB,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EACvC,KAAK,EAAE,UAAU,GAAG,MAAM,EAC1B,IAAI,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAC7B,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"defineColorPalette.d.ts","sourceRoot":"","sources":["../src/defineColorPalette.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAY,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE7F;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC;CACxC,CAAC;AAaF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,CAAC,SAAS,uBAAuB,EACxE,CAAC,EAAE,CAAC,GACH,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,CAgC7C","sourcesContent":["// BYO-palette authoring helper. See the companion test file for the full\n// matrix of accepted value shapes; see the README \"Bring your own palette\"\n// section for how callers are meant to reach for this.\n//\n// Why this exists: without it, a BYO palette needs\n// `{ colors: {...}, ... } as const satisfies Palette<'Red' | 'Blue'>`\n// which requires listing the key union twice and only accepts `HexColor`\n// values. With this helper, callers pass any `ColorInput` value (hex, rgb\n// string, hsl object, tuple, etc.) and the helper normalizes every entry\n// to `HexColor` at define time, so downstream `identify`/`resolve`/`convert`\n// and the indexing caches still see a uniform hex-only palette.\n//\n// Error policy: on an unparseable value we `console.warn` and drop the\n// key rather than throw, so one bad entry doesn't sink a whole palette.\n// The caller sees the warning with the palette name and the offending\n// value; the resulting palette has the surviving entries and behaves\n// normally.\n\nimport { rgbaToHex } from './conversions/hex.js';\nimport { toRgba } from './convert.js';\nimport type { ColorInput, DistanceMetric, HexColor, NormalizeFn, Palette } from './types.js';\n\n/**\n * The authoring shape accepted by {@link defineColorPalette}: same as\n * {@link Palette}, except `colors` values may be any {@link ColorInput}\n * rather than requiring {@link HexColor}. Exported mainly for\n * type-level inspection; most callers should not reference it directly.\n */\nexport type DefineColorPaletteInput = {\n readonly name: string;\n readonly colors: Readonly<Record<string, ColorInput>>;\n readonly normalize: NormalizeFn;\n readonly defaultMetric: DistanceMetric;\n};\n\nfunction describe(value: unknown): string {\n if (value === undefined) return 'undefined';\n if (value === null) return 'null';\n try {\n const s = JSON.stringify(value);\n return s ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Author a BYO palette with mixed-format color values. Values are\n * normalized to {@link HexColor} at call time; unparseable entries are\n * dropped with a `console.warn`.\n *\n * The `const` type parameter preserves the literal-key union so downstream\n * `identify`/`resolve`/`convert` narrow their return types to the palette's\n * actual keys, the same way the built-in palettes do.\n *\n * @example\n * // Mixed input formats; all end up as HexColor in the returned palette.\n * const brand = defineColorPalette({\n * name: 'brand',\n * colors: {\n * 'Acme Red': '#ff0044',\n * 'Acme Blue': 'rgb(0, 68, 255)',\n * 'Acme Ink': { r: 20, g: 20, b: 30 },\n * 'Acme Mist': [240, 244, 248],\n * },\n * normalize: (s) => s.toLowerCase().replace(/\\s+/g, ''),\n * defaultMetric: 'deltaE2000',\n * });\n *\n * identify('#ff0000', { palette: brand });\n * // typed as \"'Acme Red' | 'Acme Blue' | 'Acme Ink' | 'Acme Mist' | null\"\n *\n * @example\n * // A bad value doesn't break the palette; it's dropped with a warning.\n * const partial = defineColorPalette({\n * name: 'partial',\n * colors: { good: '#00ff00', bad: 'taco' as never },\n * normalize: (s) => s,\n * defaultMetric: 'deltaE76',\n * });\n * // console.warn: [chromonym] defineColorPalette(\"partial\"): skipping key\n * // \"bad\"; expected a color, got \"taco\"\n * // partial.colors === { good: '#00ff00' }\n */\nexport function defineColorPalette<const P extends DefineColorPaletteInput>(\n p: P,\n): Palette<Extract<keyof P['colors'], string>> {\n // Prototype-free accumulator, not a plain `{}`. A caller hydrating\n // `p.colors` from JSON (common for BYO palettes sourced from a CMS,\n // a brand spec, etc.) can legitimately have a key like `__proto__`\n // or `constructor`; palette data is just names and hex strings, so\n // those names have no special meaning here. With `{}`, assigning\n // `'#ff0000'` to `normalized['__proto__']` would be silently eaten\n // by the `Object.prototype.__proto__` setter (which rejects string\n // values without throwing), and the key would disappear without\n // hitting the bad-value `console.warn` path. `Object.create(null)`\n // has no setter to intercept, so every key round-trips as a plain\n // own property.\n const normalized = Object.create(null) as Record<string, HexColor>;\n for (const [key, value] of Object.entries(p.colors)) {\n try {\n normalized[key] = rgbaToHex(toRgba(value));\n } catch {\n // Library-level diagnostic on user misconfiguration; intentional\n // so authors see the dropped key without blowing up the whole\n // module load.\n console.warn(\n `[chromonym] defineColorPalette(${JSON.stringify(p.name)}): ` +\n `skipping key ${JSON.stringify(key)}; expected a color, got ${describe(value)}`,\n );\n }\n }\n return {\n name: p.name,\n colors: normalized as Readonly<Record<Extract<keyof P['colors'], string>, HexColor>>,\n normalize: p.normalize,\n defaultMetric: p.defaultMetric,\n };\n}\n"]}
1
+ {"version":3,"file":"defineColorPalette.d.ts","sourceRoot":"","sources":["../src/defineColorPalette.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAY,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE7F;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC;CACxC,CAAC;AAaF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,CAAC,SAAS,uBAAuB,EACxE,CAAC,EAAE,CAAC,GACH,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,CAgC7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"detectFormat.d.ts","sourceRoot":"","sources":["../src/detectFormat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,SAAS,CAAC;AAErD,kGAAkG;AAClG,eAAO,MAAM,MAAM,QAA8C,CAAC;AAMlE;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAE3D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,cAAc,CA8B9D","sourcesContent":["import type { ColorFormat, ColorInput } from './types.js';\n\n/**\n * Return type of {@link detectFormat}. Either a {@link ColorFormat} key\n * (`'HEX'` / `'RGB'` / `'RGBA'` / `'HSL'` / `'HSV'`) or the sentinel\n * string `'UNKNOWN'` when the input doesn't match any recognized color\n * shape. The sentinel is the dispatch miss condition for\n * format-specific converters; prefer {@link isColor} when you only\n * need a boolean guard.\n */\nexport type DetectedFormat = ColorFormat | 'UNKNOWN';\n\n/** Shared with `src/conversions/hex.ts`. Capture group is used there; .test() ignores it here. */\nexport const HEX_RE = /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i;\nconst RGBA_STR_RE = /^rgba\\s*\\(/i;\nconst RGB_STR_RE = /^rgb\\s*\\(/i;\nconst HSL_STR_RE = /^hsl\\s*\\(/i;\nconst HSV_STR_RE = /^hsv\\s*\\(/i;\n\n/**\n * Runtime type-guard — returns `true` if `input` looks like something any of\n * chromonym's converters can parse. Cheaper than catching a `convert` throw\n * and more ergonomic than hand-rolling `detectFormat(x) !== 'UNKNOWN'`.\n */\nexport function isColor(input: unknown): input is ColorInput {\n return detectFormat(input as ColorInput) !== 'UNKNOWN';\n}\n\n/**\n * Classify a color input by shape, returning the {@link ColorFormat}\n * key used to dispatch format-specific converters. Returns the\n * sentinel `'UNKNOWN'` when the input doesn't match any recognized\n * shape; callers that only need a boolean guard should prefer\n * {@link isColor} instead.\n *\n * Pure shape detection; no value validation. `detectFormat('#zzz')`\n * still returns `'UNKNOWN'` because the hex regex rejects it, but\n * `detectFormat({ r: 999, g: -1, b: 'nope' })` returns `'RGB'` (the\n * shape matches; the values are the converter's problem).\n *\n * @example\n * detectFormat('#ff0000'); // 'HEX'\n * detectFormat('rgb(255, 0, 0)'); // 'RGB'\n * detectFormat([255, 0, 0]); // 'RGB'\n * detectFormat([255, 0, 0, 0.5]); // 'RGBA'\n * detectFormat({ h: 0, s: 100, l: 50 });// 'HSL'\n * detectFormat('banana'); // 'UNKNOWN'\n */\nexport function detectFormat(input: ColorInput): DetectedFormat {\n if (typeof input === 'string') {\n // Runtime guard against JS callers that bypass the string template union.\n if ((input as string).length === 0) return 'UNKNOWN';\n if (HEX_RE.test(input)) return 'HEX';\n if (RGBA_STR_RE.test(input)) return 'RGBA';\n if (RGB_STR_RE.test(input)) return 'RGB';\n if (HSL_STR_RE.test(input)) return 'HSL';\n if (HSV_STR_RE.test(input)) return 'HSV';\n return 'UNKNOWN';\n }\n\n if (Array.isArray(input)) {\n if (input.length === 4) return 'RGBA';\n if (input.length === 3) return 'RGB';\n return 'UNKNOWN';\n }\n\n if (input !== null && typeof input === 'object') {\n // Use Object.hasOwn — `in` walks the prototype chain and can be\n // abused by attacker-controlled prototypes to misclassify inputs.\n const has = Object.hasOwn;\n if (has(input, 'h') && has(input, 'v')) return 'HSV';\n if (has(input, 'h') && has(input, 'l')) return 'HSL';\n if (has(input, 'r') && has(input, 'a')) return 'RGBA';\n if (has(input, 'r')) return 'RGB';\n return 'UNKNOWN';\n }\n\n return 'UNKNOWN';\n}\n"]}
1
+ {"version":3,"file":"detectFormat.d.ts","sourceRoot":"","sources":["../src/detectFormat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,SAAS,CAAC;AAErD,kGAAkG;AAClG,eAAO,MAAM,MAAM,QAA8C,CAAC;AAMlE;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAE3D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,cAAc,CA8B9D"}
@@ -1 +1 @@
1
- {"version":3,"file":"identify.d.ts","sourceRoot":"","sources":["../src/identify.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAQ,MAAM,YAAY,CAAC;AAElG;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,SAAS,MAAM,IAAI;IAC/C,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,GAAG,IAAI;IAC5D;;OAEG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACrB;;;;;;;;;OASG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;CAClC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,GAAG,IAAI,eAAe,CAAC,CAAC,CAAC,GAAG;IACvF;;;OAGG;IACH,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAmBF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAYH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,GAAG,EACrD,KAAK,EAAE,UAAU,GAAG,MAAM,EAC1B,IAAI,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GACxB,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AAGxB,wBAAgB,QAAQ,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,GAAG,EACrD,KAAK,EAAE,UAAU,GAAG,MAAM,EAC1B,IAAI,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAC7B,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC","sourcesContent":["import { hexToRgba } from './conversions/hex.js';\nimport { toRgba } from './convert.js';\nimport { detectFormat } from './detectFormat.js';\nimport { getNameIndex, nearest, nearestAll } from './indexing.js';\nimport { web } from './palettes/web.js';\nimport type { ColorInput, DistanceMetric, HexColor, Palette, PaletteKey, Rgba } from './types.js';\n\n/**\n * One ranked nearest-match entry when `identify` is called with `k`.\n * `value` is the palette's stored hex for the match (useful for rendering\n * swatches). `distance` is in the selected metric's natural units: ΔE for\n * `deltaE*` metrics, channel-unit Euclidean for the others.\n */\nexport type IdentifyMatch<Name extends string> = {\n readonly name: Name;\n readonly value: HexColor;\n readonly distance: number;\n};\n\n/**\n * Options for {@link identify}. Generic over the target palette so the\n * return type narrows to its literal-key union.\n *\n * @example\n * identify('#ff0000', { palette: pantone, metric: 'deltaE2000' });\n * identify('rebeccapurple', { palette: x11, source: web });\n */\nexport type IdentifyOptions<P extends Palette = typeof web> = {\n /**\n * Target palette to search in. Defaults to `web` (CSS named colors).\n */\n readonly palette?: P;\n /**\n * Source palette for cross-palette name input: when `input` is a name\n * from a different palette (e.g. `'rebeccapurple'` when `palette` is\n * `pantone`), set `source` to the palette that owns the name so it can\n * be resolved to an Rgba before the nearest-match lookup.\n *\n * @remarks\n * The `input` argument isn't validated against `source`'s keys at\n * compile time; unknown names resolve to `null` at runtime.\n */\n readonly source?: Palette;\n /**\n * Override the distance metric. Defaults to `palette.defaultMetric`\n * (web/x11: `'deltaE76'`, pantone: `'deltaE2000'`, crayola: `'deltaEok'`).\n */\n readonly metric?: DistanceMetric;\n};\n\n/**\n * Options for the ranked top-k variant of {@link identify}. Returns an\n * array of {@link IdentifyMatch} entries instead of a single name.\n *\n * @example\n * identify('#ff0080', { palette: pantone, k: 3 });\n * // [\n * // { name: '219 C', value: '#da1884', distance: 2.1 },\n * // { name: '226 C', value: '#d0006f', distance: 3.9 },\n * // { name: 'Red 032 C',value: '#ef3340', distance: 5.4 },\n * // ]\n */\nexport type IdentifyRankedOptions<P extends Palette = typeof web> = IdentifyOptions<P> & {\n /**\n * Number of ranked matches to return. When present, `identify`\n * returns `IdentifyMatch[]` instead of a single key.\n */\n readonly k: number;\n};\n\n/**\n * Parse a string input that may be a color literal or a palette name.\n * Returns the canonical Rgba, or `null` if nothing matches.\n */\nfunction parseInput(input: ColorInput | string, source?: Palette): Rgba | null {\n const detected = detectFormat(input as ColorInput);\n if (detected !== 'UNKNOWN') return toRgba(input as ColorInput, detected);\n if (source !== undefined && typeof input === 'string') {\n const canonical = getNameIndex(source).get(source.normalize(input));\n if (canonical === undefined) return null;\n const hex = (source.colors as Record<string, HexColor>)[canonical];\n if (hex === undefined) return null;\n return hexToRgba(hex);\n }\n return null;\n}\n\n/**\n * Identify the nearest-named color for any color input (or palette name\n * from another palette via `source`).\n *\n * **Simple case — color in, name out:**\n * identify('#ff0000') → 'red'\n * identify('#ff0000', { palette: pantone }) → '172 C'\n *\n * **Cross-palette — name from one palette, nearest in another:**\n * identify('rebeccapurple', { palette: pantone, source: web }) → '267 C'\n * identify('Razzmatazz', { palette: pantone, source: crayola }) → '213 C'\n *\n * **Top-k ranked matches with ΔE distances:**\n * identify('#ff0000', { palette: pantone, k: 3 })\n * // [{ name: '172 C', value: '#fa4616', distance: 3.2 }, ...]\n *\n * The distance metric defaults to the target palette's `defaultMetric`\n * (web/x11: `deltaE76`, pantone: `deltaE2000`, crayola: `deltaEok`).\n * Override with `metric`.\n *\n * Tie-breaking: on exact-distance ties, the first-declared entry in\n * the palette's `colors` object wins. Deterministic across metrics\n * and across the single-match / top-k paths.\n *\n * `k` is forgiving: fractional values round, negatives and zero\n * return `[]`, and `NaN` / `±Infinity` return `[]` too. No throws on\n * invalid `k` — callers can safely pipe a slider value in without\n * pre-validating.\n *\n * Returns `null` (or `[]` when `k` is set) if the input can't be parsed.\n */\n\n// Input accepts `ColorInput | string`. The `string` widening is load-bearing\n// for two flows: (1) cross-palette name lookup (`identify(name, { source })`),\n// and (2) interactive callers passing untrusted user text; the library\n// returns `null` on unparseable input rather than throwing, so consumers can\n// feed it directly from a text field. Tightening to `ColorInput`-only would\n// break both patterns and force every interactive consumer to cast or\n// validate at every call site. Runtime safety is maintained by `parseInput`\n// returning `null` for anything it can't interpret.\n\n// Overload 1: no `k` — single name (or null). Unchanged legacy shape.\nexport function identify<P extends Palette = typeof web>(\n input: ColorInput | string,\n opts?: IdentifyOptions<P>,\n): PaletteKey<P> | null;\n\n// Overload 2: `k` present — ranked Match[] with distances.\nexport function identify<P extends Palette = typeof web>(\n input: ColorInput | string,\n opts: IdentifyRankedOptions<P>,\n): Array<IdentifyMatch<PaletteKey<P>>>;\n\n// Implementation.\nexport function identify(\n input: ColorInput | string,\n opts: IdentifyOptions & { k?: number } = {},\n): string | null | Array<IdentifyMatch<string>> {\n const palette = opts.palette ?? web;\n const metric = opts.metric ?? palette.defaultMetric;\n const rgba = parseInput(input, opts.source);\n\n if (opts.k !== undefined) {\n if (rgba === null) return [];\n const raw = nearestAll(rgba, palette, metric, opts.k);\n return raw.map((m) => {\n const value = (palette.colors as Record<string, HexColor>)[m.name];\n return { name: m.name, value: value as HexColor, distance: m.distance };\n });\n }\n\n if (rgba === null) return null;\n const name = nearest(rgba, palette, metric);\n return name || null;\n}\n"]}
1
+ {"version":3,"file":"identify.d.ts","sourceRoot":"","sources":["../src/identify.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAQ,MAAM,YAAY,CAAC;AAElG;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,SAAS,MAAM,IAAI;IAC/C,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,GAAG,IAAI;IAC5D;;OAEG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACrB;;;;;;;;;OASG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;CAClC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,GAAG,IAAI,eAAe,CAAC,CAAC,CAAC,GAAG;IACvF;;;OAGG;IACH,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAmBF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAYH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,GAAG,EACrD,KAAK,EAAE,UAAU,GAAG,MAAM,EAC1B,IAAI,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GACxB,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AAGxB,wBAAgB,QAAQ,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,GAAG,EACrD,KAAK,EAAE,UAAU,GAAG,MAAM,EAC1B,IAAI,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAC7B,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,OAAO,EAAE,MAAoB,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,OAAO,EACP,QAAQ,EACR,MAAM,GACP,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,uBAAuB,EAC5B,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,cAAc,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,QAAQ,GACT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,KAAK,iBAAiB,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,aAAa,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,WAAW,EACX,UAAU,EACV,UAAU,EACV,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAS,EACT,QAAQ,EACR,SAAS,EACT,SAAS,EACT,WAAW,EACX,OAAO,EACP,UAAU,EACV,IAAI,EACJ,SAAS,EACT,UAAU,EACV,SAAS,EACT,QAAQ,EACR,SAAS,EACT,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC","sourcesContent":["// Public API barrel; explicit named re-exports only (tree-shake friendly).\n// No default export; no side effects at module scope.\n\nimport pkg from '../package.json' with { type: 'json' };\n\nexport const VERSION: string = pkg.version;\n\nexport { hexToRgba, rgbaToHex } from './conversions/hex.js';\nexport { hslToRgba, rgbaToHsl } from './conversions/hsl.js';\nexport { hsvToRgba, rgbaToHsv } from './conversions/hsv.js';\nexport { pantoneToRgba, rgbaToPantone } from './conversions/pantone.js';\nexport { rgbaToRgb, rgbToRgba } from './conversions/rgb.js';\nexport {\n type ConvertNameOptions,\n type ConvertPaletteOptions,\n type ConvertStructuralOptions,\n convert,\n fromRgba,\n toRgba,\n} from './convert.js';\nexport {\n type DefineColorPaletteInput,\n defineColorPalette,\n} from './defineColorPalette.js';\nexport { type DetectedFormat, detectFormat, isColor } from './detectFormat.js';\nexport {\n type IdentifyMatch,\n type IdentifyOptions,\n type IdentifyRankedOptions,\n identify,\n} from './identify.js';\nexport { type CrayolaColorName, crayola } from './palettes/crayola.js';\nexport { type Fs595bColorName, fs595b } from './palettes/fs595b.js';\nexport { type Fs595cColorName, fs595c } from './palettes/fs595c.js';\nexport { type IsccNbsColorName, isccNbs } from './palettes/isccNbs.js';\nexport { type NbsColorName, nbs } from './palettes/nbs.js';\nexport { type NcsColorName, ncs } from './palettes/ncs.js';\nexport { type NtcColorName, ntc } from './palettes/ntc.js';\nexport { type PantoneColorName, pantone } from './palettes/pantone.js';\nexport { type PokemonColorName, pokemon } from './palettes/pokemon.js';\nexport { type RalColorName, ral } from './palettes/ral.js';\nexport { type ReseneColorName, resene } from './palettes/resene.js';\nexport { type TailwindColorName, tailwind } from './palettes/tailwind.js';\nexport { type WebColorName, web } from './palettes/web.js';\nexport { type WernerColorName, werner } from './palettes/werner.js';\nexport { type X11ColorName, x11 } from './palettes/x11.js';\nexport { type XkcdColorName, xkcd } from './palettes/xkcd.js';\nexport {\n type ResolveFuzzyOptions,\n type ResolveMatch,\n type ResolveOptions,\n resolve,\n} from './resolve.js';\nexport type {\n ColorFormat,\n ColorInput,\n ColorValue,\n DistanceMetric,\n HexColor,\n HslInput,\n HslObject,\n HslString,\n HsvInput,\n HsvObject,\n HsvString,\n NormalizeFn,\n Palette,\n PaletteKey,\n Rgba,\n RgbaInput,\n RgbaString,\n RgbaTuple,\n RgbInput,\n RgbObject,\n RgbString,\n RgbTuple,\n} from './types.js';\nexport { COLOR_FORMATS } from './types.js';\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,OAAO,EAAE,MAAoB,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,OAAO,EACP,QAAQ,EACR,MAAM,GACP,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,uBAAuB,EAC5B,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,cAAc,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,QAAQ,GACT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,KAAK,iBAAiB,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,aAAa,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,WAAW,EACX,UAAU,EACV,UAAU,EACV,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAS,EACT,QAAQ,EACR,SAAS,EACT,SAAS,EACT,WAAW,EACX,OAAO,EACP,UAAU,EACV,IAAI,EACJ,SAAS,EACT,UAAU,EACV,SAAS,EACT,QAAQ,EACR,SAAS,EACT,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"indexing.d.ts","sourceRoot":"","sources":["../src/indexing.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;;;GAMG;AAEH,KAAK,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAKlC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAWnE;AAID;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAU1E;AAsGD;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CAavF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,IAAI,EACZ,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,cAAc,EACtB,CAAC,CAAC,EAAE,MAAM,GACT,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkF3C","sourcesContent":["import { hexToRgba } from './conversions/hex.js';\nimport { rgbaToLab, rgbaToLinearRgb, rgbaToOklab } from './math/colorSpace.js';\nimport { deltaE76Squared, deltaE94, deltaE2000, deltaEokSquared } from './math/deltaE.js';\nimport { squaredDistanceRgb } from './math/euclideanDistance.js';\nimport type { DistanceMetric, Palette, Rgba } from './types.js';\n\n/**\n * Per-palette lookup indexes for name resolution and nearest-match.\n *\n * Caches are keyed by the Palette wrapper (WeakMap), so each palette's\n * indexes are built once per process and reused by every caller —\n * including BYO palettes the user supplies.\n */\n\ntype AnyPalette = Palette<string>;\n\nconst nameIndexCache = new WeakMap<AnyPalette, Map<string, string>>();\nconst rgbaIndexCache = new WeakMap<AnyPalette, Array<readonly [string, Rgba]>>();\n\n/**\n * Normalized-name → canonical-key map for a given palette. Built once\n * per palette using its own `normalize` function.\n */\nexport function getNameIndex(space: AnyPalette): Map<string, string> {\n let idx = nameIndexCache.get(space);\n if (idx === undefined) {\n idx = new Map();\n const { normalize } = space;\n for (const key of Object.keys(space.colors)) {\n idx.set(normalize(key), key);\n }\n nameIndexCache.set(space, idx);\n }\n return idx;\n}\n\nconst reverseIndexCache = new WeakMap<AnyPalette, Map<string, string>>();\n\n/**\n * Hex → canonical-key map (reverse of `palette.colors`). Built once per\n * palette. Used by `convert(color, { palette, format: 'NAME' })` for\n * O(1) exact reverse lookup. Returns `undefined` on miss — the caller\n * decides whether that's an error (convert throws; use `identify` for\n * nearest-match semantics).\n *\n * Hex values are lowercased for the key so callers can normalize their\n * input with `rgbaToHex(...).toLowerCase()` before lookup.\n */\nexport function getReverseNameIndex(space: AnyPalette): Map<string, string> {\n let idx = reverseIndexCache.get(space);\n if (idx === undefined) {\n idx = new Map();\n for (const [name, hex] of Object.entries(space.colors)) {\n idx.set((hex as string).toLowerCase(), name);\n }\n reverseIndexCache.set(space, idx);\n }\n return idx;\n}\n\n/**\n * Canonical-key → Rgba entries for a given palette, built by parsing\n * each hex value once. Used by nearest-match lookups (identify, rgbaToPantone).\n */\nfunction getRgbaIndex(space: AnyPalette): Array<readonly [string, Rgba]> {\n let idx = rgbaIndexCache.get(space);\n if (idx === undefined) {\n idx = Object.entries(space.colors).map(([name, hex]) => [name, hexToRgba(hex)] as const);\n rgbaIndexCache.set(space, idx);\n }\n return idx;\n}\n\n/**\n * Find the nearest-named entry in a palette to the given Rgba, using\n * squared Euclidean distance in sRGB (alpha ignored). Used by `identify`\n * and `rgbaToPantone` when metric === 'euclidean-srgb'.\n */\nfunction nearestByRgb(target: Rgba, space: AnyPalette): string {\n const entries = getRgbaIndex(space);\n let bestName = entries[0]?.[0] ?? '';\n let bestDistance = Number.POSITIVE_INFINITY;\n for (const [name, candidate] of entries) {\n const d = squaredDistanceRgb(target, candidate);\n if (d < bestDistance) {\n bestDistance = d;\n bestName = name;\n }\n }\n return bestName;\n}\n\n// Precomputed Lab entries for delta-E metrics. Same shape as rgba index.\ntype LabTriple = readonly [number, number, number];\nconst labIndexCache = new WeakMap<AnyPalette, Array<readonly [string, LabTriple]>>();\n\nfunction getLabIndex(space: AnyPalette): Array<readonly [string, LabTriple]> {\n let idx = labIndexCache.get(space);\n if (idx === undefined) {\n idx = getRgbaIndex(space).map(([name, rgba]) => [name, rgbaToLab(rgba)] as const);\n labIndexCache.set(space, idx);\n }\n return idx;\n}\n\n// Precomputed linear-RGB entries for euclidean-linear metric.\nconst linearIndexCache = new WeakMap<AnyPalette, Array<readonly [string, LabTriple]>>();\n\nfunction getLinearIndex(space: AnyPalette): Array<readonly [string, LabTriple]> {\n let idx = linearIndexCache.get(space);\n if (idx === undefined) {\n idx = getRgbaIndex(space).map(([name, rgba]) => [name, rgbaToLinearRgb(rgba)] as const);\n linearIndexCache.set(space, idx);\n }\n return idx;\n}\n\n// Precomputed OKLAB entries for deltaEok metric.\nconst oklabIndexCache = new WeakMap<AnyPalette, Array<readonly [string, LabTriple]>>();\n\nfunction getOklabIndex(space: AnyPalette): Array<readonly [string, LabTriple]> {\n let idx = oklabIndexCache.get(space);\n if (idx === undefined) {\n idx = getRgbaIndex(space).map(([name, rgba]) => [name, rgbaToOklab(rgba)] as const);\n oklabIndexCache.set(space, idx);\n }\n return idx;\n}\n\n/**\n * Generic argmin over an `[name, value]` entries array with a custom\n * distance function. Factored so the three metric branches in `nearest`\n * share one loop body instead of duplicating it three times.\n */\nfunction argminBy<T>(\n entries: Array<readonly [string, T]>,\n target: T,\n dist: (a: T, b: T) => number,\n): string {\n let bestName = entries[0]?.[0] ?? '';\n let bestDistance = Number.POSITIVE_INFINITY;\n for (const [name, candidate] of entries) {\n const d = dist(target, candidate);\n if (d < bestDistance) {\n bestDistance = d;\n bestName = name;\n }\n }\n return bestName;\n}\n\n// Squared Euclidean on a [number, number, number] triple. Used for the\n// linear-RGB metric (sharing shape with Lab but different meaning).\nfunction squaredDistanceTriple(a: LabTriple, b: LabTriple): number {\n const d0 = a[0] - b[0];\n const d1 = a[1] - b[1];\n const d2 = a[2] - b[2];\n return d0 * d0 + d1 * d1 + d2 * d2;\n}\n\n/**\n * Find the nearest-named entry in a palette under the specified distance\n * metric. Dispatches to the right index (rgba / linear-rgb / Lab) and\n * the right distance function. See `DistanceMetric` in types.ts for how\n * to pick a metric.\n *\n * `metric` is required — callers should pass `space.defaultMetric` if\n * they want the palette's declared preference. A silent default would\n * hide the distance-metric choice from the hot path.\n */\nexport function nearest(target: Rgba, space: AnyPalette, metric: DistanceMetric): string {\n if (metric === 'euclidean-srgb') return nearestByRgb(target, space);\n if (metric === 'euclidean-linear') {\n return argminBy(getLinearIndex(space), rgbaToLinearRgb(target), squaredDistanceTriple);\n }\n if (metric === 'deltaEok') {\n return argminBy(getOklabIndex(space), rgbaToOklab(target), deltaEokSquared);\n }\n const labTarget = rgbaToLab(target);\n const labIndex = getLabIndex(space);\n if (metric === 'deltaE76') return argminBy(labIndex, labTarget, deltaE76Squared);\n if (metric === 'deltaE94') return argminBy(labIndex, labTarget, deltaE94);\n return argminBy(labIndex, labTarget, deltaE2000);\n}\n\n/**\n * Rank every palette entry by distance to `target`. Returns an array of\n * `{ name, distance }` sorted ascending (nearest first). Optional `k`\n * truncates to the top-k matches.\n *\n * Distances are **real** metric values (not squared) — ΔE76 / ΔE94 /\n * ΔE2000 / ΔE-OK are in standard ΔE units (≈1 = just-noticeable for\n * most of the gamut on ΔE76/2000); `euclidean-srgb` / `euclidean-linear`\n * are in their respective channel-unit Euclidean distances.\n *\n * Cost:\n * - `k < n`: O(n · k) via bounded insertion-sort; much faster than a\n * full sort for small k on cheap metrics where allocation dominates.\n * - `k >= n` or `k === undefined`: O(n log n) via full push-and-sort,\n * returning every entry ranked.\n *\n * Tie-breaking: on exact-distance ties, the first-declared entry in\n * the palette's `colors` object wins. Matches the single-match\n * `nearest` contract.\n *\n * `k` normalization is forgiving: fractional values are rounded,\n * negatives clamp to 0, and `NaN` / `±Infinity` collapse to 0\n * (empty result). No throws.\n */\nexport function nearestAll(\n target: Rgba,\n space: AnyPalette,\n metric: DistanceMetric,\n k?: number,\n): Array<{ name: string; distance: number }> {\n const rgbaIndex = getRgbaIndex(space);\n const n = rgbaIndex.length;\n\n // k normalization. Forgiving by design: fractional values are rounded,\n // negatives clamp to 0, NaN / ±Infinity collapse to 0 (empty result).\n // A previous version crashed with `RangeError: Invalid array length`\n // on NaN / fractional k because `new Array(NaN)` throws; the\n // `Number.isFinite` guard eliminates that class of bug.\n const safeK = k === undefined ? n : Number.isFinite(k) ? Math.max(0, Math.round(k)) : 0;\n if (safeK === 0) return [];\n\n // When the caller wants at least every entry ranked, the bounded\n // insertion-sort gives no benefit — it degenerates to O(n^2) on a\n // full result set. Use the plain push-and-sort path instead.\n // When safeK < n, the bounded insertion-sort keeps only the top k\n // entries seen so far, cutting work from O(n log n) to O(n · k)\n // with a much smaller constant; the win is dramatic for cheap\n // metrics (deltaEok at k=5 / 1950-entry ncs measured ~50x) where\n // the full sort's allocation dominates the distance math.\n const useBounded = safeK < n;\n\n const best: Array<{ name: string; distance: number }> = [];\n\n // Single per-candidate branch, chosen once up front. `offer` either\n // pushes unconditionally (full-sort path) or inserts into a bounded\n // sorted window (bounded path). Splitting the switch and the merge\n // strategy into a closure avoids a 6-way metric switch × 2 modes\n // duplication.\n const offer = useBounded\n ? (name: string, dist: number): void => {\n if (best.length < safeK) {\n let j = best.length;\n while (j > 0 && (best[j - 1] as { distance: number }).distance > dist) j--;\n best.splice(j, 0, { name, distance: dist });\n } else if (dist < (best[safeK - 1] as { distance: number }).distance) {\n let j = safeK - 1;\n while (j > 0 && (best[j - 1] as { distance: number }).distance > dist) j--;\n best.splice(j, 0, { name, distance: dist });\n best.pop();\n }\n }\n : (name: string, dist: number): void => {\n best.push({ name, distance: dist });\n };\n\n if (metric === 'euclidean-srgb') {\n for (const [name, candidate] of rgbaIndex) {\n offer(name, Math.sqrt(squaredDistanceRgb(target, candidate)));\n }\n } else if (metric === 'euclidean-linear') {\n const tgt = rgbaToLinearRgb(target);\n for (const [name, candidate] of getLinearIndex(space)) {\n offer(name, Math.sqrt(squaredDistanceTriple(tgt, candidate)));\n }\n } else if (metric === 'deltaEok') {\n const tgt = rgbaToOklab(target);\n for (const [name, candidate] of getOklabIndex(space)) {\n offer(name, Math.sqrt(deltaEokSquared(tgt, candidate)));\n }\n } else {\n const tgt = rgbaToLab(target);\n const labIndex = getLabIndex(space);\n if (metric === 'deltaE76') {\n for (const [name, candidate] of labIndex) {\n offer(name, Math.sqrt(deltaE76Squared(tgt, candidate)));\n }\n } else if (metric === 'deltaE94') {\n for (const [name, candidate] of labIndex) {\n offer(name, deltaE94(tgt, candidate));\n }\n } else {\n for (const [name, candidate] of labIndex) {\n offer(name, deltaE2000(tgt, candidate));\n }\n }\n }\n\n if (!useBounded) {\n best.sort((a, b) => a.distance - b.distance);\n }\n return best;\n}\n"]}
1
+ {"version":3,"file":"indexing.d.ts","sourceRoot":"","sources":["../src/indexing.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;;;GAMG;AAEH,KAAK,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAKlC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAWnE;AAID;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAU1E;AAsGD;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CAavF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,IAAI,EACZ,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,cAAc,EACtB,CAAC,CAAC,EAAE,MAAM,GACT,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkF3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"clamp.d.ts","sourceRoot":"","sources":["../../src/math/clamp.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK/D","sourcesContent":["/**\n * Clamp n to [lo, hi]. Caller must ensure n is a finite number.\n */\nexport function clamp(n: number, lo: number, hi: number): number {\n return Math.max(lo, Math.min(hi, n));\n}\n\n/**\n * Require a finite number at an API boundary; throws otherwise.\n * Used by converter entry points to reject NaN, Infinity, and non-numeric\n * values before they propagate through color math.\n */\nexport function requireFinite(n: unknown, label: string): number {\n if (typeof n !== 'number' || !Number.isFinite(n)) {\n throw new Error(`Expected finite number for ${label}, got ${typeof n}: ${String(n)}`);\n }\n return n;\n}\n"]}
1
+ {"version":3,"file":"clamp.d.ts","sourceRoot":"","sources":["../../src/math/clamp.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK/D"}
@@ -1 +1 @@
1
- {"version":3,"file":"colorSpace.d.ts","sourceRoot":"","sources":["../../src/math/colorSpace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC;;;;;;;;;;;;GAYG;AAEH,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,0DAA0D;AAC1D,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAEpE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAKxF;AAaD,6FAA6F;AAC7F,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAQlF;AAED,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAI9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAa1F;AAED,mCAAmC;AACnC,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAGhE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAItF;AAED,gDAAgD;AAChD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAGtF;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAGhE","sourcesContent":["import type { Rgba } from '../types.js';\n\n/**\n * Color-space conversions needed by the perceptual distance metrics.\n *\n * Two pipelines:\n * CIELAB: sRGB (0..255) → linear RGB → XYZ (D65) → Lab\n * OKLAB: sRGB (0..255) → linear RGB → LMS (cbrt) → OKLAB\n *\n * References:\n * sRGB EOTF / companding: IEC 61966-2-1\n * sRGB → XYZ (D65): Bruce Lindbloom, http://www.brucelindbloom.com/\n * XYZ → Lab: CIE 15:2004\n * OKLAB: Ottosson, https://bottosson.github.io/posts/oklab/\n */\n\n/** sRGB → linear for a single channel in [0, 255]. Returns [0, 1]. */\nexport function srgbToLinear(channel: number): number {\n const s = channel / 255;\n return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n}\n\n/** Linear → sRGB for a single channel in [0, 1]. Returns [0, 1] (scale by 255 if needed). */\nexport function linearToSrgb(linear: number): number {\n return linear <= 0.0031308 ? 12.92 * linear : 1.055 * linear ** (1 / 2.4) - 0.055;\n}\n\n/** Rgba → linear RGB triple in [0, 1] (alpha dropped). */\nexport function rgbaToLinearRgb(rgba: Rgba): [number, number, number] {\n return [srgbToLinear(rgba.r), srgbToLinear(rgba.g), srgbToLinear(rgba.b)];\n}\n\n/**\n * Linear RGB (D65) → CIE XYZ (D65), using the standard sRGB matrix.\n * Input and output both in [0, 1] on each axis (approximately; Y = 1 is white).\n */\nexport function linearRgbToXyz(r: number, g: number, b: number): [number, number, number] {\n const x = r * 0.4124564 + g * 0.3575761 + b * 0.1804375;\n const y = r * 0.2126729 + g * 0.7151522 + b * 0.072175;\n const z = r * 0.0193339 + g * 0.119192 + b * 0.9503041;\n return [x, y, z];\n}\n\n// D65 white reference (CIE 1931 2° observer).\nconst XN = 0.95047;\nconst YN = 1.0;\nconst ZN = 1.08883;\n\n// f(t) in the CIE Lab formula; cube-root with a linear toe near origin.\nfunction labF(t: number): number {\n const DELTA = 6 / 29;\n return t > DELTA ** 3 ? Math.cbrt(t) : t / (3 * DELTA ** 2) + 4 / 29;\n}\n\n/** CIE XYZ (D65) → CIE Lab. L ∈ [0, 100] approx; a,b unbounded but typically [-128, 127]. */\nexport function xyzToLab(x: number, y: number, z: number): [number, number, number] {\n const fx = labF(x / XN);\n const fy = labF(y / YN);\n const fz = labF(z / ZN);\n const l = 116 * fy - 16;\n const a = 500 * (fx - fy);\n const b = 200 * (fy - fz);\n return [l, a, b];\n}\n\n/** Rgba (sRGB, 0..255) → CIE Lab. Canonical pipeline for perceptual distance. */\nexport function rgbaToLab(rgba: Rgba): [number, number, number] {\n const [r, g, b] = rgbaToLinearRgb(rgba);\n const [x, y, z] = linearRgbToXyz(r, g, b);\n return xyzToLab(x, y, z);\n}\n\n/**\n * Linear sRGB → OKLAB (Björn Ottosson, 2020). OKLAB is strictly more\n * perceptually uniform than CIELAB, especially in the blue/purple region\n * where even CIEDE2000 has residual error. Distance in OKLAB is plain\n * Euclidean — no weighting formula needed, because the space itself is\n * designed around uniformity.\n *\n * Reference: https://bottosson.github.io/posts/oklab/\n */\nexport function linearRgbToOklab(r: number, g: number, b: number): [number, number, number] {\n const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;\n const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;\n const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;\n\n const l_ = Math.cbrt(l);\n const m_ = Math.cbrt(m);\n const s_ = Math.cbrt(s);\n\n const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;\n const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;\n const b2 = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;\n return [L, a, b2];\n}\n\n/** Rgba (sRGB, 0..255) → OKLAB. */\nexport function rgbaToOklab(rgba: Rgba): [number, number, number] {\n const [r, g, b] = rgbaToLinearRgb(rgba);\n return linearRgbToOklab(r, g, b);\n}\n\n/**\n * OKLAB → OKLCh (polar form of OKLAB). L stays the same; a,b become\n * chroma and hue. Useful for hue-aware manipulation and naming strategies\n * that want to reason about hue distance independently of lightness.\n *\n * Returns [L, C, h] where C >= 0 and h is in degrees [0, 360).\n * Achromatic colors (C ≈ 0) return h = 0 by convention.\n */\nexport function oklabToOklch(L: number, a: number, b: number): [number, number, number] {\n const C = Math.sqrt(a * a + b * b);\n const h = C === 0 ? 0 : ((Math.atan2(b, a) * 180) / Math.PI + 360) % 360;\n return [L, C, h];\n}\n\n/** OKLCh → OKLAB. Inverse of `oklabToOklch`. */\nexport function oklchToOklab(L: number, C: number, h: number): [number, number, number] {\n const rad = (h * Math.PI) / 180;\n return [L, C * Math.cos(rad), C * Math.sin(rad)];\n}\n\n/** Rgba (sRGB, 0..255) → OKLCh. Composition shortcut. */\nexport function rgbaToOklch(rgba: Rgba): [number, number, number] {\n const [L, a, b] = rgbaToOklab(rgba);\n return oklabToOklch(L, a, b);\n}\n"]}
1
+ {"version":3,"file":"colorSpace.d.ts","sourceRoot":"","sources":["../../src/math/colorSpace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC;;;;;;;;;;;;GAYG;AAEH,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,0DAA0D;AAC1D,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAEpE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAKxF;AAaD,6FAA6F;AAC7F,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAQlF;AAED,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAI9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAa1F;AAED,mCAAmC;AACnC,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAGhE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAItF;AAED,gDAAgD;AAChD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAGtF;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAGhE"}
@@ -1 +1 @@
1
- {"version":3,"file":"deltaE.d.ts","sourceRoot":"","sources":["../../src/math/deltaE.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAKtD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAE/C;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAwB/C;AAgCD,wBAAgB,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,SAAI,EAAE,EAAE,SAAI,EAAE,EAAE,SAAI,GAAG,MAAM,CAoFzE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAKtD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAE/C","sourcesContent":["/**\n * Color-difference metrics. Inputs are `Lab` triples (L, a, b). The\n * CIELAB family (ΔE*76 / ΔE*94 / ΔE*00) takes coordinates from\n * `rgbaToLab`; ΔE*ok takes coordinates from `rgbaToOklab`. Both spaces\n * share the `Lab` tuple shape but are not interchangeable — see\n * `deltaEokSquared` below.\n *\n * Within the CIELAB family, the metrics differ in how each region of\n * Lab space is weighted:\n * ΔE*76 — simple Euclidean in Lab (CIE 1976). Fast, decent.\n * ΔE*94 — adds chroma/hue weighting (CIE 1994). Better saturation handling.\n * ΔE00 — also adjusts L/C/h + rotation correction in blue-purple region\n * (CIE 2000, aka CIEDE2000). Current industry standard.\n *\n * References:\n * CIE 15:2004 (Colorimetry), CIE TC1-29 (ΔE2000).\n * G. Sharma, W. Wu, E.N. Dalal, \"The CIEDE2000 Color-Difference Formula\"\n * (Color Research & Application, 2005) — canonical test vectors.\n */\n\nexport type Lab = readonly [l: number, a: number, b: number];\n\n/**\n * ΔE*ab (CIE 1976). Simple Euclidean distance in Lab.\n * Returns the *square* for speed — identify loops only need argmin, and\n * sqrt is monotonic. Use `deltaE76` if you need the actual distance.\n */\nexport function deltaE76Squared(p: Lab, q: Lab): number {\n const dl = p[0] - q[0];\n const da = p[1] - q[1];\n const db = p[2] - q[2];\n return dl * dl + da * da + db * db;\n}\n\nexport function deltaE76(p: Lab, q: Lab): number {\n return Math.sqrt(deltaE76Squared(p, q));\n}\n\n/**\n * ΔE*94 (CIE 1994). Weights the chroma and hue contributions relative to\n * Lab Euclidean distance — fixes the \"saturated colors feel too far apart\"\n * problem of ΔE*76. Uses graphic-arts constants (kL=1, K1=0.045, K2=0.015).\n *\n * Not symmetric in the strict sense (reference vs sample), but we treat\n * both inputs as graphic-arts samples — the formula reduces to a\n * symmetric form below.\n */\nexport function deltaE94(p: Lab, q: Lab): number {\n const [l1, a1, b1] = p;\n const [l2, a2, b2] = q;\n const dL = l1 - l2;\n const c1 = Math.hypot(a1, b1);\n const c2 = Math.hypot(a2, b2);\n const dC = c1 - c2;\n const da = a1 - a2;\n const db = b1 - b2;\n const dH2 = da * da + db * db - dC * dC;\n // dH² can go slightly negative due to floating-point — clamp.\n const dH2Safe = dH2 < 0 ? 0 : dH2;\n\n const K1 = 0.045;\n const K2 = 0.015;\n const sL = 1;\n const sC = 1 + K1 * c1;\n const sH = 1 + K2 * c1;\n\n const termL = dL / sL;\n const termC = dC / sC;\n const termH = Math.sqrt(dH2Safe) / sH;\n\n return Math.sqrt(termL * termL + termC * termC + termH * termH);\n}\n\n// ---- ΔE00 helpers --------------------------------------------------------\n\nconst DEG = Math.PI / 180;\nconst RAD = 180 / Math.PI;\n\nfunction hueDeg(b: number, a: number): number {\n if (b === 0 && a === 0) return 0;\n return (Math.atan2(b, a) * RAD + 360) % 360;\n}\n\n/**\n * ΔE*00 (CIE 2000 / CIEDE2000). Current industry-standard perceptual\n * color-difference formula. Fixes the saturated-blue failure of ΔE76/94\n * with a rotation term in the blue-purple region (h ≈ 275°).\n *\n * kL / kC / kH are parametric factors (default 1/1/1 = graphic arts).\n * Reference: G. Sharma, W. Wu, E.N. Dalal, \"The CIEDE2000 Color-Difference\n * Formula\" (Color Research & Application, 2005).\n */\n// Precomputed constant: 25^7 = 6,103,515,625. Appears twice in the formula.\nconst POW_25_7 = 6103515625;\n\n// Inline pow(x, 7) — Math.pow with non-integer exponent is slower in V8\n// than three multiplies. x² → x⁴ → x⁶·x.\nfunction pow7(x: number): number {\n const x2 = x * x;\n const x4 = x2 * x2;\n return x4 * x2 * x;\n}\n\nexport function deltaE2000(p: Lab, q: Lab, kL = 1, kC = 1, kH = 1): number {\n const l1 = p[0];\n const a1 = p[1];\n const b1 = p[2];\n const l2 = q[0];\n const a2 = q[1];\n const b2 = q[2];\n\n // Chromas and mean chroma. Lab values stay within ±150 so overflow\n // protection in Math.hypot is unnecessary — plain sqrt(a²+b²) is ~3×\n // faster in V8 and more than precise enough for our range.\n const c1 = Math.sqrt(a1 * a1 + b1 * b1);\n const c2 = Math.sqrt(a2 * a2 + b2 * b2);\n const cBar = (c1 + c2) / 2;\n const cBar7 = pow7(cBar);\n\n // G-factor boost for a* in low-chroma regions.\n const g = 0.5 * (1 - Math.sqrt(cBar7 / (cBar7 + POW_25_7)));\n const a1p = (1 + g) * a1;\n const a2p = (1 + g) * a2;\n\n // Primed chroma and hue.\n const c1p = Math.sqrt(a1p * a1p + b1 * b1);\n const c2p = Math.sqrt(a2p * a2p + b2 * b2);\n const h1p = hueDeg(b1, a1p);\n const h2p = hueDeg(b2, a2p);\n\n // Differences.\n const dLp = l2 - l1;\n const dCp = c2p - c1p;\n\n let dhp: number;\n if (c1p * c2p === 0) {\n dhp = 0;\n } else {\n const raw = h2p - h1p;\n if (Math.abs(raw) <= 180) dhp = raw;\n else if (raw > 180) dhp = raw - 360;\n else dhp = raw + 360;\n }\n const dHp = 2 * Math.sqrt(c1p * c2p) * Math.sin((dhp * DEG) / 2);\n\n // Means.\n const lBarP = (l1 + l2) / 2;\n const cBarP = (c1p + c2p) / 2;\n\n let hBarP: number;\n if (c1p * c2p === 0) {\n hBarP = h1p + h2p;\n } else if (Math.abs(h1p - h2p) <= 180) {\n hBarP = (h1p + h2p) / 2;\n } else if (h1p + h2p < 360) {\n hBarP = (h1p + h2p + 360) / 2;\n } else {\n hBarP = (h1p + h2p - 360) / 2;\n }\n\n // Weighting function T.\n const hBarRad = hBarP * DEG;\n const t =\n 1 -\n 0.17 * Math.cos(hBarRad - 30 * DEG) +\n 0.24 * Math.cos(2 * hBarRad) +\n 0.32 * Math.cos(3 * hBarRad + 6 * DEG) -\n 0.2 * Math.cos(4 * hBarRad - 63 * DEG);\n\n // Lightness, chroma, hue weighting factors.\n const lBarMinus50Sq = (lBarP - 50) ** 2;\n const sL = 1 + (0.015 * lBarMinus50Sq) / Math.sqrt(20 + lBarMinus50Sq);\n const sC = 1 + 0.045 * cBarP;\n const sH = 1 + 0.015 * cBarP * t;\n\n // Rotation term — the blue-purple correction that ΔE94 lacks.\n const hShift = (hBarP - 275) / 25;\n const dTheta = 30 * Math.exp(-(hShift * hShift));\n const cBarP7 = pow7(cBarP);\n const rC = 2 * Math.sqrt(cBarP7 / (cBarP7 + POW_25_7));\n const rT = -Math.sin(2 * dTheta * DEG) * rC;\n\n const termL = dLp / (kL * sL);\n const termC = dCp / (kC * sC);\n const termH = dHp / (kH * sH);\n\n return Math.sqrt(termL * termL + termC * termC + termH * termH + rT * termC * termH);\n}\n\n/**\n * Squared Euclidean distance in OKLAB space (Björn Ottosson, 2020).\n * OKLAB is perceptually uniform by construction — plain Euclidean IS the\n * perceptual distance, no weighting needed. Returns the square for\n * argmin speed; `deltaEok` returns the actual distance.\n *\n * Often gives more visually-accurate nearest-matches than CIEDE2000 in\n * the saturated blue/purple region.\n *\n * NOTE: the body is byte-identical to `deltaE76Squared` — both compute\n * `dl² + da² + db²`. The semantic difference is entirely in *which* space\n * the caller passes coordinates from: CIELAB (for ΔE*76) vs OKLAB (for this).\n * Kept separate so callers and tests can't cross-wire the indexes.\n */\nexport function deltaEokSquared(p: Lab, q: Lab): number {\n const dl = p[0] - q[0];\n const da = p[1] - q[1];\n const db = p[2] - q[2];\n return dl * dl + da * da + db * db;\n}\n\nexport function deltaEok(p: Lab, q: Lab): number {\n return Math.sqrt(deltaEokSquared(p, q));\n}\n"]}
1
+ {"version":3,"file":"deltaE.d.ts","sourceRoot":"","sources":["../../src/math/deltaE.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAKtD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAE/C;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAwB/C;AAgCD,wBAAgB,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,SAAI,EAAE,EAAE,SAAI,EAAE,EAAE,SAAI,GAAG,MAAM,CAoFzE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAKtD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAE/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"editDistance.d.ts","sourceRoot":"","sources":["../../src/math/editDistance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CA8BxD","sourcesContent":["/**\n * Levenshtein edit distance between two strings. Classic dynamic-programming\n * implementation; returns the minimum number of single-character insertions,\n * deletions, or substitutions required to transform `a` into `b`.\n *\n * Used by `resolve(_, { k })` for fuzzy-name matching — operating on the\n * palette's already-normalized keys (lowercase, alphanumeric) so typos,\n * casing, and punctuation all reduce to the same canonical forms before\n * the edit distance is measured.\n *\n * Space-optimized: uses two rolling rows instead of a full n×m matrix\n * (O(min(n,m)) space, O(n·m) time). For palette keys (< 20 chars each)\n * this runs sub-microsecond per pair, so a full scan over 907 Pantone\n * entries fits well inside a millisecond.\n */\nexport function levenshtein(a: string, b: string): number {\n if (a === b) return 0;\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n\n // Ensure `a` is the shorter string so the rolling row is minimal.\n if (a.length > b.length) [a, b] = [b, a];\n\n const aLen = a.length;\n const bLen = b.length;\n\n // `prev[i]` = edit distance between a[0..i] and b[0..j-1] (previous row).\n // `curr[i]` = edit distance between a[0..i] and b[0..j] (current row).\n let prev = new Array<number>(aLen + 1);\n let curr = new Array<number>(aLen + 1);\n for (let i = 0; i <= aLen; i++) prev[i] = i;\n\n for (let j = 1; j <= bLen; j++) {\n curr[0] = j;\n const bj = b.charCodeAt(j - 1);\n for (let i = 1; i <= aLen; i++) {\n const cost = a.charCodeAt(i - 1) === bj ? 0 : 1;\n const deletion = (prev[i] ?? 0) + 1;\n const insertion = (curr[i - 1] ?? 0) + 1;\n const substitution = (prev[i - 1] ?? 0) + cost;\n curr[i] = Math.min(deletion, insertion, substitution);\n }\n [prev, curr] = [curr, prev];\n }\n return prev[aLen] ?? 0;\n}\n"]}
1
+ {"version":3,"file":"editDistance.d.ts","sourceRoot":"","sources":["../../src/math/editDistance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CA8BxD"}
@@ -1 +1 @@
1
- {"version":3,"file":"euclideanDistance.d.ts","sourceRoot":"","sources":["../../src/math/euclideanDistance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAK3D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAE1D","sourcesContent":["import type { Rgba } from '../types.js';\n\n/**\n * Squared Euclidean distance between two colors in RGB space.\n * Alpha channel is ignored. Faster than `euclideanDistance` — use this\n * when you only need to compare or minimize (sqrt is monotonic, so\n * argmin(d) === argmin(d²)).\n */\nexport function squaredDistanceRgb(a: Rgba, b: Rgba): number {\n const dr = a.r - b.r;\n const dg = a.g - b.g;\n const db = a.b - b.b;\n return dr * dr + dg * dg + db * db;\n}\n\n/**\n * Euclidean distance between two colors in RGB space.\n * Alpha channel is ignored (matches classic `detect-color` behavior).\n * Not perceptually accurate — use deltaE (CIE Lab) for color matching\n * where perceptual uniformity matters.\n */\nexport function euclideanDistance(a: Rgba, b: Rgba): number {\n return Math.sqrt(squaredDistanceRgb(a, b));\n}\n"]}
1
+ {"version":3,"file":"euclideanDistance.d.ts","sourceRoot":"","sources":["../../src/math/euclideanDistance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAK3D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAE1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"hueSector.d.ts","sourceRoot":"","sources":["../../src/math/hueSector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAO1B","sourcesContent":["/**\n * Map a normalized hue sector value (range [0, 6)) plus chroma and its\n * secondary into the primary-color tuple `[r', g', b']` used by the\n * standard HSL→RGB and HSV→RGB algorithms. Each component is in [0, chroma].\n *\n * Shared by `hslToRgba` and `hsvToRgba`: same six-sector table, different\n * formulas for chroma and the offset. The caller adds the offset and\n * scales by 255.\n *\n * hueSector = h / 60 (h wrapped to [0, 360))\n * chroma = HSL: (1 − |2l − 1|)·s ; HSV: v·s\n * secondary = chroma · (1 − |hueSector mod 2 − 1|)\n */\nexport function hueSectorToPrime(\n hueSector: number,\n chroma: number,\n secondary: number,\n): [number, number, number] {\n if (hueSector < 1) return [chroma, secondary, 0];\n if (hueSector < 2) return [secondary, chroma, 0];\n if (hueSector < 3) return [0, chroma, secondary];\n if (hueSector < 4) return [0, secondary, chroma];\n if (hueSector < 5) return [secondary, 0, chroma];\n return [chroma, 0, secondary];\n}\n"]}
1
+ {"version":3,"file":"hueSector.d.ts","sourceRoot":"","sources":["../../src/math/hueSector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAO1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"crayola.d.ts","sourceRoot":"","sources":["../../src/palettes/crayola.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Palette } from '../types.js';\nimport { standardNormalize } from './normalize.js';\n\n/**\n * Crayola crayon colors — canonical subset. ~85 entries covering the\n * current 64-standard box, iconic fluorescents, and widely-recognized\n * modern additions.\n *\n * Keys are Title Case with spaces (`'Granny Smith Apple'`,\n * `'Razzmatazz'`) — how the names are printed on the crayon wrapper.\n * `standardNormalize` strips spaces + case + punctuation on input, so\n * `resolve('granny-smith-apple')` and `resolve('Granny Smith Apple')`\n * both hit the same entry.\n *\n * sRGB values are community-sourced approximations (Wikipedia's\n * well-cited list of Crayola crayon colors). They do not represent\n * a licensed Crayola reference. See NOTICE.md for trademark note.\n *\n * Default metric: `deltaEok`. The Crayola set spans a wide gamut with\n * many saturated brights (fluorescents especially) where CIELAB-based\n * metrics are less perceptually uniform than OKLAB. Same cost profile\n * as deltaE76, better neighbor selection in saturated regions.\n */\nconst crayolaColors = {\n // --- Current standard box: the 12 primary/secondary hue wheel ---\n Red: '#ee204d',\n 'Red Orange': '#ff5349',\n Orange: '#ff7538',\n 'Yellow Orange': '#ffae42',\n Yellow: '#fce883',\n 'Yellow Green': '#c5e384',\n Green: '#1cac78',\n 'Blue Green': '#0d98ba',\n Blue: '#1f75fe',\n 'Blue Violet': '#7366bd',\n Violet: '#926eae',\n 'Red Violet': '#c0448f',\n\n // --- Achromatics ---\n Black: '#232323',\n Brown: '#b4674d',\n White: '#ededed',\n Gray: '#95918c',\n\n // --- 64-box additions (pre-1990 core set) ---\n 'Carnation Pink': '#ffaacc',\n 'Sky Blue': '#80daeb',\n Tan: '#faa76c',\n Apricot: '#fdd9b5',\n Peach: '#ffcfab',\n 'Cadet Blue': '#b0b7c6',\n Salmon: '#ff9baa',\n 'Forest Green': '#6dae81',\n 'Lemon Yellow': '#fff44f',\n Mahogany: '#cd4a4c',\n Maroon: '#c8385a',\n Bittersweet: '#fd7c6e',\n Sepia: '#a5694f',\n 'Burnt Sienna': '#ea7e5d',\n 'Burnt Orange': '#ff7f49',\n 'Raw Sienna': '#d68a59',\n\n // --- Metallics ---\n Silver: '#cdc5c2',\n Gold: '#e7c697',\n Copper: '#dd9475',\n\n // --- Earth / nature tones ---\n 'Green Yellow': '#f0e891',\n 'Pine Green': '#158078',\n 'Olive Green': '#bab86c',\n Indigo: '#5d76cb',\n Periwinkle: '#c5d0e6',\n Cerulean: '#1dacd6',\n 'Sea Green': '#9fe2bf',\n 'Turquoise Blue': '#77dde7',\n\n // --- Fluorescents (the iconic \"Neon 24\" era) ---\n 'Atomic Tangerine': '#ff9966',\n 'Blizzard Blue': '#ace5ee',\n 'Hot Magenta': '#ff1dce',\n 'Laser Lemon': '#fdfc74',\n 'Neon Carrot': '#ffa343',\n 'Purple Pizzazz': '#fe4eda',\n 'Razzle Dazzle Rose': '#ff48d0',\n Razzmatazz: '#e3256b',\n \"Screamin' Green\": '#76ff7a',\n 'Shocking Pink': '#fb7efd',\n 'Tickle Me Pink': '#fc89ac',\n 'Unmellow Yellow': '#ffff66',\n 'Wild Watermelon': '#fc6c85',\n 'Outrageous Orange': '#ff6e4a',\n 'Electric Lime': '#ceff1d',\n\n // --- Modern / whimsical additions ---\n 'Granny Smith Apple': '#a8e4a0',\n 'Macaroni and Cheese': '#ffbd88',\n 'Banana Mania': '#fae7b5',\n 'Caribbean Green': '#1cd3a2',\n Cerise: '#dd4492',\n 'Cotton Candy': '#ffbcd9',\n 'Fuzzy Wuzzy': '#cc6666',\n Inchworm: '#b2ec5d',\n 'Jazzberry Jam': '#ca3767',\n Manatee: '#979aaa',\n 'Mango Tango': '#ff8243',\n Mauvelous: '#ef98aa',\n 'Midnight Blue': '#1a4876',\n 'Navy Blue': '#1974d2',\n 'Pacific Blue': '#1ca9c9',\n 'Piggy Pink': '#fddde6',\n Plum: '#8e4585',\n 'Purple Heart': '#7442c8',\n \"Robin's Egg Blue\": '#1fcecb',\n 'Royal Purple': '#7851a9',\n Scarlet: '#fc2847',\n Timberwolf: '#dbd7d2',\n Tumbleweed: '#deaa88',\n 'Violet Red': '#f75394',\n 'Vivid Violet': '#8f509d',\n Wisteria: '#cda4de',\n} as const;\n\nexport type CrayolaColorName = keyof typeof crayolaColors;\n\n/**\n * Crayola crayon-color palette (84 entries), community-curated. Not\n * Crayola-licensed or certified; see `NOTICE.md` for trademark details\n * and the set's scope (classic 64 box + fluorescent neons + selected\n * modern additions).\n *\n * Keys use the Title Case form printed on the crayon wrapper\n * (`'Razzmatazz'`, `'Granny Smith Apple'`). Default metric is `'deltaEok'`:\n * OKLAB's perceptual uniformity better separates the palette's\n * saturated-heavy distribution than ΔE76.\n *\n * @example\n * identify('#e20074', { palette: crayola }); // 'Razzmatazz'\n * resolve('Granny Smith Apple', { palette: crayola }); // '#a8e4a0'\n * crayola.colors.Razzmatazz; // '#e3256b'\n */\nexport const crayola = {\n name: 'crayola',\n colors: crayolaColors,\n normalize: standardNormalize,\n defaultMetric: 'deltaEok',\n} as const satisfies Palette<CrayolaColorName>;\n"]}
1
+ {"version":3,"file":"crayola.d.ts","sourceRoot":"","sources":["../../src/palettes/crayola.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fs595b.d.ts","sourceRoot":"","sources":["../../src/palettes/fs595b.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,YAAY;aAChB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;CACb,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,YAAY,CAAC;AAExD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,MAAM;mBACX,QAAQ;;6BAnOF,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;;;4BAsBN,YAAY;CACgB,CAAC","sourcesContent":["import type { Palette } from '../types.js';\nimport { standardNormalize } from './normalize.js';\n\n/**\n * Federal Standard 595B (FS595B) palette: the 1989 revision of the\n * US Federal Government paint-color specification. Superseded by\n * FS595C in 2008 but still referenced by modelers and restorers\n * for equipment documented against the B revision. 209 entries.\n *\n * Source: upstream dataset is Color::Names::FS595B from\n * @thundergnat/Color-Names (Raku module), which digitizes the\n * published Federal Standard paint chips. See NOTICE.md.\n *\n * Keys are the 5-digit FS codes prefixed with 'FS ' (e.g.\n * 'FS 11136'), matching the FS595C palette's convention. Common\n * names (\"Brown Special\", \"Insignia Red\", etc.) are captured as\n * trailing comments for human readers but are NOT unique (the\n * spec reuses many across different chips) so they are not used\n * as lookup keys. 209 of 209 entries carry\n * a common name in the upstream data.\n *\n * Same-coded chips can differ in hex between the B and C\n * revisions; for example 'FS 11136' ('Insignia Red') is\n * #9b2f25 in this palette versus a slightly different\n * value in FS595C. Pick whichever matches your reference\n * documentation.\n */\nconst fs595bColors = {\n 'FS 10140': '#532f15', // Brown Special\n 'FS 11136': '#9b2f25', // Insignia Red\n 'FS 11630': '#ecb2a6', // Pink\n 'FS 12197': '#ba160c', // International Orange\n 'FS 13538': '#f5ab30', // Orange Yellow\n 'FS 13591': '#f7d100', // Yellow\n 'FS 13655': '#fdd31d', // Blue Angels Yellow\n 'FS 13670': '#dbe568', // Lime Yellow\n 'FS 14052': '#373d2f', // Green\n 'FS 14062': '#3d6e3f', // Dark Green\n 'FS 14087': '#3c341f', // Olive Drab\n 'FS 14115': '#006845', // Green\n 'FS 14258': '#515e32', // Green\n 'FS 15042': '#070d09', // Sea Blue\n 'FS 15044': '#2a3141', // Insignia Blue\n 'FS 15050': '#070d1b', // \"Blue Angels\" Blue\n 'FS 15056': '#001068', // Blue\n 'FS 15102': '#023457', // Dark Blue\n 'FS 15183': '#0e5a8b', // Bright Blue\n 'FS 15200': '#7cbce0', // Sky Blue\n 'FS 15450': '#72a0c1', // Air Superiority Blue\n 'FS 16076': '#353736', // Engine Gray\n 'FS 16081': '#3b3f42', // Engine Gray\n 'FS 16440': '#8a8685', // Light Gull Gray\n 'FS 16473': '#9ea2a3', // Aircraft Gray\n 'FS 16515': '#b8b7a3', // Canadian Voodoo Gray\n 'FS 17038': '#03120f', // Black\n 'FS 17043': '#826a3a', // Gold\n 'FS 17100': '#794b7c', // Purple\n 'FS 17178': '#b2babc', // Aluminum / Silver\n 'FS 17875': '#edf2f8', // Insignia White\n 'FS 17925': '#f8f9f3', // Insignia White\n 'FS 18913': '#fc4827', // Fluorescent Red Orange\n 'FS 20061': '#531f23', // Maroon\n 'FS 20062': '#4a3733', // Brown\n 'FS 20100': '#93400a', // Brown Yellow\n 'FS 20109': '#83321f', // Red Brown\n 'FS 20140': '#694024', // Brown Special\n 'FS 20252': '#bc7756', // Tan\n 'FS 20260': '#af8d50', // Tan\n 'FS 20266': '#a28744', // Yellow Sand\n 'FS 20400': '#b9845c', // Tan\n 'FS 20450': '#ab967b', // Night Tan\n 'FS 21105': '#b51f11', // Red\n 'FS 21310': '#e43301', // Red\n 'FS 21400': '#e94400', // Red\n 'FS 22190': '#e43301', // Red\n 'FS 22516': '#e09f69', // Tan\n 'FS 23275': '#ce981a', // Earth Yellow\n 'FS 23578': '#dbcca5', // Cream\n 'FS 23594': '#dec26e', // Beige\n 'FS 23655': '#fcce16', // Yellow\n 'FS 23697': '#facc7f', // Yellow Sand\n 'FS 23722': '#eeddaf', // Sand\n 'FS 24052': '#373d2f', // Green\n 'FS 24079': '#41402c', // Forest Green\n 'FS 24190': '#4ea04e', // Green\n 'FS 24272': '#6d9477', // Green\n 'FS 24410': '#91a395', // Green\n 'FS 25095': '#2758b5', // Blue\n 'FS 25352': '#96abac', // Blue\n 'FS 25550': '#cfd8dd', // Light Blue\n 'FS 26008': '#343a48', // Dark Gray\n 'FS 26044': '#172339', // Gray\n 'FS 26081': '#3b3f42', // Seaplane Gray\n 'FS 26118': '#3f4952', // Medium Gunship Gray\n 'FS 26152': '#6a737a', // Gray\n 'FS 26270': '#797f7f', // Medium Gray\n 'FS 26320': '#808c8c', // Dark Compass Ghost Gray\n 'FS 26375': '#9598a1', // Light Campers Ghost Gray\n 'FS 26440': '#878684', // Light Gull Gray\n 'FS 27038': '#051111', // Black\n 'FS 27780': '#fbfeeb', // White\n 'FS 27875': '#edf2f8', // Insignia White\n 'FS 28913': '#fe4728', // Fluorescent Red Orange\n 'FS 28915': '#fb2b11', // Fluorescent Red\n 'FS 30045': '#543b34', // Brown\n 'FS 30051': '#443724', // Leather Brown\n 'FS 30075': '#4d140b', // Hull Red\n 'FS 30091': '#612f24', // Red Brown\n 'FS 30097': '#564032', // Brown\n 'FS 30099': '#473622', // Brown\n 'FS 30108': '#3c1e16', // Red Brown\n 'FS 30111': '#4c2a21', // Brown\n 'FS 30117': '#704437', // Earth Red\n 'FS 30118': '#5b462b', // Field Drab\n 'FS 30140': '#532f17', // Brown Special\n 'FS 30160': '#6b433b', // Brown\n 'FS 30215': '#70472b', // Brown\n 'FS 30219': '#715540', // Tan\n 'FS 30227': '#8d7a69', // Tan\n 'FS 30257': '#b48e5d', // Tan\n 'FS 30266': '#a28744', // Yellow Sand\n 'FS 30277': '#948b6c', // Sand Brown\n 'FS 30279': '#a58e7e', // Sand\n 'FS 30372': '#b2a68c', // Sand\n 'FS 30400': '#b58159', // Yellow Sand\n 'FS 31090': '#694223', // Brown\n 'FS 31136': '#9a2e24', // Insignia Red\n 'FS 31302': '#d32200', // Red\n 'FS 31350': '#c41d0a', // Red\n 'FS 31400': '#e94400', // Red\n 'FS 32473': '#ef6c00', // Orange\n 'FS 32648': '#e2c293', // Sand\n 'FS 33105': '#5d4b33', // Brown\n 'FS 33245': '#8f693a', // Tan\n 'FS 33303': '#957f56', // Sand\n 'FS 33434': '#bd8846', // Ochre\n 'FS 33440': '#9f9059', // Tan\n 'FS 33446': '#a38c6c', // Dessert Tan\n 'FS 33448': '#a59272', // Dark Yellow\n 'FS 33531': '#c7ab84', // Middlestone\n 'FS 33538': '#fec110', // Orange Yellow\n 'FS 33613': '#f1c7a1', // Radome Tan\n 'FS 33617': '#c6b490', // Sand\n 'FS 33690': '#e3cfb7', // Sand\n 'FS 33695': '#f5ca86', // Yellow Sand\n 'FS 33711': '#dfcba8', // Sand\n 'FS 33717': '#f0d6b1', // Sand\n 'FS 34031': '#2a2c1f', // Dark Green\n 'FS 34052': '#373d31', // USMC Green\n 'FS 34058': '#46696f', // Sea Blue\n 'FS 34064': '#373828', // Dark Green\n 'FS 34077': '#344034', // Green\n 'FS 34079': '#423f2c', // Forest Green\n 'FS 34082': '#44503a', // Green\n 'FS 34083': '#3a4630', // Green\n 'FS 34084': '#282a1d', // Green\n 'FS 34086': '#404034', // I. R. Dark Green\n 'FS 34087': '#3c3421', // Olive Drab\n 'FS 34088': '#3c341f', // Olive Drab\n 'FS 34092': '#364a41', // Dark Green\n 'FS 34094': '#3e3d29', // Green\n 'FS 34095': '#3b482c', // Field Green\n 'FS 34096': '#454d42', // Dark Green\n 'FS 34097': '#4a4c34', // Field Green\n 'FS 34098': '#4f5338', // Green\n 'FS 34102': '#454932', // Light Green\n 'FS 34108': '#1b4b21', // Medium Green\n 'FS 34127': '#455238', // Green\n 'FS 34128': '#4b654a', // Deep Green\n 'FS 34138': '#19481e', // Green\n 'FS 34151': '#536437', // Interior Green\n 'FS 34159': '#585e50', // Green\n 'FS 34201': '#685d47', // Tan Green\n 'FS 34227': '#4d6b53', // Medium Gray Green\n 'FS 34230': '#2f6031', // Green\n 'FS 34258': '#6f8054', // Green\n 'FS 34259': '#51680e', // Yellow Green\n 'FS 34414': '#a8b693', // Green\n 'FS 34417': '#9fad8c', // Light Gray Green\n 'FS 34424': '#a0b29a', // Light Gray Green\n 'FS 34552': '#c4da99', // Light Green\n 'FS 34554': '#c7c9a4', // Sky\n 'FS 34666': '#d8efab', // Green\n 'FS 35042': '#151b17', // Sea Blue\n 'FS 35044': '#323c48', // Insignia Blue\n 'FS 35045': '#355061', // Dark Blue\n 'FS 35052': '#263a75', // Blue\n 'FS 35109': '#273d55', // Dark Blue\n 'FS 35164': '#56626e', // Intermediate Blue\n 'FS 35177': '#436f94', // Medium Blue\n 'FS 35189': '#687681', // Blue Gray\n 'FS 35190': '#6a85a2', // Dark Blue\n 'FS 35231': '#757fa3', // Azure Blue\n 'FS 35237': '#67757e', // Gray Blue\n 'FS 35240': '#7882a5', // Blue\n 'FS 35250': '#3592bd', // Blue\n 'FS 35352': '#8fabae', // Blue\n 'FS 35414': '#789b9d', // Blue\n 'FS 35450': '#7499ac', // Air Superiority Blue\n 'FS 35526': '#9db4c6', // Light Sky Blue\n 'FS 35622': '#c9d5d1', // Light Blue\n 'FS 36076': '#3b3e51', // Gray\n 'FS 36081': '#3b3f42', // Dark Gunship Gray\n 'FS 36099': '#474d49', // Dark Gray\n 'FS 36118': '#414a53', // Medium Gunship Gray\n 'FS 36152': '#545e56', // Gray\n 'FS 36165': '#7a755f', // Gray\n 'FS 36173': '#606666', // Neutral Gray\n 'FS 36176': '#40474d', // Dark Gull Gray\n 'FS 36231': '#6f7571', // Dark Gull Gray\n 'FS 36251': '#6a6c6b', // Gray\n 'FS 36270': '#7a7f82', // Medium Gray\n 'FS 36280': '#7f8581', // Dark Gray\n 'FS 36300': '#939498', // Aircraft Exterior Gray\n 'FS 36307': '#95928d', // Gray\n 'FS 36314': '#8b8c84', // Flint Gray\n 'FS 36320': '#818b8d', // Dark Compass Ghost Gray\n 'FS 36329': '#819490', // Light Gray\n 'FS 36373': '#8a8e8d', // Light Gray\n 'FS 36375': '#9598a1', // Light Compass Ghost Gray\n 'FS 36424': '#bab2a5', // Medium Gray\n 'FS 36440': '#acaca4', // Light Gull Gray\n 'FS 36463': '#a7b6b9', // Gray\n 'FS 36473': '#98a6a7', // Sky Gray\n 'FS 36492': '#b7b4ab', // Gray\n 'FS 36495': '#c6c5ca', // Light Gray\n 'FS 36521': '#b9b19c', // Tan\n 'FS 36555': '#a3947d', // Tan\n 'FS 36559': '#bfbbb2', // Gray\n 'FS 36622': '#c8c1b1', // Gray\n 'FS 36628': '#cfd5cb', // Flat Aluminum\n 'FS 37031': '#24272e', // Black Gray\n 'FS 37038': '#051111', // Black\n 'FS 37100': '#794b7a', // Purple\n 'FS 37855': '#fdfbd2', // White\n 'FS 37875': '#edf2f8', // Insignia White\n 'FS 37925': '#f8f9f3', // Insignia White\n} as const;\n\nexport type Fs595bColorName = keyof typeof fs595bColors;\n\n/**\n * Federal Standard 595B paint chips (209 entries),\n * the 1989 revision later superseded by FS595C in 2008. Same\n * `'FS {code}'` key format as fs595c; different hex on many\n * shared codes. Pick whichever revision matches the piece of\n * equipment or documentation you're working from. Default\n * metric CIEDE2000.\n *\n * @example\n * identify('#9b2f25', { palette: fs595b }); // 'FS 11136' (aka \"Insignia Red\")\n * resolve('FS 11136', { palette: fs595b }); // '#9b2f25'\n * fs595b.colors['FS 10140']; // '#532f15' (aka \"Brown Special\")\n */\nexport const fs595b = {\n name: 'fs595b',\n colors: fs595bColors,\n normalize: standardNormalize,\n defaultMetric: 'deltaE2000',\n} as const satisfies Palette<Fs595bColorName>;\n"]}
1
+ {"version":3,"file":"fs595b.d.ts","sourceRoot":"","sources":["../../src/palettes/fs595b.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,YAAY;aAChB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;aACrB,UAAU,EAAE,SAAS;CACb,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,YAAY,CAAC;AAExD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,MAAM;mBACX,QAAQ;;6BAnOF,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;6BACT,SAAS;;;4BAsBN,YAAY;CACgB,CAAC"}