@luntta/swatch 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.0.1 — PATCH
4
+
5
+ - Fixed protan/deutan/tritan CVD simulation matrices to use the Machado severity table in linear-light sRGB, making protanopia and deuteranopia previews visibly distinct again.
6
+ - Updated the batch `simulateImageData`/`daltonizeImageData` paths to share the same CVD matrix builder as color-level simulation.
7
+ - Fixed the docs image playground fallback path so non-worker previews pass canonical CVD type keys.
8
+
3
9
  ## 3.0.0 — BREAKING
4
10
 
5
11
  A complete rewrite. Storage moved to a canonical `{ space, coords, alpha }` state (colorjs.io / culori model) so wide-gamut inputs are preserved losslessly, conversions go through a lazy CIE XYZ D65 hub, and the monolithic `src/swatch.js` has been split into `src/core`, `src/spaces`, `src/parse`, `src/format`, `src/operations`, `src/scale`, `src/palettes`, and `src/data`.
@@ -41,7 +47,7 @@ See [`MIGRATING.md`](./MIGRATING.md) for the v2 → v3 cookbook.
41
47
 
42
48
  The CVD / APCA / WCAG story is preserved end-to-end:
43
49
 
44
- - `simulate(type, { severity })` — Brettel/Viénot dichromat simulation with a severity continuum
50
+ - `simulate(type, { severity })` — CVD simulation with a severity continuum
45
51
  - `daltonize(type, { severity })` — Fidaner error redistribution
46
52
  - `swatch.checkPalette(colors, { cvd, minDeltaE, mode })`
47
53
  - `swatch.nearestDistinguishable(target, against, { cvd, minDeltaE, step })`
package/MIGRATING.md CHANGED
@@ -178,7 +178,7 @@ See [README.md](./README.md) for examples of each.
178
178
 
179
179
  The CVD/APCA/WCAG story — the heart of swatch — is unchanged:
180
180
 
181
- - `simulate(type, { severity })` — Brettel/Viénot dichromat simulation
181
+ - `simulate(type, { severity })` — CVD simulation with a severity continuum
182
182
  - `daltonize(type, { severity })` — Fidaner error redistribution
183
183
  - `swatch.checkPalette(colors, { cvd, minDeltaE, mode })`
184
184
  - `swatch.nearestDistinguishable(target, against, { cvd, minDeltaE, step })`
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Swatch
2
2
 
3
- A color library with **first-class colorblind support** — physically correct Brettel/Viénot simulation, severity continuum, Fidaner daltonization, and palette distinguishability checks — plus the things you expect from a modern color library: CSS Color 4 parsing, wide-gamut spaces, OKLab/OKLCh manipulation, color scales, built-in scientific palettes, blend modes, naming, temperature, WCAG 2.1, and APCA.
3
+ A color library with **first-class colorblind support** — Machado CVD simulation, severity continuum, Fidaner daltonization, and palette distinguishability checks — plus the things you expect from a modern color library: CSS Color 4 parsing, wide-gamut spaces, OKLab/OKLCh manipulation, color scales, built-in scientific palettes, blend modes, naming, temperature, WCAG 2.1, and APCA.
4
4
 
5
5
  **Docs & interactive playground:** <https://luntta.github.io/swatch/>
6
6
 
@@ -281,7 +281,7 @@ The `.srgb` / `.linearSrgb` / `.hsl` getters return raw conversions, so wide-gam
281
281
 
282
282
  ## Colorblind simulation
283
283
 
284
- Physically correct sRGB linear LMS projection onto the dichromat confusion plane (Brettel 1997 / Viénot 1999).
284
+ Physiologically based Machado/Oliveira/Fernandes CVD simulation in linear-light sRGB.
285
285
 
286
286
  ```js
287
287
  const red = swatch("#ff0000");
@@ -294,7 +294,7 @@ red.simulate("achroma"); // Rec. 709 grayscale
294
294
 
295
295
  Accepted aliases: `protanopia`/`protanomaly` → `protan`, `deuteranopia`/`deuteranomaly` → `deutan`, `tritanopia`/`tritanomaly` → `tritan`, `achromatopsia` → `achroma`.
296
296
 
297
- Severity `0.0` is identity, `1.0` is the full dichromat, in between is a linear interpolation of the RGB transform matrix.
297
+ Severity `0.0` is identity, `1.0` is the full dichromat, and in-between values interpolate across the published Machado severity table.
298
298
 
299
299
  ### ImageData simulation
300
300
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luntta/swatch",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "A color library with first-class colorblind support, CSS Color 4 parsing, wide-gamut spaces, OKLCh manipulation, color scales, built-in palettes, blend modes, WCAG 2.1, and APCA.",
5
5
  "type": "module",
6
6
  "main": "./src/swatch.js",
@@ -1,18 +1,15 @@
1
1
  // CVD (Color Vision Deficiency) simulation matrices.
2
2
  //
3
- // We build dichromat projection matrices in linear sRGB space by
4
- // lifting the LMS plane projection through standard linear-RGB ↔ LMS
5
- // transforms:
3
+ // Protan/deutan/tritan simulation uses the Machado, Oliveira & Fernandes
4
+ // physiologically-based matrices in linear-light sRGB. The table contains
5
+ // severity samples from 0.0 (identity) through 1.0 (full dichromacy); callers
6
+ // interpolate between adjacent samples for the severity continuum.
6
7
  //
7
- // M_RGB = M_LMS→RGB · M_dichromat_LMS · M_RGB→LMS
8
- //
9
- // The LMS plane for each dichromat type is constructed via the
10
- // Brettel/Viénot anchor-line method: the plane passes through white
11
- // and a confusion-line anchor (blue for protan/deutan, red for
12
- // tritan). The missing cone's response is reconstructed as
13
- // a·X + b·Y in LMS space, solved via Cramer's rule.
8
+ // This replaces the old single-plane LMS projection, which used the sRGB blue
9
+ // primary as the shared protan/deutan anchor. That shortcut forced red and
10
+ // green output rows to collapse together, so image previews for protanopia and
11
+ // deuteranopia were much closer than expected.
14
12
 
15
- import { multiplyMatrices, invertMatrix } from "../util/matrix.js";
16
13
  import { appendSuggestion } from "../util/suggest.js";
17
14
 
18
15
  const CVD_TYPES = [
@@ -30,107 +27,201 @@ const CVD_TYPES = [
30
27
  "achromatomaly"
31
28
  ];
32
29
 
33
- // sRGB→XYZ (D65), ported from src/swatch.js:1737-1743.
34
- const M_RGB_TO_XYZ = [
35
- [0.4124564, 0.3575761, 0.1804375],
36
- [0.2126729, 0.7151522, 0.072175],
37
- [0.0193339, 0.119192, 0.9503041]
30
+ export const IDENTITY3 = [
31
+ [1, 0, 0],
32
+ [0, 1, 0],
33
+ [0, 0, 1]
38
34
  ];
39
35
 
40
- // Hunt-Pointer-Estevez XYZ→LMS (normalized to equal-energy).
41
- const M_XYZ_TO_LMS = [
42
- [0.4002, 0.7076, -0.0808],
43
- [-0.2263, 1.1653, 0.0457],
44
- [0, 0, 0.9182]
36
+ // Rec. 709 luminance row, used for the achromatopsia projection.
37
+ export const ACHROMA_MATRIX = [
38
+ [0.2126, 0.7152, 0.0722],
39
+ [0.2126, 0.7152, 0.0722],
40
+ [0.2126, 0.7152, 0.0722]
45
41
  ];
46
42
 
47
- export const M_LINEAR_RGB_TO_LMS = multiplyMatrices(
48
- M_XYZ_TO_LMS,
49
- M_RGB_TO_XYZ
50
- );
51
- export const M_LMS_TO_LINEAR_RGB = invertMatrix(M_LINEAR_RGB_TO_LMS);
52
-
53
- function mat3mul3(M, v) {
54
- return [
55
- M[0][0] * v[0] + M[0][1] * v[1] + M[0][2] * v[2],
56
- M[1][0] * v[0] + M[1][1] * v[1] + M[1][2] * v[2],
57
- M[2][0] * v[0] + M[2][1] * v[1] + M[2][2] * v[2]
58
- ];
59
- }
60
-
61
- function linearRgbToLms(rgb) {
62
- return mat3mul3(M_LINEAR_RGB_TO_LMS, rgb);
63
- }
64
-
65
- // LMS primaries used as dichromat anchors.
66
- const blueLms = linearRgbToLms([0, 0, 1]);
67
- const redLms = linearRgbToLms([1, 0, 0]);
68
- const whiteLms = linearRgbToLms([1, 1, 1]);
69
-
70
- // Protan: L is missing → L = a·M + b·S, anchor = blue.
71
- function dichromatProtanopia() {
72
- const wL = whiteLms[0],
73
- wM = whiteLms[1],
74
- wS = whiteLms[2];
75
- const bL = blueLms[0],
76
- bM = blueLms[1],
77
- bS = blueLms[2];
78
- const det = wM * bS - bM * wS;
79
- const a = (wL * bS - bL * wS) / det;
80
- const b = (wM * bL - bM * wL) / det;
81
- return [
82
- [0, a, b],
83
- [0, 1, 0],
84
- [0, 0, 1]
85
- ];
86
- }
87
-
88
- // Deutan: M is missing → M = a·L + b·S, anchor = blue.
89
- function dichromatDeuteranopia() {
90
- const wL = whiteLms[0],
91
- wM = whiteLms[1],
92
- wS = whiteLms[2];
93
- const bL = blueLms[0],
94
- bM = blueLms[1],
95
- bS = blueLms[2];
96
- const det = wL * bS - bL * wS;
97
- const a = (wM * bS - bM * wS) / det;
98
- const b = (wL * bM - bL * wM) / det;
99
- return [
100
- [1, 0, 0],
101
- [a, 0, b],
102
- [0, 0, 1]
103
- ];
104
- }
105
-
106
- // Tritan: S is missing → S = a·L + b·M, anchor = red.
107
- function dichromatTritanopia() {
108
- const wL = whiteLms[0],
109
- wM = whiteLms[1];
110
- const rL = redLms[0],
111
- rM = redLms[1],
112
- rS = redLms[2];
113
- const det = wL * rM - rL * wM;
114
- const a = (whiteLms[2] * rM - rS * wM) / det;
115
- const b = (wL * rS - rL * whiteLms[2]) / det;
116
- return [
117
- [1, 0, 0],
118
- [0, 1, 0],
119
- [a, b, 0]
120
- ];
121
- }
122
-
123
- function buildRgbMatrix(dichromatLms) {
124
- return multiplyMatrices(
125
- M_LMS_TO_LINEAR_RGB,
126
- multiplyMatrices(dichromatLms, M_LINEAR_RGB_TO_LMS)
127
- );
128
- }
43
+ // Machado (2010) Φ_CVD matrices, sampled at severity 0.0, 0.1, …, 1.0.
44
+ // Matrix rows are linear-sRGB output channels; columns are linear-sRGB input
45
+ // channels. The 1.0 samples correspond to protanopia, deuteranopia, and
46
+ // tritanopia respectively.
47
+ export const CVD_MACHADO_MATRICES = {
48
+ protan: [
49
+ [
50
+ [1.0, 0.0, -0.0],
51
+ [0.0, 1.0, 0.0],
52
+ [-0.0, -0.0, 1.0]
53
+ ],
54
+ [
55
+ [0.856167, 0.182038, -0.038205],
56
+ [0.029342, 0.955115, 0.015544],
57
+ [-0.00288, -0.001563, 1.004443]
58
+ ],
59
+ [
60
+ [0.734766, 0.334872, -0.069637],
61
+ [0.05184, 0.919198, 0.028963],
62
+ [-0.004928, -0.004209, 1.009137]
63
+ ],
64
+ [
65
+ [0.630323, 0.465641, -0.095964],
66
+ [0.069181, 0.890046, 0.040773],
67
+ [-0.006308, -0.007724, 1.014032]
68
+ ],
69
+ [
70
+ [0.539009, 0.579343, -0.118352],
71
+ [0.082546, 0.866121, 0.051332],
72
+ [-0.007136, -0.011959, 1.019095]
73
+ ],
74
+ [
75
+ [0.458064, 0.679578, -0.137642],
76
+ [0.092785, 0.846313, 0.060902],
77
+ [-0.007494, -0.016807, 1.024301]
78
+ ],
79
+ [
80
+ [0.38545, 0.769005, -0.154455],
81
+ [0.100526, 0.829802, 0.069673],
82
+ [-0.007442, -0.02219, 1.029632]
83
+ ],
84
+ [
85
+ [0.319627, 0.849633, -0.169261],
86
+ [0.106241, 0.815969, 0.07779],
87
+ [-0.007025, -0.028051, 1.035076]
88
+ ],
89
+ [
90
+ [0.259411, 0.923008, -0.18242],
91
+ [0.110296, 0.80434, 0.085364],
92
+ [-0.006276, -0.034346, 1.040622]
93
+ ],
94
+ [
95
+ [0.203876, 0.990338, -0.194214],
96
+ [0.112975, 0.794542, 0.092483],
97
+ [-0.005222, -0.041043, 1.046265]
98
+ ],
99
+ [
100
+ [0.152286, 1.052583, -0.204868],
101
+ [0.114503, 0.786281, 0.099216],
102
+ [-0.003882, -0.048116, 1.051998]
103
+ ]
104
+ ],
105
+ deutan: [
106
+ [
107
+ [1.0, 0.0, -0.0],
108
+ [0.0, 1.0, 0.0],
109
+ [-0.0, -0.0, 1.0]
110
+ ],
111
+ [
112
+ [0.866435, 0.177704, -0.044139],
113
+ [0.049567, 0.939063, 0.01137],
114
+ [-0.003453, 0.007233, 0.99622]
115
+ ],
116
+ [
117
+ [0.760729, 0.319078, -0.079807],
118
+ [0.090568, 0.889315, 0.020117],
119
+ [-0.006027, 0.013325, 0.992702]
120
+ ],
121
+ [
122
+ [0.675425, 0.43385, -0.109275],
123
+ [0.125303, 0.847755, 0.026942],
124
+ [-0.00795, 0.018572, 0.989378]
125
+ ],
126
+ [
127
+ [0.605511, 0.52856, -0.134071],
128
+ [0.155318, 0.812366, 0.032316],
129
+ [-0.009376, 0.023176, 0.9862]
130
+ ],
131
+ [
132
+ [0.547494, 0.607765, -0.155259],
133
+ [0.181692, 0.781742, 0.036566],
134
+ [-0.01041, 0.027275, 0.983136]
135
+ ],
136
+ [
137
+ [0.498864, 0.674741, -0.173604],
138
+ [0.205199, 0.754872, 0.039929],
139
+ [-0.011131, 0.030969, 0.980162]
140
+ ],
141
+ [
142
+ [0.457771, 0.731899, -0.18967],
143
+ [0.226409, 0.731012, 0.042579],
144
+ [-0.011595, 0.034333, 0.977261]
145
+ ],
146
+ [
147
+ [0.422823, 0.781057, -0.203881],
148
+ [0.245752, 0.709602, 0.044646],
149
+ [-0.011843, 0.037423, 0.974421]
150
+ ],
151
+ [
152
+ [0.392952, 0.82361, -0.216562],
153
+ [0.263559, 0.69021, 0.046232],
154
+ [-0.01191, 0.040281, 0.97163]
155
+ ],
156
+ [
157
+ [0.367322, 0.860646, -0.227968],
158
+ [0.280085, 0.672501, 0.047413],
159
+ [-0.01182, 0.04294, 0.968881]
160
+ ]
161
+ ],
162
+ tritan: [
163
+ [
164
+ [1.0, 0.0, -0.0],
165
+ [0.0, 1.0, 0.0],
166
+ [-0.0, -0.0, 1.0]
167
+ ],
168
+ [
169
+ [0.92667, 0.092514, -0.019184],
170
+ [0.021191, 0.964503, 0.014306],
171
+ [0.008437, 0.054813, 0.93675]
172
+ ],
173
+ [
174
+ [0.89572, 0.13333, -0.02905],
175
+ [0.029997, 0.9454, 0.024603],
176
+ [0.013027, 0.104707, 0.882266]
177
+ ],
178
+ [
179
+ [0.905871, 0.127791, -0.033662],
180
+ [0.026856, 0.941251, 0.031893],
181
+ [0.01341, 0.148296, 0.838294]
182
+ ],
183
+ [
184
+ [0.948035, 0.08949, -0.037526],
185
+ [0.014364, 0.946792, 0.038844],
186
+ [0.010853, 0.193991, 0.795156]
187
+ ],
188
+ [
189
+ [1.017277, 0.027029, -0.044306],
190
+ [-0.006113, 0.958479, 0.047634],
191
+ [0.006379, 0.248708, 0.744913]
192
+ ],
193
+ [
194
+ [1.104996, -0.046633, -0.058363],
195
+ [-0.032137, 0.971635, 0.060503],
196
+ [0.001336, 0.317922, 0.680742]
197
+ ],
198
+ [
199
+ [1.193214, -0.109812, -0.083402],
200
+ [-0.058496, 0.97941, 0.079086],
201
+ [-0.002346, 0.403492, 0.598854]
202
+ ],
203
+ [
204
+ [1.257728, -0.139648, -0.118081],
205
+ [-0.078003, 0.975409, 0.102594],
206
+ [-0.003316, 0.501214, 0.502102]
207
+ ],
208
+ [
209
+ [1.278864, -0.125333, -0.153531],
210
+ [-0.084748, 0.957674, 0.127074],
211
+ [-0.000989, 0.601151, 0.399838]
212
+ ],
213
+ [
214
+ [1.255528, -0.076749, -0.178779],
215
+ [-0.078411, 0.930809, 0.147602],
216
+ [0.004733, 0.691367, 0.3039]
217
+ ]
218
+ ]
219
+ };
129
220
 
130
221
  export const CVD_RGB_MATRICES = {
131
- protan: buildRgbMatrix(dichromatProtanopia()),
132
- deutan: buildRgbMatrix(dichromatDeuteranopia()),
133
- tritan: buildRgbMatrix(dichromatTritanopia())
222
+ protan: CVD_MACHADO_MATRICES.protan[10],
223
+ deutan: CVD_MACHADO_MATRICES.deutan[10],
224
+ tritan: CVD_MACHADO_MATRICES.tritan[10]
134
225
  };
135
226
 
136
227
  export function normalizeCVDType(type) {
@@ -151,18 +242,11 @@ export function normalizeCVDType(type) {
151
242
  );
152
243
  }
153
244
 
154
- export const IDENTITY3 = [
155
- [1, 0, 0],
156
- [0, 1, 0],
157
- [0, 0, 1]
158
- ];
159
-
160
- // Rec. 709 luminance row, used for the achromatopsia projection.
161
- export const ACHROMA_MATRIX = [
162
- [0.2126, 0.7152, 0.0722],
163
- [0.2126, 0.7152, 0.0722],
164
- [0.2126, 0.7152, 0.0722]
165
- ];
245
+ export function normalizeCVDSeverity(severity) {
246
+ const n = Number(severity);
247
+ if (!Number.isFinite(n)) return 1;
248
+ return n < 0 ? 0 : n > 1 ? 1 : n;
249
+ }
166
250
 
167
251
  export function interpolateMatrix3(A, B, t) {
168
252
  const out = [
@@ -177,3 +261,24 @@ export function interpolateMatrix3(A, B, t) {
177
261
  }
178
262
  return out;
179
263
  }
264
+
265
+ function interpolateMachadoTable(table, severity) {
266
+ if (severity <= 0) return table[0];
267
+ if (severity >= 1) return table[10];
268
+
269
+ const scaled = severity * 10;
270
+ const lo = Math.min(9, Math.floor(scaled));
271
+ const hi = lo + 1;
272
+ const t = scaled - lo;
273
+ if (t === 0) return table[lo];
274
+ return interpolateMatrix3(table[lo], table[hi], t);
275
+ }
276
+
277
+ export function cvdSimulationMatrix(type, severity = 1) {
278
+ const normalized = normalizeCVDType(type);
279
+ const sev = normalizeCVDSeverity(severity);
280
+ if (normalized === "achroma") {
281
+ return interpolateMatrix3(IDENTITY3, ACHROMA_MATRIX, sev);
282
+ }
283
+ return interpolateMachadoTable(CVD_MACHADO_MATRICES[normalized], sev);
284
+ }
@@ -1,19 +1,16 @@
1
1
  // Color Vision Deficiency simulation and daltonization.
2
2
  //
3
- // Projection matrices for protan/deutan/tritan come from
4
- // data/cvd-matrices.js via the Brettel/Viénot anchor-line method.
5
- // simulate() interpolates between the identity and the dichromat
6
- // matrix by `severity` (0..1). daltonize() uses Fidaner-style error
7
- // redistribution: compute what the dichromat loses (the delta in
8
- // linear sRGB) and shift it into channels the user can still see.
3
+ // Projection matrices for protan/deutan/tritan come from the
4
+ // Machado/Oliveira/Fernandes severity table in data/cvd-matrices.js.
5
+ // daltonize() uses Fidaner-style error redistribution: compute what the
6
+ // dichromat loses (the delta in linear sRGB) and shift it into channels the
7
+ // user can still see.
9
8
 
10
9
  import { Swatch, swatch } from "../core/swatch-class.js";
11
10
  import { srgbToLinear, linearToSrgb } from "../spaces/srgb.js";
12
11
  import {
13
- CVD_RGB_MATRICES,
14
- IDENTITY3,
15
- ACHROMA_MATRIX,
16
- interpolateMatrix3,
12
+ cvdSimulationMatrix,
13
+ normalizeCVDSeverity,
17
14
  normalizeCVDType
18
15
  } from "../data/cvd-matrices.js";
19
16
 
@@ -39,19 +36,7 @@ function clamp01Triplet(v) {
39
36
 
40
37
  export function simulate(input, type, { severity = 1 } = {}) {
41
38
  const s = toSwatch(input);
42
- const sev = Math.max(0, Math.min(1, severity));
43
- const normalized = normalizeCVDType(type);
44
-
45
- let M;
46
- if (normalized === "achroma") {
47
- M = interpolateMatrix3(IDENTITY3, ACHROMA_MATRIX, sev);
48
- } else {
49
- M = interpolateMatrix3(
50
- IDENTITY3,
51
- CVD_RGB_MATRICES[normalized],
52
- sev
53
- );
54
- }
39
+ const M = cvdSimulationMatrix(type, severity);
55
40
 
56
41
  const { r, g, b } = s.srgb;
57
42
  const lin = srgbToLinear([r, g, b]);
@@ -67,7 +52,7 @@ export function simulate(input, type, { severity = 1 } = {}) {
67
52
 
68
53
  export function daltonize(input, type, { severity = 1 } = {}) {
69
54
  const s = toSwatch(input);
70
- const sev = Math.max(0, Math.min(1, severity));
55
+ const sev = normalizeCVDSeverity(severity);
71
56
  const normalized = normalizeCVDType(type);
72
57
  if (normalized === "achroma") {
73
58
  throw new Error(
@@ -75,11 +60,7 @@ export function daltonize(input, type, { severity = 1 } = {}) {
75
60
  );
76
61
  }
77
62
 
78
- const M = interpolateMatrix3(
79
- IDENTITY3,
80
- CVD_RGB_MATRICES[normalized],
81
- sev
82
- );
63
+ const M = cvdSimulationMatrix(normalized, sev);
83
64
 
84
65
  const { r, g, b } = s.srgb;
85
66
  const lin = srgbToLinear([r, g, b]);
@@ -6,10 +6,8 @@
6
6
  // and preserves alpha untouched.
7
7
 
8
8
  import {
9
- CVD_RGB_MATRICES,
10
- IDENTITY3,
11
- ACHROMA_MATRIX,
12
- interpolateMatrix3,
9
+ cvdSimulationMatrix,
10
+ normalizeCVDSeverity,
13
11
  normalizeCVDType
14
12
  } from "../data/cvd-matrices.js";
15
13
 
@@ -36,12 +34,6 @@ function clamp01ToByte(v) {
36
34
  return LINEAR_TO_SRGB8[(v * (LUT_SIZE - 1) + 0.5) | 0];
37
35
  }
38
36
 
39
- function normalizeSeverity(severity) {
40
- const n = Number(severity);
41
- if (!Number.isFinite(n)) return 1;
42
- return n < 0 ? 0 : n > 1 ? 1 : n;
43
- }
44
-
45
37
  function assertImageDataLike(imageData) {
46
38
  if (!imageData || !imageData.data) {
47
39
  throw new Error("imageData: expected { data, width, height }");
@@ -102,12 +94,7 @@ function targetImageData(imageData, inPlace) {
102
94
  }
103
95
 
104
96
  function simulationMatrix(type, severity) {
105
- const normalized = normalizeCVDType(type);
106
- const sev = normalizeSeverity(severity);
107
- const target = normalized === "achroma"
108
- ? ACHROMA_MATRIX
109
- : CVD_RGB_MATRICES[normalized];
110
- return interpolateMatrix3(IDENTITY3, target, sev);
97
+ return cvdSimulationMatrix(type, severity);
111
98
  }
112
99
 
113
100
  function correctionMatrix(type, severity) {
@@ -119,11 +106,7 @@ function correctionMatrix(type, severity) {
119
106
  }
120
107
  return {
121
108
  normalized,
122
- matrix: interpolateMatrix3(
123
- IDENTITY3,
124
- CVD_RGB_MATRICES[normalized],
125
- normalizeSeverity(severity)
126
- )
109
+ matrix: cvdSimulationMatrix(normalized, normalizeCVDSeverity(severity))
127
110
  };
128
111
  }
129
112