chromametry 0.2.0 → 0.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.
package/README.md CHANGED
@@ -1,155 +1,236 @@
1
- # Chromametry
2
- > A metrics framework for evaluating web-accessible sequential color palettes.
3
-
4
-
5
- ![Web-accessible Palette Ranking](paper/figures/web-accessible-palette-ranking.png)
6
- *Figure 1. Web-accessible Palette Ranking*
7
-
8
- ## Metric Definitions
9
-
10
- 1. **Contrast Efficiency:** Measures how efficiently contrast space is used to achieve WCAG 4.5:1 contrast.
11
- 2. **Lightness Linearity:** Evaluates the linearity of lightness (with Helmholtz–Kohlrausch correction).
12
- 3. **Chroma Smoothness:** Checks for artifacts and kinks in the saturation curve using Monotone Cubic Splines.
13
- 4. **Hue Stability:** Quantifies hue shift/drift across the lightness ramp.
14
- 5. **Spacing Uniformity:** Measures the consistency of color spacing (DeltaE 2000).
15
- >[Read full Methodology](https://github.com/chromametry/paper/paper.pdf)
16
-
17
- > All lightness, chroma, hue, and DeltaE2000 computations are performed in the CIELAB color space.
18
-
19
- ## Benchmark Rankings
20
-
21
- Comparison of popular design systems based on Chromametry metrics.
22
-
23
- | Rank | Design System | Steps | Span (K) | Contrast Efficiency | Lightness Linearity | Chroma Smoothness | Hue Stability | Spacing Uniformity | **SCORE** |
24
- | :---: | :------------------------- | :---: | :--------: | :-----------------: | :-----------------: | :---------------: | :-----------: | :----------------: | :-------: |
25
- | 🥇 | **IBM Carbon** | 12 | 6 | 0.906 | 0.932 | 0.864 | 0.930 | 0.794 | **88.36** |
26
- | 🥈 | **Adobe Spectrum** | 18 | 9 | 0.929 | 0.935 | 0.871 | 0.917 | 0.775 | **88.33** |
27
- | 🥉 | **U.S. Web Design System** | 12 | 6 | 0.906 | 0.936 | 0.805 | 0.942 | 0.801 | **87.58** |
28
- | 4 | Salesforce Lightning 2 | 14 | 7 | 0.916 | 0.921 | 0.839 | 0.938 | 0.712 | **86.06** |
29
- | 5 | GitHub Primer Brand | 12 | 6 | 0.906 | 0.926 | 0.838 | 0.946 | 0.685 | **85.43** |
30
- | 6 | Atlassian | 14 | 8 | 0.785 | 0.897 | 0.914 | 0.950 | 0.714 | **84.72** |
31
- | 7 | Tailwind CSS | 13 | 8 | 0.774 | 0.873 | 0.849 | 0.918 | 0.677 | **81.37** |
32
- | 8 | Ant Design | 12 | 9 | 0.698 | 0.860 | 0.861 | 0.913 | 0.656 | **79.08** |
33
- | 9 | Material UI | 12 | 11 | 0.554 | 0.797 | 0.773 | 0.931 | 0.550 | **70.56** |
34
- | 10 | Radix UI | 13 | 10 | 0.533 | 0.800 | 0.745 | 0.947 | 0.520 | **68.98** |
35
- | 11 | Shopify Polaris | 17 | 15 | 0.349 | 0.730 | 0.642 | 0.920 | 0.467 | **58.78** |
36
-
37
- *Table 1. Benchmark ranking of design systems evaluated using Chromametry metrics.*
38
-
39
- > **Note:** Design systems like Bootstrap,Google Material 3, Apple Human Interface or Fluent UI are excluded as they define discrete semantic tokens rather than algorithmic sequential ramps.
40
-
41
- > **Overall Score** is computed as the weighted mean of the five normalized metrics, using equal weights by default.
42
-
43
- ### Example: A Typical Report
44
-
45
- ![Adobe Spectrum Color Palette](paper/figures/adobe-spectrum-color-palette.png)
46
- *Figure 2. Adobe Spectrum Color Palette.*
47
-
48
- ![IBM Carbon Palette Metrics](paper/figures/adobe-spectrum-palette-metrics.png)
49
- *Figure 3. Adobe Spectrum Palette Metrics.*
50
-
51
- ![IBM Carbon Palette Charts](paper/figures/adobe-spectrum-palette-charts.png)
52
- *Figure 4. Adobe Spectrum Palette Charts.*
53
-
54
- ## Benchmark result page
55
-
56
- - Online Report : [Benchmark page](https://github.com/chromametry/benchmarks/monochromatic)
57
- - Local `/benchmarks/monochromatic/output/index.html` (double click)
58
-
59
- ## Analyze Palettes
1
+ # Chromametry
2
+ > A metrics framework for evaluating web-accessible sequential color palettes.
3
+
4
+
5
+ ![Web-accessible Palette Ranking](paper/figures/web-accessible-palette-ranking.png)
6
+ *Figure 1. Web-accessible Palette Ranking*
7
+
8
+ ## Metric Definitions
9
+
10
+ 1. **Contrast Efficiency:** Measures how efficiently contrast space is used to achieve WCAG 4.5:1 contrast.
11
+ 2. **Lightness Linearity:** Evaluates the linearity of lightness (with Helmholtz–Kohlrausch correction).
12
+ 3. **Chroma Smoothness:** Checks for artifacts and kinks in the saturation curve using Monotone Cubic Splines.
13
+ 4. **Hue Stability:** Quantifies hue shift/drift across the lightness ramp.
14
+ 5. **Spacing Uniformity:** Measures the consistency of color spacing (DeltaE 2000).
15
+
16
+
17
+ >[Read full paper](paper/paper.pdf)
18
+
19
+ > All lightness, chroma, hue, and DeltaE2000 computations are performed in the CIELAB color space.
20
+
21
+ ## Benchmark Rankings
22
+
23
+ Comparison of popular design systems based on Chromametry metrics.
24
+ | Design System | Steps | Span (K) | Contrast Efficiency | Lightness Linearity | Chroma Smoothness | Hue Stability | Spacing Uniformity | **SCORE** |
25
+ | :--------------------- | :---: | :------: | :-----------------: | :-----------------: | :---------------: | :-----------: | :----------------: | :-------: |
26
+ | Adobe Spectrum | 18 | 9 | 0.947 | 0.9333 | 0.8786 | 0.9138 | 0.7722 | **88.67** |
27
+ | IBM Carbon | 12 | 6 | 0.923 | 0.9303 | 0.8688 | 0.9252 | 0.7919 | **88.62** |
28
+ | U.S. Web Design System | 12 | 6 | 0.923 | 0.9359 | 0.8096 | 0.9380 | 0.7997 | **87.90** |
29
+ | Salesforce Lightning 2 | 14 | 7 | 0.933 | 0.9187 | 0.8464 | 0.9372 | 0.7107 | **86.47** |
30
+ | GitHub Primer Brand | 12 | 6 | 0.923 | 0.9243 | 0.8405 | 0.9408 | 0.6841 | **85.67** |
31
+ | Atlassian | 14 | 8 | 0.800 | 0.8964 | 0.9094 | 0.9465 | 0.7129 | **84.86** |
32
+ | Tailwind CSS | 13 | 8 | 0.789 | 0.8705 | 0.8565 | 0.9147 | 0.6780 | **81.74** |
33
+ | Ant Design | 12 | 9 | 0.711 | 0.8586 | 0.8734 | 0.9276 | 0.6550 | **79.81** |
34
+ | Material UI | 12 | 11 | 0.565 | 0.7967 | 0.7861 | 0.9239 | 0.5500 | **70.95** |
35
+ | Radix UI | 13 | 10 | 0.543 | 0.7979 | 0.7679 | 0.9481 | 0.5207 | **69.67** |
36
+ | Shopify Polaris | 17 | 15 | 0.356 | 0.7281 | 0.6892 | 0.9223 | 0.4667 | **59.86** |
37
+
38
+
39
+
40
+
41
+ *Table 1. Benchmark ranking of design systems evaluated using Chromametry metrics.*
42
+
43
+ > **Note:** Design systems like Bootstrap,Google Material 3, Apple Human Interface or Fluent UI are excluded as they define discrete semantic tokens rather than algorithmic sequential ramps.
44
+
45
+ > **Overall Score** is computed as the weighted mean of the five normalized metrics, using equal weights by default.
46
+
47
+ ### Example: A Typical Report
48
+
49
+ ![Adobe Spectrum Color Palette](paper/figures/adobe-spectrum-color-palette.png)
50
+ *Figure 2. Adobe Spectrum Color Palette.*
51
+
52
+ ![IBM Carbon Palette Metrics](paper/figures/adobe-spectrum-palette-metrics.png)
53
+ *Figure 3. Adobe Spectrum Palette Metrics.*
54
+
55
+ ![IBM Carbon Palette Charts](paper/figures/adobe-spectrum-palette-charts.png)
56
+ *Figure 4. Adobe Spectrum Palette Charts.*
57
+
58
+ ## Benchmark result page
59
+
60
+ - Online Report : [Benchmark page](https://chromametry.github.io/chromametry/benchmark/)
61
+ - Local `/benchmark/index.html` (double click)
62
+
63
+ ## API
60
64
  ### Installation
61
- **NPM Package:**
62
65
  ```bash
63
66
  npm install chromametry
64
67
  ```
65
- **CDN (Browser) ESM:**
66
- ```js
68
+
69
+ ### Usage
70
+ ```ts
71
+ import { Palette, Ramp, Shade } from "chromametry";
72
+
73
+ const blue = new Ramp([
74
+ "#ffffff",
75
+ "#eff6fb",
76
+ "#d9e8f6",
77
+ "#aacdec",
78
+ "#73b3e7",
79
+ "#4f97d1",
80
+ "#2378c3",
81
+ "#2c608a",
82
+ "#274863",
83
+ "#1f303e",
84
+ "#11181d",
85
+ "#000000",
86
+ ], "blue");
87
+
88
+ console.log(blue.baseColor);
89
+ console.log(blue.wcag[45].span);
90
+ console.log(blue.metrics);
91
+ console.log(blue.score);
92
+
93
+ const brand = new Palette({
94
+ blue: blue.colors,
95
+ orange: [
96
+ "#ffffff",
97
+ "#fff2e8",
98
+ "#ffd9be",
99
+ "#ffb784",
100
+ "#ff832b",
101
+ "#eb6200",
102
+ "#ba4e00",
103
+ "#8a3800",
104
+ "#5e2900",
105
+ "#3e1a00",
106
+ "#231000",
107
+ "#000000",
108
+ ],
109
+ }, "My Brand");
110
+
111
+ console.log(brand.metrics);
112
+ console.log(brand.wcag[45]);
113
+ console.log(brand.score);
114
+
115
+ const shade = new Shade("#2378c3");
116
+ console.log(shade.lab);
117
+ console.log(shade.chroma);
118
+ ```
119
+
120
+ ### Browser
121
+ **ESM**
122
+ ```html
67
123
  <script type="module">
68
- import { analyzeMonochromaticPalette } from 'https://esm.sh/chromametry';
69
- </script>
70
- const result = Chromametry.analyzeMonochromaticPalette({ ... });
71
- </script>
124
+ import { Palette, Ramp } from "https://esm.sh/chromametry";
72
125
 
126
+ const ramp = new Ramp(["#ffffff", "#2378c3", "#000000"], "blue");
127
+ console.log(ramp.score);
128
+ </script>
73
129
  ```
74
130
 
75
- **CDN (Browser) Global:**
76
- ```js
131
+ **Global**
132
+ ```html
77
133
  <script src="https://unpkg.com/chromametry/dist/index.global.js"></script>
78
134
  <script>
79
- const result = Chromametry.analyzeMonochromaticPalette({ ... });
135
+ const ramp = new Chromametry.Ramp(["#ffffff", "#2378c3", "#000000"], "blue");
136
+ console.log(ramp.score);
80
137
  </script>
81
138
  ```
82
139
 
83
- ### Usage
84
- ```ts
85
- import { analyzeMonochromaticPalette } from 'chromametry';
86
-
87
- // 1. Define your colors (must include white/black anchors for accurate scoring)
88
- const colors = {
89
- yellow: ["#ffffff","#fcf4d6","#fddc69","#f1c21b","#d2a106","#b28600","#8e6a00","#684e00","#483700","#302400","#1c1500","#000000"],
90
- orange: ["#ffffff","#fff2e8","#ffd9be","#ffb784","#ff832b","#eb6200","#ba4e00","#8a3800","#5e2900","#3e1a00","#231000","#000000"]
91
- };
92
-
93
- // 2. Define step names corresponding to the array length
94
- const stepNames = [0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950,1000];
95
-
96
- // 3. Run analysis
97
- const result = analyzeMonochromaticPalette({
98
- name: "My Custom Brand",
99
- stepNames: stepNames,
100
- colors: colors
101
- });
102
-
103
- console.log(result.metrics);
104
- console.log(`System Score: ${result.score}`);
105
- ```
140
+ ### Class Reference
141
+ #### Shade
142
+ | Property | Description |
143
+ | :--- | :--- |
144
+ | `constructor(hex)` | Create a shade from a hex color string. |
145
+ | `hex` | Original hex color. |
146
+ | `rgb` | Linear RGB values. |
147
+ | `lab` | CIELAB coordinates. |
148
+ | `lch` | LCH coordinates derived from LAB. |
149
+ | `lightness` | Perceptual lightness with Helmholtz-Kohlrausch correction. |
150
+ | `chroma` | Chroma of the shade. |
151
+ | `hue` | Hue angle in degrees. |
152
+ | `luminance` | Relative luminance used for contrast. |
153
+ | `wcag` | WCAG contrast ratio against white. |
154
+ | `apca` | APCA contrast value against white. |
155
+
156
+ #### Ramp
157
+ | Property | Description |
158
+ | :--- | :--- |
159
+ | `constructor(colors, name?)` | Create a sequential ramp from hex colors. |
160
+ | `name` | Ramp name. |
161
+ | `shades` | `Shade[]` built from the input colors. |
162
+ | `colors` | Original ramp colors as hex strings. |
163
+ | `steps` | Number of steps in the ramp. |
164
+ | `peakChroma` | Hex color with the highest chroma in the inner ramp. |
165
+ | `baseColor` | Base color used as the ramp anchor. |
166
+ | `baseIndex` | Index of the base color. |
167
+ | `wcag` | WCAG contrast spans for levels `30`, `45`, and `70`. |
168
+ | `apca` | APCA contrast spans for levels `45`, `60`, and `75`. |
169
+ | `contrasts` | Combined contrast object with `wcag` and `apca`. |
170
+ | `deltaECurve` | Cumulative DeltaE curve across ramp steps. |
171
+ | `unwrapHues` | Hue sequence with wrap-around discontinuities removed. |
172
+ | `lightnessLinearity` | Linearity score of the lightness curve. |
173
+ | `chromaSmoothness` | Smoothness score of the chroma curve. |
174
+ | `spacingUniformity` | Uniformity score of DeltaE spacing. |
175
+ | `hueStability` | Stability score of hue drift across the ramp. |
176
+ | `contrastEfficiency` | Efficiency score of using contrast span for WCAG 4.5. |
177
+ | `metrics` | Object containing the five ramp metrics. |
178
+ | `score` | Composite ramp score. |
179
+
180
+ #### Palette
181
+ | Property | Description |
182
+ | :--- | :--- |
183
+ | `constructor(colors, name?)` | Create a palette from named ramps. |
184
+ | `name` | Palette name. |
185
+ | `ramps` | `Ramp[]` built from the input record. |
186
+ | `colors` | Original palette colors as `Record<string, string[]>`. |
187
+ | `steps` | Number of steps shared by the ramps. |
188
+ | `direction` | Ramp direction inferred from the first ramp. |
189
+ | `wcag` | Palette-level WCAG contrast spans aggregated across ramps. |
190
+ | `apca` | Palette-level APCA contrast spans aggregated across ramps. |
191
+ | `contrasts` | Combined contrast object with `wcag` and `apca`. |
192
+ | `metrics` | Object containing the five palette metrics aggregated from ramps. |
193
+ | `score` | Composite palette score. |
106
194
 
107
195
  ## Reproducing Benchmarks
108
196
  To run the benchmark generator locally:
109
197
  ```bash
110
198
  git clone https://github.com/chromametry/chromametry.git
111
- cd chromametry
112
- npm install
113
- npm run generate
114
- ```
115
-
116
- ## Adding Custom Palettes to Benchmark
117
- Create a new .ts file in benchmarks/monochromatic/input/ (e.g., my-palette.ts).
118
-
199
+ cd chromametry
200
+ npm install
201
+ npm run generate
202
+ ```
203
+
204
+ ## Adding Custom Palettes to Benchmark
205
+ Create a new .ts file in benchmark/input/ (e.g., my-palette.ts).
206
+
119
207
  ```ts
120
- import { MonochromaticPaletteData } from "../../../src/index.js";
121
208
  import { red, volcano, gold } from '@ant-design/colors';
122
209
 
123
210
  // Define colors (imported or inline object)
124
211
  let colors: Record<string, string[]> = { red, volcano, gold };
125
-
126
- // Ensure white/black anchors exist if your ramp misses them
127
- for (let name in colors) {
128
- if (colors[name][0] !== "#ffffff") colors[name].unshift("#ffffff");
129
- if (colors[name][colors[name].length - 1] !== "#000000") colors[name].push("#000000");
130
- }
131
-
132
- const stepNames = Object.keys(Object.values(colors)[0]);
133
-
134
- const palette: MonochromaticPaletteData = {
135
- name: "Ant Design",
136
- stepNames, // string[]
137
- colors // Record<string, string[]>
212
+
213
+ // Ensure white/black anchors exist if your ramp misses them
214
+ for (let name in colors) {
215
+ if (colors[name][0] !== "#ffffff") colors[name].unshift("#ffffff");
216
+ if (colors[name][colors[name].length - 1] !== "#000000") colors[name].push("#000000");
217
+ }
218
+ export default {
219
+ name: "Ant Design",
220
+ colors,
138
221
  };
139
-
140
- export default palette;
141
- ```
142
- Then regenerate the report:
143
- ```bash
144
- npm run generate
145
222
  ```
146
-
147
- ### Input Requirements
148
- - Equal Steps: All color ramps must have the same number of steps.
149
-
150
- - Format: Colors must be Hex strings.
151
-
152
- - Monotonicity: Lightness must strictly increase or decrease (sorted).
153
-
154
- - Anchors: Start/End colors should ideally be Black and White.
155
-
223
+ Then regenerate the report:
224
+ ```bash
225
+ npm run generate
226
+ ```
227
+
228
+ ### Input Requirements
229
+ - Equal Steps: All color ramps must have the same number of steps.
230
+
231
+ - Format: Colors must be Hex strings.
232
+
233
+ - Monotonicity: Lightness must strictly increase or decrease (sorted).
234
+
235
+ - Anchors: Start/End colors should ideally be Black and White.
236
+
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var P=Object.defineProperty;var ot=Object.getOwnPropertyDescriptor;var at=Object.getOwnPropertyNames;var st=Object.prototype.hasOwnProperty;var ct=(r,t)=>{for(var n in t)P(r,n,{get:t[n],enumerable:!0})},mt=(r,t,n,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of at(t))!st.call(r,o)&&o!==n&&P(r,o,{get:()=>t[o],enumerable:!(e=ot(t,o))||e.enumerable});return r};var ht=r=>mt(P({},"__esModule",{value:!0}),r);var dt={};ct(dt,{analyzeMonochromatic:()=>O,analyzeMonochromaticPalette:()=>xt,calcChromaSmoothness:()=>K,calcContrastEfficiency:()=>Q,calcDeltaE2000:()=>A,calcHueStability:()=>Z,calcLightnessLinearity:()=>W,calcScore:()=>I,calcSpacingUniformity:()=>J,calcStatistics:()=>ft,contrastList:()=>H,createMonotone:()=>z,cssRgbToRgb:()=>gt,findMaxChromaHex:()=>k,fromLightnessEAL:()=>ut,getApcaContrast:()=>L,getMonochromaticContrasts:()=>N,getPaletteContrasts:()=>X,getRelativeLuminance:()=>D,getWcagContrast:()=>R,hexToRgb:()=>f,labToLch:()=>q,labToRgb:()=>lt,lchToLab:()=>bt,lrgbToSrgb:()=>G,rgbToHex:()=>it,rgbToLab:()=>x,rootMeanSquare:()=>y,simulateDeuteranopia:()=>Mt,simulateProtanopia:()=>pt,srgbToLrgb:()=>_,toLightnessEAL:()=>T,unwrapHue:()=>v});module.exports=ht(dt);var D=r=>{let[t,n,e]=r;return .2126*t+.7152*n+.0722*e},G=r=>{let t=n=>{let e=Math.max(0,Math.min(1,n)),o=e<=.0031308?12.92*e:1.055*Math.pow(e,1/2.4)-.055;return Math.max(0,Math.min(255,Math.round(o*255)))};return r.map(t)},_=r=>{let t=n=>n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92;return r.map(t)},it=r=>{let[t,n,e]=G(r);return t=t.toString(16).padStart(2,"0"),n=n.toString(16).padStart(2,"0"),e=e.toString(16).padStart(2,"0"),`#${t}${n}${e}`},f=r=>{let t=parseInt(r.slice(1,3),16)/255,n=parseInt(r.slice(3,5),16)/255,e=parseInt(r.slice(5,7),16)/255;return _([t,n,e])},T=r=>{let[t,n,e]=r,o=Math.sqrt(n*n+e*e),s=(Math.atan2(e,n)*180/Math.PI+360)%360,i=.1644,b=.0603,m=.1307,u=.006,h=i*Math.abs(Math.sin((s-90)/2*(Math.PI/180)))+b,a=0;return(s<=90||s>=270)&&(a=m*Math.abs(Math.cos(s*(Math.PI/180)))+u),t+(h+a)*o},ut=(r,t)=>{let[,n,e]=t,o=Math.sqrt(n*n+e*e),s=(Math.atan2(e,n)*180/Math.PI+360)%360,i=.1644,b=.0603,m=.1307,u=.006,h=i*Math.abs(Math.sin((s-90)/2*(Math.PI/180)))+b,a=0;return(s<=90||s>=270)&&(a=m*Math.abs(Math.cos(s*(Math.PI/180)))+u),Math.max(0,r-(h+a)*o)},bt=r=>{let[t,n,e]=r,o=e*Math.PI/180;return[t,n*Math.cos(o),n*Math.sin(o)]},x=r=>{let[t,n,e]=r,o=.4124564*t+.3575761*n+.1804375*e,c=.2126729*t+.7151522*n+.072175*e,s=.0193339*t+.119192*n+.9503041*e,i=.95047,b=1,m=1.08883,u=p=>p>.008856?Math.cbrt(p):7.787*p+16/116,h=u(o/i),a=u(c/b),l=u(s/m);return[116*a-16,500*(h-a),200*(a-l)]},lt=r=>{let[t,n,e]=r,o=(t+16)/116,c=n/500+o,s=o-e/200,i=p=>p**3>.008856?p**3:(p-16/116)/7.787,b=.95047,m=1,u=1.08883,h=i(c)*b,a=i(o)*m,l=i(s)*u;return[3.2404542*h-1.5371385*a-.4985314*l,-.969266*h+1.8760108*a+.041556*l,.0556434*h-.2040259*a+1.0572252*l]},q=r=>{let[t,n,e]=r,o=Math.sqrt(n*n+e*e);if(o<1e-4)return[t,0,0];let s=(Math.atan2(e,n)*180/Math.PI+360)%360;return s>=359.9999&&(s=0),[t,o,s]},A=(r,t)=>{let[n,e,o]=r,[c,s,i]=t,b=(n+c)/2,m=Math.sqrt(e*e+o*o),u=Math.sqrt(s*s+i*i),h=(m+u)/2,a=.5*(1-Math.sqrt(Math.pow(h,7)/(Math.pow(h,7)+Math.pow(25,7)))),l=e*(1+a),p=s*(1+a),M=Math.sqrt(l*l+o*o),d=Math.sqrt(p*p+i*i),S=(M+d)/2,C=Math.atan2(o,l)*180/Math.PI+(Math.atan2(o,l)<0?360:0),g=Math.atan2(i,p)*180/Math.PI+(Math.atan2(i,p)<0?360:0),E=g-C;Math.abs(E)>180&&(E+=g<=C?360:-360);let w=Math.abs(C-g)>180?(C+g+360)/2:(C+g)/2,V=1-.17*Math.cos((w-30)*Math.PI/180)+.24*Math.cos(2*w*Math.PI/180)+.32*Math.cos((3*w+6)*Math.PI/180)-.2*Math.cos((4*w-63)*Math.PI/180),tt=c-n,Y=d-M,B=2*Math.sqrt(M*d)*Math.sin(E/2*Math.PI/180),nt=1+.015*Math.pow(b-50,2)/Math.sqrt(20+Math.pow(b-50,2)),U=1+.045*S,$=1+.015*S*V,rt=30*Math.exp(-Math.pow((w-275)/25,2)),et=-(2*Math.sqrt(Math.pow(S,7)/(Math.pow(S,7)+Math.pow(25,7))))*Math.sin(2*rt*Math.PI/180);return Math.sqrt(Math.pow(tt/nt,2)+Math.pow(Y/U,2)+Math.pow(B/$,2)+et*(Y/U)*(B/$))},k=r=>{let t="",n=-1/0;for(let e of r){let o=x(f(e)),[,c]=q(o);c>n&&(n=c,t=e)}return t};function v(r){let t=[r[0]];for(let n=1;n<r.length;n++){let e=r[n]-r[n-1];e>180?e-=360:e<-180&&(e+=360),t.push(t[n-1]+e)}return t}function pt(r){let[t,n,e]=r;return[.152286*t+1.052583*n-.204868*e,.114503*t+.786281*n+.099216*e,-.003882*t-.048116*n+1.051998*e]}function Mt(r){let[t,n,e]=r;return[.367322*t+.860646*n-.227968*e,.280085*t+.672501*n+.047413*e,-.01182*t+.04294*n+.968881*e]}var gt=r=>{let t=r.match(/\d+(\.\d+)?/g);if(!t||t.length<3)throw new Error("Invalid CSS rgb()");let n=e=>{let o=e/255;return o<=.04045?o/12.92:Math.pow((o+.055)/1.055,2.4)};return[n(Number(t[0])),n(Number(t[1])),n(Number(t[2]))]};var R=(r,t)=>(Math.max(r,t)+.05)/(Math.min(r,t)+.05),L=(r,t)=>{let n=s=>s>5e-4?s:s+Math.pow(5e-4-s,.8),e=n(r),o=n(t),c=(Math.pow(e,.56)-Math.pow(o,.56))*100;return Math.abs(c)<.1?0:(c=c>0?c<1?0:c-.25:c>-1?0:c+.25,Math.round(c))};function j(r){let t=r.match(/^(wcag|apca)(\d+)$/);if(!t)throw new Error(`Invalid contrast: ${r}`);let n=t[1]==="wcag"?Number(t[2])/10:Number(t[2]);return{system:t[1],target:n}}var N=r=>{let t={},n=r.length,e=n-1;return H.forEach(o=>{let{system:c,target:s}=j(o),i=e,b=0;for(let m=1;m<n;m++){let u=1/0;for(let h=0;h<n-m;h++){let a=c==="wcag"?R(r[h].luminance,r[h+m].luminance):Math.max(Math.abs(L(r[h+m].luminance,r[h].luminance)),Math.abs(L(r[h].luminance,r[h+m].luminance)));a<u&&(u=a)}if(u>=s){i=m,b=u;break}m===e&&(b=u)}t[o]={system:c,efficiency:i/e,target:s,span:i,value:b,name:o}}),t},H=["wcag30","wcag45","wcag70","apca45","apca60","apca75"],X=r=>{let t={};return H.forEach(n=>{var m;let{target:e,system:o}=j(n),c=r.map(u=>u.contrasts[n]),s=((m=r[0])==null?void 0:m.shades.length)||0,i=Math.max(...c.map(u=>(u==null?void 0:u.span)||0)),b=c.reduce((u,h)=>u+((h==null?void 0:h.value)||0),0);t[n]={system:o,target:e,span:i,value:b/(r.length||1),name:n,efficiency:i/(s-1||1)}}),t};var F=r=>{let t=f(r),n=x(t),e=D(t),o=T(n),c=q(n);return{hex:r,rgb:t,lab:n,lch:c,lightness:o,chroma:c[1],hue:c[2],luminance:e,parameter:0,cumDeltaE00:0,cumProtDeltaE00:0,cumDeutDeltaE00:0,wcag:R(e,1),apca:L(e,1)}};var z=r=>{if(r.length<1)return m=>0;let t=[...r].sort((m,u)=>m[0]-u[0]),n=[];for(let m=0;m<t.length;m++)(m===0||t[m][0]!==t[m-1][0])&&n.push(t[m]);let e=n.length;if(e===1)return m=>n[0][1];let o=n.map(m=>m[0]),c=n.map(m=>m[1]),s=[],i=[];for(let m=0;m<e-1;m++)s[m]=o[m+1]-o[m],i[m]=(c[m+1]-c[m])/s[m];let b=new Array(e);b[0]=i[0],b[e-1]=i[e-2];for(let m=1;m<e-1;m++){let u=i[m-1],h=i[m];if(u*h<=0)b[m]=0;else{let a=(1+s[m]/(s[m-1]+s[m]))/3;b[m]=u*h/((1-a)*u+a*h)}}return m=>{if(m<=o[0])return c[0];if(m>=o[e-1])return c[e-1];let u=0,h=e-2,a=0;for(;u<=h;){let g=Math.floor((u+h)/2);if(m>=o[g]&&m<=o[g+1]){a=g;break}m<o[g]?h=g-1:u=g+1}let l=s[a],p=(m-o[a])/l,M=p*p,d=M*p,S=b[a]*l,C=b[a+1]*l;return(2*d-3*M+1)*c[a]+(d-2*M+p)*S+(-2*d+3*M)*c[a+1]+(d-M)*C}};function y(r){let t=r.length;if(t===0)return 0;let n=0;for(let e=0;e<t;e++)n+=r[e]*r[e];return Math.sqrt(n/t)}var ft=r=>{let t=r.length;if(t===0)return{min:0,max:0,avg:0};let n=r[0],e=r[0],o=0;for(let c=0;c<t;c++){let s=r[c];s<n&&(n=s),s>e&&(e=s),o+=s}return{min:n,max:e,avg:o/t}},I=r=>{let t=r.length;if(t===0)return 0;let n=1e-6,e=r.reduce((s,i)=>s*(i+n),1),o=Math.pow(e,1/t),c=Math.max(0,Math.min(1,o));return parseFloat((c*100).toFixed(2))};var O=(r,t,n)=>{t||(t="brand"),n||(n=[...Array(r.length).keys()]);let e=x(f(r[0]))[0],o=x(f(r[r.length-1]))[0];e>o&&r.reverse();let c=r.map(a=>F(a));for(let a=1;a<c.length;a++){let l=A(c[a-1].lab,c[a].lab);c[a].cumDeltaE00=c[a-1].cumDeltaE00+l}let s=k(r.slice(2,-2))||r[Math.floor(r.length/2)],i=r.findIndex(a=>a.toLowerCase()===(s==null?void 0:s.toLowerCase())),b=v(c.map(a=>a.hue).slice(1,-1));for(let a=1;a<c.length-1;a++)c[a].hue=b[a-1];let m=Z(c.map(a=>a.hue).slice(1,-1),c[i].hue),u=N(c),h={lightnessLinearity:W(c.map(a=>a.lightness)),chromaSmoothness:K(c.map(a=>a.chroma)),spacingUniformity:J(c.map(a=>a.cumDeltaE00)),contrastEfficiency:Q(u.wcag45.span,n.length),hueStability:m};return{name:t,colors:r,baseIndex:i,baseColor:s,shades:c,contrasts:u,metrics:h,score:I(Object.values(h))}},xt=r=>{let{stepNames:t,name:n,colors:e}=r,o=Object.values(e)[0],c=x(f(o[0]))[0],s=x(f(o[o.length-1]))[0],i=c>s?"darken":"lighten",b=[],m={};for(let h in e){let a=O(e[h],h,t);b.push(a),m[h]=a.baseColor}let u={contrastEfficiency:y(b.map(h=>h.metrics.contrastEfficiency)),lightnessLinearity:y(b.map(h=>h.metrics.lightnessLinearity)),chromaSmoothness:y(b.map(h=>h.metrics.chromaSmoothness)),hueStability:y(b.map(h=>h.metrics.hueStability)),spacingUniformity:y(b.map(h=>h.metrics.spacingUniformity))};return{name:n,baseColors:m,stepNames:t,direction:i,steps:t.length,colors:e,contrasts:X(b),scales:b,metrics:u,score:I(Object.values(u))}};function W(r){let t=r.length;if(t<2)return 1;let n=0,e=0,o=0,c=0;for(let a=0;a<t;a++)n+=a,e+=r[a],o+=a*r[a],c+=a*a;let s=t*c-n*n;if(Math.abs(s)<1e-10)return 1;let i=(t*o-n*e)/s,b=(e-i*n)/t;if(Math.abs(i*(t-1))<.001)return 1;let u=0,h=0;for(let a=0;a<t;a++){let l=i*a+b,p=r[a]-l;u+=p*p;let M=Math.max(l-Math.min(b,i*(t-1)+b),Math.max(b,i*(t-1)+b)-l);h+=M*M}return Math.max(0,Math.min(1,1-Math.sqrt(u/t)/Math.sqrt(h/t)))}function Z(r,t){let n=r.length;if(n<2)return 1;let e=0,o=0;for(let c=0;c<n;c++){let s=Math.abs(r[c]-t)%360;s>180&&(s=360-s),e+=s*s;let i=c/(n-1)*180;o+=i*i}return Math.max(0,Math.min(1,1-Math.sqrt(e/n)/(Math.sqrt(o/n)||1)))}var K=r=>{let t=r.length;if(t<3)return 1;let n=133.8,e=Math.max(...r);if(e<=.01)return 1;let o=r.map(h=>h/e*n),c=Math.min(...o),s=Math.max(...o),i=o.findIndex(h=>h===s),b=z([[0,o[0]],[i,s],[t-1,o[t-1]]]),m=0,u=0;for(let h=0;h<t;h++){let a=b(h),l=o[h]-a;m+=l*l,u+=Math.pow(Math.max(a-c,s-a),2)}return Math.max(0,Math.min(1,1-Math.sqrt(m/t)/Math.sqrt(u/t)))},J=r=>{let t=r.length;if(t<2)return 1;let n=[];for(let s=1;s<t;s++){let i=r[s]-r[s-1];if(i<0)return 0;n.push(i)}let e=n.reduce((s,i)=>s+i,0)/n.length;if(e<=1e-6)return 0;let o=0;for(let s of n)o+=Math.pow(s-e,2);let c=Math.sqrt(o/n.length)/e;return Math.max(0,Math.min(1,1/(1+c)))},Q=(r,t)=>{if(t<=1)return 1;let n=.5,e=r/t,o=n*((t-1)/t);return e<=o?1:e>=1?0:(1-e)/(1-o)};0&&(module.exports={analyzeMonochromatic,analyzeMonochromaticPalette,calcChromaSmoothness,calcContrastEfficiency,calcDeltaE2000,calcHueStability,calcLightnessLinearity,calcScore,calcSpacingUniformity,calcStatistics,contrastList,createMonotone,cssRgbToRgb,findMaxChromaHex,fromLightnessEAL,getApcaContrast,getMonochromaticContrasts,getPaletteContrasts,getRelativeLuminance,getWcagContrast,hexToRgb,labToLch,labToRgb,lchToLab,lrgbToSrgb,rgbToHex,rgbToLab,rootMeanSquare,simulateDeuteranopia,simulateProtanopia,srgbToLrgb,toLightnessEAL,unwrapHue});
1
+ "use strict";var v=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var O=Object.prototype.hasOwnProperty;var N=(m,t)=>{for(var s in t)v(m,s,{get:t[s],enumerable:!0})},V=(m,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of j(t))!O.call(m,e)&&e!==s&&v(m,e,{get:()=>t[e],enumerable:!(n=G(t,e))||n.enumerable});return m};var $=m=>V(v({},"__esModule",{value:!0}),m);var et={};N(et,{Palette:()=>T,Ramp:()=>q,Shade:()=>y,calcDeltaE2000:()=>P,calcScore:()=>L,calcStatistics:()=>nt,createMonotone:()=>E,cssRgbToRgb:()=>st,fromLightnessEAL:()=>J,hexToRgb:()=>C,labToLch:()=>k,labToRgb:()=>tt,lchToLab:()=>Q,rgbToHex:()=>Z,rgbToLab:()=>S,rootMeanSquare:()=>x,toLightnessEAL:()=>_});module.exports=$(et);var F=m=>{let t=s=>{let n=Math.max(0,Math.min(1,s)),e=n<=.0031308?12.92*n:1.055*Math.pow(n,1/2.4)-.055;return Math.max(0,Math.min(255,Math.round(e*255)))};return m.map(t)},K=m=>{let t=s=>s>.04045?Math.pow((s+.055)/1.055,2.4):s/12.92;return m.map(t)},Z=m=>{let[t,s,n]=F(m);return t=t.toString(16).padStart(2,"0"),s=s.toString(16).padStart(2,"0"),n=n.toString(16).padStart(2,"0"),`#${t}${s}${n}`},C=m=>{let t=parseInt(m.slice(1,3),16)/255,s=parseInt(m.slice(3,5),16)/255,n=parseInt(m.slice(5,7),16)/255;return K([t,s,n])},_=m=>{let[t,s,n]=m,e=Math.sqrt(s*s+n*n),a=(Math.atan2(n,s)*180/Math.PI+360)%360,h=.1644,u=.0603,r=.1307,i=.006,l=h*Math.abs(Math.sin((a-90)/2*(Math.PI/180)))+u,c=0;return(a<=90||a>=270)&&(c=r*Math.abs(Math.cos(a*(Math.PI/180)))+i),t+(l+c)*e},J=(m,t)=>{let[,s,n]=t,e=Math.sqrt(s*s+n*n),a=(Math.atan2(n,s)*180/Math.PI+360)%360,h=.1644,u=.0603,r=.1307,i=.006,l=h*Math.abs(Math.sin((a-90)/2*(Math.PI/180)))+u,c=0;return(a<=90||a>=270)&&(c=r*Math.abs(Math.cos(a*(Math.PI/180)))+i),Math.max(0,m-(l+c)*e)},Q=m=>{let[t,s,n]=m,e=n*Math.PI/180;return[t,s*Math.cos(e),s*Math.sin(e)]},S=m=>{let[t,s,n]=m,e=.4124564*t+.3575761*s+.1804375*n,o=.2126729*t+.7151522*s+.072175*n,a=.0193339*t+.119192*s+.9503041*n,h=.95047,u=1,r=1.08883,i=g=>g>.008856?Math.cbrt(g):7.787*g+16/116,l=i(e/h),c=i(o/u),p=i(a/r);return[116*c-16,500*(l-c),200*(c-p)]},tt=m=>{let[t,s,n]=m,e=(t+16)/116,o=s/500+e,a=e-n/200,h=g=>g**3>.008856?g**3:(g-16/116)/7.787,u=.95047,r=1,i=1.08883,l=h(o)*u,c=h(e)*r,p=h(a)*i;return[3.2404542*l-1.5371385*c-.4985314*p,-.969266*l+1.8760108*c+.041556*p,.0556434*l-.2040259*c+1.0572252*p]},k=m=>{let[t,s,n]=m,e=Math.sqrt(s*s+n*n);if(e<1e-4)return[t,0,0];let a=(Math.atan2(n,s)*180/Math.PI+360)%360;return a>=359.9999&&(a=0),[t,e,a]},P=(m,t)=>{let[s,n,e]=m,[o,a,h]=t,u=(s+o)/2,r=Math.sqrt(n*n+e*e),i=Math.sqrt(a*a+h*h),l=(r+i)/2,c=.5*(1-Math.sqrt(Math.pow(l,7)/(Math.pow(l,7)+Math.pow(25,7)))),p=n*(1+c),g=a*(1+c),M=Math.sqrt(p*p+e*e),b=Math.sqrt(g*g+h*h),w=(M+b)/2,d=Math.atan2(e,p)*180/Math.PI+(Math.atan2(e,p)<0?360:0),f=Math.atan2(h,g)*180/Math.PI+(Math.atan2(h,g)<0?360:0),R=f-d;Math.abs(R)>180&&(R+=f<=d?360:-360);let I=Math.abs(d-f)>180?(d+f+360)/2:(d+f)/2,U=1-.17*Math.cos((I-30)*Math.PI/180)+.24*Math.cos(2*I*Math.PI/180)+.32*Math.cos((3*I+6)*Math.PI/180)-.2*Math.cos((4*I-63)*Math.PI/180),W=o-s,A=b-M,D=2*Math.sqrt(M*b)*Math.sin(R/2*Math.PI/180),X=1+.015*Math.pow(u-50,2)/Math.sqrt(20+Math.pow(u-50,2)),H=1+.045*w,Y=1+.015*w*U,z=30*Math.exp(-Math.pow((I-275)/25,2)),B=-(2*Math.sqrt(Math.pow(w,7)/(Math.pow(w,7)+Math.pow(25,7))))*Math.sin(2*z*Math.PI/180);return Math.sqrt(Math.pow(W/X,2)+Math.pow(A/H,2)+Math.pow(D/Y,2)+B*(A/H)*(D/Y))},st=m=>{let t=m.match(/\d+(\.\d+)?/g);if(!t||t.length<3)throw new Error("Invalid CSS rgb()");let s=n=>{let e=n/255;return e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4)};return[s(Number(t[0])),s(Number(t[1])),s(Number(t[2]))]},E=m=>{if(m.length<1)return r=>0;let t=[...m].sort((r,i)=>r[0]-i[0]),s=[];for(let r=0;r<t.length;r++)(r===0||t[r][0]!==t[r-1][0])&&s.push(t[r]);let n=s.length;if(n===1)return r=>s[0][1];let e=s.map(r=>r[0]),o=s.map(r=>r[1]),a=[],h=[];for(let r=0;r<n-1;r++)a[r]=e[r+1]-e[r],h[r]=(o[r+1]-o[r])/a[r];let u=new Array(n);u[0]=h[0],u[n-1]=h[n-2];for(let r=1;r<n-1;r++){let i=h[r-1],l=h[r];if(i*l<=0)u[r]=0;else{let c=(1+a[r]/(a[r-1]+a[r]))/3;u[r]=i*l/((1-c)*i+c*l)}}return r=>{if(r<=e[0])return o[0];if(r>=e[n-1])return o[n-1];let i=0,l=n-2,c=0;for(;i<=l;){let f=Math.floor((i+l)/2);if(r>=e[f]&&r<=e[f+1]){c=f;break}r<e[f]?l=f-1:i=f+1}let p=a[c],g=(r-e[c])/p,M=g*g,b=M*g,w=u[c]*p,d=u[c+1]*p;return(2*b-3*M+1)*o[c]+(b-2*M+g)*w+(-2*b+3*M)*o[c+1]+(b-M)*d}};function x(m){let t=m.length;if(t===0)return 0;let s=0;for(let n=0;n<t;n++)s+=m[n]*m[n];return Math.sqrt(s/t)}var nt=m=>{let t=m.length;if(t===0)return{min:0,max:0,avg:0};let s=m[0],n=m[0],e=0;for(let o=0;o<t;o++){let a=m[o];a<s&&(s=a),a>n&&(n=a),e+=a}return{min:s,max:n,avg:e/t}},L=m=>{let t=m.length;if(t===0)return 0;let s=1e-6,n=m.reduce((a,h)=>a*(h+s),1),e=Math.pow(n,1/t),o=Math.max(0,Math.min(1,e));return parseFloat((o*100).toFixed(2))};var y=class{constructor(t){this.hex=t}get rgb(){return C(this.hex)}get lab(){return S(this.rgb)}get lch(){return k(this.lab)}get lightness(){let[t,s,n]=this.lab,e=Math.sqrt(s*s+n*n),a=(Math.atan2(n,s)*180/Math.PI+360)%360,h=.1644,u=.0603,r=.1307,i=.006,l=h*Math.abs(Math.sin((a-90)/2*(Math.PI/180)))+u,c=0;return(a<=90||a>=270)&&(c=r*Math.abs(Math.cos(a*(Math.PI/180)))+i),t+(l+c)*e}get chroma(){return this.lch[1]}get hue(){return this.lch[2]}get luminance(){let[t,s,n]=this.rgb;return .2126*t+.7152*s+.0722*n}get wcag(){return(Math.max(this.luminance,1)+.05)/(Math.min(this.luminance,1)+.05)}get apca(){let t=o=>o>5e-4?o:o+Math.pow(5e-4-o,.8),s=t(this.luminance),n=t(1),e=(Math.pow(s,.56)-Math.pow(n,.56))*100;return Math.abs(e)<.1?0:(e=e>0?e<1?0:e-.25:e>-1?0:e+.25,Math.round(e))}};var q=class{constructor(t=[],s="brand"){this.shades=t.map(n=>new y(n)),this.name=s}get colors(){return this.shades.map(t=>t.hex)}get peakChroma(){let t=this.colors.slice(2,-2),s="",n=-1/0;for(let e of t){let o=new y(e);o.chroma>n&&(n=o.chroma,s=e)}return s}get steps(){return this.colors.length}get baseColor(){return this.colors.length===0?"":this.peakChroma||this.colors[Math.floor(this.colors.length/2)]}get baseIndex(){return this.colors.length===0?-1:this.colors.findIndex(t=>t.toLowerCase()===this.baseColor.toLowerCase())}get wcag(){let t=this.shades,s=t.length,n=s-1,e={};for(let o of[30,45,70]){let a=o/10,h=n,u=0;for(let r=1;r<s;r++){let i=1/0;for(let l=0;l<s-r;l++){let c=t[l].luminance,p=t[l+r].luminance,g=(Math.max(c,p)+.05)/(Math.min(c,p)+.05);g<i&&(i=g)}if(i>=a){h=r,u=i;break}r===n&&(u=i)}e[o]={efficiency:h/n,target:a,span:h,value:u}}return e}get apca(){let t=this.shades,s=t.length,n=s-1,e={},o=(a,h)=>{let u=c=>c>5e-4?c:c+Math.pow(5e-4-c,.8),r=u(a),i=u(h),l=(Math.pow(r,.56)-Math.pow(i,.56))*100;return Math.abs(l)<.1?0:(l=l>0?l<1?0:l-.25:l>-1?0:l+.25,Math.round(l))};for(let a of[45,60,75]){let h=a,u=n,r=0;for(let i=1;i<s;i++){let l=1/0;for(let c=0;c<s-i;c++){let p=Math.max(Math.abs(o(t[c+i].luminance,t[c].luminance)),Math.abs(o(t[c].luminance,t[c+i].luminance)));p<l&&(l=p)}if(l>=h){u=i,r=l;break}i===n&&(r=l)}e[a]={efficiency:u/n,target:h,span:u,value:r}}return e}get contrasts(){return{wcag:this.wcag,apca:this.apca}}get deltaECurve(){let t=[0];for(let s=1;s<this.shades.length;s++){let n=P(this.shades[s-1].lab,this.shades[s].lab);t.push(t[s-1]+n)}return t}get unwrapHues(){let t=this.shades.map(n=>n.hue).slice(1,-1);if(t.length===0)return[];let s=[t[0]];for(let n=1;n<t.length;n++){let e=t[n]-t[n-1];e>180?e-=360:e<-180&&(e+=360),s.push(s[n-1]+e)}return s}get lightnessLinearity(){let t=this.shades.map(p=>p.lightness),s=t.length;if(s<2)return 1;let n=0,e=0,o=0,a=0;for(let p=0;p<s;p++)n+=p,e+=t[p],o+=p*t[p],a+=p*p;let h=s*a-n*n;if(Math.abs(h)<1e-10)return 1;let u=(s*o-n*e)/h,r=(e-u*n)/s;if(Math.abs(u*(s-1))<.001)return 1;let l=0,c=0;for(let p=0;p<s;p++){let g=u*p+r,M=t[p]-g;l+=M*M;let b=Math.max(g-Math.min(r,u*(s-1)+r),Math.max(r,u*(s-1)+r)-g);c+=b*b}return Math.max(0,Math.min(1,1-Math.sqrt(l/s)/Math.sqrt(c/s)))}get chromaSmoothness(){let t=this.shades.map(c=>c.chroma),s=t.length;if(s<3)return 1;let n=133.8,e=Math.max(...t);if(e<=.01)return 1;let o=t.map(c=>c/e*n),a=Math.min(...o),h=Math.max(...o),u=o.findIndex(c=>c===h),r=E([[0,o[0]],[u,h],[s-1,o[s-1]]]),i=0,l=0;for(let c=0;c<s;c++){let p=r(c),g=o[c]-p;i+=g*g,l+=Math.pow(Math.max(p-a,h-p),2)}return Math.max(0,Math.min(1,1-Math.sqrt(i/s)/Math.sqrt(l/s)))}get spacingUniformity(){let t=this.deltaECurve,s=t.length;if(s<2)return 1;let n=[];for(let h=1;h<s;h++){let u=t[h]-t[h-1];if(u<0)return 0;n.push(u)}let e=n.reduce((h,u)=>h+u,0)/n.length;if(e<=1e-6)return 0;let o=0;for(let h of n)o+=Math.pow(h-e,2);let a=Math.sqrt(o/n.length)/e;return Math.max(0,Math.min(1,1/(1+a)))}get hueStability(){var a,h,u;let t=this.unwrapHues,s=t.length;if(s<2)return 1;let n=(u=(h=t[this.baseIndex-1])!=null?h:(a=this.shades[this.baseIndex])==null?void 0:a.hue)!=null?u:0,e=0,o=0;for(let r=0;r<s;r++){let i=Math.abs(t[r]-n)%360;i>180&&(i=360-i),e+=i*i;let l=r/(s-1)*180;o+=l*l}return Math.max(0,Math.min(1,1-Math.sqrt(e/s)/(Math.sqrt(o/s)||1)))}get contrastEfficiency(){let t=this.wcag[45].span,s=this.steps;if(s<=1)return 1;let n=.5,e=t/s,o=n*((s-1)/s);return e<=o?1:e>=1?0:(1-e)/(1-o)}get metrics(){return{lightnessLinearity:this.lightnessLinearity,chromaSmoothness:this.chromaSmoothness,spacingUniformity:this.spacingUniformity,hueStability:this.hueStability,contrastEfficiency:this.contrastEfficiency}}get score(){return L(Object.values(this.metrics))}};var T=class{constructor(t={},s="palette"){this.ramps=Object.entries(t).map(([n,e])=>new q(e,n)),this.name=s}get colors(){return Object.fromEntries(this.ramps.map(t=>[t.name,t.colors]))}get steps(){var t;return((t=this.ramps[0])==null?void 0:t.steps)||0}get direction(){var e;let t=(e=this.ramps[0])==null?void 0:e.colors;if(!(t!=null&&t.length))return"lighten";let s=S(C(t[0])),n=S(C(t[t.length-1]));return s[0]>n[0]?"darken":"lighten"}get wcag(){var s;let t={};for(let n of[30,45,70]){let e=this.ramps.map(r=>r.wcag[n]),o=((s=this.ramps[0])==null?void 0:s.steps)||0,a=Math.max(...e.map(r=>(r==null?void 0:r.span)||0)),h=e.reduce((r,i)=>r+((i==null?void 0:i.value)||0),0),u=e[0];t[n]={target:(u==null?void 0:u.target)||0,span:a,value:h/(this.ramps.length||1),efficiency:a/(o-1||1)}}return t}get apca(){var s;let t={};for(let n of[45,60,75]){let e=this.ramps.map(r=>r.apca[n]),o=((s=this.ramps[0])==null?void 0:s.steps)||0,a=Math.max(...e.map(r=>(r==null?void 0:r.span)||0)),h=e.reduce((r,i)=>r+((i==null?void 0:i.value)||0),0),u=e[0];t[n]={target:(u==null?void 0:u.target)||0,span:a,value:h/(this.ramps.length||1),efficiency:a/(o-1||1)}}return t}get contrasts(){return{wcag:this.wcag,apca:this.apca}}get metrics(){return{contrastEfficiency:x(this.ramps.map(t=>t.contrastEfficiency)),lightnessLinearity:x(this.ramps.map(t=>t.lightnessLinearity)),chromaSmoothness:x(this.ramps.map(t=>t.chromaSmoothness)),hueStability:x(this.ramps.map(t=>t.hueStability)),spacingUniformity:x(this.ramps.map(t=>t.spacingUniformity))}}get score(){return L(Object.values(this.metrics))}};0&&(module.exports={Palette,Ramp,Shade,calcDeltaE2000,calcScore,calcStatistics,createMonotone,cssRgbToRgb,fromLightnessEAL,hexToRgb,labToLch,labToRgb,lchToLab,rgbToHex,rgbToLab,rootMeanSquare,toLightnessEAL});
package/dist/index.d.cts CHANGED
@@ -1,7 +1,3 @@
1
- /** Calculate relative luminance from linear RGB (0-1). */
2
- declare const getRelativeLuminance: (rgb: number[]) => number;
3
- declare const lrgbToSrgb: (rgb: number[]) => number[];
4
- declare const srgbToLrgb: (rgb: number[]) => number[];
5
1
  /** Convert linear RGB to sRGB Hex string. */
6
2
  declare const rgbToHex: (rgb: number[]) => string;
7
3
  /** Convert sRGB Hex string to linear RGB. */
@@ -20,111 +16,8 @@ declare const labToRgb: (lab: number[]) => number[];
20
16
  declare const labToLch: (lab: number[]) => number[];
21
17
  /** Calculate color difference using CIEDE2000 formula. */
22
18
  declare const calcDeltaE2000: (lab1: number[], lab2: number[]) => number;
23
- /** Find the Hex color with the highest Chroma in a list. */
24
- declare const findMaxChromaHex: (scale: string[]) => string;
25
- /** Normalize hue values to prevent large jumps during interpolation. */
26
- declare function unwrapHue(hues: number[]): number[];
27
- /** Simulate Protanopia (red-blindness) on linear RGB. */
28
- declare function simulateProtanopia(rgb: number[]): number[];
29
- /** Simulate Deuteranopia (green-blindness) on linear RGB. */
30
- declare function simulateDeuteranopia(rgb: number[]): number[];
31
19
  /** Convert CSS rgb() string to linear RGB. */
32
20
  declare const cssRgbToRgb: (css: string) => number[];
33
-
34
- type ColorShade = {
35
- hex: string;
36
- rgb: number[];
37
- lab: number[];
38
- lch: number[];
39
- parameter: number;
40
- lightness: number;
41
- chroma: number;
42
- hue: number;
43
- luminance: number;
44
- wcag: number;
45
- apca: number;
46
- cumDeltaE00: number;
47
- cumProtDeltaE00: number;
48
- cumDeutDeltaE00: number;
49
- };
50
-
51
- type ContrastName = 'wcag20' | 'wcag30' | 'wcag45' | 'wcag70' | 'apca45' | 'apca60' | 'apca75' | 'apca90';
52
- type Contrast = {
53
- system: string;
54
- target: number;
55
- span: number;
56
- value: number;
57
- efficiency: number;
58
- name: ContrastName;
59
- };
60
- /** Calculate WCAG 2.x contrast ratio. */
61
- declare const getWcagContrast: (l1: number, l2: number) => number;
62
- /** Calculate APCA Lc (Lightness Contrast) value. */
63
- declare const getApcaContrast: (yText: number, yBg: number) => number;
64
- /** Analyze contrast metrics for a single Monochromatic scale. */
65
- declare const getMonochromaticContrasts: (metrics: ColorShade[]) => Record<string, Contrast>;
66
- declare const contrastList: ContrastName[];
67
- /** Aggregate contrast metrics across multiple color scales. */
68
- declare const getPaletteContrasts: (colorScales: any[]) => Record<ContrastName, Contrast>;
69
-
70
- type MonochromaticAnalysis = {
71
- name: string;
72
- colors: string[];
73
- baseIndex: number;
74
- baseColor: string;
75
- shades: ColorShade[];
76
- metrics: MonochromaticMetrics;
77
- contrasts: Record<ContrastName, Contrast>;
78
- score: number;
79
- };
80
- type MonochromaticMetrics = {
81
- lightnessLinearity: number;
82
- chromaSmoothness: number;
83
- spacingUniformity: number;
84
- hueStability: number;
85
- contrastEfficiency: number;
86
- };
87
- /** Analyze a single monochromatic color scale. */
88
- declare const analyzeMonochromatic: (colors: string[], name?: string, stepNames?: Array<number | string>) => MonochromaticAnalysis;
89
- type MonochromaticPaletteData = {
90
- name: string;
91
- stepNames: Array<number | string>;
92
- colors: Record<string, string[]>;
93
- };
94
- /** Analyze a full palette containing multiple monochromatic scales. */
95
- declare const analyzeMonochromaticPalette: (paletteData: MonochromaticPaletteData) => {
96
- name: string;
97
- baseColors: Record<string, string>;
98
- stepNames: (string | number)[];
99
- direction: string;
100
- steps: number;
101
- colors: Record<string, string[]>;
102
- contrasts: Record<ContrastName, Contrast>;
103
- scales: MonochromaticAnalysis[];
104
- metrics: {
105
- contrastEfficiency: number;
106
- lightnessLinearity: number;
107
- chromaSmoothness: number;
108
- hueStability: number;
109
- spacingUniformity: number;
110
- };
111
- score: number;
112
- };
113
- /** Measure how close lightness values follow a linear trend. */
114
- declare function calcLightnessLinearity(values: number[]): number;
115
- /** Measure hue deviation from a reference color. */
116
- declare function calcHueStability(values: number[], ref: number): number;
117
- /** Measure the smoothness of chroma transitions using a spline peak. */
118
- declare const calcChromaSmoothness: (C: number[]) => number;
119
- /** Measure visual spacing uniformity using DeltaE2000. */
120
- declare const calcSpacingUniformity: (cumulativeDeltaE00: number[]) => number;
121
- /**
122
- * Evaluate Contrast Span Efficiency (η) using Continuous Linear Scaling.
123
- * This scientific approach removes quantization bias (no ceil/floor),
124
- * ensuring fairness across both odd and even step counts.
125
- */
126
- declare const calcContrastEfficiency: (span: number, steps: number) => number;
127
-
128
21
  /**
129
22
  * Create a Monotone Cubic Hermite Interpolator.
130
23
  * Ensures monotonicity is preserved between points.
@@ -142,4 +35,84 @@ declare const calcStatistics: (array: number[]) => {
142
35
  /** Calculate geometric mean score (0-100) from metrics. */
143
36
  declare const calcScore: (metrics: number[]) => number;
144
37
 
145
- export { type Contrast, type ContrastName, type MonochromaticAnalysis, type MonochromaticMetrics, type MonochromaticPaletteData, analyzeMonochromatic, analyzeMonochromaticPalette, calcChromaSmoothness, calcContrastEfficiency, calcDeltaE2000, calcHueStability, calcLightnessLinearity, calcScore, calcSpacingUniformity, calcStatistics, contrastList, createMonotone, cssRgbToRgb, findMaxChromaHex, fromLightnessEAL, getApcaContrast, getMonochromaticContrasts, getPaletteContrasts, getRelativeLuminance, getWcagContrast, hexToRgb, labToLch, labToRgb, lchToLab, lrgbToSrgb, rgbToHex, rgbToLab, rootMeanSquare, simulateDeuteranopia, simulateProtanopia, srgbToLrgb, toLightnessEAL, unwrapHue };
38
+ declare class Shade {
39
+ readonly hex: string;
40
+ constructor(hex: string);
41
+ get rgb(): number[];
42
+ get lab(): number[];
43
+ get lch(): number[];
44
+ get lightness(): number;
45
+ get chroma(): number;
46
+ get hue(): number;
47
+ get luminance(): number;
48
+ get wcag(): number;
49
+ get apca(): number;
50
+ }
51
+
52
+ type ContrastValue = {
53
+ efficiency: number;
54
+ target: number;
55
+ span: number;
56
+ value: number;
57
+ };
58
+ type WcagContrasts = Record<30 | 45 | 70, ContrastValue>;
59
+ type ApcaContrasts = Record<45 | 60 | 75, ContrastValue>;
60
+ declare class Ramp {
61
+ shades: Shade[];
62
+ name: string;
63
+ constructor(colors?: string[], name?: string);
64
+ get colors(): string[];
65
+ get peakChroma(): string;
66
+ get steps(): number;
67
+ get baseColor(): string;
68
+ get baseIndex(): number;
69
+ get wcag(): WcagContrasts;
70
+ get apca(): ApcaContrasts;
71
+ get contrasts(): {
72
+ wcag: WcagContrasts;
73
+ apca: ApcaContrasts;
74
+ };
75
+ get deltaECurve(): number[];
76
+ get unwrapHues(): number[];
77
+ get lightnessLinearity(): number;
78
+ get chromaSmoothness(): number;
79
+ get spacingUniformity(): number;
80
+ get hueStability(): number;
81
+ get contrastEfficiency(): number;
82
+ get metrics(): {
83
+ lightnessLinearity: number;
84
+ chromaSmoothness: number;
85
+ spacingUniformity: number;
86
+ hueStability: number;
87
+ contrastEfficiency: number;
88
+ };
89
+ get score(): number;
90
+ }
91
+
92
+ type PaletteMetrics = {
93
+ contrastEfficiency: number;
94
+ lightnessLinearity: number;
95
+ chromaSmoothness: number;
96
+ hueStability: number;
97
+ spacingUniformity: number;
98
+ };
99
+ declare class Palette {
100
+ ramps: Ramp[];
101
+ name: string;
102
+ constructor(colors?: Record<string, string[]>, name?: string);
103
+ get colors(): {
104
+ [k: string]: string[];
105
+ };
106
+ get steps(): number;
107
+ get direction(): "lighten" | "darken";
108
+ get wcag(): WcagContrasts;
109
+ get apca(): ApcaContrasts;
110
+ get contrasts(): {
111
+ wcag: WcagContrasts;
112
+ apca: ApcaContrasts;
113
+ };
114
+ get metrics(): PaletteMetrics;
115
+ get score(): number;
116
+ }
117
+
118
+ export { type ApcaContrasts, type ContrastValue, Palette, type PaletteMetrics, Ramp, Shade, type WcagContrasts, calcDeltaE2000, calcScore, calcStatistics, createMonotone, cssRgbToRgb, fromLightnessEAL, hexToRgb, labToLch, labToRgb, lchToLab, rgbToHex, rgbToLab, rootMeanSquare, toLightnessEAL };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,3 @@
1
- /** Calculate relative luminance from linear RGB (0-1). */
2
- declare const getRelativeLuminance: (rgb: number[]) => number;
3
- declare const lrgbToSrgb: (rgb: number[]) => number[];
4
- declare const srgbToLrgb: (rgb: number[]) => number[];
5
1
  /** Convert linear RGB to sRGB Hex string. */
6
2
  declare const rgbToHex: (rgb: number[]) => string;
7
3
  /** Convert sRGB Hex string to linear RGB. */
@@ -20,111 +16,8 @@ declare const labToRgb: (lab: number[]) => number[];
20
16
  declare const labToLch: (lab: number[]) => number[];
21
17
  /** Calculate color difference using CIEDE2000 formula. */
22
18
  declare const calcDeltaE2000: (lab1: number[], lab2: number[]) => number;
23
- /** Find the Hex color with the highest Chroma in a list. */
24
- declare const findMaxChromaHex: (scale: string[]) => string;
25
- /** Normalize hue values to prevent large jumps during interpolation. */
26
- declare function unwrapHue(hues: number[]): number[];
27
- /** Simulate Protanopia (red-blindness) on linear RGB. */
28
- declare function simulateProtanopia(rgb: number[]): number[];
29
- /** Simulate Deuteranopia (green-blindness) on linear RGB. */
30
- declare function simulateDeuteranopia(rgb: number[]): number[];
31
19
  /** Convert CSS rgb() string to linear RGB. */
32
20
  declare const cssRgbToRgb: (css: string) => number[];
33
-
34
- type ColorShade = {
35
- hex: string;
36
- rgb: number[];
37
- lab: number[];
38
- lch: number[];
39
- parameter: number;
40
- lightness: number;
41
- chroma: number;
42
- hue: number;
43
- luminance: number;
44
- wcag: number;
45
- apca: number;
46
- cumDeltaE00: number;
47
- cumProtDeltaE00: number;
48
- cumDeutDeltaE00: number;
49
- };
50
-
51
- type ContrastName = 'wcag20' | 'wcag30' | 'wcag45' | 'wcag70' | 'apca45' | 'apca60' | 'apca75' | 'apca90';
52
- type Contrast = {
53
- system: string;
54
- target: number;
55
- span: number;
56
- value: number;
57
- efficiency: number;
58
- name: ContrastName;
59
- };
60
- /** Calculate WCAG 2.x contrast ratio. */
61
- declare const getWcagContrast: (l1: number, l2: number) => number;
62
- /** Calculate APCA Lc (Lightness Contrast) value. */
63
- declare const getApcaContrast: (yText: number, yBg: number) => number;
64
- /** Analyze contrast metrics for a single Monochromatic scale. */
65
- declare const getMonochromaticContrasts: (metrics: ColorShade[]) => Record<string, Contrast>;
66
- declare const contrastList: ContrastName[];
67
- /** Aggregate contrast metrics across multiple color scales. */
68
- declare const getPaletteContrasts: (colorScales: any[]) => Record<ContrastName, Contrast>;
69
-
70
- type MonochromaticAnalysis = {
71
- name: string;
72
- colors: string[];
73
- baseIndex: number;
74
- baseColor: string;
75
- shades: ColorShade[];
76
- metrics: MonochromaticMetrics;
77
- contrasts: Record<ContrastName, Contrast>;
78
- score: number;
79
- };
80
- type MonochromaticMetrics = {
81
- lightnessLinearity: number;
82
- chromaSmoothness: number;
83
- spacingUniformity: number;
84
- hueStability: number;
85
- contrastEfficiency: number;
86
- };
87
- /** Analyze a single monochromatic color scale. */
88
- declare const analyzeMonochromatic: (colors: string[], name?: string, stepNames?: Array<number | string>) => MonochromaticAnalysis;
89
- type MonochromaticPaletteData = {
90
- name: string;
91
- stepNames: Array<number | string>;
92
- colors: Record<string, string[]>;
93
- };
94
- /** Analyze a full palette containing multiple monochromatic scales. */
95
- declare const analyzeMonochromaticPalette: (paletteData: MonochromaticPaletteData) => {
96
- name: string;
97
- baseColors: Record<string, string>;
98
- stepNames: (string | number)[];
99
- direction: string;
100
- steps: number;
101
- colors: Record<string, string[]>;
102
- contrasts: Record<ContrastName, Contrast>;
103
- scales: MonochromaticAnalysis[];
104
- metrics: {
105
- contrastEfficiency: number;
106
- lightnessLinearity: number;
107
- chromaSmoothness: number;
108
- hueStability: number;
109
- spacingUniformity: number;
110
- };
111
- score: number;
112
- };
113
- /** Measure how close lightness values follow a linear trend. */
114
- declare function calcLightnessLinearity(values: number[]): number;
115
- /** Measure hue deviation from a reference color. */
116
- declare function calcHueStability(values: number[], ref: number): number;
117
- /** Measure the smoothness of chroma transitions using a spline peak. */
118
- declare const calcChromaSmoothness: (C: number[]) => number;
119
- /** Measure visual spacing uniformity using DeltaE2000. */
120
- declare const calcSpacingUniformity: (cumulativeDeltaE00: number[]) => number;
121
- /**
122
- * Evaluate Contrast Span Efficiency (η) using Continuous Linear Scaling.
123
- * This scientific approach removes quantization bias (no ceil/floor),
124
- * ensuring fairness across both odd and even step counts.
125
- */
126
- declare const calcContrastEfficiency: (span: number, steps: number) => number;
127
-
128
21
  /**
129
22
  * Create a Monotone Cubic Hermite Interpolator.
130
23
  * Ensures monotonicity is preserved between points.
@@ -142,4 +35,84 @@ declare const calcStatistics: (array: number[]) => {
142
35
  /** Calculate geometric mean score (0-100) from metrics. */
143
36
  declare const calcScore: (metrics: number[]) => number;
144
37
 
145
- export { type Contrast, type ContrastName, type MonochromaticAnalysis, type MonochromaticMetrics, type MonochromaticPaletteData, analyzeMonochromatic, analyzeMonochromaticPalette, calcChromaSmoothness, calcContrastEfficiency, calcDeltaE2000, calcHueStability, calcLightnessLinearity, calcScore, calcSpacingUniformity, calcStatistics, contrastList, createMonotone, cssRgbToRgb, findMaxChromaHex, fromLightnessEAL, getApcaContrast, getMonochromaticContrasts, getPaletteContrasts, getRelativeLuminance, getWcagContrast, hexToRgb, labToLch, labToRgb, lchToLab, lrgbToSrgb, rgbToHex, rgbToLab, rootMeanSquare, simulateDeuteranopia, simulateProtanopia, srgbToLrgb, toLightnessEAL, unwrapHue };
38
+ declare class Shade {
39
+ readonly hex: string;
40
+ constructor(hex: string);
41
+ get rgb(): number[];
42
+ get lab(): number[];
43
+ get lch(): number[];
44
+ get lightness(): number;
45
+ get chroma(): number;
46
+ get hue(): number;
47
+ get luminance(): number;
48
+ get wcag(): number;
49
+ get apca(): number;
50
+ }
51
+
52
+ type ContrastValue = {
53
+ efficiency: number;
54
+ target: number;
55
+ span: number;
56
+ value: number;
57
+ };
58
+ type WcagContrasts = Record<30 | 45 | 70, ContrastValue>;
59
+ type ApcaContrasts = Record<45 | 60 | 75, ContrastValue>;
60
+ declare class Ramp {
61
+ shades: Shade[];
62
+ name: string;
63
+ constructor(colors?: string[], name?: string);
64
+ get colors(): string[];
65
+ get peakChroma(): string;
66
+ get steps(): number;
67
+ get baseColor(): string;
68
+ get baseIndex(): number;
69
+ get wcag(): WcagContrasts;
70
+ get apca(): ApcaContrasts;
71
+ get contrasts(): {
72
+ wcag: WcagContrasts;
73
+ apca: ApcaContrasts;
74
+ };
75
+ get deltaECurve(): number[];
76
+ get unwrapHues(): number[];
77
+ get lightnessLinearity(): number;
78
+ get chromaSmoothness(): number;
79
+ get spacingUniformity(): number;
80
+ get hueStability(): number;
81
+ get contrastEfficiency(): number;
82
+ get metrics(): {
83
+ lightnessLinearity: number;
84
+ chromaSmoothness: number;
85
+ spacingUniformity: number;
86
+ hueStability: number;
87
+ contrastEfficiency: number;
88
+ };
89
+ get score(): number;
90
+ }
91
+
92
+ type PaletteMetrics = {
93
+ contrastEfficiency: number;
94
+ lightnessLinearity: number;
95
+ chromaSmoothness: number;
96
+ hueStability: number;
97
+ spacingUniformity: number;
98
+ };
99
+ declare class Palette {
100
+ ramps: Ramp[];
101
+ name: string;
102
+ constructor(colors?: Record<string, string[]>, name?: string);
103
+ get colors(): {
104
+ [k: string]: string[];
105
+ };
106
+ get steps(): number;
107
+ get direction(): "lighten" | "darken";
108
+ get wcag(): WcagContrasts;
109
+ get apca(): ApcaContrasts;
110
+ get contrasts(): {
111
+ wcag: WcagContrasts;
112
+ apca: ApcaContrasts;
113
+ };
114
+ get metrics(): PaletteMetrics;
115
+ get score(): number;
116
+ }
117
+
118
+ export { type ApcaContrasts, type ContrastValue, Palette, type PaletteMetrics, Ramp, Shade, type WcagContrasts, calcDeltaE2000, calcScore, calcStatistics, createMonotone, cssRgbToRgb, fromLightnessEAL, hexToRgb, labToLch, labToRgb, lchToLab, rgbToHex, rgbToLab, rootMeanSquare, toLightnessEAL };
@@ -1 +1 @@
1
- "use strict";var Chromametry=(()=>{var P=Object.defineProperty;var ot=Object.getOwnPropertyDescriptor;var at=Object.getOwnPropertyNames;var st=Object.prototype.hasOwnProperty;var ct=(r,t)=>{for(var n in t)P(r,n,{get:t[n],enumerable:!0})},mt=(r,t,n,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of at(t))!st.call(r,o)&&o!==n&&P(r,o,{get:()=>t[o],enumerable:!(e=ot(t,o))||e.enumerable});return r};var ht=r=>mt(P({},"__esModule",{value:!0}),r);var dt={};ct(dt,{analyzeMonochromatic:()=>O,analyzeMonochromaticPalette:()=>xt,calcChromaSmoothness:()=>K,calcContrastEfficiency:()=>Q,calcDeltaE2000:()=>A,calcHueStability:()=>Z,calcLightnessLinearity:()=>W,calcScore:()=>I,calcSpacingUniformity:()=>J,calcStatistics:()=>ft,contrastList:()=>H,createMonotone:()=>z,cssRgbToRgb:()=>gt,findMaxChromaHex:()=>k,fromLightnessEAL:()=>ut,getApcaContrast:()=>L,getMonochromaticContrasts:()=>N,getPaletteContrasts:()=>X,getRelativeLuminance:()=>D,getWcagContrast:()=>R,hexToRgb:()=>f,labToLch:()=>q,labToRgb:()=>lt,lchToLab:()=>bt,lrgbToSrgb:()=>G,rgbToHex:()=>it,rgbToLab:()=>x,rootMeanSquare:()=>y,simulateDeuteranopia:()=>Mt,simulateProtanopia:()=>pt,srgbToLrgb:()=>_,toLightnessEAL:()=>T,unwrapHue:()=>v});var D=r=>{let[t,n,e]=r;return .2126*t+.7152*n+.0722*e},G=r=>{let t=n=>{let e=Math.max(0,Math.min(1,n)),o=e<=.0031308?12.92*e:1.055*Math.pow(e,1/2.4)-.055;return Math.max(0,Math.min(255,Math.round(o*255)))};return r.map(t)},_=r=>{let t=n=>n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92;return r.map(t)},it=r=>{let[t,n,e]=G(r);return t=t.toString(16).padStart(2,"0"),n=n.toString(16).padStart(2,"0"),e=e.toString(16).padStart(2,"0"),`#${t}${n}${e}`},f=r=>{let t=parseInt(r.slice(1,3),16)/255,n=parseInt(r.slice(3,5),16)/255,e=parseInt(r.slice(5,7),16)/255;return _([t,n,e])},T=r=>{let[t,n,e]=r,o=Math.sqrt(n*n+e*e),s=(Math.atan2(e,n)*180/Math.PI+360)%360,i=.1644,b=.0603,m=.1307,u=.006,h=i*Math.abs(Math.sin((s-90)/2*(Math.PI/180)))+b,a=0;return(s<=90||s>=270)&&(a=m*Math.abs(Math.cos(s*(Math.PI/180)))+u),t+(h+a)*o},ut=(r,t)=>{let[,n,e]=t,o=Math.sqrt(n*n+e*e),s=(Math.atan2(e,n)*180/Math.PI+360)%360,i=.1644,b=.0603,m=.1307,u=.006,h=i*Math.abs(Math.sin((s-90)/2*(Math.PI/180)))+b,a=0;return(s<=90||s>=270)&&(a=m*Math.abs(Math.cos(s*(Math.PI/180)))+u),Math.max(0,r-(h+a)*o)},bt=r=>{let[t,n,e]=r,o=e*Math.PI/180;return[t,n*Math.cos(o),n*Math.sin(o)]},x=r=>{let[t,n,e]=r,o=.4124564*t+.3575761*n+.1804375*e,c=.2126729*t+.7151522*n+.072175*e,s=.0193339*t+.119192*n+.9503041*e,i=.95047,b=1,m=1.08883,u=p=>p>.008856?Math.cbrt(p):7.787*p+16/116,h=u(o/i),a=u(c/b),l=u(s/m);return[116*a-16,500*(h-a),200*(a-l)]},lt=r=>{let[t,n,e]=r,o=(t+16)/116,c=n/500+o,s=o-e/200,i=p=>p**3>.008856?p**3:(p-16/116)/7.787,b=.95047,m=1,u=1.08883,h=i(c)*b,a=i(o)*m,l=i(s)*u;return[3.2404542*h-1.5371385*a-.4985314*l,-.969266*h+1.8760108*a+.041556*l,.0556434*h-.2040259*a+1.0572252*l]},q=r=>{let[t,n,e]=r,o=Math.sqrt(n*n+e*e);if(o<1e-4)return[t,0,0];let s=(Math.atan2(e,n)*180/Math.PI+360)%360;return s>=359.9999&&(s=0),[t,o,s]},A=(r,t)=>{let[n,e,o]=r,[c,s,i]=t,b=(n+c)/2,m=Math.sqrt(e*e+o*o),u=Math.sqrt(s*s+i*i),h=(m+u)/2,a=.5*(1-Math.sqrt(Math.pow(h,7)/(Math.pow(h,7)+Math.pow(25,7)))),l=e*(1+a),p=s*(1+a),M=Math.sqrt(l*l+o*o),d=Math.sqrt(p*p+i*i),S=(M+d)/2,C=Math.atan2(o,l)*180/Math.PI+(Math.atan2(o,l)<0?360:0),g=Math.atan2(i,p)*180/Math.PI+(Math.atan2(i,p)<0?360:0),E=g-C;Math.abs(E)>180&&(E+=g<=C?360:-360);let w=Math.abs(C-g)>180?(C+g+360)/2:(C+g)/2,V=1-.17*Math.cos((w-30)*Math.PI/180)+.24*Math.cos(2*w*Math.PI/180)+.32*Math.cos((3*w+6)*Math.PI/180)-.2*Math.cos((4*w-63)*Math.PI/180),tt=c-n,Y=d-M,B=2*Math.sqrt(M*d)*Math.sin(E/2*Math.PI/180),nt=1+.015*Math.pow(b-50,2)/Math.sqrt(20+Math.pow(b-50,2)),U=1+.045*S,$=1+.015*S*V,rt=30*Math.exp(-Math.pow((w-275)/25,2)),et=-(2*Math.sqrt(Math.pow(S,7)/(Math.pow(S,7)+Math.pow(25,7))))*Math.sin(2*rt*Math.PI/180);return Math.sqrt(Math.pow(tt/nt,2)+Math.pow(Y/U,2)+Math.pow(B/$,2)+et*(Y/U)*(B/$))},k=r=>{let t="",n=-1/0;for(let e of r){let o=x(f(e)),[,c]=q(o);c>n&&(n=c,t=e)}return t};function v(r){let t=[r[0]];for(let n=1;n<r.length;n++){let e=r[n]-r[n-1];e>180?e-=360:e<-180&&(e+=360),t.push(t[n-1]+e)}return t}function pt(r){let[t,n,e]=r;return[.152286*t+1.052583*n-.204868*e,.114503*t+.786281*n+.099216*e,-.003882*t-.048116*n+1.051998*e]}function Mt(r){let[t,n,e]=r;return[.367322*t+.860646*n-.227968*e,.280085*t+.672501*n+.047413*e,-.01182*t+.04294*n+.968881*e]}var gt=r=>{let t=r.match(/\d+(\.\d+)?/g);if(!t||t.length<3)throw new Error("Invalid CSS rgb()");let n=e=>{let o=e/255;return o<=.04045?o/12.92:Math.pow((o+.055)/1.055,2.4)};return[n(Number(t[0])),n(Number(t[1])),n(Number(t[2]))]};var R=(r,t)=>(Math.max(r,t)+.05)/(Math.min(r,t)+.05),L=(r,t)=>{let n=s=>s>5e-4?s:s+Math.pow(5e-4-s,.8),e=n(r),o=n(t),c=(Math.pow(e,.56)-Math.pow(o,.56))*100;return Math.abs(c)<.1?0:(c=c>0?c<1?0:c-.25:c>-1?0:c+.25,Math.round(c))};function j(r){let t=r.match(/^(wcag|apca)(\d+)$/);if(!t)throw new Error(`Invalid contrast: ${r}`);let n=t[1]==="wcag"?Number(t[2])/10:Number(t[2]);return{system:t[1],target:n}}var N=r=>{let t={},n=r.length,e=n-1;return H.forEach(o=>{let{system:c,target:s}=j(o),i=e,b=0;for(let m=1;m<n;m++){let u=1/0;for(let h=0;h<n-m;h++){let a=c==="wcag"?R(r[h].luminance,r[h+m].luminance):Math.max(Math.abs(L(r[h+m].luminance,r[h].luminance)),Math.abs(L(r[h].luminance,r[h+m].luminance)));a<u&&(u=a)}if(u>=s){i=m,b=u;break}m===e&&(b=u)}t[o]={system:c,efficiency:i/e,target:s,span:i,value:b,name:o}}),t},H=["wcag30","wcag45","wcag70","apca45","apca60","apca75"],X=r=>{let t={};return H.forEach(n=>{var m;let{target:e,system:o}=j(n),c=r.map(u=>u.contrasts[n]),s=((m=r[0])==null?void 0:m.shades.length)||0,i=Math.max(...c.map(u=>(u==null?void 0:u.span)||0)),b=c.reduce((u,h)=>u+((h==null?void 0:h.value)||0),0);t[n]={system:o,target:e,span:i,value:b/(r.length||1),name:n,efficiency:i/(s-1||1)}}),t};var F=r=>{let t=f(r),n=x(t),e=D(t),o=T(n),c=q(n);return{hex:r,rgb:t,lab:n,lch:c,lightness:o,chroma:c[1],hue:c[2],luminance:e,parameter:0,cumDeltaE00:0,cumProtDeltaE00:0,cumDeutDeltaE00:0,wcag:R(e,1),apca:L(e,1)}};var z=r=>{if(r.length<1)return m=>0;let t=[...r].sort((m,u)=>m[0]-u[0]),n=[];for(let m=0;m<t.length;m++)(m===0||t[m][0]!==t[m-1][0])&&n.push(t[m]);let e=n.length;if(e===1)return m=>n[0][1];let o=n.map(m=>m[0]),c=n.map(m=>m[1]),s=[],i=[];for(let m=0;m<e-1;m++)s[m]=o[m+1]-o[m],i[m]=(c[m+1]-c[m])/s[m];let b=new Array(e);b[0]=i[0],b[e-1]=i[e-2];for(let m=1;m<e-1;m++){let u=i[m-1],h=i[m];if(u*h<=0)b[m]=0;else{let a=(1+s[m]/(s[m-1]+s[m]))/3;b[m]=u*h/((1-a)*u+a*h)}}return m=>{if(m<=o[0])return c[0];if(m>=o[e-1])return c[e-1];let u=0,h=e-2,a=0;for(;u<=h;){let g=Math.floor((u+h)/2);if(m>=o[g]&&m<=o[g+1]){a=g;break}m<o[g]?h=g-1:u=g+1}let l=s[a],p=(m-o[a])/l,M=p*p,d=M*p,S=b[a]*l,C=b[a+1]*l;return(2*d-3*M+1)*c[a]+(d-2*M+p)*S+(-2*d+3*M)*c[a+1]+(d-M)*C}};function y(r){let t=r.length;if(t===0)return 0;let n=0;for(let e=0;e<t;e++)n+=r[e]*r[e];return Math.sqrt(n/t)}var ft=r=>{let t=r.length;if(t===0)return{min:0,max:0,avg:0};let n=r[0],e=r[0],o=0;for(let c=0;c<t;c++){let s=r[c];s<n&&(n=s),s>e&&(e=s),o+=s}return{min:n,max:e,avg:o/t}},I=r=>{let t=r.length;if(t===0)return 0;let n=1e-6,e=r.reduce((s,i)=>s*(i+n),1),o=Math.pow(e,1/t),c=Math.max(0,Math.min(1,o));return parseFloat((c*100).toFixed(2))};var O=(r,t,n)=>{t||(t="brand"),n||(n=[...Array(r.length).keys()]);let e=x(f(r[0]))[0],o=x(f(r[r.length-1]))[0];e>o&&r.reverse();let c=r.map(a=>F(a));for(let a=1;a<c.length;a++){let l=A(c[a-1].lab,c[a].lab);c[a].cumDeltaE00=c[a-1].cumDeltaE00+l}let s=k(r.slice(2,-2))||r[Math.floor(r.length/2)],i=r.findIndex(a=>a.toLowerCase()===(s==null?void 0:s.toLowerCase())),b=v(c.map(a=>a.hue).slice(1,-1));for(let a=1;a<c.length-1;a++)c[a].hue=b[a-1];let m=Z(c.map(a=>a.hue).slice(1,-1),c[i].hue),u=N(c),h={lightnessLinearity:W(c.map(a=>a.lightness)),chromaSmoothness:K(c.map(a=>a.chroma)),spacingUniformity:J(c.map(a=>a.cumDeltaE00)),contrastEfficiency:Q(u.wcag45.span,n.length),hueStability:m};return{name:t,colors:r,baseIndex:i,baseColor:s,shades:c,contrasts:u,metrics:h,score:I(Object.values(h))}},xt=r=>{let{stepNames:t,name:n,colors:e}=r,o=Object.values(e)[0],c=x(f(o[0]))[0],s=x(f(o[o.length-1]))[0],i=c>s?"darken":"lighten",b=[],m={};for(let h in e){let a=O(e[h],h,t);b.push(a),m[h]=a.baseColor}let u={contrastEfficiency:y(b.map(h=>h.metrics.contrastEfficiency)),lightnessLinearity:y(b.map(h=>h.metrics.lightnessLinearity)),chromaSmoothness:y(b.map(h=>h.metrics.chromaSmoothness)),hueStability:y(b.map(h=>h.metrics.hueStability)),spacingUniformity:y(b.map(h=>h.metrics.spacingUniformity))};return{name:n,baseColors:m,stepNames:t,direction:i,steps:t.length,colors:e,contrasts:X(b),scales:b,metrics:u,score:I(Object.values(u))}};function W(r){let t=r.length;if(t<2)return 1;let n=0,e=0,o=0,c=0;for(let a=0;a<t;a++)n+=a,e+=r[a],o+=a*r[a],c+=a*a;let s=t*c-n*n;if(Math.abs(s)<1e-10)return 1;let i=(t*o-n*e)/s,b=(e-i*n)/t;if(Math.abs(i*(t-1))<.001)return 1;let u=0,h=0;for(let a=0;a<t;a++){let l=i*a+b,p=r[a]-l;u+=p*p;let M=Math.max(l-Math.min(b,i*(t-1)+b),Math.max(b,i*(t-1)+b)-l);h+=M*M}return Math.max(0,Math.min(1,1-Math.sqrt(u/t)/Math.sqrt(h/t)))}function Z(r,t){let n=r.length;if(n<2)return 1;let e=0,o=0;for(let c=0;c<n;c++){let s=Math.abs(r[c]-t)%360;s>180&&(s=360-s),e+=s*s;let i=c/(n-1)*180;o+=i*i}return Math.max(0,Math.min(1,1-Math.sqrt(e/n)/(Math.sqrt(o/n)||1)))}var K=r=>{let t=r.length;if(t<3)return 1;let n=133.8,e=Math.max(...r);if(e<=.01)return 1;let o=r.map(h=>h/e*n),c=Math.min(...o),s=Math.max(...o),i=o.findIndex(h=>h===s),b=z([[0,o[0]],[i,s],[t-1,o[t-1]]]),m=0,u=0;for(let h=0;h<t;h++){let a=b(h),l=o[h]-a;m+=l*l,u+=Math.pow(Math.max(a-c,s-a),2)}return Math.max(0,Math.min(1,1-Math.sqrt(m/t)/Math.sqrt(u/t)))},J=r=>{let t=r.length;if(t<2)return 1;let n=[];for(let s=1;s<t;s++){let i=r[s]-r[s-1];if(i<0)return 0;n.push(i)}let e=n.reduce((s,i)=>s+i,0)/n.length;if(e<=1e-6)return 0;let o=0;for(let s of n)o+=Math.pow(s-e,2);let c=Math.sqrt(o/n.length)/e;return Math.max(0,Math.min(1,1/(1+c)))},Q=(r,t)=>{if(t<=1)return 1;let n=.5,e=r/t,o=n*((t-1)/t);return e<=o?1:e>=1?0:(1-e)/(1-o)};return ht(dt);})();
1
+ "use strict";var Chromametry=(()=>{var v=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var O=Object.prototype.hasOwnProperty;var N=(m,t)=>{for(var s in t)v(m,s,{get:t[s],enumerable:!0})},V=(m,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of j(t))!O.call(m,e)&&e!==s&&v(m,e,{get:()=>t[e],enumerable:!(n=G(t,e))||n.enumerable});return m};var $=m=>V(v({},"__esModule",{value:!0}),m);var et={};N(et,{Palette:()=>T,Ramp:()=>q,Shade:()=>y,calcDeltaE2000:()=>P,calcScore:()=>L,calcStatistics:()=>nt,createMonotone:()=>E,cssRgbToRgb:()=>st,fromLightnessEAL:()=>J,hexToRgb:()=>C,labToLch:()=>k,labToRgb:()=>tt,lchToLab:()=>Q,rgbToHex:()=>Z,rgbToLab:()=>S,rootMeanSquare:()=>x,toLightnessEAL:()=>_});var F=m=>{let t=s=>{let n=Math.max(0,Math.min(1,s)),e=n<=.0031308?12.92*n:1.055*Math.pow(n,1/2.4)-.055;return Math.max(0,Math.min(255,Math.round(e*255)))};return m.map(t)},K=m=>{let t=s=>s>.04045?Math.pow((s+.055)/1.055,2.4):s/12.92;return m.map(t)},Z=m=>{let[t,s,n]=F(m);return t=t.toString(16).padStart(2,"0"),s=s.toString(16).padStart(2,"0"),n=n.toString(16).padStart(2,"0"),`#${t}${s}${n}`},C=m=>{let t=parseInt(m.slice(1,3),16)/255,s=parseInt(m.slice(3,5),16)/255,n=parseInt(m.slice(5,7),16)/255;return K([t,s,n])},_=m=>{let[t,s,n]=m,e=Math.sqrt(s*s+n*n),a=(Math.atan2(n,s)*180/Math.PI+360)%360,h=.1644,u=.0603,r=.1307,i=.006,l=h*Math.abs(Math.sin((a-90)/2*(Math.PI/180)))+u,c=0;return(a<=90||a>=270)&&(c=r*Math.abs(Math.cos(a*(Math.PI/180)))+i),t+(l+c)*e},J=(m,t)=>{let[,s,n]=t,e=Math.sqrt(s*s+n*n),a=(Math.atan2(n,s)*180/Math.PI+360)%360,h=.1644,u=.0603,r=.1307,i=.006,l=h*Math.abs(Math.sin((a-90)/2*(Math.PI/180)))+u,c=0;return(a<=90||a>=270)&&(c=r*Math.abs(Math.cos(a*(Math.PI/180)))+i),Math.max(0,m-(l+c)*e)},Q=m=>{let[t,s,n]=m,e=n*Math.PI/180;return[t,s*Math.cos(e),s*Math.sin(e)]},S=m=>{let[t,s,n]=m,e=.4124564*t+.3575761*s+.1804375*n,o=.2126729*t+.7151522*s+.072175*n,a=.0193339*t+.119192*s+.9503041*n,h=.95047,u=1,r=1.08883,i=g=>g>.008856?Math.cbrt(g):7.787*g+16/116,l=i(e/h),c=i(o/u),p=i(a/r);return[116*c-16,500*(l-c),200*(c-p)]},tt=m=>{let[t,s,n]=m,e=(t+16)/116,o=s/500+e,a=e-n/200,h=g=>g**3>.008856?g**3:(g-16/116)/7.787,u=.95047,r=1,i=1.08883,l=h(o)*u,c=h(e)*r,p=h(a)*i;return[3.2404542*l-1.5371385*c-.4985314*p,-.969266*l+1.8760108*c+.041556*p,.0556434*l-.2040259*c+1.0572252*p]},k=m=>{let[t,s,n]=m,e=Math.sqrt(s*s+n*n);if(e<1e-4)return[t,0,0];let a=(Math.atan2(n,s)*180/Math.PI+360)%360;return a>=359.9999&&(a=0),[t,e,a]},P=(m,t)=>{let[s,n,e]=m,[o,a,h]=t,u=(s+o)/2,r=Math.sqrt(n*n+e*e),i=Math.sqrt(a*a+h*h),l=(r+i)/2,c=.5*(1-Math.sqrt(Math.pow(l,7)/(Math.pow(l,7)+Math.pow(25,7)))),p=n*(1+c),g=a*(1+c),M=Math.sqrt(p*p+e*e),b=Math.sqrt(g*g+h*h),w=(M+b)/2,d=Math.atan2(e,p)*180/Math.PI+(Math.atan2(e,p)<0?360:0),f=Math.atan2(h,g)*180/Math.PI+(Math.atan2(h,g)<0?360:0),R=f-d;Math.abs(R)>180&&(R+=f<=d?360:-360);let I=Math.abs(d-f)>180?(d+f+360)/2:(d+f)/2,U=1-.17*Math.cos((I-30)*Math.PI/180)+.24*Math.cos(2*I*Math.PI/180)+.32*Math.cos((3*I+6)*Math.PI/180)-.2*Math.cos((4*I-63)*Math.PI/180),W=o-s,A=b-M,D=2*Math.sqrt(M*b)*Math.sin(R/2*Math.PI/180),X=1+.015*Math.pow(u-50,2)/Math.sqrt(20+Math.pow(u-50,2)),H=1+.045*w,Y=1+.015*w*U,z=30*Math.exp(-Math.pow((I-275)/25,2)),B=-(2*Math.sqrt(Math.pow(w,7)/(Math.pow(w,7)+Math.pow(25,7))))*Math.sin(2*z*Math.PI/180);return Math.sqrt(Math.pow(W/X,2)+Math.pow(A/H,2)+Math.pow(D/Y,2)+B*(A/H)*(D/Y))},st=m=>{let t=m.match(/\d+(\.\d+)?/g);if(!t||t.length<3)throw new Error("Invalid CSS rgb()");let s=n=>{let e=n/255;return e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4)};return[s(Number(t[0])),s(Number(t[1])),s(Number(t[2]))]},E=m=>{if(m.length<1)return r=>0;let t=[...m].sort((r,i)=>r[0]-i[0]),s=[];for(let r=0;r<t.length;r++)(r===0||t[r][0]!==t[r-1][0])&&s.push(t[r]);let n=s.length;if(n===1)return r=>s[0][1];let e=s.map(r=>r[0]),o=s.map(r=>r[1]),a=[],h=[];for(let r=0;r<n-1;r++)a[r]=e[r+1]-e[r],h[r]=(o[r+1]-o[r])/a[r];let u=new Array(n);u[0]=h[0],u[n-1]=h[n-2];for(let r=1;r<n-1;r++){let i=h[r-1],l=h[r];if(i*l<=0)u[r]=0;else{let c=(1+a[r]/(a[r-1]+a[r]))/3;u[r]=i*l/((1-c)*i+c*l)}}return r=>{if(r<=e[0])return o[0];if(r>=e[n-1])return o[n-1];let i=0,l=n-2,c=0;for(;i<=l;){let f=Math.floor((i+l)/2);if(r>=e[f]&&r<=e[f+1]){c=f;break}r<e[f]?l=f-1:i=f+1}let p=a[c],g=(r-e[c])/p,M=g*g,b=M*g,w=u[c]*p,d=u[c+1]*p;return(2*b-3*M+1)*o[c]+(b-2*M+g)*w+(-2*b+3*M)*o[c+1]+(b-M)*d}};function x(m){let t=m.length;if(t===0)return 0;let s=0;for(let n=0;n<t;n++)s+=m[n]*m[n];return Math.sqrt(s/t)}var nt=m=>{let t=m.length;if(t===0)return{min:0,max:0,avg:0};let s=m[0],n=m[0],e=0;for(let o=0;o<t;o++){let a=m[o];a<s&&(s=a),a>n&&(n=a),e+=a}return{min:s,max:n,avg:e/t}},L=m=>{let t=m.length;if(t===0)return 0;let s=1e-6,n=m.reduce((a,h)=>a*(h+s),1),e=Math.pow(n,1/t),o=Math.max(0,Math.min(1,e));return parseFloat((o*100).toFixed(2))};var y=class{constructor(t){this.hex=t}get rgb(){return C(this.hex)}get lab(){return S(this.rgb)}get lch(){return k(this.lab)}get lightness(){let[t,s,n]=this.lab,e=Math.sqrt(s*s+n*n),a=(Math.atan2(n,s)*180/Math.PI+360)%360,h=.1644,u=.0603,r=.1307,i=.006,l=h*Math.abs(Math.sin((a-90)/2*(Math.PI/180)))+u,c=0;return(a<=90||a>=270)&&(c=r*Math.abs(Math.cos(a*(Math.PI/180)))+i),t+(l+c)*e}get chroma(){return this.lch[1]}get hue(){return this.lch[2]}get luminance(){let[t,s,n]=this.rgb;return .2126*t+.7152*s+.0722*n}get wcag(){return(Math.max(this.luminance,1)+.05)/(Math.min(this.luminance,1)+.05)}get apca(){let t=o=>o>5e-4?o:o+Math.pow(5e-4-o,.8),s=t(this.luminance),n=t(1),e=(Math.pow(s,.56)-Math.pow(n,.56))*100;return Math.abs(e)<.1?0:(e=e>0?e<1?0:e-.25:e>-1?0:e+.25,Math.round(e))}};var q=class{constructor(t=[],s="brand"){this.shades=t.map(n=>new y(n)),this.name=s}get colors(){return this.shades.map(t=>t.hex)}get peakChroma(){let t=this.colors.slice(2,-2),s="",n=-1/0;for(let e of t){let o=new y(e);o.chroma>n&&(n=o.chroma,s=e)}return s}get steps(){return this.colors.length}get baseColor(){return this.colors.length===0?"":this.peakChroma||this.colors[Math.floor(this.colors.length/2)]}get baseIndex(){return this.colors.length===0?-1:this.colors.findIndex(t=>t.toLowerCase()===this.baseColor.toLowerCase())}get wcag(){let t=this.shades,s=t.length,n=s-1,e={};for(let o of[30,45,70]){let a=o/10,h=n,u=0;for(let r=1;r<s;r++){let i=1/0;for(let l=0;l<s-r;l++){let c=t[l].luminance,p=t[l+r].luminance,g=(Math.max(c,p)+.05)/(Math.min(c,p)+.05);g<i&&(i=g)}if(i>=a){h=r,u=i;break}r===n&&(u=i)}e[o]={efficiency:h/n,target:a,span:h,value:u}}return e}get apca(){let t=this.shades,s=t.length,n=s-1,e={},o=(a,h)=>{let u=c=>c>5e-4?c:c+Math.pow(5e-4-c,.8),r=u(a),i=u(h),l=(Math.pow(r,.56)-Math.pow(i,.56))*100;return Math.abs(l)<.1?0:(l=l>0?l<1?0:l-.25:l>-1?0:l+.25,Math.round(l))};for(let a of[45,60,75]){let h=a,u=n,r=0;for(let i=1;i<s;i++){let l=1/0;for(let c=0;c<s-i;c++){let p=Math.max(Math.abs(o(t[c+i].luminance,t[c].luminance)),Math.abs(o(t[c].luminance,t[c+i].luminance)));p<l&&(l=p)}if(l>=h){u=i,r=l;break}i===n&&(r=l)}e[a]={efficiency:u/n,target:h,span:u,value:r}}return e}get contrasts(){return{wcag:this.wcag,apca:this.apca}}get deltaECurve(){let t=[0];for(let s=1;s<this.shades.length;s++){let n=P(this.shades[s-1].lab,this.shades[s].lab);t.push(t[s-1]+n)}return t}get unwrapHues(){let t=this.shades.map(n=>n.hue).slice(1,-1);if(t.length===0)return[];let s=[t[0]];for(let n=1;n<t.length;n++){let e=t[n]-t[n-1];e>180?e-=360:e<-180&&(e+=360),s.push(s[n-1]+e)}return s}get lightnessLinearity(){let t=this.shades.map(p=>p.lightness),s=t.length;if(s<2)return 1;let n=0,e=0,o=0,a=0;for(let p=0;p<s;p++)n+=p,e+=t[p],o+=p*t[p],a+=p*p;let h=s*a-n*n;if(Math.abs(h)<1e-10)return 1;let u=(s*o-n*e)/h,r=(e-u*n)/s;if(Math.abs(u*(s-1))<.001)return 1;let l=0,c=0;for(let p=0;p<s;p++){let g=u*p+r,M=t[p]-g;l+=M*M;let b=Math.max(g-Math.min(r,u*(s-1)+r),Math.max(r,u*(s-1)+r)-g);c+=b*b}return Math.max(0,Math.min(1,1-Math.sqrt(l/s)/Math.sqrt(c/s)))}get chromaSmoothness(){let t=this.shades.map(c=>c.chroma),s=t.length;if(s<3)return 1;let n=133.8,e=Math.max(...t);if(e<=.01)return 1;let o=t.map(c=>c/e*n),a=Math.min(...o),h=Math.max(...o),u=o.findIndex(c=>c===h),r=E([[0,o[0]],[u,h],[s-1,o[s-1]]]),i=0,l=0;for(let c=0;c<s;c++){let p=r(c),g=o[c]-p;i+=g*g,l+=Math.pow(Math.max(p-a,h-p),2)}return Math.max(0,Math.min(1,1-Math.sqrt(i/s)/Math.sqrt(l/s)))}get spacingUniformity(){let t=this.deltaECurve,s=t.length;if(s<2)return 1;let n=[];for(let h=1;h<s;h++){let u=t[h]-t[h-1];if(u<0)return 0;n.push(u)}let e=n.reduce((h,u)=>h+u,0)/n.length;if(e<=1e-6)return 0;let o=0;for(let h of n)o+=Math.pow(h-e,2);let a=Math.sqrt(o/n.length)/e;return Math.max(0,Math.min(1,1/(1+a)))}get hueStability(){var a,h,u;let t=this.unwrapHues,s=t.length;if(s<2)return 1;let n=(u=(h=t[this.baseIndex-1])!=null?h:(a=this.shades[this.baseIndex])==null?void 0:a.hue)!=null?u:0,e=0,o=0;for(let r=0;r<s;r++){let i=Math.abs(t[r]-n)%360;i>180&&(i=360-i),e+=i*i;let l=r/(s-1)*180;o+=l*l}return Math.max(0,Math.min(1,1-Math.sqrt(e/s)/(Math.sqrt(o/s)||1)))}get contrastEfficiency(){let t=this.wcag[45].span,s=this.steps;if(s<=1)return 1;let n=.5,e=t/s,o=n*((s-1)/s);return e<=o?1:e>=1?0:(1-e)/(1-o)}get metrics(){return{lightnessLinearity:this.lightnessLinearity,chromaSmoothness:this.chromaSmoothness,spacingUniformity:this.spacingUniformity,hueStability:this.hueStability,contrastEfficiency:this.contrastEfficiency}}get score(){return L(Object.values(this.metrics))}};var T=class{constructor(t={},s="palette"){this.ramps=Object.entries(t).map(([n,e])=>new q(e,n)),this.name=s}get colors(){return Object.fromEntries(this.ramps.map(t=>[t.name,t.colors]))}get steps(){var t;return((t=this.ramps[0])==null?void 0:t.steps)||0}get direction(){var e;let t=(e=this.ramps[0])==null?void 0:e.colors;if(!(t!=null&&t.length))return"lighten";let s=S(C(t[0])),n=S(C(t[t.length-1]));return s[0]>n[0]?"darken":"lighten"}get wcag(){var s;let t={};for(let n of[30,45,70]){let e=this.ramps.map(r=>r.wcag[n]),o=((s=this.ramps[0])==null?void 0:s.steps)||0,a=Math.max(...e.map(r=>(r==null?void 0:r.span)||0)),h=e.reduce((r,i)=>r+((i==null?void 0:i.value)||0),0),u=e[0];t[n]={target:(u==null?void 0:u.target)||0,span:a,value:h/(this.ramps.length||1),efficiency:a/(o-1||1)}}return t}get apca(){var s;let t={};for(let n of[45,60,75]){let e=this.ramps.map(r=>r.apca[n]),o=((s=this.ramps[0])==null?void 0:s.steps)||0,a=Math.max(...e.map(r=>(r==null?void 0:r.span)||0)),h=e.reduce((r,i)=>r+((i==null?void 0:i.value)||0),0),u=e[0];t[n]={target:(u==null?void 0:u.target)||0,span:a,value:h/(this.ramps.length||1),efficiency:a/(o-1||1)}}return t}get contrasts(){return{wcag:this.wcag,apca:this.apca}}get metrics(){return{contrastEfficiency:x(this.ramps.map(t=>t.contrastEfficiency)),lightnessLinearity:x(this.ramps.map(t=>t.lightnessLinearity)),chromaSmoothness:x(this.ramps.map(t=>t.chromaSmoothness)),hueStability:x(this.ramps.map(t=>t.hueStability)),spacingUniformity:x(this.ramps.map(t=>t.spacingUniformity))}}get score(){return L(Object.values(this.metrics))}};return $(et);})();
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var k=e=>{let[t,n,r]=e;return .2126*t+.7152*n+.0722*r},Z=e=>{let t=n=>{let r=Math.max(0,Math.min(1,n)),o=r<=.0031308?12.92*r:1.055*Math.pow(r,1/2.4)-.055;return Math.max(0,Math.min(255,Math.round(o*255)))};return e.map(t)},K=e=>{let t=n=>n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92;return e.map(t)},ot=e=>{let[t,n,r]=Z(e);return t=t.toString(16).padStart(2,"0"),n=n.toString(16).padStart(2,"0"),r=r.toString(16).padStart(2,"0"),`#${t}${n}${r}`},x=e=>{let t=parseInt(e.slice(1,3),16)/255,n=parseInt(e.slice(3,5),16)/255,r=parseInt(e.slice(5,7),16)/255;return K([t,n,r])},v=e=>{let[t,n,r]=e,o=Math.sqrt(n*n+r*r),s=(Math.atan2(r,n)*180/Math.PI+360)%360,i=.1644,b=.0603,m=.1307,u=.006,h=i*Math.abs(Math.sin((s-90)/2*(Math.PI/180)))+b,a=0;return(s<=90||s>=270)&&(a=m*Math.abs(Math.cos(s*(Math.PI/180)))+u),t+(h+a)*o},at=(e,t)=>{let[,n,r]=t,o=Math.sqrt(n*n+r*r),s=(Math.atan2(r,n)*180/Math.PI+360)%360,i=.1644,b=.0603,m=.1307,u=.006,h=i*Math.abs(Math.sin((s-90)/2*(Math.PI/180)))+b,a=0;return(s<=90||s>=270)&&(a=m*Math.abs(Math.cos(s*(Math.PI/180)))+u),Math.max(0,e-(h+a)*o)},st=e=>{let[t,n,r]=e,o=r*Math.PI/180;return[t,n*Math.cos(o),n*Math.sin(o)]},d=e=>{let[t,n,r]=e,o=.4124564*t+.3575761*n+.1804375*r,c=.2126729*t+.7151522*n+.072175*r,s=.0193339*t+.119192*n+.9503041*r,i=.95047,b=1,m=1.08883,u=p=>p>.008856?Math.cbrt(p):7.787*p+16/116,h=u(o/i),a=u(c/b),l=u(s/m);return[116*a-16,500*(h-a),200*(a-l)]},ct=e=>{let[t,n,r]=e,o=(t+16)/116,c=n/500+o,s=o-r/200,i=p=>p**3>.008856?p**3:(p-16/116)/7.787,b=.95047,m=1,u=1.08883,h=i(c)*b,a=i(o)*m,l=i(s)*u;return[3.2404542*h-1.5371385*a-.4985314*l,-.969266*h+1.8760108*a+.041556*l,.0556434*h-.2040259*a+1.0572252*l]},R=e=>{let[t,n,r]=e,o=Math.sqrt(n*n+r*r);if(o<1e-4)return[t,0,0];let s=(Math.atan2(r,n)*180/Math.PI+360)%360;return s>=359.9999&&(s=0),[t,o,s]},N=(e,t)=>{let[n,r,o]=e,[c,s,i]=t,b=(n+c)/2,m=Math.sqrt(r*r+o*o),u=Math.sqrt(s*s+i*i),h=(m+u)/2,a=.5*(1-Math.sqrt(Math.pow(h,7)/(Math.pow(h,7)+Math.pow(25,7)))),l=r*(1+a),p=s*(1+a),M=Math.sqrt(l*l+o*o),f=Math.sqrt(p*p+i*i),y=(M+f)/2,C=Math.atan2(o,l)*180/Math.PI+(Math.atan2(o,l)<0?360:0),g=Math.atan2(i,p)*180/Math.PI+(Math.atan2(i,p)<0?360:0),q=g-C;Math.abs(q)>180&&(q+=g<=C?360:-360);let w=Math.abs(C-g)>180?(C+g+360)/2:(C+g)/2,_=1-.17*Math.cos((w-30)*Math.PI/180)+.24*Math.cos(2*w*Math.PI/180)+.32*Math.cos((3*w+6)*Math.PI/180)-.2*Math.cos((4*w-63)*Math.PI/180),j=c-n,P=f-M,D=2*Math.sqrt(M*f)*Math.sin(q/2*Math.PI/180),F=1+.015*Math.pow(b-50,2)/Math.sqrt(20+Math.pow(b-50,2)),T=1+.045*y,A=1+.015*y*_,O=30*Math.exp(-Math.pow((w-275)/25,2)),W=-(2*Math.sqrt(Math.pow(y,7)/(Math.pow(y,7)+Math.pow(25,7))))*Math.sin(2*O*Math.PI/180);return Math.sqrt(Math.pow(j/F,2)+Math.pow(P/T,2)+Math.pow(D/A,2)+W*(P/T)*(D/A))},H=e=>{let t="",n=-1/0;for(let r of e){let o=d(x(r)),[,c]=R(o);c>n&&(n=c,t=r)}return t};function X(e){let t=[e[0]];for(let n=1;n<e.length;n++){let r=e[n]-e[n-1];r>180?r-=360:r<-180&&(r+=360),t.push(t[n-1]+r)}return t}function mt(e){let[t,n,r]=e;return[.152286*t+1.052583*n-.204868*r,.114503*t+.786281*n+.099216*r,-.003882*t-.048116*n+1.051998*r]}function ht(e){let[t,n,r]=e;return[.367322*t+.860646*n-.227968*r,.280085*t+.672501*n+.047413*r,-.01182*t+.04294*n+.968881*r]}var it=e=>{let t=e.match(/\d+(\.\d+)?/g);if(!t||t.length<3)throw new Error("Invalid CSS rgb()");let n=r=>{let o=r/255;return o<=.04045?o/12.92:Math.pow((o+.055)/1.055,2.4)};return[n(Number(t[0])),n(Number(t[1])),n(Number(t[2]))]};var I=(e,t)=>(Math.max(e,t)+.05)/(Math.min(e,t)+.05),L=(e,t)=>{let n=s=>s>5e-4?s:s+Math.pow(5e-4-s,.8),r=n(e),o=n(t),c=(Math.pow(r,.56)-Math.pow(o,.56))*100;return Math.abs(c)<.1?0:(c=c>0?c<1?0:c-.25:c>-1?0:c+.25,Math.round(c))};function z(e){let t=e.match(/^(wcag|apca)(\d+)$/);if(!t)throw new Error(`Invalid contrast: ${e}`);let n=t[1]==="wcag"?Number(t[2])/10:Number(t[2]);return{system:t[1],target:n}}var Y=e=>{let t={},n=e.length,r=n-1;return B.forEach(o=>{let{system:c,target:s}=z(o),i=r,b=0;for(let m=1;m<n;m++){let u=1/0;for(let h=0;h<n-m;h++){let a=c==="wcag"?I(e[h].luminance,e[h+m].luminance):Math.max(Math.abs(L(e[h+m].luminance,e[h].luminance)),Math.abs(L(e[h].luminance,e[h+m].luminance)));a<u&&(u=a)}if(u>=s){i=m,b=u;break}m===r&&(b=u)}t[o]={system:c,efficiency:i/r,target:s,span:i,value:b,name:o}}),t},B=["wcag30","wcag45","wcag70","apca45","apca60","apca75"],U=e=>{let t={};return B.forEach(n=>{var m;let{target:r,system:o}=z(n),c=e.map(u=>u.contrasts[n]),s=((m=e[0])==null?void 0:m.shades.length)||0,i=Math.max(...c.map(u=>(u==null?void 0:u.span)||0)),b=c.reduce((u,h)=>u+((h==null?void 0:h.value)||0),0);t[n]={system:o,target:r,span:i,value:b/(e.length||1),name:n,efficiency:i/(s-1||1)}}),t};var $=e=>{let t=x(e),n=d(t),r=k(t),o=v(n),c=R(n);return{hex:e,rgb:t,lab:n,lch:c,lightness:o,chroma:c[1],hue:c[2],luminance:r,parameter:0,cumDeltaE00:0,cumProtDeltaE00:0,cumDeutDeltaE00:0,wcag:I(r,1),apca:L(r,1)}};var G=e=>{if(e.length<1)return m=>0;let t=[...e].sort((m,u)=>m[0]-u[0]),n=[];for(let m=0;m<t.length;m++)(m===0||t[m][0]!==t[m-1][0])&&n.push(t[m]);let r=n.length;if(r===1)return m=>n[0][1];let o=n.map(m=>m[0]),c=n.map(m=>m[1]),s=[],i=[];for(let m=0;m<r-1;m++)s[m]=o[m+1]-o[m],i[m]=(c[m+1]-c[m])/s[m];let b=new Array(r);b[0]=i[0],b[r-1]=i[r-2];for(let m=1;m<r-1;m++){let u=i[m-1],h=i[m];if(u*h<=0)b[m]=0;else{let a=(1+s[m]/(s[m-1]+s[m]))/3;b[m]=u*h/((1-a)*u+a*h)}}return m=>{if(m<=o[0])return c[0];if(m>=o[r-1])return c[r-1];let u=0,h=r-2,a=0;for(;u<=h;){let g=Math.floor((u+h)/2);if(m>=o[g]&&m<=o[g+1]){a=g;break}m<o[g]?h=g-1:u=g+1}let l=s[a],p=(m-o[a])/l,M=p*p,f=M*p,y=b[a]*l,C=b[a+1]*l;return(2*f-3*M+1)*c[a]+(f-2*M+p)*y+(-2*f+3*M)*c[a+1]+(f-M)*C}};function S(e){let t=e.length;if(t===0)return 0;let n=0;for(let r=0;r<t;r++)n+=e[r]*e[r];return Math.sqrt(n/t)}var gt=e=>{let t=e.length;if(t===0)return{min:0,max:0,avg:0};let n=e[0],r=e[0],o=0;for(let c=0;c<t;c++){let s=e[c];s<n&&(n=s),s>r&&(r=s),o+=s}return{min:n,max:r,avg:o/t}},E=e=>{let t=e.length;if(t===0)return 0;let n=1e-6,r=e.reduce((s,i)=>s*(i+n),1),o=Math.pow(r,1/t),c=Math.max(0,Math.min(1,o));return parseFloat((c*100).toFixed(2))};var J=(e,t,n)=>{t||(t="brand"),n||(n=[...Array(e.length).keys()]);let r=d(x(e[0]))[0],o=d(x(e[e.length-1]))[0];r>o&&e.reverse();let c=e.map(a=>$(a));for(let a=1;a<c.length;a++){let l=N(c[a-1].lab,c[a].lab);c[a].cumDeltaE00=c[a-1].cumDeltaE00+l}let s=H(e.slice(2,-2))||e[Math.floor(e.length/2)],i=e.findIndex(a=>a.toLowerCase()===(s==null?void 0:s.toLowerCase())),b=X(c.map(a=>a.hue).slice(1,-1));for(let a=1;a<c.length-1;a++)c[a].hue=b[a-1];let m=V(c.map(a=>a.hue).slice(1,-1),c[i].hue),u=Y(c),h={lightnessLinearity:Q(c.map(a=>a.lightness)),chromaSmoothness:tt(c.map(a=>a.chroma)),spacingUniformity:nt(c.map(a=>a.cumDeltaE00)),contrastEfficiency:rt(u.wcag45.span,n.length),hueStability:m};return{name:t,colors:e,baseIndex:i,baseColor:s,shades:c,contrasts:u,metrics:h,score:E(Object.values(h))}},Et=e=>{let{stepNames:t,name:n,colors:r}=e,o=Object.values(r)[0],c=d(x(o[0]))[0],s=d(x(o[o.length-1]))[0],i=c>s?"darken":"lighten",b=[],m={};for(let h in r){let a=J(r[h],h,t);b.push(a),m[h]=a.baseColor}let u={contrastEfficiency:S(b.map(h=>h.metrics.contrastEfficiency)),lightnessLinearity:S(b.map(h=>h.metrics.lightnessLinearity)),chromaSmoothness:S(b.map(h=>h.metrics.chromaSmoothness)),hueStability:S(b.map(h=>h.metrics.hueStability)),spacingUniformity:S(b.map(h=>h.metrics.spacingUniformity))};return{name:n,baseColors:m,stepNames:t,direction:i,steps:t.length,colors:r,contrasts:U(b),scales:b,metrics:u,score:E(Object.values(u))}};function Q(e){let t=e.length;if(t<2)return 1;let n=0,r=0,o=0,c=0;for(let a=0;a<t;a++)n+=a,r+=e[a],o+=a*e[a],c+=a*a;let s=t*c-n*n;if(Math.abs(s)<1e-10)return 1;let i=(t*o-n*r)/s,b=(r-i*n)/t;if(Math.abs(i*(t-1))<.001)return 1;let u=0,h=0;for(let a=0;a<t;a++){let l=i*a+b,p=e[a]-l;u+=p*p;let M=Math.max(l-Math.min(b,i*(t-1)+b),Math.max(b,i*(t-1)+b)-l);h+=M*M}return Math.max(0,Math.min(1,1-Math.sqrt(u/t)/Math.sqrt(h/t)))}function V(e,t){let n=e.length;if(n<2)return 1;let r=0,o=0;for(let c=0;c<n;c++){let s=Math.abs(e[c]-t)%360;s>180&&(s=360-s),r+=s*s;let i=c/(n-1)*180;o+=i*i}return Math.max(0,Math.min(1,1-Math.sqrt(r/n)/(Math.sqrt(o/n)||1)))}var tt=e=>{let t=e.length;if(t<3)return 1;let n=133.8,r=Math.max(...e);if(r<=.01)return 1;let o=e.map(h=>h/r*n),c=Math.min(...o),s=Math.max(...o),i=o.findIndex(h=>h===s),b=G([[0,o[0]],[i,s],[t-1,o[t-1]]]),m=0,u=0;for(let h=0;h<t;h++){let a=b(h),l=o[h]-a;m+=l*l,u+=Math.pow(Math.max(a-c,s-a),2)}return Math.max(0,Math.min(1,1-Math.sqrt(m/t)/Math.sqrt(u/t)))},nt=e=>{let t=e.length;if(t<2)return 1;let n=[];for(let s=1;s<t;s++){let i=e[s]-e[s-1];if(i<0)return 0;n.push(i)}let r=n.reduce((s,i)=>s+i,0)/n.length;if(r<=1e-6)return 0;let o=0;for(let s of n)o+=Math.pow(s-r,2);let c=Math.sqrt(o/n.length)/r;return Math.max(0,Math.min(1,1/(1+c)))},rt=(e,t)=>{if(t<=1)return 1;let n=.5,r=e/t,o=n*((t-1)/t);return r<=o?1:r>=1?0:(1-r)/(1-o)};export{J as analyzeMonochromatic,Et as analyzeMonochromaticPalette,tt as calcChromaSmoothness,rt as calcContrastEfficiency,N as calcDeltaE2000,V as calcHueStability,Q as calcLightnessLinearity,E as calcScore,nt as calcSpacingUniformity,gt as calcStatistics,B as contrastList,G as createMonotone,it as cssRgbToRgb,H as findMaxChromaHex,at as fromLightnessEAL,L as getApcaContrast,Y as getMonochromaticContrasts,U as getPaletteContrasts,k as getRelativeLuminance,I as getWcagContrast,x as hexToRgb,R as labToLch,ct as labToRgb,st as lchToLab,Z as lrgbToSrgb,ot as rgbToHex,d as rgbToLab,S as rootMeanSquare,ht as simulateDeuteranopia,mt as simulateProtanopia,K as srgbToLrgb,v as toLightnessEAL,X as unwrapHue};
1
+ var B=l=>{let t=s=>{let n=Math.max(0,Math.min(1,s)),e=n<=.0031308?12.92*n:1.055*Math.pow(n,1/2.4)-.055;return Math.max(0,Math.min(255,Math.round(e*255)))};return l.map(t)},G=l=>{let t=s=>s>.04045?Math.pow((s+.055)/1.055,2.4):s/12.92;return l.map(t)},O=l=>{let[t,s,n]=B(l);return t=t.toString(16).padStart(2,"0"),s=s.toString(16).padStart(2,"0"),n=n.toString(16).padStart(2,"0"),`#${t}${s}${n}`},S=l=>{let t=parseInt(l.slice(1,3),16)/255,s=parseInt(l.slice(3,5),16)/255,n=parseInt(l.slice(5,7),16)/255;return G([t,s,n])},N=l=>{let[t,s,n]=l,e=Math.sqrt(s*s+n*n),a=(Math.atan2(n,s)*180/Math.PI+360)%360,h=.1644,u=.0603,r=.1307,i=.006,m=h*Math.abs(Math.sin((a-90)/2*(Math.PI/180)))+u,c=0;return(a<=90||a>=270)&&(c=r*Math.abs(Math.cos(a*(Math.PI/180)))+i),t+(m+c)*e},V=(l,t)=>{let[,s,n]=t,e=Math.sqrt(s*s+n*n),a=(Math.atan2(n,s)*180/Math.PI+360)%360,h=.1644,u=.0603,r=.1307,i=.006,m=h*Math.abs(Math.sin((a-90)/2*(Math.PI/180)))+u,c=0;return(a<=90||a>=270)&&(c=r*Math.abs(Math.cos(a*(Math.PI/180)))+i),Math.max(0,l-(m+c)*e)},$=l=>{let[t,s,n]=l,e=n*Math.PI/180;return[t,s*Math.cos(e),s*Math.sin(e)]},y=l=>{let[t,s,n]=l,e=.4124564*t+.3575761*s+.1804375*n,o=.2126729*t+.7151522*s+.072175*n,a=.0193339*t+.119192*s+.9503041*n,h=.95047,u=1,r=1.08883,i=g=>g>.008856?Math.cbrt(g):7.787*g+16/116,m=i(e/h),c=i(o/u),p=i(a/r);return[116*c-16,500*(m-c),200*(c-p)]},F=l=>{let[t,s,n]=l,e=(t+16)/116,o=s/500+e,a=e-n/200,h=g=>g**3>.008856?g**3:(g-16/116)/7.787,u=.95047,r=1,i=1.08883,m=h(o)*u,c=h(e)*r,p=h(a)*i;return[3.2404542*m-1.5371385*c-.4985314*p,-.969266*m+1.8760108*c+.041556*p,.0556434*m-.2040259*c+1.0572252*p]},T=l=>{let[t,s,n]=l,e=Math.sqrt(s*s+n*n);if(e<1e-4)return[t,0,0];let a=(Math.atan2(n,s)*180/Math.PI+360)%360;return a>=359.9999&&(a=0),[t,e,a]},A=(l,t)=>{let[s,n,e]=l,[o,a,h]=t,u=(s+o)/2,r=Math.sqrt(n*n+e*e),i=Math.sqrt(a*a+h*h),m=(r+i)/2,c=.5*(1-Math.sqrt(Math.pow(m,7)/(Math.pow(m,7)+Math.pow(25,7)))),p=n*(1+c),g=a*(1+c),M=Math.sqrt(p*p+e*e),b=Math.sqrt(g*g+h*h),x=(M+b)/2,d=Math.atan2(e,p)*180/Math.PI+(Math.atan2(e,p)<0?360:0),f=Math.atan2(h,g)*180/Math.PI+(Math.atan2(h,g)<0?360:0),R=f-d;Math.abs(R)>180&&(R+=f<=d?360:-360);let C=Math.abs(d-f)>180?(d+f+360)/2:(d+f)/2,Y=1-.17*Math.cos((C-30)*Math.PI/180)+.24*Math.cos(2*C*Math.PI/180)+.32*Math.cos((3*C+6)*Math.PI/180)-.2*Math.cos((4*C-63)*Math.PI/180),U=o-s,v=b-M,k=2*Math.sqrt(M*b)*Math.sin(R/2*Math.PI/180),W=1+.015*Math.pow(u-50,2)/Math.sqrt(20+Math.pow(u-50,2)),P=1+.045*x,E=1+.015*x*Y,X=30*Math.exp(-Math.pow((C-275)/25,2)),z=-(2*Math.sqrt(Math.pow(x,7)/(Math.pow(x,7)+Math.pow(25,7))))*Math.sin(2*X*Math.PI/180);return Math.sqrt(Math.pow(U/W,2)+Math.pow(v/P,2)+Math.pow(k/E,2)+z*(v/P)*(k/E))},K=l=>{let t=l.match(/\d+(\.\d+)?/g);if(!t||t.length<3)throw new Error("Invalid CSS rgb()");let s=n=>{let e=n/255;return e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4)};return[s(Number(t[0])),s(Number(t[1])),s(Number(t[2]))]},D=l=>{if(l.length<1)return r=>0;let t=[...l].sort((r,i)=>r[0]-i[0]),s=[];for(let r=0;r<t.length;r++)(r===0||t[r][0]!==t[r-1][0])&&s.push(t[r]);let n=s.length;if(n===1)return r=>s[0][1];let e=s.map(r=>r[0]),o=s.map(r=>r[1]),a=[],h=[];for(let r=0;r<n-1;r++)a[r]=e[r+1]-e[r],h[r]=(o[r+1]-o[r])/a[r];let u=new Array(n);u[0]=h[0],u[n-1]=h[n-2];for(let r=1;r<n-1;r++){let i=h[r-1],m=h[r];if(i*m<=0)u[r]=0;else{let c=(1+a[r]/(a[r-1]+a[r]))/3;u[r]=i*m/((1-c)*i+c*m)}}return r=>{if(r<=e[0])return o[0];if(r>=e[n-1])return o[n-1];let i=0,m=n-2,c=0;for(;i<=m;){let f=Math.floor((i+m)/2);if(r>=e[f]&&r<=e[f+1]){c=f;break}r<e[f]?m=f-1:i=f+1}let p=a[c],g=(r-e[c])/p,M=g*g,b=M*g,x=u[c]*p,d=u[c+1]*p;return(2*b-3*M+1)*o[c]+(b-2*M+g)*x+(-2*b+3*M)*o[c+1]+(b-M)*d}};function w(l){let t=l.length;if(t===0)return 0;let s=0;for(let n=0;n<t;n++)s+=l[n]*l[n];return Math.sqrt(s/t)}var Z=l=>{let t=l.length;if(t===0)return{min:0,max:0,avg:0};let s=l[0],n=l[0],e=0;for(let o=0;o<t;o++){let a=l[o];a<s&&(s=a),a>n&&(n=a),e+=a}return{min:s,max:n,avg:e/t}},L=l=>{let t=l.length;if(t===0)return 0;let s=1e-6,n=l.reduce((a,h)=>a*(h+s),1),e=Math.pow(n,1/t),o=Math.max(0,Math.min(1,e));return parseFloat((o*100).toFixed(2))};var I=class{constructor(t){this.hex=t}get rgb(){return S(this.hex)}get lab(){return y(this.rgb)}get lch(){return T(this.lab)}get lightness(){let[t,s,n]=this.lab,e=Math.sqrt(s*s+n*n),a=(Math.atan2(n,s)*180/Math.PI+360)%360,h=.1644,u=.0603,r=.1307,i=.006,m=h*Math.abs(Math.sin((a-90)/2*(Math.PI/180)))+u,c=0;return(a<=90||a>=270)&&(c=r*Math.abs(Math.cos(a*(Math.PI/180)))+i),t+(m+c)*e}get chroma(){return this.lch[1]}get hue(){return this.lch[2]}get luminance(){let[t,s,n]=this.rgb;return .2126*t+.7152*s+.0722*n}get wcag(){return(Math.max(this.luminance,1)+.05)/(Math.min(this.luminance,1)+.05)}get apca(){let t=o=>o>5e-4?o:o+Math.pow(5e-4-o,.8),s=t(this.luminance),n=t(1),e=(Math.pow(s,.56)-Math.pow(n,.56))*100;return Math.abs(e)<.1?0:(e=e>0?e<1?0:e-.25:e>-1?0:e+.25,Math.round(e))}};var q=class{constructor(t=[],s="brand"){this.shades=t.map(n=>new I(n)),this.name=s}get colors(){return this.shades.map(t=>t.hex)}get peakChroma(){let t=this.colors.slice(2,-2),s="",n=-1/0;for(let e of t){let o=new I(e);o.chroma>n&&(n=o.chroma,s=e)}return s}get steps(){return this.colors.length}get baseColor(){return this.colors.length===0?"":this.peakChroma||this.colors[Math.floor(this.colors.length/2)]}get baseIndex(){return this.colors.length===0?-1:this.colors.findIndex(t=>t.toLowerCase()===this.baseColor.toLowerCase())}get wcag(){let t=this.shades,s=t.length,n=s-1,e={};for(let o of[30,45,70]){let a=o/10,h=n,u=0;for(let r=1;r<s;r++){let i=1/0;for(let m=0;m<s-r;m++){let c=t[m].luminance,p=t[m+r].luminance,g=(Math.max(c,p)+.05)/(Math.min(c,p)+.05);g<i&&(i=g)}if(i>=a){h=r,u=i;break}r===n&&(u=i)}e[o]={efficiency:h/n,target:a,span:h,value:u}}return e}get apca(){let t=this.shades,s=t.length,n=s-1,e={},o=(a,h)=>{let u=c=>c>5e-4?c:c+Math.pow(5e-4-c,.8),r=u(a),i=u(h),m=(Math.pow(r,.56)-Math.pow(i,.56))*100;return Math.abs(m)<.1?0:(m=m>0?m<1?0:m-.25:m>-1?0:m+.25,Math.round(m))};for(let a of[45,60,75]){let h=a,u=n,r=0;for(let i=1;i<s;i++){let m=1/0;for(let c=0;c<s-i;c++){let p=Math.max(Math.abs(o(t[c+i].luminance,t[c].luminance)),Math.abs(o(t[c].luminance,t[c+i].luminance)));p<m&&(m=p)}if(m>=h){u=i,r=m;break}i===n&&(r=m)}e[a]={efficiency:u/n,target:h,span:u,value:r}}return e}get contrasts(){return{wcag:this.wcag,apca:this.apca}}get deltaECurve(){let t=[0];for(let s=1;s<this.shades.length;s++){let n=A(this.shades[s-1].lab,this.shades[s].lab);t.push(t[s-1]+n)}return t}get unwrapHues(){let t=this.shades.map(n=>n.hue).slice(1,-1);if(t.length===0)return[];let s=[t[0]];for(let n=1;n<t.length;n++){let e=t[n]-t[n-1];e>180?e-=360:e<-180&&(e+=360),s.push(s[n-1]+e)}return s}get lightnessLinearity(){let t=this.shades.map(p=>p.lightness),s=t.length;if(s<2)return 1;let n=0,e=0,o=0,a=0;for(let p=0;p<s;p++)n+=p,e+=t[p],o+=p*t[p],a+=p*p;let h=s*a-n*n;if(Math.abs(h)<1e-10)return 1;let u=(s*o-n*e)/h,r=(e-u*n)/s;if(Math.abs(u*(s-1))<.001)return 1;let m=0,c=0;for(let p=0;p<s;p++){let g=u*p+r,M=t[p]-g;m+=M*M;let b=Math.max(g-Math.min(r,u*(s-1)+r),Math.max(r,u*(s-1)+r)-g);c+=b*b}return Math.max(0,Math.min(1,1-Math.sqrt(m/s)/Math.sqrt(c/s)))}get chromaSmoothness(){let t=this.shades.map(c=>c.chroma),s=t.length;if(s<3)return 1;let n=133.8,e=Math.max(...t);if(e<=.01)return 1;let o=t.map(c=>c/e*n),a=Math.min(...o),h=Math.max(...o),u=o.findIndex(c=>c===h),r=D([[0,o[0]],[u,h],[s-1,o[s-1]]]),i=0,m=0;for(let c=0;c<s;c++){let p=r(c),g=o[c]-p;i+=g*g,m+=Math.pow(Math.max(p-a,h-p),2)}return Math.max(0,Math.min(1,1-Math.sqrt(i/s)/Math.sqrt(m/s)))}get spacingUniformity(){let t=this.deltaECurve,s=t.length;if(s<2)return 1;let n=[];for(let h=1;h<s;h++){let u=t[h]-t[h-1];if(u<0)return 0;n.push(u)}let e=n.reduce((h,u)=>h+u,0)/n.length;if(e<=1e-6)return 0;let o=0;for(let h of n)o+=Math.pow(h-e,2);let a=Math.sqrt(o/n.length)/e;return Math.max(0,Math.min(1,1/(1+a)))}get hueStability(){var a,h,u;let t=this.unwrapHues,s=t.length;if(s<2)return 1;let n=(u=(h=t[this.baseIndex-1])!=null?h:(a=this.shades[this.baseIndex])==null?void 0:a.hue)!=null?u:0,e=0,o=0;for(let r=0;r<s;r++){let i=Math.abs(t[r]-n)%360;i>180&&(i=360-i),e+=i*i;let m=r/(s-1)*180;o+=m*m}return Math.max(0,Math.min(1,1-Math.sqrt(e/s)/(Math.sqrt(o/s)||1)))}get contrastEfficiency(){let t=this.wcag[45].span,s=this.steps;if(s<=1)return 1;let n=.5,e=t/s,o=n*((s-1)/s);return e<=o?1:e>=1?0:(1-e)/(1-o)}get metrics(){return{lightnessLinearity:this.lightnessLinearity,chromaSmoothness:this.chromaSmoothness,spacingUniformity:this.spacingUniformity,hueStability:this.hueStability,contrastEfficiency:this.contrastEfficiency}}get score(){return L(Object.values(this.metrics))}};var H=class{constructor(t={},s="palette"){this.ramps=Object.entries(t).map(([n,e])=>new q(e,n)),this.name=s}get colors(){return Object.fromEntries(this.ramps.map(t=>[t.name,t.colors]))}get steps(){var t;return((t=this.ramps[0])==null?void 0:t.steps)||0}get direction(){var e;let t=(e=this.ramps[0])==null?void 0:e.colors;if(!(t!=null&&t.length))return"lighten";let s=y(S(t[0])),n=y(S(t[t.length-1]));return s[0]>n[0]?"darken":"lighten"}get wcag(){var s;let t={};for(let n of[30,45,70]){let e=this.ramps.map(r=>r.wcag[n]),o=((s=this.ramps[0])==null?void 0:s.steps)||0,a=Math.max(...e.map(r=>(r==null?void 0:r.span)||0)),h=e.reduce((r,i)=>r+((i==null?void 0:i.value)||0),0),u=e[0];t[n]={target:(u==null?void 0:u.target)||0,span:a,value:h/(this.ramps.length||1),efficiency:a/(o-1||1)}}return t}get apca(){var s;let t={};for(let n of[45,60,75]){let e=this.ramps.map(r=>r.apca[n]),o=((s=this.ramps[0])==null?void 0:s.steps)||0,a=Math.max(...e.map(r=>(r==null?void 0:r.span)||0)),h=e.reduce((r,i)=>r+((i==null?void 0:i.value)||0),0),u=e[0];t[n]={target:(u==null?void 0:u.target)||0,span:a,value:h/(this.ramps.length||1),efficiency:a/(o-1||1)}}return t}get contrasts(){return{wcag:this.wcag,apca:this.apca}}get metrics(){return{contrastEfficiency:w(this.ramps.map(t=>t.contrastEfficiency)),lightnessLinearity:w(this.ramps.map(t=>t.lightnessLinearity)),chromaSmoothness:w(this.ramps.map(t=>t.chromaSmoothness)),hueStability:w(this.ramps.map(t=>t.hueStability)),spacingUniformity:w(this.ramps.map(t=>t.spacingUniformity))}}get score(){return L(Object.values(this.metrics))}};export{H as Palette,q as Ramp,I as Shade,A as calcDeltaE2000,L as calcScore,Z as calcStatistics,D as createMonotone,K as cssRgbToRgb,V as fromLightnessEAL,S as hexToRgb,T as labToLch,F as labToRgb,$ as lchToLab,O as rgbToHex,y as rgbToLab,w as rootMeanSquare,N as toLightnessEAL};
package/package.json CHANGED
@@ -1,44 +1,44 @@
1
- {
2
- "name": "chromametry",
3
- "version": "0.2.0",
4
- "description": "Web-accessible Color Palette Metrics",
5
- "main": "./dist/index.cjs",
6
- "module": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "type": "module",
9
- "scripts": {
10
- "test": "vitest",
11
- "generate": "tsx benchmarks/generate.ts",
12
- "build": "tsup",
13
- "prepublishOnly": "npm run build && npm run test"
14
- },
15
- "keywords": [
16
- "color",
17
- "color-palette",
18
- "color-metrics",
19
- "palette",
20
- "monochromatic",
21
- "accessibility",
22
- "wcag",
23
- "design-system"
24
- ],
25
- "author": "Huu Khanh Nguyen",
26
- "license": "MIT",
27
- "devDependencies": {
28
- "@ant-design/colors": "^8.0.1",
29
- "@atlaskit/tokens": "^10.0.1",
30
- "@material/material-color-utilities": "^0.3.0",
31
- "@types/node": "^25.2.0",
32
- "chartjs-node-canvas": "^5.0.0",
33
- "tsup": "^8.5.0",
34
- "tsx": "^4.21.0",
35
- "typescript": "^5.8.3",
36
- "vitest": "^4.0.18"
37
- },
38
- "unpkg": "dist/index.global.js",
39
- "jsdelivr": "dist/index.global.js",
40
- "files": [
41
- "dist",
42
- "README.md"
43
- ]
44
- }
1
+ {
2
+ "name": "chromametry",
3
+ "version": "0.3.0",
4
+ "description": "Web-accessible Color Palette Metrics",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "type": "module",
9
+ "scripts": {
10
+ "test": "vitest",
11
+ "generate": "tsx scripts/generate.ts",
12
+ "build": "tsup",
13
+ "prepublishOnly": "npm run test &&npm run build"
14
+ },
15
+ "keywords": [
16
+ "color",
17
+ "color-palette",
18
+ "color-metrics",
19
+ "palette",
20
+ "monochromatic",
21
+ "accessibility",
22
+ "wcag",
23
+ "design-system"
24
+ ],
25
+ "author": "Huu Khanh Nguyen",
26
+ "license": "MIT",
27
+ "devDependencies": {
28
+ "@ant-design/colors": "^8.0.1",
29
+ "@atlaskit/tokens": "^10.0.1",
30
+ "@material/material-color-utilities": "^0.3.0",
31
+ "@types/node": "^25.2.0",
32
+ "chartjs-node-canvas": "^5.0.0",
33
+ "tsup": "^8.5.0",
34
+ "tsx": "^4.21.0",
35
+ "typescript": "^5.8.3",
36
+ "vitest": "^4.0.18"
37
+ },
38
+ "unpkg": "dist/index.global.js",
39
+ "jsdelivr": "dist/index.global.js",
40
+ "files": [
41
+ "dist",
42
+ "README.md"
43
+ ]
44
+ }