chromonym 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/NOTICE.md +39 -0
  2. package/README.md +93 -8
  3. package/dist/colorspaces/registry.d.ts +26 -0
  4. package/dist/colorspaces/registry.d.ts.map +1 -0
  5. package/dist/colorspaces/registry.js +36 -0
  6. package/dist/colorspaces/registry.js.map +1 -0
  7. package/dist/conversions/hex.d.ts.map +1 -1
  8. package/dist/conversions/hex.js +6 -5
  9. package/dist/conversions/hex.js.map +1 -1
  10. package/dist/conversions/hsl.d.ts.map +1 -1
  11. package/dist/conversions/hsl.js +34 -52
  12. package/dist/conversions/hsl.js.map +1 -1
  13. package/dist/conversions/hsv.d.ts.map +1 -1
  14. package/dist/conversions/hsv.js +30 -48
  15. package/dist/conversions/hsv.js.map +1 -1
  16. package/dist/conversions/pantone.d.ts +5 -2
  17. package/dist/conversions/pantone.d.ts.map +1 -1
  18. package/dist/conversions/pantone.js +8 -44
  19. package/dist/conversions/pantone.js.map +1 -1
  20. package/dist/conversions/rgb.d.ts +4 -2
  21. package/dist/conversions/rgb.d.ts.map +1 -1
  22. package/dist/conversions/rgb.js +28 -17
  23. package/dist/conversions/rgb.js.map +1 -1
  24. package/dist/convert.d.ts +12 -1
  25. package/dist/convert.d.ts.map +1 -1
  26. package/dist/convert.js +24 -6
  27. package/dist/convert.js.map +1 -1
  28. package/dist/detectFormat.d.ts +8 -0
  29. package/dist/detectFormat.d.ts.map +1 -1
  30. package/dist/detectFormat.js +17 -5
  31. package/dist/detectFormat.js.map +1 -1
  32. package/dist/identify.d.ts +13 -5
  33. package/dist/identify.d.ts.map +1 -1
  34. package/dist/identify.js +20 -35
  35. package/dist/identify.js.map +1 -1
  36. package/dist/index.d.ts +2 -2
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +2 -2
  39. package/dist/index.js.map +1 -1
  40. package/dist/indexing.d.ts +44 -0
  41. package/dist/indexing.d.ts.map +1 -0
  42. package/dist/indexing.js +140 -0
  43. package/dist/indexing.js.map +1 -0
  44. package/dist/math/clamp.d.ts +11 -0
  45. package/dist/math/clamp.d.ts.map +1 -0
  46. package/dist/math/clamp.js +18 -0
  47. package/dist/math/clamp.js.map +1 -0
  48. package/dist/math/colorSpace.d.ts +55 -0
  49. package/dist/math/colorSpace.d.ts.map +1 -0
  50. package/dist/math/colorSpace.js +111 -0
  51. package/dist/math/colorSpace.js.map +1 -0
  52. package/dist/math/deltaE.d.ts +52 -0
  53. package/dist/math/deltaE.d.ts.map +1 -0
  54. package/dist/math/deltaE.js +190 -0
  55. package/dist/math/deltaE.js.map +1 -0
  56. package/dist/math/euclideanDistance.d.ts +7 -0
  57. package/dist/math/euclideanDistance.d.ts.map +1 -1
  58. package/dist/math/euclideanDistance.js +13 -4
  59. package/dist/math/euclideanDistance.js.map +1 -1
  60. package/dist/math/hueSector.d.ts +15 -0
  61. package/dist/math/hueSector.d.ts.map +1 -0
  62. package/dist/math/hueSector.js +27 -0
  63. package/dist/math/hueSector.js.map +1 -0
  64. package/dist/resolve.d.ts.map +1 -1
  65. package/dist/resolve.js +11 -34
  66. package/dist/resolve.js.map +1 -1
  67. package/dist/types.d.ts +1 -0
  68. package/dist/types.d.ts.map +1 -1
  69. package/package.json +72 -8
  70. package/dist/math/index.d.ts +0 -2
  71. package/dist/math/index.d.ts.map +0 -1
  72. package/dist/math/index.js +0 -4
  73. package/dist/math/index.js.map +0 -1
@@ -0,0 +1,140 @@
1
+ import { hexToRgba } from './conversions/hex';
2
+ import { rgbaToLab, rgbaToLinearRgb, rgbaToOklab } from './math/colorSpace';
3
+ import { deltaE76Squared, deltaE94, deltaE2000, deltaEokSquared } from './math/deltaE';
4
+ import { squaredDistanceRgb } from './math/euclideanDistance';
5
+ /** Lowercase + strip non-alphanumeric. Used for web and x11. */
6
+ export const standardNormalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, '');
7
+ /**
8
+ * Pantone: also strip a leading "Pantone" or "PMS" prefix so that
9
+ * "185 C", "185c", "Pantone 185 C", "PMS185C" all map to "185c".
10
+ */
11
+ export const pantoneNormalize = (s) => s
12
+ .toLowerCase()
13
+ .replace(/^(pantone|pms)\s*/, '')
14
+ .replace(/[^a-z0-9]/g, '');
15
+ const nameIndexCache = new WeakMap();
16
+ const rgbaIndexCache = new WeakMap();
17
+ /**
18
+ * Normalized-name → canonical-key map for a given colorspace.
19
+ * Each (colorspace, normalize) pair must be stable — callers are
20
+ * expected to always pair a given colorspace with the same normalizer.
21
+ */
22
+ export function getNameIndex(space, normalize) {
23
+ let idx = nameIndexCache.get(space);
24
+ if (idx === undefined) {
25
+ idx = new Map();
26
+ for (const key of Object.keys(space)) {
27
+ idx.set(normalize(key), key);
28
+ }
29
+ nameIndexCache.set(space, idx);
30
+ }
31
+ return idx;
32
+ }
33
+ /**
34
+ * Canonical-key → Rgba entries for a given colorspace, built by parsing
35
+ * each hex value once. Used by nearest-match lookups (identify, rgbaToPantone).
36
+ */
37
+ export function getRgbaIndex(space) {
38
+ let idx = rgbaIndexCache.get(space);
39
+ if (idx === undefined) {
40
+ idx = Object.entries(space).map(([name, hex]) => [name, hexToRgba(hex)]);
41
+ rgbaIndexCache.set(space, idx);
42
+ }
43
+ return idx;
44
+ }
45
+ /**
46
+ * Find the nearest-named entry in a colorspace to the given Rgba, using
47
+ * squared Euclidean distance in sRGB (alpha ignored). Used by `identify`
48
+ * and `rgbaToPantone` when metric === 'euclidean-srgb'.
49
+ */
50
+ export function nearestByRgb(target, space) {
51
+ const entries = getRgbaIndex(space);
52
+ let bestName = entries[0]?.[0] ?? '';
53
+ let bestDistance = Number.POSITIVE_INFINITY;
54
+ for (const [name, candidate] of entries) {
55
+ const d = squaredDistanceRgb(target, candidate);
56
+ if (d < bestDistance) {
57
+ bestDistance = d;
58
+ bestName = name;
59
+ }
60
+ }
61
+ return bestName;
62
+ }
63
+ const labIndexCache = new WeakMap();
64
+ function getLabIndex(space) {
65
+ let idx = labIndexCache.get(space);
66
+ if (idx === undefined) {
67
+ idx = getRgbaIndex(space).map(([name, rgba]) => [name, rgbaToLab(rgba)]);
68
+ labIndexCache.set(space, idx);
69
+ }
70
+ return idx;
71
+ }
72
+ // Precomputed linear-RGB entries for euclidean-linear metric.
73
+ const linearIndexCache = new WeakMap();
74
+ function getLinearIndex(space) {
75
+ let idx = linearIndexCache.get(space);
76
+ if (idx === undefined) {
77
+ idx = getRgbaIndex(space).map(([name, rgba]) => [name, rgbaToLinearRgb(rgba)]);
78
+ linearIndexCache.set(space, idx);
79
+ }
80
+ return idx;
81
+ }
82
+ // Precomputed OKLAB entries for deltaEok metric.
83
+ const oklabIndexCache = new WeakMap();
84
+ function getOklabIndex(space) {
85
+ let idx = oklabIndexCache.get(space);
86
+ if (idx === undefined) {
87
+ idx = getRgbaIndex(space).map(([name, rgba]) => [name, rgbaToOklab(rgba)]);
88
+ oklabIndexCache.set(space, idx);
89
+ }
90
+ return idx;
91
+ }
92
+ /**
93
+ * Generic argmin over an `[name, value]` entries array with a custom
94
+ * distance function. Factored so the three metric branches in `nearest`
95
+ * share one loop body instead of duplicating it three times.
96
+ */
97
+ function argminBy(entries, target, dist) {
98
+ let bestName = entries[0]?.[0] ?? '';
99
+ let bestDistance = Number.POSITIVE_INFINITY;
100
+ for (const [name, candidate] of entries) {
101
+ const d = dist(target, candidate);
102
+ if (d < bestDistance) {
103
+ bestDistance = d;
104
+ bestName = name;
105
+ }
106
+ }
107
+ return bestName;
108
+ }
109
+ // Squared Euclidean on a [number, number, number] triple. Used for the
110
+ // linear-RGB metric (sharing shape with Lab but different meaning).
111
+ function squaredDistanceTriple(a, b) {
112
+ const d0 = a[0] - b[0];
113
+ const d1 = a[1] - b[1];
114
+ const d2 = a[2] - b[2];
115
+ return d0 * d0 + d1 * d1 + d2 * d2;
116
+ }
117
+ /**
118
+ * Find the nearest-named entry in a colorspace under the specified distance
119
+ * metric. Dispatches to the right index (rgba / linear-rgb / Lab) and
120
+ * the right distance function. See `DistanceMetric` in types.ts for how
121
+ * to pick a metric.
122
+ */
123
+ export function nearest(target, space, metric = 'euclidean-srgb') {
124
+ if (metric === 'euclidean-srgb')
125
+ return nearestByRgb(target, space);
126
+ if (metric === 'euclidean-linear') {
127
+ return argminBy(getLinearIndex(space), rgbaToLinearRgb(target), squaredDistanceTriple);
128
+ }
129
+ if (metric === 'deltaEok') {
130
+ return argminBy(getOklabIndex(space), rgbaToOklab(target), deltaEokSquared);
131
+ }
132
+ const labTarget = rgbaToLab(target);
133
+ const labIndex = getLabIndex(space);
134
+ if (metric === 'deltaE76')
135
+ return argminBy(labIndex, labTarget, deltaE76Squared);
136
+ if (metric === 'deltaE94')
137
+ return argminBy(labIndex, labTarget, deltaE94);
138
+ return argminBy(labIndex, labTarget, deltaE2000);
139
+ }
140
+ //# sourceMappingURL=indexing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexing.js","sourceRoot":"","sources":["../src/indexing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Clamp n to [lo, hi]. Caller must ensure n is a finite number.
3
+ */
4
+ export declare function clamp(n: number, lo: number, hi: number): number;
5
+ /**
6
+ * Require a finite number at an API boundary; throws otherwise.
7
+ * Used by converter entry points to reject NaN, Infinity, and non-numeric
8
+ * values before they propagate through color math.
9
+ */
10
+ export declare function requireFinite(n: unknown, label: string): number;
11
+ //# sourceMappingURL=clamp.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Clamp n to [lo, hi]. Caller must ensure n is a finite number.
3
+ */
4
+ export function clamp(n, lo, hi) {
5
+ return Math.max(lo, Math.min(hi, n));
6
+ }
7
+ /**
8
+ * Require a finite number at an API boundary; throws otherwise.
9
+ * Used by converter entry points to reject NaN, Infinity, and non-numeric
10
+ * values before they propagate through color math.
11
+ */
12
+ export function requireFinite(n, label) {
13
+ if (typeof n !== 'number' || !Number.isFinite(n)) {
14
+ throw new Error(`Expected finite number for ${label}, got ${typeof n}: ${String(n)}`);
15
+ }
16
+ return n;
17
+ }
18
+ //# sourceMappingURL=clamp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clamp.js","sourceRoot":"","sources":["../../src/math/clamp.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,CAAS,EAAE,EAAU,EAAE,EAAU;IACrD,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,CAAU,EAAE,KAAa;IACrD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,8BAA8B,KAAK,SAAS,OAAO,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { Rgba } from '../types';
2
+ /**
3
+ * Color-space conversions needed by the perceptual distance metrics.
4
+ *
5
+ * Two pipelines:
6
+ * CIELAB: sRGB (0..255) → linear RGB → XYZ (D65) → Lab
7
+ * OKLAB: sRGB (0..255) → linear RGB → LMS (cbrt) → OKLAB
8
+ *
9
+ * References:
10
+ * sRGB EOTF / companding: IEC 61966-2-1
11
+ * sRGB → XYZ (D65): Bruce Lindbloom, http://www.brucelindbloom.com/
12
+ * XYZ → Lab: CIE 15:2004
13
+ * OKLAB: Ottosson, https://bottosson.github.io/posts/oklab/
14
+ */
15
+ /** sRGB → linear for a single channel in [0, 255]. Returns [0, 1]. */
16
+ export declare function srgbToLinear(channel: number): number;
17
+ /** Linear → sRGB for a single channel in [0, 1]. Returns [0, 1] (scale by 255 if needed). */
18
+ export declare function linearToSrgb(linear: number): number;
19
+ /** Rgba → linear RGB triple in [0, 1] (alpha dropped). */
20
+ export declare function rgbaToLinearRgb(rgba: Rgba): [number, number, number];
21
+ /**
22
+ * Linear RGB (D65) → CIE XYZ (D65), using the standard sRGB matrix.
23
+ * Input and output both in [0, 1] on each axis (approximately; Y = 1 is white).
24
+ */
25
+ export declare function linearRgbToXyz(r: number, g: number, b: number): [number, number, number];
26
+ /** CIE XYZ (D65) → CIE Lab. L ∈ [0, 100] approx; a,b unbounded but typically [-128, 127]. */
27
+ export declare function xyzToLab(x: number, y: number, z: number): [number, number, number];
28
+ /** Rgba (sRGB, 0..255) → CIE Lab. Canonical pipeline for perceptual distance. */
29
+ export declare function rgbaToLab(rgba: Rgba): [number, number, number];
30
+ /**
31
+ * Linear sRGB → OKLAB (Björn Ottosson, 2020). OKLAB is strictly more
32
+ * perceptually uniform than CIELAB, especially in the blue/purple region
33
+ * where even CIEDE2000 has residual error. Distance in OKLAB is plain
34
+ * Euclidean — no weighting formula needed, because the space itself is
35
+ * designed around uniformity.
36
+ *
37
+ * Reference: https://bottosson.github.io/posts/oklab/
38
+ */
39
+ export declare function linearRgbToOklab(r: number, g: number, b: number): [number, number, number];
40
+ /** Rgba (sRGB, 0..255) → OKLAB. */
41
+ export declare function rgbaToOklab(rgba: Rgba): [number, number, number];
42
+ /**
43
+ * OKLAB → OKLCh (polar form of OKLAB). L stays the same; a,b become
44
+ * chroma and hue. Useful for hue-aware manipulation and naming strategies
45
+ * that want to reason about hue distance independently of lightness.
46
+ *
47
+ * Returns [L, C, h] where C >= 0 and h is in degrees [0, 360).
48
+ * Achromatic colors (C ≈ 0) return h = 0 by convention.
49
+ */
50
+ export declare function oklabToOklch(L: number, a: number, b: number): [number, number, number];
51
+ /** OKLCh → OKLAB. Inverse of `oklabToOklch`. */
52
+ export declare function oklchToOklab(L: number, C: number, h: number): [number, number, number];
53
+ /** Rgba (sRGB, 0..255) → OKLCh. Composition shortcut. */
54
+ export declare function rgbaToOklch(rgba: Rgba): [number, number, number];
55
+ //# sourceMappingURL=colorSpace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colorSpace.d.ts","sourceRoot":"","sources":["../../src/math/colorSpace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAErC;;;;;;;;;;;;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"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Color-space conversions needed by the perceptual distance metrics.
3
+ *
4
+ * Two pipelines:
5
+ * CIELAB: sRGB (0..255) → linear RGB → XYZ (D65) → Lab
6
+ * OKLAB: sRGB (0..255) → linear RGB → LMS (cbrt) → OKLAB
7
+ *
8
+ * References:
9
+ * sRGB EOTF / companding: IEC 61966-2-1
10
+ * sRGB → XYZ (D65): Bruce Lindbloom, http://www.brucelindbloom.com/
11
+ * XYZ → Lab: CIE 15:2004
12
+ * OKLAB: Ottosson, https://bottosson.github.io/posts/oklab/
13
+ */
14
+ /** sRGB → linear for a single channel in [0, 255]. Returns [0, 1]. */
15
+ export function srgbToLinear(channel) {
16
+ const s = channel / 255;
17
+ return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
18
+ }
19
+ /** Linear → sRGB for a single channel in [0, 1]. Returns [0, 1] (scale by 255 if needed). */
20
+ export function linearToSrgb(linear) {
21
+ return linear <= 0.0031308 ? 12.92 * linear : 1.055 * linear ** (1 / 2.4) - 0.055;
22
+ }
23
+ /** Rgba → linear RGB triple in [0, 1] (alpha dropped). */
24
+ export function rgbaToLinearRgb(rgba) {
25
+ return [srgbToLinear(rgba.r), srgbToLinear(rgba.g), srgbToLinear(rgba.b)];
26
+ }
27
+ /**
28
+ * Linear RGB (D65) → CIE XYZ (D65), using the standard sRGB matrix.
29
+ * Input and output both in [0, 1] on each axis (approximately; Y = 1 is white).
30
+ */
31
+ export function linearRgbToXyz(r, g, b) {
32
+ const x = r * 0.4124564 + g * 0.3575761 + b * 0.1804375;
33
+ const y = r * 0.2126729 + g * 0.7151522 + b * 0.072175;
34
+ const z = r * 0.0193339 + g * 0.119192 + b * 0.9503041;
35
+ return [x, y, z];
36
+ }
37
+ // D65 white reference (CIE 1931 2° observer).
38
+ const XN = 0.95047;
39
+ const YN = 1.0;
40
+ const ZN = 1.08883;
41
+ // f(t) in the CIE Lab formula; cube-root with a linear toe near origin.
42
+ function labF(t) {
43
+ const DELTA = 6 / 29;
44
+ return t > DELTA ** 3 ? Math.cbrt(t) : t / (3 * DELTA ** 2) + 4 / 29;
45
+ }
46
+ /** CIE XYZ (D65) → CIE Lab. L ∈ [0, 100] approx; a,b unbounded but typically [-128, 127]. */
47
+ export function xyzToLab(x, y, z) {
48
+ const fx = labF(x / XN);
49
+ const fy = labF(y / YN);
50
+ const fz = labF(z / ZN);
51
+ const l = 116 * fy - 16;
52
+ const a = 500 * (fx - fy);
53
+ const b = 200 * (fy - fz);
54
+ return [l, a, b];
55
+ }
56
+ /** Rgba (sRGB, 0..255) → CIE Lab. Canonical pipeline for perceptual distance. */
57
+ export function rgbaToLab(rgba) {
58
+ const [r, g, b] = rgbaToLinearRgb(rgba);
59
+ const [x, y, z] = linearRgbToXyz(r, g, b);
60
+ return xyzToLab(x, y, z);
61
+ }
62
+ /**
63
+ * Linear sRGB → OKLAB (Björn Ottosson, 2020). OKLAB is strictly more
64
+ * perceptually uniform than CIELAB, especially in the blue/purple region
65
+ * where even CIEDE2000 has residual error. Distance in OKLAB is plain
66
+ * Euclidean — no weighting formula needed, because the space itself is
67
+ * designed around uniformity.
68
+ *
69
+ * Reference: https://bottosson.github.io/posts/oklab/
70
+ */
71
+ export function linearRgbToOklab(r, g, b) {
72
+ const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
73
+ const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
74
+ const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
75
+ const l_ = Math.cbrt(l);
76
+ const m_ = Math.cbrt(m);
77
+ const s_ = Math.cbrt(s);
78
+ const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
79
+ const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
80
+ const b2 = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
81
+ return [L, a, b2];
82
+ }
83
+ /** Rgba (sRGB, 0..255) → OKLAB. */
84
+ export function rgbaToOklab(rgba) {
85
+ const [r, g, b] = rgbaToLinearRgb(rgba);
86
+ return linearRgbToOklab(r, g, b);
87
+ }
88
+ /**
89
+ * OKLAB → OKLCh (polar form of OKLAB). L stays the same; a,b become
90
+ * chroma and hue. Useful for hue-aware manipulation and naming strategies
91
+ * that want to reason about hue distance independently of lightness.
92
+ *
93
+ * Returns [L, C, h] where C >= 0 and h is in degrees [0, 360).
94
+ * Achromatic colors (C ≈ 0) return h = 0 by convention.
95
+ */
96
+ export function oklabToOklch(L, a, b) {
97
+ const C = Math.sqrt(a * a + b * b);
98
+ const h = C === 0 ? 0 : ((Math.atan2(b, a) * 180) / Math.PI + 360) % 360;
99
+ return [L, C, h];
100
+ }
101
+ /** OKLCh → OKLAB. Inverse of `oklabToOklch`. */
102
+ export function oklchToOklab(L, C, h) {
103
+ const rad = (h * Math.PI) / 180;
104
+ return [L, C * Math.cos(rad), C * Math.sin(rad)];
105
+ }
106
+ /** Rgba (sRGB, 0..255) → OKLCh. Composition shortcut. */
107
+ export function rgbaToOklch(rgba) {
108
+ const [L, a, b] = rgbaToOklab(rgba);
109
+ return oklabToOklch(L, a, b);
110
+ }
111
+ //# sourceMappingURL=colorSpace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colorSpace.js","sourceRoot":"","sources":["../../src/math/colorSpace.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * CIE color-difference metrics. Inputs are `Lab` triples (L, a, b) as
3
+ * produced by `rgbaToLab` from `colorSpace.ts`.
4
+ *
5
+ * All three metrics operate in CIELAB; the differences are in how each
6
+ * region of Lab space is weighted:
7
+ * ΔE*76 — simple Euclidean in Lab (CIE 1976). Fast, decent.
8
+ * ΔE*94 — adds chroma/hue weighting (CIE 1994). Better saturation handling.
9
+ * ΔE00 — also adjusts L/C/h + rotation correction in blue-purple region
10
+ * (CIE 2000, aka CIEDE2000). Current industry standard.
11
+ *
12
+ * References:
13
+ * CIE 15:2004 (Colorimetry), CIE TC1-29 (ΔE2000).
14
+ * G. Sharma, W. Wu, E.N. Dalal, "The CIEDE2000 Color-Difference Formula"
15
+ * (Color Research & Application, 2005) — canonical test vectors.
16
+ */
17
+ export type Lab = readonly [l: number, a: number, b: number];
18
+ /**
19
+ * ΔE*ab (CIE 1976). Simple Euclidean distance in Lab.
20
+ * Returns the *square* for speed — identify loops only need argmin, and
21
+ * sqrt is monotonic. Use `deltaE76` if you need the actual distance.
22
+ */
23
+ export declare function deltaE76Squared(p: Lab, q: Lab): number;
24
+ export declare function deltaE76(p: Lab, q: Lab): number;
25
+ /**
26
+ * ΔE*94 (CIE 1994). Weights the chroma and hue contributions relative to
27
+ * Lab Euclidean distance — fixes the "saturated colors feel too far apart"
28
+ * problem of ΔE*76. Uses graphic-arts constants (kL=1, K1=0.045, K2=0.015).
29
+ *
30
+ * Not symmetric in the strict sense (reference vs sample), but we treat
31
+ * both inputs as graphic-arts samples — the formula reduces to a
32
+ * symmetric form below.
33
+ */
34
+ export declare function deltaE94(p: Lab, q: Lab): number;
35
+ export declare function deltaE2000(p: Lab, q: Lab, kL?: number, kC?: number, kH?: number): number;
36
+ /**
37
+ * Squared Euclidean distance in OKLAB space (Björn Ottosson, 2020).
38
+ * OKLAB is perceptually uniform by construction — plain Euclidean IS the
39
+ * perceptual distance, no weighting needed. Returns the square for
40
+ * argmin speed; `deltaEok` returns the actual distance.
41
+ *
42
+ * Often gives more visually-accurate nearest-matches than CIEDE2000 in
43
+ * the saturated blue/purple region.
44
+ *
45
+ * NOTE: the body is byte-identical to `deltaE76Squared` — both compute
46
+ * `dl² + da² + db²`. The semantic difference is entirely in *which* space
47
+ * the caller passes coordinates from: CIELAB (for ΔE*76) vs OKLAB (for this).
48
+ * Kept separate so callers and tests can't cross-wire the indexes.
49
+ */
50
+ export declare function deltaEokSquared(p: Lab, q: Lab): number;
51
+ export declare function deltaEok(p: Lab, q: Lab): number;
52
+ //# sourceMappingURL=deltaE.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deltaE.d.ts","sourceRoot":"","sources":["../../src/math/deltaE.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;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"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * CIE color-difference metrics. Inputs are `Lab` triples (L, a, b) as
3
+ * produced by `rgbaToLab` from `colorSpace.ts`.
4
+ *
5
+ * All three metrics operate in CIELAB; the differences are in how each
6
+ * region of Lab space is weighted:
7
+ * ΔE*76 — simple Euclidean in Lab (CIE 1976). Fast, decent.
8
+ * ΔE*94 — adds chroma/hue weighting (CIE 1994). Better saturation handling.
9
+ * ΔE00 — also adjusts L/C/h + rotation correction in blue-purple region
10
+ * (CIE 2000, aka CIEDE2000). Current industry standard.
11
+ *
12
+ * References:
13
+ * CIE 15:2004 (Colorimetry), CIE TC1-29 (ΔE2000).
14
+ * G. Sharma, W. Wu, E.N. Dalal, "The CIEDE2000 Color-Difference Formula"
15
+ * (Color Research & Application, 2005) — canonical test vectors.
16
+ */
17
+ /**
18
+ * ΔE*ab (CIE 1976). Simple Euclidean distance in Lab.
19
+ * Returns the *square* for speed — identify loops only need argmin, and
20
+ * sqrt is monotonic. Use `deltaE76` if you need the actual distance.
21
+ */
22
+ export function deltaE76Squared(p, q) {
23
+ const dl = p[0] - q[0];
24
+ const da = p[1] - q[1];
25
+ const db = p[2] - q[2];
26
+ return dl * dl + da * da + db * db;
27
+ }
28
+ export function deltaE76(p, q) {
29
+ return Math.sqrt(deltaE76Squared(p, q));
30
+ }
31
+ /**
32
+ * ΔE*94 (CIE 1994). Weights the chroma and hue contributions relative to
33
+ * Lab Euclidean distance — fixes the "saturated colors feel too far apart"
34
+ * problem of ΔE*76. Uses graphic-arts constants (kL=1, K1=0.045, K2=0.015).
35
+ *
36
+ * Not symmetric in the strict sense (reference vs sample), but we treat
37
+ * both inputs as graphic-arts samples — the formula reduces to a
38
+ * symmetric form below.
39
+ */
40
+ export function deltaE94(p, q) {
41
+ const [l1, a1, b1] = p;
42
+ const [l2, a2, b2] = q;
43
+ const dL = l1 - l2;
44
+ const c1 = Math.hypot(a1, b1);
45
+ const c2 = Math.hypot(a2, b2);
46
+ const dC = c1 - c2;
47
+ const da = a1 - a2;
48
+ const db = b1 - b2;
49
+ const dH2 = da * da + db * db - dC * dC;
50
+ // dH² can go slightly negative due to floating-point — clamp.
51
+ const dH2Safe = dH2 < 0 ? 0 : dH2;
52
+ const K1 = 0.045;
53
+ const K2 = 0.015;
54
+ const sL = 1;
55
+ const sC = 1 + K1 * c1;
56
+ const sH = 1 + K2 * c1;
57
+ const termL = dL / sL;
58
+ const termC = dC / sC;
59
+ const termH = Math.sqrt(dH2Safe) / sH;
60
+ return Math.sqrt(termL * termL + termC * termC + termH * termH);
61
+ }
62
+ // ---- ΔE00 helpers --------------------------------------------------------
63
+ const DEG = Math.PI / 180;
64
+ const RAD = 180 / Math.PI;
65
+ function hueDeg(b, a) {
66
+ if (b === 0 && a === 0)
67
+ return 0;
68
+ return (Math.atan2(b, a) * RAD + 360) % 360;
69
+ }
70
+ /**
71
+ * ΔE*00 (CIE 2000 / CIEDE2000). Current industry-standard perceptual
72
+ * color-difference formula. Fixes the saturated-blue failure of ΔE76/94
73
+ * with a rotation term in the blue-purple region (h ≈ 275°).
74
+ *
75
+ * kL / kC / kH are parametric factors (default 1/1/1 = graphic arts).
76
+ * Reference: G. Sharma, W. Wu, E.N. Dalal, "The CIEDE2000 Color-Difference
77
+ * Formula" (Color Research & Application, 2005).
78
+ */
79
+ // Precomputed constant: 25^7 = 6,103,515,625. Appears twice in the formula.
80
+ const POW_25_7 = 6103515625;
81
+ // Inline pow(x, 7) — Math.pow with non-integer exponent is slower in V8
82
+ // than three multiplies. x² → x⁴ → x⁶·x.
83
+ function pow7(x) {
84
+ const x2 = x * x;
85
+ const x4 = x2 * x2;
86
+ return x4 * x2 * x;
87
+ }
88
+ export function deltaE2000(p, q, kL = 1, kC = 1, kH = 1) {
89
+ const l1 = p[0];
90
+ const a1 = p[1];
91
+ const b1 = p[2];
92
+ const l2 = q[0];
93
+ const a2 = q[1];
94
+ const b2 = q[2];
95
+ // Chromas and mean chroma. Lab values stay within ±150 so overflow
96
+ // protection in Math.hypot is unnecessary — plain sqrt(a²+b²) is ~3×
97
+ // faster in V8 and more than precise enough for our range.
98
+ const c1 = Math.sqrt(a1 * a1 + b1 * b1);
99
+ const c2 = Math.sqrt(a2 * a2 + b2 * b2);
100
+ const cBar = (c1 + c2) / 2;
101
+ const cBar7 = pow7(cBar);
102
+ // G-factor boost for a* in low-chroma regions.
103
+ const g = 0.5 * (1 - Math.sqrt(cBar7 / (cBar7 + POW_25_7)));
104
+ const a1p = (1 + g) * a1;
105
+ const a2p = (1 + g) * a2;
106
+ // Primed chroma and hue.
107
+ const c1p = Math.sqrt(a1p * a1p + b1 * b1);
108
+ const c2p = Math.sqrt(a2p * a2p + b2 * b2);
109
+ const h1p = hueDeg(b1, a1p);
110
+ const h2p = hueDeg(b2, a2p);
111
+ // Differences.
112
+ const dLp = l2 - l1;
113
+ const dCp = c2p - c1p;
114
+ let dhp;
115
+ if (c1p * c2p === 0) {
116
+ dhp = 0;
117
+ }
118
+ else {
119
+ const raw = h2p - h1p;
120
+ if (Math.abs(raw) <= 180)
121
+ dhp = raw;
122
+ else if (raw > 180)
123
+ dhp = raw - 360;
124
+ else
125
+ dhp = raw + 360;
126
+ }
127
+ const dHp = 2 * Math.sqrt(c1p * c2p) * Math.sin((dhp * DEG) / 2);
128
+ // Means.
129
+ const lBarP = (l1 + l2) / 2;
130
+ const cBarP = (c1p + c2p) / 2;
131
+ let hBarP;
132
+ if (c1p * c2p === 0) {
133
+ hBarP = h1p + h2p;
134
+ }
135
+ else if (Math.abs(h1p - h2p) <= 180) {
136
+ hBarP = (h1p + h2p) / 2;
137
+ }
138
+ else if (h1p + h2p < 360) {
139
+ hBarP = (h1p + h2p + 360) / 2;
140
+ }
141
+ else {
142
+ hBarP = (h1p + h2p - 360) / 2;
143
+ }
144
+ // Weighting function T.
145
+ const hBarRad = hBarP * DEG;
146
+ const t = 1 -
147
+ 0.17 * Math.cos(hBarRad - 30 * DEG) +
148
+ 0.24 * Math.cos(2 * hBarRad) +
149
+ 0.32 * Math.cos(3 * hBarRad + 6 * DEG) -
150
+ 0.2 * Math.cos(4 * hBarRad - 63 * DEG);
151
+ // Lightness, chroma, hue weighting factors.
152
+ const lBarMinus50Sq = (lBarP - 50) ** 2;
153
+ const sL = 1 + (0.015 * lBarMinus50Sq) / Math.sqrt(20 + lBarMinus50Sq);
154
+ const sC = 1 + 0.045 * cBarP;
155
+ const sH = 1 + 0.015 * cBarP * t;
156
+ // Rotation term — the blue-purple correction that ΔE94 lacks.
157
+ const hShift = (hBarP - 275) / 25;
158
+ const dTheta = 30 * Math.exp(-(hShift * hShift));
159
+ const cBarP7 = pow7(cBarP);
160
+ const rC = 2 * Math.sqrt(cBarP7 / (cBarP7 + POW_25_7));
161
+ const rT = -Math.sin(2 * dTheta * DEG) * rC;
162
+ const termL = dLp / (kL * sL);
163
+ const termC = dCp / (kC * sC);
164
+ const termH = dHp / (kH * sH);
165
+ return Math.sqrt(termL * termL + termC * termC + termH * termH + rT * termC * termH);
166
+ }
167
+ /**
168
+ * Squared Euclidean distance in OKLAB space (Björn Ottosson, 2020).
169
+ * OKLAB is perceptually uniform by construction — plain Euclidean IS the
170
+ * perceptual distance, no weighting needed. Returns the square for
171
+ * argmin speed; `deltaEok` returns the actual distance.
172
+ *
173
+ * Often gives more visually-accurate nearest-matches than CIEDE2000 in
174
+ * the saturated blue/purple region.
175
+ *
176
+ * NOTE: the body is byte-identical to `deltaE76Squared` — both compute
177
+ * `dl² + da² + db²`. The semantic difference is entirely in *which* space
178
+ * the caller passes coordinates from: CIELAB (for ΔE*76) vs OKLAB (for this).
179
+ * Kept separate so callers and tests can't cross-wire the indexes.
180
+ */
181
+ export function deltaEokSquared(p, q) {
182
+ const dl = p[0] - q[0];
183
+ const da = p[1] - q[1];
184
+ const db = p[2] - q[2];
185
+ return dl * dl + da * da + db * db;
186
+ }
187
+ export function deltaEok(p, q) {
188
+ return Math.sqrt(deltaEokSquared(p, q));
189
+ }
190
+ //# sourceMappingURL=deltaE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deltaE.js","sourceRoot":"","sources":["../../src/math/deltaE.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,11 @@
1
1
  import type { Rgba } from '../types';
2
+ /**
3
+ * Squared Euclidean distance between two colors in RGB space.
4
+ * Alpha channel is ignored. Faster than `euclideanDistance` — use this
5
+ * when you only need to compare or minimize (sqrt is monotonic, so
6
+ * argmin(d) === argmin(d²)).
7
+ */
8
+ export declare function squaredDistanceRgb(a: Rgba, b: Rgba): number;
2
9
  /**
3
10
  * Euclidean distance between two colors in RGB space.
4
11
  * Alpha channel is ignored (matches classic `detect-color` behavior).
@@ -1 +1 @@
1
- {"version":3,"file":"euclideanDistance.d.ts","sourceRoot":"","sources":["../../src/math/euclideanDistance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAErC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAK1D"}
1
+ {"version":3,"file":"euclideanDistance.d.ts","sourceRoot":"","sources":["../../src/math/euclideanDistance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAErC;;;;;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"}