@studiotoolkit/color-palette-generator 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Studio Toolkit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @studiotoolkit/color-palette-generator
2
+
3
+ Generate color palettes (Total 57) using various algorithms including Algorithmic (11), Contrast (7), Data visualization (7), Harmony (11), Image (10), Perceptual (10), and design specific (60-30-10) generators.
4
+
5
+ **Play around and Generate component code here:**
6
+ https://studiotoolkit.github.io/build-palette-generator
7
+
8
+ **Complete Demo:**
9
+ https://studiotoolkit.github.io/demo-all
10
+
11
+ **Complete Documentation:**
12
+ https://studiotoolkit.github.io/color-palettes
13
+
14
+ **60-30-10 Design Documentation:**
15
+ https://studiotoolkit.github.io/60-30-10
16
+
17
+ **Radium Colors Generation Documentation:**
18
+ https://studiotoolkit.github.io/radium-help
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pnpm add @studiotoolkit/color-palette-generator
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```typescript
29
+ import {
30
+ AlgorithmicGenerator,
31
+ ContrastGenerator,
32
+ HarmonyGenerator,
33
+ ImageGenerator,
34
+ PerceptualGenerator,
35
+ RadiumGenerator,
36
+ DataVisualsGenerator,
37
+ Select603010,
38
+ } from '@studiotoolkit/color-palette-generator';
39
+
40
+ // Generate a harmony-based palette
41
+ const harmonyPalette = HarmonyGenerator.generate('#FF5733');
42
+
43
+ // Generate a contrast palette
44
+ const contrastPalette = ContrastGenerator.generate('#FF5733');
45
+
46
+ // Generate from an image
47
+ const imagePalette = await ImageGenerator.extractFromImage(imageElement);
48
+ ```
49
+
50
+ ## Generators
51
+
52
+ - **AlgorithmicGenerator** - Mathematical color generation algorithms
53
+ - **ContrastGenerator** - Generate high-contrast color combinations
54
+ - **DataVisualsGenerator** - Palettes optimized for data visualization
55
+ - **HarmonyGenerator** - Color harmony-based palettes (complementary, triadic, etc.)
56
+ - **ImageGenerator** - Extract color palettes from images
57
+ - **PerceptualGenerator** - Perceptually uniform color palettes
58
+ - **RadiumGenerator** - Design system color generation
59
+ - **Select603010** - 60-30-10 color rule generator
60
+
61
+ ## License
62
+
63
+ MIT
@@ -0,0 +1,28 @@
1
+ /**
2
+ * AlgorithmicGenerator
3
+ * Generates 11 algorithmic / generative palette types from a square input:
4
+ * random, goldenRatio, noise, temperature, bezierInterpolation,
5
+ * easeInOut, blackbody, fibonacci, harmonicSeries, sinusoidal, cubehelix
6
+ *
7
+ * Color math: OKLab / OKLCH for perceptual uniformity.
8
+ * Deterministic by default via seeded pseudo-random (mulberry32).
9
+ * Zero external dependencies.
10
+ */
11
+ export interface AlgorithmicInput {
12
+ square: string[];
13
+ }
14
+ export interface AlgorithmicOutput {
15
+ random: string[];
16
+ goldenRatio: string[];
17
+ noise: string[];
18
+ temperature: string[];
19
+ bezierInterpolation: string[];
20
+ easeInOut: string[];
21
+ blackbody: string[];
22
+ fibonacci: string[];
23
+ harmonicSeries: string[];
24
+ sinusoidal: string[];
25
+ cubehelix: string[];
26
+ }
27
+ export declare const generateAlgorithmic: (input: AlgorithmicInput, n?: number) => AlgorithmicOutput;
28
+ //# sourceMappingURL=AlgorithmicGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlgorithmicGenerator.d.ts","sourceRoot":"","sources":["../../src/generators/AlgorithmicGenerator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAsBH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AACD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AA6eD,eAAO,MAAM,mBAAmB,GAC9B,OAAO,gBAAgB,EACvB,IAAG,MAAU,KACZ,iBAoBF,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Contrast-Based (Accessibility) Color Palette Generator
3
+ * Implements: contrastScale, accessible, wcag, apca, colorBlindSafe, colorTokenized, highContrast
4
+ *
5
+ * Fix history:
6
+ * R1 — adjustToWcagRatio: directional binary searches anchored to hsl.l
7
+ * R1 — apca: binary search direction corrected
8
+ * R1 — colorTokenized: TokenRole interface typed, no `as any`
9
+ * R2 — adjustToWcagRatio: fallback to nearest extreme (black/white)
10
+ * R2 — apca: upper bound widened to hi=1.0
11
+ * R3 — wcag: pre-offset lightness per slot for distinct swatches
12
+ * R3 — highContrast: dark-side ramp starts at l=0.05
13
+ * R4 — adjustToWcagRatio: early-return restored (R3 removal broke accessible)
14
+ * R4 — wcag: lOffset replaced with fixed canonical startL tiers per target type
15
+ * R4 — highContrast: per-slot spread across wider ranges; explicit slot counts
16
+ * R5 — wcag: cycle saturation step 0.15→0.30; per-cycle lShift ±0.08 added
17
+ * R5 — highContrast: dark-side saturation fades slot-by-slot to escape dead zone
18
+ * R6 — highContrast: adjustToWcagRatioFromL helper added — skips early-return,
19
+ * searches outward from a caller-supplied startL so every slot is forced
20
+ * to produce a unique result even when the candidate already passes.
21
+ * Dark side: fade s → 0 and cap l at 0.28 to guarantee passing range.
22
+ * Light side: searches from per-slot startL rather than converging to white.
23
+ */
24
+ interface PaletteInput {
25
+ [key: string]: string[];
26
+ }
27
+ interface PaletteOutput {
28
+ [key: string]: string[];
29
+ }
30
+ export declare const generateContrastPalettes: (input: PaletteInput, x?: number) => PaletteOutput;
31
+ export {};
32
+ //# sourceMappingURL=ContrastGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContrastGenerator.d.ts","sourceRoot":"","sources":["../../src/generators/ContrastGenerator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAeH,UAAU,YAAY;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACzB;AAED,UAAU,aAAa;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACzB;AAmSD,eAAO,MAAM,wBAAwB,GACnC,OAAO,YAAY,EACnB,IAAG,MAAU,KACZ,aA4LF,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * DataVisualsGenerator
3
+ * Generates 7 data visualization palette types from a square input:
4
+ * sequential, diverging, qualitative, bivariate,
5
+ * cyclical, spectral, stepped
6
+ *
7
+ * All color math in OKLab/OKLCH for perceptual uniformity.
8
+ * Zero external dependencies.
9
+ */
10
+ export interface DataVisualsInput {
11
+ square: string[];
12
+ }
13
+ export interface DataVisualsOutput {
14
+ sequential: string[];
15
+ diverging: string[];
16
+ qualitative: string[];
17
+ bivariate: string[];
18
+ cyclical: string[];
19
+ spectral: string[];
20
+ stepped: string[];
21
+ }
22
+ export declare const generateDataVisuals: (input: DataVisualsInput, n?: number) => DataVisualsOutput;
23
+ //# sourceMappingURL=DataVisualsGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataVisualsGenerator.d.ts","sourceRoot":"","sources":["../../src/generators/DataVisualsGenerator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsBH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AACD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAqQD,eAAO,MAAM,mBAAmB,GAC9B,OAAO,gBAAgB,EACvB,IAAG,MAAU,KACZ,iBA6BF,CAAC"}
@@ -0,0 +1,15 @@
1
+ interface PaletteInput {
2
+ [key: string]: string[];
3
+ }
4
+ interface PaletteOutput {
5
+ [key: string]: string[];
6
+ }
7
+ /**
8
+ * PaletteGenerator Library
9
+ * @param input - Object with harmonyPalette array of hex colors
10
+ * @param count - Number of colors to generate for scalable palettes (default: 9)
11
+ * @returns Object with multiple palette variations
12
+ */
13
+ export declare const generateHarmonyPalettes: (input: PaletteInput, count?: number) => PaletteOutput;
14
+ export {};
15
+ //# sourceMappingURL=HarmonyGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HarmonyGenerator.d.ts","sourceRoot":"","sources":["../../src/generators/HarmonyGenerator.ts"],"names":[],"mappings":"AAQA,UAAU,YAAY;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACzB;AAED,UAAU,aAAa;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACzB;AAsDD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAClC,OAAO,YAAY,EACnB,QAAO,MAAU,KAChB,aAuEF,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * ImageGenerator
3
+ * Extracts color palettes from image pixel data using 10 algorithms:
4
+ * kmeans, medianCut, dominant, vibrant, muted,
5
+ * octree, colorMoments, neuralQuant, histogram, deltaE
6
+ *
7
+ * Input: Uint8ClampedArray (RGBA from canvas.getImageData) — optional.
8
+ * Falls back to synthetic pixels generated from input.square.
9
+ * Output: { [algorithmName]: string[] } — hex arrays, always length k.
10
+ *
11
+ * All perceptual math in OKLab. Zero external dependencies.
12
+ */
13
+ export interface ImageGeneratorInput {
14
+ square: string[];
15
+ }
16
+ export interface ImageGeneratorOutput {
17
+ kmeans: string[];
18
+ medianCut: string[];
19
+ dominant: string[];
20
+ vibrant: string[];
21
+ muted: string[];
22
+ octree: string[];
23
+ colorMoments: string[];
24
+ neuralQuant: string[];
25
+ histogram: string[];
26
+ deltaE: string[];
27
+ }
28
+ /**
29
+ * generateImagePalettes
30
+ *
31
+ * @param input { square: string[] } — fallback colors used when data is absent
32
+ * @param k Colors to extract per algorithm (default 6)
33
+ * @param data Optional RGBA Uint8ClampedArray from canvas.getImageData().
34
+ * When omitted, synthetic pixels are generated from input.square.
35
+ */
36
+ export declare const generateImagePalettes: (input: ImageGeneratorInput, k?: number, data?: Uint8ClampedArray) => ImageGeneratorOutput;
37
+ //# sourceMappingURL=ImageGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageGenerator.d.ts","sourceRoot":"","sources":["../../src/generators/ImageGenerator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAiBH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AA8oBD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,OAAO,mBAAmB,EAC1B,IAAG,MAAU,EACb,OAAO,iBAAiB,KACvB,oBAgCF,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Perceptual Color Space Generator (Final Corrected Version)
3
+ */
4
+ interface PaletteInput {
5
+ [key: string]: string[];
6
+ }
7
+ interface PaletteOutput {
8
+ [key: string]: string[];
9
+ }
10
+ export declare const generatePerceptualPalettes: (input: PaletteInput, x?: number) => PaletteOutput;
11
+ export {};
12
+ //# sourceMappingURL=PerceptualGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PerceptualGenerator.d.ts","sourceRoot":"","sources":["../../src/generators/PerceptualGenerator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,UAAU,YAAY;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACzB;AACD,UAAU,aAAa;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACzB;AAsID,eAAO,MAAM,0BAA0B,GACrC,OAAO,YAAY,EACnB,IAAG,MAAU,KACZ,aAiIF,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * RadiumGenerator
3
+ * Accepts any color palette JSON structure and returns the same structure
4
+ * with Radium-generated colors — same keys, same array lengths, new colors.
5
+ *
6
+ * Base color is inferred from the first valid hex found in the input.
7
+ * All color math uses OKLab/OKLCH for perceptual uniformity.
8
+ * Zero external dependencies.
9
+ */
10
+ /**
11
+ * Any JSON object whose values are arrays of hex-color strings.
12
+ * The exact shape (keys + array lengths) is mirrored in the output.
13
+ *
14
+ * @example
15
+ * {
16
+ * triadic: ["#ff0000", "#00ff00", "#0000ff"],
17
+ * monochromatic: ["#4d0000", ..., "#ffb3b3"], // 16 entries
18
+ * }
19
+ */
20
+ export type RadiumInput = Record<string, string[]>;
21
+ export type RadiumOutput = Record<string, string[]>;
22
+ /**
23
+ * Accepts **any** color palette JSON and returns the **exact same structure** —
24
+ * identical keys and array lengths — filled with Radium-generated colors.
25
+ *
26
+ * Each key independently derives its base color from its **own first value**.
27
+ * Semantic key names drive perceptually accurate OKLCH transforms:
28
+ *
29
+ * - `neutralLight` → L 0.93, chroma drained (near-white tint)
30
+ * - `neutralDark` → L 0.10, chroma drained (near-black shade)
31
+ * - `*shade` / `*dark` → L 0.30 / 0.22, hue exactly preserved (gamut-safe)
32
+ * - `*light` / `*tint` → L 0.88, chroma halved
33
+ * - `accent*` → L 0.62, chroma ≥ 0.22 (vivid, gamut-safe)
34
+ * - `main*` / `primary*` → L 0.52, chroma ≥ 0.22 (saturated, gamut-safe)
35
+ * - harmony keys → hue-rotation sets
36
+ * - ramp keys → lightness ramps
37
+ * - unknown single-swatch → L 0.55, C ≥ 0.18, hue preserved
38
+ *
39
+ * All single-swatch outputs use gamut-safe chroma reduction to prevent
40
+ * hue drift when the target lightness lies outside the sRGB gamut.
41
+ *
42
+ * @param input Any `Record<string, string[]>` palette map.
43
+ * @returns Same keys + same lengths, Radium-computed colors.
44
+ */
45
+ export declare const generateRadiumColors: (input: RadiumInput) => RadiumOutput;
46
+ /** Converts a hex string to `{ r, g, b }` in 0–255 range */
47
+ export declare const hexToRgb: (hex: string) => {
48
+ r: number;
49
+ g: number;
50
+ b: number;
51
+ };
52
+ /** Converts a hex string to a CSS `rgba(…)` string */
53
+ export declare const hexToRgba: (hex: string, alpha?: number) => string;
54
+ /** WCAG relative luminance (0 = black, 1 = white) */
55
+ export declare const getLuminance: (hex: string) => number;
56
+ /** WCAG contrast ratio between two hex colors */
57
+ export declare const getContrastRatio: (hex1: string, hex2: string) => number;
58
+ /** Returns `"#000000"` or `"#ffffff"` for accessible text on the given background */
59
+ export declare const getReadableTextColor: (bg: string) => "#000000" | "#ffffff";
60
+ //# sourceMappingURL=RadiumGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadiumGenerator.d.ts","sourceRoot":"","sources":["../../src/generators/RadiumGenerator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0BH;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AACnD,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AA8UpD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,WAAW,KAAG,YAOvD,CAAC;AAMJ,4DAA4D;AAC5D,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,KAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAOvE,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,SAAS,GAAI,KAAK,MAAM,EAAE,cAAS,KAAG,MAGlD,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,MAG1C,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,MAI7D,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,oBAAoB,GAAI,IAAI,MAAM,KAAG,SAAS,GAAG,SACZ,CAAC"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * select60-30-10.ts
3
+ * ─────────────────────────────────────────────────────────────────────────────
4
+ * Converts any palette of hex colors into the five roles of the 60–30–10
5
+ * design composition rule, using OKLab perceptual color math throughout.
6
+ *
7
+ * Zero dependencies. Works in any TypeScript / ES2020+ environment.
8
+ *
9
+ * ─── CHANGES FROM ORIGINAL ───────────────────────────────────────────────────
10
+ *
11
+ * FIX 1 (latent mutation bug — all 5 steps)
12
+ * Every Array.sort() call was operating directly on a shared reference
13
+ * (nearNeutrals, px, midBand, darkNeutrals, sameHue, rem12, farHue, rem123).
14
+ * JavaScript's Array.prototype.sort() sorts IN PLACE and returns the same
15
+ * array reference. When the ternary `(a.length > 0 ? a : b).sort()` falls
16
+ * back to `b`, it mutates `b` for all subsequent code.
17
+ *
18
+ * Concrete failure scenario:
19
+ * • If the palette has no near-neutrals, step 1 falls back and sorts `px`
20
+ * by L descending. Step 2 then receives a `px` sorted by L, not by
21
+ * original insertion order. When step 2's midBand is also empty and
22
+ * falls back to `px`, it sorts an already-L-sorted `px` by C — which
23
+ * still produces the correct winner, but any future change to algorithm
24
+ * logic that relies on `px` order would silently break.
25
+ * • darkNeutrals.sort() in step 3 mutates the local filter result; while
26
+ * this is currently harmless, it is inconsistent and fragile.
27
+ *
28
+ * Fix: prepend .slice() before every .sort() so a new array is sorted
29
+ * instead of the original reference.
30
+ *
31
+ * FIX 2 (_normaliseHex — missing typeof guard)
32
+ * The original code called raw.trim() without first checking that raw is a
33
+ * string. Passing a number, null, or undefined would throw a generic
34
+ * "raw.trim is not a function" TypeError instead of the descriptive message
35
+ * that makes library errors actionable.
36
+ * Fix: add `if (typeof raw !== 'string')` guard at top of _normaliseHex.
37
+ *
38
+ * FIX 3 (select60_30_10 — incomplete input validation)
39
+ * `if (!palette.length)` throws when palette is null or undefined because
40
+ * accessing .length on null/undefined is a TypeError at the call site, not
41
+ * a helpful message from the library.
42
+ * Fix: check Array.isArray(palette) first.
43
+ *
44
+ * FIX 4 (rem12 / rem123 — Set-based exclusion for O(1) lookup)
45
+ * `![...].includes(hex)` is O(k) per element where k is the number of
46
+ * excluded hexes. Using a Set makes exclusion O(1). Not a correctness bug
47
+ * but good practice for a library function.
48
+ */
49
+ export interface LCH {
50
+ /** Perceptual lightness, range 0–1 */
51
+ L: number;
52
+ /** Chroma (colourfulness), range 0–~0.4 */
53
+ C: number;
54
+ /** Hue angle in degrees, range 0–360 */
55
+ H: number;
56
+ }
57
+ export interface ColorRole {
58
+ /** Normalised "#rrggbb" hex string */
59
+ hex: string;
60
+ /** Role key, e.g. "neutralLight" */
61
+ role: string;
62
+ /** Human label, e.g. "Neutral Light" */
63
+ label: string;
64
+ /** Design proportion weight: "60%", "30%", "10%", or "—" */
65
+ weight: string;
66
+ /** OKLab-derived LCH coordinates */
67
+ lch: LCH;
68
+ /** true when this color was synthesised, not picked from the input palette */
69
+ derived: boolean;
70
+ /** "#ffffff" or "#111111" — highest-contrast text to place on this background */
71
+ textColor: string;
72
+ /** WCAG 2.x contrast ratio against neutralLight */
73
+ contrast: number;
74
+ }
75
+ export interface RuleResult {
76
+ neutralLight: ColorRole;
77
+ neutralDark: ColorRole;
78
+ mainColor: ColorRole;
79
+ mainColorShade: ColorRole;
80
+ accentColor: ColorRole;
81
+ }
82
+ export interface SelectOptions {
83
+ /** OKLab C ceiling to qualify as "neutral". Default 0.06. */
84
+ neutralChromaMax?: number;
85
+ /** OKLab L floor for mainColor candidate band. Default 0.40. */
86
+ mainLightnessMin?: number;
87
+ /** OKLab L ceiling for mainColor candidate band. Default 0.72. */
88
+ mainLightnessMax?: number;
89
+ /** Max ΔH° for shade to count as "same hue" as main. Default 30. */
90
+ shadeHueTolerance?: number;
91
+ /** Min ΔH° for accent to count as "opposite" to main. Default 100. */
92
+ accentHueMin?: number;
93
+ /** Lightness of synthesised neutralDark. Default 0.20. */
94
+ derivedDarkL?: number;
95
+ /** Chroma of synthesised neutralDark. Default 0.035. */
96
+ derivedDarkC?: number;
97
+ }
98
+ /**
99
+ * WCAG 2.x contrast ratio between two colors. Always ≥ 1.
100
+ * Accepts any valid hex format: "#rgb", "#rrggbb", with or without "#".
101
+ */
102
+ export declare const wcagContrast: (hexA: string, hexB: string) => number;
103
+ /**
104
+ * Returns "#ffffff" or "#111111" — whichever has higher contrast on bgHex.
105
+ */
106
+ export declare const bestTextOn: (bgHex: string) => string;
107
+ /**
108
+ * Convert a palette into the five 60–30–10 color roles.
109
+ *
110
+ * @param palette Non-empty array of hex strings (any valid CSS hex format).
111
+ * @param opts Optional algorithm parameter overrides.
112
+ */
113
+ export declare function select60_30_10(palette: string[], opts?: SelectOptions): RuleResult;
114
+ /**
115
+ * Returns the five hex strings in role order:
116
+ * [neutralLight, neutralDark, mainColor, mainColorShade, accentColor]
117
+ */
118
+ export declare const toHexArray: (result: RuleResult) => string[];
119
+ /**
120
+ * Returns a flat { roleKey: hex } object.
121
+ *
122
+ * @example
123
+ * {
124
+ * neutralLight: "#b7ccab",
125
+ * neutralDark: "#2b2000",
126
+ * mainColor: "#ee5034",
127
+ * mainColorShade: "#b4260a",
128
+ * accentColor: "#4d7627",
129
+ * }
130
+ */
131
+ export declare const toObject: (result: RuleResult) => {
132
+ neutralLight: string;
133
+ neutralDark: string;
134
+ mainColor: string;
135
+ mainColorShade: string;
136
+ accentColor: string;
137
+ };
138
+ /**
139
+ * Returns a CSS `:root` block with five custom properties.
140
+ *
141
+ * @param result Output of select60_30_10.
142
+ * @param prefix CSS variable name prefix. Defaults to "--color".
143
+ *
144
+ * @example
145
+ * toCssVars(result)
146
+ * // :root {
147
+ * // --color-neutral-light: #b7ccab;
148
+ * // --color-neutral-dark: #2b2000;
149
+ * // --color-main: #ee5034;
150
+ * // --color-main-shade: #b4260a;
151
+ * // --color-accent: #4d7627;
152
+ * // }
153
+ */
154
+ export declare const toCssVars: (result: RuleResult, prefix?: string) => string;
155
+ //# sourceMappingURL=select60-30-10.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select60-30-10.d.ts","sourceRoot":"","sources":["../../src/generators/select60-30-10.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAIH,MAAM,WAAW,GAAG;IAClB,sCAAsC;IACtC,CAAC,EAAE,MAAM,CAAC;IACV,2CAA2C;IAC3C,CAAC,EAAE,MAAM,CAAC;IACV,wCAAwC;IACxC,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,SAAS;IACxB,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,GAAG,EAAE,GAAG,CAAC;IACT,8EAA8E;IAC9E,OAAO,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,SAAS,CAAC;IACxB,WAAW,EAAE,SAAS,CAAC;IACvB,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,SAAS,CAAC;IAC1B,WAAW,EAAE,SAAS,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA0HD;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,MAQzD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MAG5B,CAAC;AAIhB;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,GAAE,aAAkB,GACvB,UAAU,CA0KZ;AAID;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,QAAQ,UAAU,KAAG,MAAM,EAMrD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,UAAU;;;;;;CAMzC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,UAAU,EAAE,eAAkB,KAAG,MAalE,CAAC"}
@@ -0,0 +1,10 @@
1
+ export { generateAlgorithmic, type AlgorithmicInput, type AlgorithmicOutput, } from "./generators/AlgorithmicGenerator";
2
+ export * from "./generators/ContrastGenerator";
3
+ export * from "./generators/DataVisualsGenerator";
4
+ export * from "./generators/HarmonyGenerator";
5
+ export * from "./generators/ImageGenerator";
6
+ export * from "./generators/PerceptualGenerator";
7
+ export * from "./generators/RadiumGenerator";
8
+ export * from "./generators/select60-30-10";
9
+ export * from "./types";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,GACvB,MAAM,mCAAmC,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AACjD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAE5C,cAAc,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const mt=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4),G=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,y=t=>Math.max(0,Math.min(1,t)),H=(t,n,o)=>t+(n-t)*o,st=Math.PI*2,Ft=({r:t,g:n,b:o})=>{const e=mt(t),s=mt(n),r=mt(o),l=Math.cbrt(.4122214708*e+.5363325363*s+.0514459929*r),c=Math.cbrt(.2119034982*e+.6806995451*s+.1073969566*r),a=Math.cbrt(.0883024619*e+.2817188376*s+.6299787005*r);return{L:.2104542553*l+.793617785*c-.0040720468*a,a:1.9779984951*l-2.428592205*c+.4505937099*a,b:.0259040371*l+.7827717662*c-.808675766*a}},Gt=({L:t,a:n,b:o})=>{const e=t+.3963377774*n+.2158037573*o,s=t-.1055613458*n-.0638541728*o,r=t-.0894841775*n-1.291485548*o,l=e*e*e,c=s*s*s,a=r*r*r;return{r:y(G(4.0767416621*l-3.3077115913*c+.2309699292*a)),g:y(G(-1.2684380046*l+2.6097574011*c-.3413193965*a)),b:y(G(-.0041960863*l-.7034186147*c+1.707614701*a))}},en=({L:t,a:n,b:o})=>({L:t,C:Math.sqrt(n*n+o*o),H:(Math.atan2(o,n)*180/Math.PI+360)%360}),sn=({L:t,C:n,H:o})=>({L:t,a:n*Math.cos(o*Math.PI/180),b:n*Math.sin(o*Math.PI/180)}),Xt=t=>({r:parseInt(t.slice(1,3),16)/255,g:parseInt(t.slice(3,5),16)/255,b:parseInt(t.slice(5,7),16)/255}),it=({r:t,g:n,b:o})=>{const e=s=>Math.round(s*255).toString(16).padStart(2,"0");return`#${e(t)}${e(n)}${e(o)}`},k=t=>en(Ft(Xt(t))),D=t=>it(Gt(sn(t))),rn=t=>it(Gt(t)),St=(t,n,o)=>({L:H(t.L,n.L,o),a:H(t.a,n.a,o),b:H(t.b,n.b,o)}),Vt=t=>{let n=t>>>0;return()=>{n+=1831565813;let o=n;return o=Math.imul(o^o>>>15,o|1),o^=o+Math.imul(o^o>>>7,o|61),((o^o>>>14)>>>0)/4294967296}},Qt=t=>{let n=0;for(let o=1;o<7;o++)n=Math.imul(31,n)+parseInt(t[o],16)|0;return Math.abs(n)},gt=t=>{const n=[],o=Vt(t);for(let s=0;s<256;s++)n.push(o());const e=s=>s*s*(3-2*s);return s=>{const r=Math.floor(s)&255,l=s-Math.floor(s);return H(n[r],n[r+1&255],e(l))}},ft=(t,n,o,e,s)=>{const r=1-s;return r*r*r*t+3*r*r*s*n+3*r*s*s*o+s*s*s*e},an=(t,n,o,e,s)=>({L:ft(t.L,n.L,o.L,e.L,s),a:ft(t.a,n.a,o.a,e.a,s),b:ft(t.b,t.b,o.b,e.b,s)}),cn=t=>t<.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2,ln=t=>{let n;t>=1667&&t<=4e3?n=-266123900/(t*t*t)-234358/(t*t)+877.6956/t+.17991:n=-3025846900/(t*t*t)+21070379e-1/(t*t)+222.6347/t+.24039;let o;t>=1667&&t<=2222?o=-1.1063814*n*n*n-1.3481102*n*n+2.18555832*n-.20219683:t<=4e3?o=-.9549476*n*n*n-1.37418593*n*n+2.09137015*n-.16748867:o=3.081758*n*n*n-5.8733867*n*n+3.75112997*n-.37001483;const e=1,s=e*n/Math.max(o,1e-6),r=e*(1-n-o)/Math.max(o,1e-6),l=3.2406*s-1.5372*e-.4986*r,c=-.9689*s+1.8758*e+.0415*r,a=.0557*s-.204*e+1.057*r,i=Math.max(l,c,a,1e-6);return{r:y(G(l/i)),g:y(G(c/i)),b:y(G(a/i))}},hn=(t,n=.5,o=-1.5,e=1.2,s=1)=>{const r=st*(n/3+o*t),l=Math.pow(t,s),c=e*l*(1-l)/2,a=Math.cos(r),i=Math.sin(r);return{r:y(l+c*(-.14861*a+1.78277*i)),g:y(l+c*(-.29227*a-.90649*i)),b:y(l+c*(1.97294*a))}},un=(t,n)=>{const o=Vt(Qt(t));return Array.from({length:n},()=>D({L:H(.35,.75,o()),C:H(.08,.2,o()),H:o()*360}))},mn=(t,n)=>{const o=k(t),e=137.50776405003785;return Array.from({length:n},(s,r)=>{const l=(o.H+e*r)%360;return D({L:H(.45,.7,r%3/2),C:Math.max(o.C,.1),H:l})})},gn=(t,n)=>{const o=k(t),e=Qt(t),s=gt(e),r=gt(e+1),l=gt(e+2);return Array.from({length:n},(c,a)=>{const i=a/Math.max(n-1,1);return D({L:y(H(.35,.8,s(i*3.5))),C:y(H(.06,.22,r(i*4.1+1))),H:(o.H+l(i*2.7+2)*120-60)%360})})},fn=(t,n)=>{const o=k(t),e=20,s=220,r=(o.H-120+360)%360;return Array.from({length:n},(l,c)=>{const a=c/(n-1),i=(H(e,s,a)+r)%360,u=.35+.45*Math.sin(a*Math.PI),g=H(.18,.12,Math.abs(a-.5)*2);return D({L:u,C:g,H:i})})},Mn=(t,n)=>{const o=t.slice(0,4).map(s=>Ft(Xt(s)));for(;o.length<4;)o.push({...o[o.length-1]});const e={L:(o[0].L+o[3].L)/2,a:(o[0].a+o[3].a)/2,b:(o[0].b+o[3].b)/2};return o[1]=St(o[1],e,.35),o[2]=St(o[2],e,.35),Array.from({length:n},(s,r)=>{const l=r/(n-1);return rn(an(o[0],o[1],o[2],o[3],l))})},bn=(t,n)=>{const o=k(t),e=.28,s=.88;return Array.from({length:n},(r,l)=>{const c=l/(n-1),a=cn(c),i=H(e,s,a),u=o.C*(1-.4*Math.abs(c-.5)*2);return D({L:i,C:u,H:o.H})})},dn=(t,n)=>{const e=k(t).H/360*3e3,s=Math.max(900,1500+e),r=Math.min(15e3,9e3+e);return Array.from({length:n},(l,c)=>{const a=c/(n-1),i=H(s,r,a);return it(ln(i))})},pn=(t,n)=>{const o=k(t),e=[1,1];for(;e.length<n;)e.push(e[e.length-1]+e[e.length-2]);return Array.from({length:n},(s,r)=>{const l=(o.H+e[r]*47%360)%360,c=H(.4,.72,r%4/3),a=Math.max(o.C,.1);return D({L:c,C:a,H:l})})},Ln=(t,n)=>{const o=k(t),e=.88,s=.28;return Array.from({length:n},(r,l)=>{const c=1/(l+1),a=1,i=1/n,u=(c-i)/(a-i),g=H(s,e,u),h=H(o.C*1.3,o.C*.5,u);return D({L:g,C:y(h),H:o.H})})},Cn=(t,n)=>{const o=k(t);return Array.from({length:n},(e,s)=>{const r=s/Math.max(n-1,1),l=.55+.25*Math.sin(st*r*1+0),c=o.C*(.7+.5*Math.sin(st*r*1.5+Math.PI/3)),a=(o.H+60*Math.sin(st*r*.75+Math.PI/6)+360)%360;return D({L:y(l),C:y(c),H:a})})},xn=(t,n)=>{const e=k(t).H/120%3;return Array.from({length:n},(s,r)=>{const l=r/(n-1);return it(hn(l,e,-1.5,1.2,1))})},Hn=(t,n=5)=>{const o=t.square??[],e=o[0]??"#0065ff",s=o[1]??"#ff0000",r=o[2]??"#00ff00",l=o[3]??"#ffff00";return{random:un(e,n),goldenRatio:mn(e,n),noise:gn(e,n),temperature:fn(e,n),bezierInterpolation:Mn([e,s,r,l],n),easeInOut:bn(e,n),blackbody:dn(e,n),fibonacci:pn(e,n),harmonicSeries:Ln(e,n),sinusoidal:Cn(e,n),cubehelix:xn(e,n)}},_t=t=>({r:parseInt(t.slice(1,3),16)/255,g:parseInt(t.slice(3,5),16)/255,b:parseInt(t.slice(5,7),16)/255}),z=({r:t,g:n,b:o})=>{const e=s=>Math.max(0,Math.min(255,Math.round(s*255))).toString(16).padStart(2,"0");return`#${e(t)}${e(n)}${e(o)}`},R=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4),X=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,B=(t,n,o)=>t+(n-t)*o,$=(t,n=0,o=1)=>Math.max(n,Math.min(o,t)),E={r:1,g:1,b:1},j={r:0,g:0,b:0},wt=({r:t,g:n,b:o})=>.2126*R(t)+.7152*R(n)+.0722*R(o),_=(t,n)=>{const o=wt(t),e=wt(n);return(Math.max(o,e)+.05)/(Math.min(o,e)+.05)},yn=(t,n)=>{const o=({r:f,g:b,b:M})=>.2126729*Math.pow(f,2.4)+.7151522*Math.pow(b,2.4)+.072175*Math.pow(M,2.4);let h=o(t),m=o(n);if(h=h>.022?h:h+Math.pow(.022-h,1.414),m=m>.022?m:m+Math.pow(.022-m,1.414),Math.abs(m-h)<5e-4)return 0;if(m>h){const f=(Math.pow(m,.56)-Math.pow(h,.57))*1.14;return f<.1?0:(f-.027)*100}else{const f=(Math.pow(m,.65)-Math.pow(h,.62))*1.14;return f>-.1?0:(f+.027)*100}},Ut=({r:t,g:n,b:o})=>{const e=Math.max(t,n,o),s=Math.min(t,n,o),r=(e+s)/2;if(e===s)return{h:0,s:0,l:r};const l=e-s,c=l/(r>.5?2-e-s:e+s);let a=0;return e===t?a=(n-o)/l+(n<o?6:0):e===n?a=(o-t)/l+2:a=(t-n)/l+4,{h:a*60,s:c,l:r}},A=({h:t,s:n,l:o})=>{const e=(1-Math.abs(2*o-1))*n,s=e*(1-Math.abs(t/60%2-1)),r=o-e/2;let l=0,c=0,a=0;return t<60?(l=e,c=s):t<120?(l=s,c=e):t<180?(c=e,a=s):t<240?(c=s,a=e):t<300?(l=s,a=e):(l=e,a=s),{r:l+r,g:c+r,b:a+r}},Pt=(t,n,o,e=48)=>{if(_(t,n)>=o)return t;const s=Ut(t);let r=null;{let l=0,c=s.l;for(let a=0;a<e;a++){const i=(l+c)/2,u=A({...s,l:i});_(u,n)>=o?(r=u,c=i):l=i}}if(r&&_(r,n)>=o)return r;{let l=s.l,c=1;for(let a=0;a<e;a++){const i=(l+c)/2,u=A({...s,l:i});_(u,n)>=o?(r=u,l=i):c=i}}return r&&_(r,n)>=o?r:_(j,n)>=_(E,n)?j:E},Rt=(t,n,o,e,s,r,l=48)=>{let c=r==="dark"?0:o,a=r==="dark"?o:1,i=null;for(let u=0;u<l;u++){const g=(c+a)/2,h=A({h:t,s:n,l:g});_(h,e)>=s?(i=h,r==="dark"?c=g:a=g):r==="dark"?a=g:c=g}return i&&_(i,e)>=s?i:_(j,e)>=_(E,e)?j:E},vt=({r:t,g:n,b:o})=>{const e=R(t),s=R(n),r=R(o);return{r:X($(.29031*e+.70969*s+0*r)),g:X($(.29031*e+.70969*s+0*r)),b:X($(-.02197*e+.02197*s+1*r))}},Ot=({r:t,g:n,b:o})=>{const e=R(t),s=R(n),r=R(o);return{r:X($(.10889*e+.89111*s+0*r)),g:X($(.10889*e+.89111*s+0*r)),b:X($(.00452*e-.00452*s+1*r))}},kt=(t,n)=>Math.sqrt((t.r-n.r)**2+(t.g-n.g)**2+(t.b-n.b)**2),An=(t,n,o=.12)=>kt(vt(t),vt(n))>o||kt(Ot(t),Ot(n))>o,Tn=(t,n=9)=>{const o=Object.values(t).find(l=>Array.isArray(l)&&l.length>0);if(!o)return{};const e=_t(o[0]),s=Ut(e),r={};r.contrastScale=Array.from({length:n},(l,c)=>{const a=c/(n-1);return z(A({h:s.h,s:s.s,l:Math.pow(a,.8)}))});{const c=Math.ceil(n/2);r.accessible=Array.from({length:n},(a,i)=>{const u=i%2===0,g=u?B(.05,.35,i/2/c):B(.88,.98,Math.floor(i/2)/c),h=A({h:s.h,s:s.s*.6,l:g}),m=A(u?{h:s.h,s:s.s*.1,l:.96}:{h:s.h,s:s.s*.8,l:.15});return z(Pt(h,m,4.5))})}{const l=[{bg:E,ratio:4.5,startL:.2},{bg:E,ratio:7,startL:.1},{bg:j,ratio:4.5,startL:.8},{bg:j,ratio:7,startL:.9}];r.wcag=Array.from({length:n},(c,a)=>{const{bg:i,ratio:u,startL:g}=l[a%l.length],h=Math.floor(a/l.length),m=$(1-h*.3),f=h*(g<.5?.08:-.08),b=A({h:s.h,s:s.s*m,l:$(g+f)});return z(Pt(b,i,u))})}{const l={r:1,g:1,b:1};r.apca=Array.from({length:n},(c,a)=>{const i=a/(n-1),u=B(30,90,i);let g=0,h=1;for(let m=0;m<48;m++){const f=(g+h)/2,b=A({h:s.h,s:s.s,l:f});Math.abs(yn(b,l))>u?g=f:h=f}return z(A({h:s.h,s:s.s,l:(g+h)/2}))})}{const l=[202,27,56,180,291,343,120,240,30],c=[];for(let a=0;a<n;a++){const i=l[a%l.length],u=B(s.h,i,.65),g=B(.25,.75,a/Math.max(n-1,1));let h=A({h:u,s:$(s.s,.4,.85),l:g});a>0&&!An(h,_t(c[a-1]))&&(h=A({h:u,s:s.s,l:$(g+.15)})),c.push(z(h))}r.colorBlindSafe=c}{const l=[{name:"background",l:.97,s:.08},{name:"surface",l:.93,s:.12},{name:"border",l:.8,s:.18},{name:"muted",l:.65,s:.25},{name:"default",l:.45,s:s.s},{name:"emphasis",l:.35,s:s.s},{name:"strong",l:.22,s:s.s},{name:"onColor",l:.98,s:.05},{name:"error",l:.4,s:.85,h:0},{name:"success",l:.35,s:.6,h:142}];r.colorTokenized=Array.from({length:n},(c,a)=>{const{h:i,s:u,l:g}=l[a%l.length];return z(A({h:i??s.h,s:u,l:g}))})}{const c=Math.ceil(n/2),a=n-c;r.highContrast=Array.from({length:n},(i,u)=>{if(u<c){const g=u/Math.max(c-1,1),h=B(.05,.28,g),m=$(B(s.s,0,g),0,1);return z(Rt(s.h,m,h,E,7,"dark"))}else{const h=(u-c)/Math.max(a-1,1),m=B(.65,.98,h),f=$(s.s*.7,.2,.8);return z(Rt(s.h,f,m,j,7,"light"))}})}return r},Mt=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4),bt=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,Z=t=>Math.max(0,Math.min(1,t)),K=(t,n,o)=>t+(n-t)*o,$n=({r:t,g:n,b:o})=>{const e=Mt(t),s=Mt(n),r=Mt(o),l=Math.cbrt(.4122214708*e+.5363325363*s+.0514459929*r),c=Math.cbrt(.2119034982*e+.6806995451*s+.1073969566*r),a=Math.cbrt(.0883024619*e+.2817188376*s+.6299787005*r);return{L:.2104542553*l+.793617785*c-.0040720468*a,a:1.9779984951*l-2.428592205*c+.4505937099*a,b:.0259040371*l+.7827717662*c-.808675766*a}},In=({L:t,a:n,b:o})=>{const e=t+.3963377774*n+.2158037573*o,s=t-.1055613458*n-.0638541728*o,r=t-.0894841775*n-1.291485548*o,l=e*e*e,c=s*s*s,a=r*r*r;return{r:Z(bt(4.0767416621*l-3.3077115913*c+.2309699292*a)),g:Z(bt(-1.2684380046*l+2.6097574011*c-.3413193965*a)),b:Z(bt(-.0041960863*l-.7034186147*c+1.707614701*a))}},Sn=({L:t,a:n,b:o})=>({L:t,C:Math.sqrt(n*n+o*o),H:(Math.atan2(o,n)*180/Math.PI+360)%360}),_n=({L:t,C:n,H:o})=>({L:t,a:n*Math.cos(o*Math.PI/180),b:n*Math.sin(o*Math.PI/180)}),wn=t=>({r:parseInt(t.slice(1,3),16)/255,g:parseInt(t.slice(3,5),16)/255,b:parseInt(t.slice(5,7),16)/255}),Pn=({r:t,g:n,b:o})=>{const e=s=>Math.round(s*255).toString(16).padStart(2,"0");return`#${e(t)}${e(n)}${e(o)}`},O=t=>Sn($n(wn(t))),q=t=>Pn(In(_n(t))),$t=(t,n,o)=>{let e=n-t;return e>180&&(e-=360),e<-180&&(e+=360),(t+e*o+360)%360},At=(t,n,o)=>({L:K(t.L,n.L,o),C:K(t.C,n.C,o),H:$t(t.H,n.H,o)}),Rn=(t,n)=>{const o=O(t);return Array.from({length:n},(e,s)=>{const r=s/(n-1);return q({L:K(.92,.25,r),C:o.C,H:o.H})})},vn=(t,n,o)=>{const e=O(t),s=O(n),r={L:.9,C:.02,H:e.H};return Array.from({length:o},(l,c)=>{const a=c/(o-1),i=a*2;if(a<=.5){const u={...e,L:.4};return q(At(u,r,i))}else{const u={...s,L:.4};return q(At(r,u,i-1))}})},On=(t,n)=>{const o=O(t),e=Z(K(.55,.65,.5)),s=Math.max(o.C,.12);return Array.from({length:n},(r,l)=>{const c=(o.H+360/n*l)%360;return q({L:e,C:s,H:c})})},kn=(t,n,o)=>{const e=O(t),s=O(n),r=[{L:.85,C:e.C*.5,H:e.H},{L:.45,C:e.C,H:e.H},{L:.85,C:s.C*.5,H:s.H},{L:.45,C:Math.max(e.C,s.C),H:$t(e.H,s.H,.5)}];return Array.from({length:o},(l,c)=>{const i=c/Math.max(o-1,1)*(r.length-1),u=Math.floor(i),g=Math.min(u+1,r.length-1);return q(At(r[u],r[g],i-u))})},zn=(t,n)=>{const o=O(t),e=Z(o.L>.7?o.L:.62),s=Math.max(o.C,.12);return Array.from({length:n},(r,l)=>{const c=l/n,a=(o.H+360*c)%360;return q({L:e,C:s,H:a})})},Bn=(t,n)=>{const o=O(t),e=(o.H-30+360)%360,s=[0,30,60,120,180,240,280].map(c=>(c+e)%360),r=Math.max(o.C,.14),l=[.45,.6,.8,.72,.62,.5,.42];return Array.from({length:n},(c,a)=>{const u=a/(n-1)*(s.length-1),g=Math.floor(u),h=Math.min(g+1,s.length-1),m=u-g;return q({L:K(l[g],l[h],m),C:r,H:$t(s[g],s[h],m)})})},qn=(t,n)=>{const o=O(t),e=.3,s=.88,r=(s-e)/n;return Array.from({length:n},(l,c)=>{const a=s-r*(c+.5);return q({L:a,C:o.C*.85,H:o.H})})},Dn=(t,n=4)=>{const o=t.square??[],e=o[0]??"#0000ff",s=o[1]??"#ff0000",r=o[2]??"#00ff00";return{sequential:Rn(e,n),diverging:vn(e,r,n),qualitative:On(e,n),bivariate:kn(e,s,n),cyclical:zn(e,n),spectral:Bn(e,n),stepped:qn(e,n)}},Nn=t=>{const n=parseInt(t.slice(1,3),16)/255,o=parseInt(t.slice(3,5),16)/255,e=parseInt(t.slice(5,7),16)/255,s=Math.max(n,o,e),r=Math.min(n,o,e);let l=0,c=0;const a=(s+r)/2;if(s!==r){const i=s-r;switch(c=a>.5?i/(2-s-r):i/(s+r),s){case n:l=(o-e)/i+(o<e?6:0);break;case o:l=(e-n)/i+2;break;case e:l=(n-o)/i+4;break}l/=6}return{h:l*360,s:c*100,l:a*100}},zt=({h:t,s:n,l:o})=>{const e=o/100,r=n/100*Math.min(e,1-e),l=c=>{const a=(c+t/30)%12,i=e-r*Math.max(Math.min(a-3,9-a,1),-1);return Math.round(255*i).toString(16).padStart(2,"0")};return`#${l(0)}${l(8)}${l(4)}`},L=(t,n)=>({...t,h:(t.h+n+360)%360}),En=(t,n=9)=>{const o=Object.values(t).find(a=>Array.isArray(a)&&a.length>0);if(!o||o.length===0)return{};const e=o[0],s=Nn(e),r={analogous:a=>[L(a,-30),a,L(a,30)],complementary:a=>[a,L(a,180)],splitComplementary:a=>[a,L(a,150),L(a,210)],triadic:a=>[a,L(a,120),L(a,240)],tetradic:a=>[a,L(a,60),L(a,180),L(a,240)],square:a=>[a,L(a,90),L(a,180),L(a,270)],accentedAnalogous:a=>[L(a,-30),a,L(a,30),L(a,180)],doubleSplitComplementary:a=>[a,L(a,30),L(a,150),L(a,210),L(a,180),L(a,240)],ambiguous:a=>[L(a,15),L(a,85),L(a,145)]},l={monochromatic:(a,i)=>Array.from({length:i},(u,g)=>({...a,l:Math.max(5,Math.min(95,15+70/(i-1||1)*g))})),monochromaticTintShade:(a,i)=>Array.from({length:i},(u,g)=>({...a,s:Math.max(0,a.s-g*2),l:Math.max(5,Math.min(95,10+80/(i-1||1)*g))}))},c={harmonyPalette:o};return Object.entries(r).forEach(([a,i])=>{c[a]=i(s).map(zt)}),Object.entries(l).forEach(([a,i])=>{c[a]=i(s,n).map(zt)}),c},dt=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4),pt=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,T=t=>Math.max(0,Math.min(1,t)),jn=({r:t,g:n,b:o})=>{const e=dt(t),s=dt(n),r=dt(o),l=Math.cbrt(.4122214708*e+.5363325363*s+.0514459929*r),c=Math.cbrt(.2119034982*e+.6806995451*s+.1073969566*r),a=Math.cbrt(.0883024619*e+.2817188376*s+.6299787005*r);return{L:.2104542553*l+.793617785*c-.0040720468*a,a:1.9779984951*l-2.428592205*c+.4505937099*a,b:.0259040371*l+.7827717662*c-.808675766*a}},Wn=({L:t,a:n,b:o})=>{const e=t+.3963377774*n+.2158037573*o,s=t-.1055613458*n-.0638541728*o,r=t-.0894841775*n-1.291485548*o,l=e*e*e,c=s*s*s,a=r*r*r;return{r:T(pt(4.0767416621*l-3.3077115913*c+.2309699292*a)),g:T(pt(-1.2684380046*l+2.6097574011*c-.3413193965*a)),b:T(pt(-.0041960863*l-.7034186147*c+1.707614701*a))}},tt=(t,n)=>(t.L-n.L)**2+(t.a-n.a)**2+(t.b-n.b)**2,Y=t=>Math.sqrt(t.a*t.a+t.b*t.b),Yn=t=>({r:parseInt(t.slice(1,3),16)/255,g:parseInt(t.slice(3,5),16)/255,b:parseInt(t.slice(5,7),16)/255}),rt=({r:t,g:n,b:o})=>{const e=s=>Math.round(s*255).toString(16).padStart(2,"0");return`#${e(t)}${e(n)}${e(o)}`},N=t=>rt(Wn(t)),U=(t,n)=>{if(t.length>=n)return t.slice(0,n);const o=[...t],e=t[t.length-1]??{L:.5,a:0,b:0};for(;o.length<n;){const s=o.length/n;o.push({...e,L:T(.2+s*.6)})}return o},ct=(t,n)=>{if(t.length>=n)return t.slice(0,n);const o=[...t];for(;o.length<n;){const e=o.length/n;o.push({r:e,g:e,b:e})}return o},Fn=(t,n=6e3)=>{const o=Math.max(1,Math.floor(t.length/4/n)),e=[],s=[];for(let r=0;r<t.length;r+=4*o){if(t[r+3]<128)continue;const l={r:t[r]/255,g:t[r+1]/255,b:t[r+2]/255};e.push(l),s.push(jn(l))}return{rgbs:e,labs:s}},Gn=t=>{const o=new Uint8ClampedArray(t.length*800*4);let e=0;for(const s of t){const r=Yn(s);for(let l=0;l<800;l++){const c=()=>(Math.random()-.5)*30;o[e++]=Math.round(T(r.r)*255+c()),o[e++]=Math.round(T(r.g)*255+c()),o[e++]=Math.round(T(r.b)*255+c()),o[e++]=255}}return o},ut=(t,n,o=25)=>{if(t.length===0)return[];const e=t.filter(i=>{const u=Y(i);return Math.random()<=(u<.05?.2:u<.15?.6:1)}),s=e.length>=n?e:t,r=s.length,l=[s[Math.floor(Math.random()*r)]];for(let i=1;i<n;i++){const u=s.map(f=>Math.min(...l.map(b=>tt(f,b)))),g=u.reduce((f,b)=>f+b,0);let h=Math.random()*g,m=0;for(let f=0;f<r;f++)if(h-=u[f],h<=0){m=f;break}l.push({...s[m]})}const c=new Int32Array(r);for(let i=0;i<o;i++){let u=!1;for(let h=0;h<r;h++){let m=0,f=1/0;for(let b=0;b<n;b++){const M=tt(s[h],l[b]);M<f&&(f=M,m=b)}c[h]!==m&&(c[h]=m,u=!0)}if(!u)break;const g=Array.from({length:n},()=>({L:0,a:0,b:0,count:0}));for(let h=0;h<r;h++){const m=c[h];g[m].L+=s[h].L,g[m].a+=s[h].a,g[m].b+=s[h].b,g[m].count++}for(let h=0;h<n;h++)g[h].count>0&&(l[h]={L:g[h].L/g[h].count,a:g[h].a/g[h].count,b:g[h].b/g[h].count})}const a=new Array(n).fill(0);for(let i=0;i<r;i++)a[c[i]]++;return U(l.map((i,u)=>({lab:i,score:a[u]*(1+3*Y(i))})).sort((i,u)=>u.score-i.score).map(i=>i.lab),n)},Xn=(t,n)=>{if(t.length===0)return ct([],n);const o=[{pixels:[...t]}],e=s=>{let r=1,l=0,c=1,a=0,i=1,u=0;for(const m of s.pixels)r=Math.min(r,m.r),l=Math.max(l,m.r),c=Math.min(c,m.g),a=Math.max(a,m.g),i=Math.min(i,m.b),u=Math.max(u,m.b);const g=l-r>=a-c&&l-r>=u-i?"r":a-c>=u-i?"g":"b";s.pixels.sort((m,f)=>m[g]-f[g]);const h=Math.floor(s.pixels.length/2);return[{pixels:s.pixels.slice(0,h)},{pixels:s.pixels.slice(h)}]};for(;o.length<n&&(o.sort((l,c)=>c.pixels.length-l.pixels.length),!(o[0].pixels.length<2));){const[s,r]=e(o.shift());o.push(s,r)}return ct(o.map(s=>{const r=s.pixels.length;return{r:s.pixels.reduce((l,c)=>l+c.r,0)/r,g:s.pixels.reduce((l,c)=>l+c.g,0)/r,b:s.pixels.reduce((l,c)=>l+c.b,0)/r}}),n)},Vn=(t,n)=>{const o=new Map;for(const e of t){const s=Math.round(e.r*7)/7,r=Math.round(e.g*7)/7,l=Math.round(e.b*7)/7,c=`${s},${r},${l}`,a=o.get(c);a?a.count++:o.set(c,{rgb:{r:s,g:r,b:l},count:1})}return ct(Array.from(o.values()).sort((e,s)=>s.count-e.count).slice(0,n).map(e=>e.rgb),n)},Qn=(t,n)=>{const o=t.filter(e=>Y(e)>.1&&e.L>.25&&e.L<.85);return ut(o.length>=n?o:t,n)},Un=(t,n)=>{const o=t.filter(e=>{const s=Y(e);return s>=.02&&s<=.09&&e.L>.2&&e.L<.9});return ut(o.length>=n?o:t,n)},Jn=(t,n)=>{const o=()=>({r:0,g:0,b:0,count:0,children:new Array(8).fill(null),isLeaf:!1}),e=o(),s=(c,a,i,u,g)=>{if(g===8){c.isLeaf=!0,c.r+=a,c.g+=i,c.b+=u,c.count++;return}const h=7-g,m=(a>>h&1)<<2|(i>>h&1)<<1|u>>h&1;c.children[m]||(c.children[m]=o()),s(c.children[m],a,i,u,g+1)},r=c=>c.isLeaf&&c.count>0?[c]:c.children.filter(Boolean).flatMap(a=>r(a));for(const c of t)s(e,Math.round(c.r*255),Math.round(c.g*255),Math.round(c.b*255),0);let l=r(e);for(;l.length>n;)l.sort((c,a)=>c.count-a.count),l[0].count=0,l=r(e);return ct(l.filter(c=>c.count>0).sort((c,a)=>a.count-c.count).slice(0,n).map(c=>({r:T(c.r/c.count/255),g:T(c.g/c.count/255),b:T(c.b/c.count/255)})),n)},Zn=(t,n)=>{if(t.length===0)return U([],n);const o=t.length,e=t.reduce((h,m)=>h+m.L,0)/o,s=t.reduce((h,m)=>h+m.a,0)/o,r=t.reduce((h,m)=>h+m.b,0)/o,l=Math.sqrt(t.reduce((h,m)=>h+(m.L-e)**2,0)/o),c=Math.sqrt(t.reduce((h,m)=>h+(m.a-s)**2,0)/o),a=Math.sqrt(t.reduce((h,m)=>h+(m.b-r)**2,0)/o),i=Math.cbrt(t.reduce((h,m)=>h+(m.L-e)**3,0)/o),u=Math.cbrt(t.reduce((h,m)=>h+(m.a-s)**3,0)/o),g=Math.cbrt(t.reduce((h,m)=>h+(m.b-r)**3,0)/o);return Array.from({length:n},(h,m)=>{const f=n===1?0:m/(n-1)*2-1;return{L:T(e+f*l+(f*f-1/3)*i*.3),a:T(s+f*c+(f*f-1/3)*u*.3),b:T(r+f*a+(f*f-1/3)*g*.3)}})},Kn=(t,n)=>{if(t.length<n)return U(ut(t,t.length),n);const o=Array.from({length:n},(c,a)=>({...t[Math.floor(a/n*t.length)]})),e=.4,s=Math.min(t.length,4e3),r=Math.max(1,Math.floor(t.length/s));for(let c=0;c<s;c++){const a=t[c*r%t.length],i=e*(1-c/s);let u=0,g=1/0;for(let m=0;m<n;m++){const f=tt(a,o[m]);f<g&&(g=f,u=m)}const h=Math.max(1,Math.round(n/4*(1-c/s)));for(let m=0;m<n;m++){const f=Math.abs(m-u);if(f>h)continue;const b=i*Math.exp(-(f*f)/(2*h*h));o[m].L+=b*(a.L-o[m].L),o[m].a+=b*(a.a-o[m].a),o[m].b+=b*(a.b-o[m].b)}}const l=[];for(const c of o)l.some(a=>tt(a,c)<5e-4)||l.push(c);return U(l,n)},to=(t,n)=>{const e=Array.from({length:72},()=>({sumL:0,sumC:0,count:0}));for(const u of t){const g=(Math.atan2(u.b,u.a)*180/Math.PI+360)%360,h=Math.floor(g/(360/72))%72;e[h].sumL+=u.L,e[h].sumC+=Y(u),e[h].count++}const s=e.map((u,g)=>({count:(e[(g-1+72)%72].count+e[g].count+e[(g+1)%72].count)/3,idx:g})),r=[];for(let u=0;u<72;u++)s[u].count>s[(u-1+72)%72].count&&s[u].count>=s[(u+1)%72].count&&e[u].count>0&&r.push(u);r.sort((u,g)=>s[g].count-s[u].count);const l=r.slice(0,n),c=[...s].sort((u,g)=>g.count-u.count);let a=0;for(;l.length<n&&a<72;)!l.includes(c[a].idx)&&e[c[a].idx].count>0&&l.push(c[a].idx),a++;let i=0;for(;l.length<n;)l.push(i),i+=Math.floor(72/n);return l.slice(0,n).map(u=>{const g=u/72*360+2.5,h=e[u].count>0?e[u].sumL/e[u].count:.5,m=e[u].count>0?e[u].sumC/e[u].count:.12,f=g*Math.PI/180;return{L:h,a:m*Math.cos(f),b:m*Math.sin(f)}})},no=(t,n)=>{if(t.length===0)return U([],n);const e=Math.max(1,Math.floor(t.length/2e3)),s=t.filter((c,a)=>a%e===0),l=[s.reduce((c,a)=>Y(a)>Y(c)?a:c)];for(;l.length<n;){let c=s[0],a=-1/0;for(const i of s){const u=l.reduce((g,h)=>Math.min(g,tt(i,h)),1/0);u>a&&(a=u,c=i)}if(a===0)break;l.push(c)}return U(l,n)},oo=(t,n=6,o)=>{const e=o??Gn(t.square??["#888888"]),{rgbs:s,labs:r}=Fn(e);if(r.length===0){const l=Array(n).fill("#000000");return{kmeans:l,medianCut:l,dominant:l,vibrant:l,muted:l,octree:l,colorMoments:l,neuralQuant:l,histogram:l,deltaE:l}}return{kmeans:ut(r,n).map(N),medianCut:Xn(s,n).map(rt),dominant:Vn(s,n).map(rt),vibrant:Qn(r,n).map(N),muted:Un(r,n).map(N),octree:Jn(s,n).map(rt),colorMoments:Zn(r,n).map(N),neuralQuant:Kn(r,n).map(N),histogram:to(r,n).map(N),deltaE:no(r,n).map(N)}},Lt=t=>{const n=parseInt(t.slice(1,3),16)/255,o=parseInt(t.slice(3,5),16)/255,e=parseInt(t.slice(5,7),16)/255;return{r:n,g:o,b:e}},eo=({r:t,g:n,b:o})=>{const e=s=>Math.max(0,Math.min(255,Math.round(s*255))).toString(16).padStart(2,"0");return`#${e(t)}${e(n)}${e(o)}`},I=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4),v=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,x=(t,n,o)=>t+(n-t)*o,Ct=(t,n,o)=>{const e=n-t,s=e>180?e-360:e<-180?e+360:e;return(t+s*o+360)%360},nt=t=>{const n=I(t.r),o=I(t.g),e=I(t.b),s=.4122*n+.5363*o+.0514*e,r=.2119*n+.6807*o+.1074*e,l=.0883*n+.2817*o+.63*e,c=Math.cbrt(s),a=Math.cbrt(r),i=Math.cbrt(l);return{L:.2104*c+.7936*a-.004*i,a:1.9779*c-2.4285*a+.4505*i,b:.0259*c+.7827*a-.8086*i}},Bt=t=>{const n=t.L+.3963*t.a+.2158*t.b,o=t.L-.1055*t.a-.0638*t.b,e=t.L-.0894*t.a-1.2914*t.b,s=n*n*n,r=o*o*o,l=e*e*e,c=4.0767*s-3.3077*r+.2309*l,a=-1.2684*s+2.6097*r-.3413*l,i=-.0041*s-.7034*r+1.7076*l;return{r:v(c),g:v(a),b:v(i)}},ot=t=>{const n=I(t.r),o=I(t.g),e=I(t.b),s=(.4124*n+.3575*o+.1804*e)/.9504,r=.2126*n+.7151*o+.0721*e,l=(.0193*n+.1191*o+.9503*e)/1.0888,c=a=>a>.008856?Math.pow(a,1/3):7.787*a+16/116;return{L:116*c(r)-16,a:500*(c(s)-c(r)),b:200*(c(r)-c(l))}},qt=t=>{const n=(t.L+16)/116,o=t.a/500+n,e=n-t.b/200,s=g=>g>.20689?g*g*g:(g-16/116)/7.787,r=s(o)*.9504,l=s(n),c=s(e)*1.0888,a=3.2404*r-1.5371*l-.4985*c,i=-.9692*r+1.8759*l+.0415*c,u=.0556*r-.204*l+1.0572*c;return{r:v(a),g:v(i),b:v(u)}},Dt=t=>{const n=Math.max(t.r,t.g,t.b),o=Math.min(t.r,t.g,t.b),e=n-o;let s=0;return e!==0&&(n===t.r?s=(t.g-t.b)/e+(t.g<t.b?6:0):n===t.g?s=(t.b-t.r)/e+2:s=(t.r-t.g)/e+4),{h:s*60,s:n===0?0:e/n,v:n}},so=({h:t,s:n,v:o})=>{const e=Math.floor(t/60)%6,s=t/60-e,r=o*(1-n),l=o*(1-s*n),c=o*(1-(1-s)*n);switch(e){case 0:return{r:o,g:c,b:r};case 1:return{r:l,g:o,b:r};case 2:return{r,g:o,b:c};case 3:return{r,g:l,b:o};case 4:return{r:c,g:r,b:o};default:return{r:o,g:r,b:l}}},ro=(t,n=9)=>{const o=Object.values(t).find(l=>Array.isArray(l));if(!o||o.length<1)return{};const e=o.length===1?[Lt(o[0]),Lt("#ffffff")]:o.map(Lt),s={};return["lab","lch","oklab","oklch","hct","cam16","hsl","hsv","jzazbz","ipt"].forEach(l=>{const c=[];for(let a=0;a<n;a++){const u=a/(n-1)*(e.length-1),g=Math.min(Math.floor(u),e.length-2),h=u-g,m=e[g],f=e[g+1];let b;switch(l){case"oklab":{const M=nt(m),p=nt(f);b=Bt({L:x(M.L,p.L,h),a:x(M.a,p.a,h),b:x(M.b,p.b,h)});break}case"oklch":{const M=nt(m),p=nt(f),F=Math.atan2(M.b,M.a)*180/Math.PI,P=Math.atan2(p.b,p.a)*180/Math.PI,d=Math.sqrt(M.a**2+M.b**2),C=Math.sqrt(p.a**2+p.b**2),S=Ct(F,P,h)*Math.PI/180,w=x(d,C,h);b=Bt({L:x(M.L,p.L,h),a:w*Math.cos(S),b:w*Math.sin(S)});break}case"lab":{const M=ot(m),p=ot(f);b=qt({L:x(M.L,p.L,h),a:x(M.a,p.a,h),b:x(M.b,p.b,h)});break}case"lch":{const M=ot(m),p=ot(f),F=Math.atan2(M.b,M.a)*180/Math.PI,P=Math.atan2(p.b,p.a)*180/Math.PI,d=Math.sqrt(M.a**2+M.b**2),C=Math.sqrt(p.a**2+p.b**2),S=Ct(F,P,h)*Math.PI/180,w=x(d,C,h);b=qt({L:x(M.L,p.L,h),a:w*Math.cos(S),b:w*Math.sin(S)});break}case"hsl":case"hsv":{const M=Dt(m),p=Dt(f);b=so({h:Ct(M.h,p.h,h),s:x(M.s,p.s,h),v:x(M.v,p.v,h)});break}case"ipt":case"jzazbz":case"cam16":case"hct":{b={r:v(x(I(m.r),I(f.r),h)),g:v(x(I(m.g),I(f.g),h)),b:v(x(I(m.b),I(f.b),h))};const M=Math.sin(Math.PI*h)*(l==="jzazbz"?.05:.02);b.r=Math.min(1,b.r+M);break}default:b={r:x(m.r,f.r,h),g:x(m.g,f.g,h),b:x(m.b,f.b,h)}}c.push(eo(b))}s[l]=c}),s},V=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4),xt=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,W=t=>Math.max(0,Math.min(1,t)),Jt=(t,n,o)=>t+(n-t)*o,It=t=>({r:parseInt(t.slice(1,3),16)/255,g:parseInt(t.slice(3,5),16)/255,b:parseInt(t.slice(5,7),16)/255}),Nt=({r:t,g:n,b:o})=>{const e=s=>Math.round(W(s)*255).toString(16).padStart(2,"0");return`#${e(t)}${e(n)}${e(o)}`},ao=({r:t,g:n,b:o})=>{const e=V(t),s=V(n),r=V(o),l=Math.cbrt(.4122214708*e+.5363325363*s+.0514459929*r),c=Math.cbrt(.2119034982*e+.6806995451*s+.1073969566*r),a=Math.cbrt(.0883024619*e+.2817188376*s+.6299787005*r);return{L:.2104542553*l+.793617785*c-.0040720468*a,a:1.9779984951*l-2.428592205*c+.4505937099*a,b:.0259040371*l+.7827717662*c-.808675766*a}},Tt=({L:t,a:n,b:o})=>{const e=t+.3963377774*n+.2158037573*o,s=t-.1055613458*n-.0638541728*o,r=t-.0894841775*n-1.291485548*o,l=e*e*e,c=s*s*s,a=r*r*r;return{r:xt(4.0767416621*l-3.3077115913*c+.2309699292*a),g:xt(-1.2684380046*l+2.6097574011*c-.3413193965*a),b:xt(-.0041960863*l-.7034186147*c+1.707614701*a)}},Et=t=>{const{r:n,g:o,b:e}=Tt(t);return{r:W(n),g:W(o),b:W(e)}},co=({L:t,a:n,b:o})=>({L:t,C:Math.sqrt(n*n+o*o),H:(Math.atan2(o,n)*180/Math.PI+360)%360}),et=({L:t,C:n,H:o})=>({L:t,a:n*Math.cos(o*Math.PI/180),b:n*Math.sin(o*Math.PI/180)}),lo=t=>co(ao(It(t))),J=t=>{const n=r=>r.r>=-.001&&r.r<=1.001&&r.g>=-.001&&r.g<=1.001&&r.b>=-.001&&r.b<=1.001,o=Tt(et(t));if(n(o))return Nt(Et(et(t)));let e=0,s=t.C;for(let r=0;r<24;r++){const l=(e+s)/2;n(Tt(et({...t,C:l})))?e=l:s=l}return Nt(Et(et({...t,C:e})))},ho={harmonypalette:[0,150,210],analogous:[-30,0,30],complementary:[0,180],splitcomplementary:[0,150,210],triadic:[0,120,240],tetradic:[0,60,180,240],square:[0,90,180,270],accentedanalogous:[-30,0,30,180],doublesplitcomplementary:[0,30,150,180,210,330],ambiguous:[15,135,255]},io=[{match:t=>t.includes("neutrallight")||t.includes("neutral")&&t.includes("light"),apply:t=>({...t,L:.93,C:Math.min(t.C*.08,.015)})},{match:t=>t.includes("neutraldark")||t.includes("neutral")&&t.includes("dark"),apply:t=>({...t,L:.1,C:Math.min(t.C*.08,.015)})},{match:t=>t.includes("neutral"),apply:t=>({...t,L:.55,C:Math.min(t.C*.06,.012)})},{match:t=>t.endsWith("shade")||t.includes("colorshade"),apply:t=>({...t,L:.3,C:t.C})},{match:t=>t.endsWith("dark"),apply:t=>({...t,L:.22,C:t.C})},{match:t=>t.endsWith("light")||t.endsWith("tint"),apply:t=>({...t,L:.88,C:t.C*.5})},{match:t=>t.startsWith("accent"),apply:t=>({...t,L:.62,C:Math.max(t.C,.22)})},{match:t=>t.startsWith("main")||t.startsWith("primary")||t.startsWith("brand"),apply:t=>({...t,L:.52,C:Math.max(t.C,.22)})},{match:t=>t.startsWith("background")||t.startsWith("bg"),apply:t=>({...t,L:.97,C:Math.min(t.C*.08,.012)})},{match:t=>t.startsWith("surface"),apply:t=>({...t,L:.91,C:Math.min(t.C*.18,.025)})},{match:t=>t.startsWith("foreground")||t.startsWith("text")||t.startsWith("on"),apply:t=>({...t,L:.18,C:Math.min(t.C*.12,.02)})}],uo=(t,n,o)=>{const e=t.toLowerCase().replace(/[^a-z]/g,"");if(o>1){if(e.includes("tintshade"))return jt(n,o);if(e.includes("monochromatic"))return fo(n,o);if(e.includes("tint")||e.includes("shade"))return jt(n,o);const s=ho[e];return s?mo(n,s,o):go(n,o)}for(const{match:s,apply:r}of io)if(s(e))return[J(r(n))];return[J({...n,L:.55,C:Math.max(n.C,.18)})]},mo=(t,n,o)=>Array.from({length:o},(e,s)=>{const r=n[s%n.length],l=Math.floor(s/n.length)*.08;return J({...t,L:W(t.L-l),H:(t.H+r+360)%360})}),go=(t,n)=>Array.from({length:n},(o,e)=>J({...t,H:(t.H+360/n*e)%360})),fo=(t,n)=>Array.from({length:n},(o,e)=>{const s=e/Math.max(n-1,1),r=Jt(.12,.94,s),l=t.C*W(1-Math.pow(Math.abs(s-.45),2.5));return J({L:r,C:l,H:t.H})}),jt=(t,n)=>Array.from({length:n},(o,e)=>{const s=e/Math.max(n-1,1),r=s<.5?.5*Math.pow(s*2,1.6):1-.5*Math.pow((1-s)*2,1.4),l=Jt(.1,.96,r),c=t.C*W(1-Math.pow((s-.4)/.7,2)*.6);return J({L:l,C:c,H:t.H})}),Mo=/^#[0-9a-fA-F]{6}$/,bo=t=>{for(const n of t)if(Mo.test(n))return n;return"#ff0000"},po=t=>Object.fromEntries(Object.entries(t).map(([n,o])=>{const e=bo(o),s=lo(e);return[n,uo(n,s,o.length)]})),Zt=t=>{const{r:n,g:o,b:e}=It(t);return{r:Math.round(n*255),g:Math.round(o*255),b:Math.round(e*255)}},Lo=(t,n=1)=>{const{r:o,g:e,b:s}=Zt(t);return`rgba(${o}, ${e}, ${s}, ${n})`},lt=t=>{const{r:n,g:o,b:e}=It(t);return .2126*V(n)+.7152*V(o)+.0722*V(e)},Co=(t,n)=>{const o=lt(t),e=lt(n);return(Math.max(o,e)+.05)/(Math.min(o,e)+.05)},xo=t=>lt(t)>.179?"#000000":"#ffffff",Q=t=>t<=.04045?t/12.92:((t+.055)/1.055)**2.4,Ht=t=>t<=.0031308?12.92*t:1.055*t**(1/2.4)-.055,at=t=>t<0?0:t>1?1:t,Ho=(t,n,o)=>{const e=Q(t),s=Q(n),r=Q(o),l=Math.cbrt(.4122214708*e+.5363325363*s+.0514459929*r),c=Math.cbrt(.2119034982*e+.6806995451*s+.1073969566*r),a=Math.cbrt(.0883024619*e+.2817188376*s+.6299787005*r);return{L:.2104542553*l+.793617785*c-.0040720468*a,a:1.9779984951*l-2.428592205*c+.4505937099*a,b:.0259040371*l+.7827717662*c-.808675766*a}},yo=(t,n,o)=>{const e=t+.3963377774*n+.2158037573*o,s=t-.1055613458*n-.0638541728*o,r=t-.0894841775*n-1.291485548*o,l=e*e*e,c=s*s*s,a=r*r*r;return{r:at(Ht(4.0767416621*l-3.3077115913*c+.2309699292*a)),g:at(Ht(-1.2684380046*l+2.6097574011*c-.3413193965*a)),b:at(Ht(-.0041960863*l-.7034186147*c+1.707614701*a))}},Kt=t=>{if(typeof t!="string")throw new TypeError(`Color must be a string, got ${typeof t}: ${JSON.stringify(t)}`);const n=t.trim().replace(/^#/,"").toLowerCase();if(/^[0-9a-f]{3}$/.test(n))return"#"+n[0]+n[0]+n[1]+n[1]+n[2]+n[2];if(/^[0-9a-f]{6}$/.test(n))return"#"+n;throw new RangeError(`Invalid hex color: "${t}" — expected "#rgb" or "#rrggbb"`)},tn=t=>({r:parseInt(t.slice(1,3),16)/255,g:parseInt(t.slice(3,5),16)/255,b:parseInt(t.slice(5,7),16)/255}),Ao=(t,n,o)=>{const e=s=>Math.round(at(s)*255).toString(16).padStart(2,"0");return`#${e(t)}${e(n)}${e(o)}`},Wt=t=>{const{r:n,g:o,b:e}=tn(t),s=Ho(n,o,e);return{L:s.L,C:Math.sqrt(s.a*s.a+s.b*s.b),H:(Math.atan2(s.b,s.a)*180/Math.PI+360)%360}},yt=(t,n,o)=>{const e=o*Math.PI/180,{r:s,g:r,b:l}=yo(t,n*Math.cos(e),n*Math.sin(e));return Ao(s,r,l)},Yt=(t,n)=>{const o=Math.abs(t-n)%360;return o>180?360-o:o},ht=(t,n)=>{const o=r=>{const{r:l,g:c,b:a}=tn(Kt(r));return .2126*Q(l)+.7152*Q(c)+.0722*Q(a)},e=o(t),s=o(n);return(Math.max(e,s)+.05)/(Math.min(e,s)+.05)},nn=t=>ht(t,"#ffffff")>=ht(t,"#111111")?"#ffffff":"#111111";function To(t,n={}){if(!Array.isArray(t)||t.length===0)throw new TypeError("palette must be a non-empty array of hex color strings");const o={neutralChromaMax:n.neutralChromaMax??.06,mainLightnessMin:n.mainLightnessMin??.4,mainLightnessMax:n.mainLightnessMax??.72,shadeHueTolerance:n.shadeHueTolerance??30,accentHueMin:n.accentHueMin??100,derivedDarkL:n.derivedDarkL??.2,derivedDarkC:n.derivedDarkC??.035},e=t.map(d=>{const C=Kt(d);return{hex:C,lch:Wt(C)}}),s=e.filter(d=>d.lch.C<o.neutralChromaMax),r=(s.length>0?s:e).slice().sort((d,C)=>C.lch.L-d.lch.L)[0],l=e.filter(d=>d.lch.L>=o.mainLightnessMin&&d.lch.L<=o.mainLightnessMax),c=(l.length>0?l:e).slice().sort((d,C)=>C.lch.C-d.lch.C)[0],a=s.filter(d=>d.lch.L<.35&&d.hex!==r.hex);let i,u;a.length>0?(i=a.slice().sort((d,C)=>d.lch.L-C.lch.L)[0].hex,u=!1):(i=yt(o.derivedDarkL,o.derivedDarkC,c.lch.H),u=!0);const g=new Set([r.hex,c.hex]),h=e.filter(d=>!g.has(d.hex));let m,f=!1;if(h.length>0){const d=h.filter(C=>Yt(C.lch.H,c.lch.H)<o.shadeHueTolerance&&C.lch.C>.1);m=(d.length>0?d:h).slice().sort((C,S)=>S.lch.C-C.lch.C)[0].hex}else m=yt(Math.max(.05,c.lch.L-.08),c.lch.C*.92,c.lch.H),f=!0;const b=new Set([r.hex,c.hex,m]),M=e.filter(d=>!b.has(d.hex));let p,F=!1;if(M.length>0){const d=M.filter(C=>Yt(C.lch.H,c.lch.H)>=o.accentHueMin);p=(d.length>0?d:M).slice().sort((C,S)=>S.lch.C-C.lch.C)[0].hex}else p=yt(.72,Math.min(c.lch.C,.18),(c.lch.H+150)%360),F=!0;const P=(d,C,S,w,on=!1)=>({hex:w,role:d,label:C,weight:S,derived:on,lch:Wt(w),textColor:nn(w),contrast:parseFloat(ht(w,r.hex).toFixed(2))});return{neutralLight:P("neutralLight","Neutral Light","60%",r.hex),neutralDark:P("neutralDark","Neutral Dark","—",i,u),mainColor:P("mainColor","Main Color","30%",c.hex),mainColorShade:P("mainColorShade","Main Color Shade","—",m,f),accentColor:P("accentColor","Accent Color","10%",p,F)}}const $o=t=>[t.neutralLight.hex,t.neutralDark.hex,t.mainColor.hex,t.mainColorShade.hex,t.accentColor.hex],Io=t=>({neutralLight:t.neutralLight.hex,neutralDark:t.neutralDark.hex,mainColor:t.mainColor.hex,mainColorShade:t.mainColorShade.hex,accentColor:t.accentColor.hex}),So=(t,n="--color")=>{const o=[["neutral-light",t.neutralLight.hex],["neutral-dark",t.neutralDark.hex],["main",t.mainColor.hex],["main-shade",t.mainColorShade.hex],["accent",t.accentColor.hex]],e=Math.max(...o.map(([r])=>(n+"-"+r).length));return`:root {
2
+ ${o.map(([r,l])=>` ${(n+"-"+r).padEnd(e)}: ${l};`).join(`
3
+ `)}
4
+ }`};exports.bestTextOn=nn;exports.generateAlgorithmic=Hn;exports.generateContrastPalettes=Tn;exports.generateDataVisuals=Dn;exports.generateHarmonyPalettes=En;exports.generateImagePalettes=oo;exports.generatePerceptualPalettes=ro;exports.generateRadiumColors=po;exports.getContrastRatio=Co;exports.getLuminance=lt;exports.getReadableTextColor=xo;exports.hexToRgb=Zt;exports.hexToRgba=Lo;exports.select60_30_10=To;exports.toCssVars=So;exports.toHexArray=$o;exports.toObject=Io;exports.wcagContrast=ht;