@luntta/swatch 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/CONTRIBUTING.md +89 -0
  3. package/LICENSE +21 -0
  4. package/MIGRATING.md +189 -0
  5. package/README.md +463 -0
  6. package/package.json +57 -0
  7. package/scripts/pack-check.mjs +18 -0
  8. package/src/bootstrap.js +159 -0
  9. package/src/core/registry.js +81 -0
  10. package/src/core/state.js +36 -0
  11. package/src/core/swatch-class.js +524 -0
  12. package/src/data/cvd-matrices.js +179 -0
  13. package/src/data/named-colors.js +157 -0
  14. package/src/format/css.js +256 -0
  15. package/src/operations/accessibility.js +103 -0
  16. package/src/operations/apca.js +80 -0
  17. package/src/operations/blend.js +72 -0
  18. package/src/operations/channels.js +123 -0
  19. package/src/operations/cvd.js +119 -0
  20. package/src/operations/deltaE.js +207 -0
  21. package/src/operations/gamut.js +206 -0
  22. package/src/operations/image.js +192 -0
  23. package/src/operations/manipulation.js +100 -0
  24. package/src/operations/mix.js +129 -0
  25. package/src/operations/naming.js +158 -0
  26. package/src/operations/palette.js +133 -0
  27. package/src/operations/random.js +75 -0
  28. package/src/operations/temperature.js +126 -0
  29. package/src/operations/tint-shade.js +42 -0
  30. package/src/palettes/colorbrewer.js +232 -0
  31. package/src/palettes/index.js +58 -0
  32. package/src/palettes/viridis.js +59 -0
  33. package/src/parse/css.js +241 -0
  34. package/src/parse/hex.js +38 -0
  35. package/src/parse/index.js +43 -0
  36. package/src/parse/legacy.js +88 -0
  37. package/src/parse/named.js +11 -0
  38. package/src/parse/objects.js +125 -0
  39. package/src/scale/index.js +382 -0
  40. package/src/scale/interpolators.js +83 -0
  41. package/src/spaces/a98.js +55 -0
  42. package/src/spaces/cmyk.js +75 -0
  43. package/src/spaces/display-p3.js +50 -0
  44. package/src/spaces/hsl.js +93 -0
  45. package/src/spaces/hsluv.js +211 -0
  46. package/src/spaces/hsv.js +78 -0
  47. package/src/spaces/hwb.js +48 -0
  48. package/src/spaces/lab.js +70 -0
  49. package/src/spaces/lch.js +65 -0
  50. package/src/spaces/oklab.js +79 -0
  51. package/src/spaces/oklch.js +53 -0
  52. package/src/spaces/prophoto.js +72 -0
  53. package/src/spaces/rec2020.js +65 -0
  54. package/src/spaces/srgb.js +85 -0
  55. package/src/spaces/xyz.js +71 -0
  56. package/src/swatch.js +57 -0
  57. package/src/util/math.js +53 -0
  58. package/src/util/matrix.js +92 -0
  59. package/src/util/suggest.js +66 -0
  60. package/types/swatch.d.ts +664 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,56 @@
1
+ # Changelog
2
+
3
+ ## 3.0.0 — BREAKING
4
+
5
+ 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`.
6
+
7
+ See [`MIGRATING.md`](./MIGRATING.md) for the v2 → v3 cookbook.
8
+
9
+ ### Breaking
10
+
11
+ - **Manipulation moved to OKLCh.** `lighten`, `darken`, `saturate`, `desaturate`, `spin`, `greyscale`, and `complement` now operate in OKLCh instead of HSL, with amounts in `0..1` OKLCh L/C units instead of `0..100` HSL %. `swatch("#ff0000").lighten(20)` (v2) becomes `swatch("#ff0000").lighten(0.1)` (v3). Rationale: HSL lightness is not perceptually uniform, so v2's `swatch("#ffff00").lighten(0.1)` looked almost unchanged while `swatch("#0000ff").lighten(0.1)` jumped.
12
+ - **Space conversions are getters, not methods.** `c.toLab()` → `c.lab`, `c.toOklch()` → `c.oklch`, `c.toRGB()` → `c.srgb`, etc. Getters are lazily memoized on the instance.
13
+ - **Wide-gamut inputs are no longer clamped at parse.** `swatch("color(display-p3 1 0 0)")` keeps its P3 coordinates; `.srgb` on that swatch returns a raw, possibly out-of-range conversion. Use `.toGamut({ space: "srgb", method: "css4" })` to get a properly chroma-reduced in-gamut version.
14
+ - **`toJSON()` shape changed** from `{ hex, rgb, hsl, isValid, format }` to `{ space, coords, alpha }`. The new shape round-trips cleanly through `swatch(...)`.
15
+ - **`equals()` signature changed** from `equals(other, { tolerance, space })` to `equals(other, epsilon)`. `other` must now be a `Swatch` instance.
16
+ - **Removed v2 fields:** `isValid`, `hasAlpha`, `_original`, `_originalFormat`. Invalid input now throws; check `alpha < 1` for alpha presence; use `c.space` / `c.coords` to introspect state.
17
+ - **`mix()` takes an options bag** for the interpolation space: `a.mix(b, 0.5, "lab")` → `a.mix(b, 0.5, { space: "lab" })`.
18
+ - **Harmonies not yet ported.** `complementary`, `triad`, `tetrad`, `splitComplement`, `analogous`, `monochromatic` are not in v3.0. They will return in a follow-up release. Workaround: `[c, c.spin(120), c.spin(240)]`.
19
+ - **Internal rename.** The v2 monolith lives at `src/_v2-monolith.js` as an internal artifact and is not part of the public API. Do not import from it.
20
+
21
+ ### Added
22
+
23
+ - **CSS Color 4 parsing and serialization.** `swatch("oklch(0.7 0.15 240)")`, `swatch("lab(52.2% 40 -70)")`, `swatch("hwb(240 0% 0%)")`, `swatch("color(display-p3 1 0 0)")`, `swatch("color(rec2020 1 0 0)")`, `swatch("color(xyz-d65 0.4 0.2 0.2)")`, modern slash-alpha, `none` keyword, percentage values, the whole set. `c.toString({ format: "oklch" })` / `"lab"` / `"hwb"` / `"lch"` / `"oklab"` / `"color"` for output.
24
+ - **Wide-gamut spaces.** Display P3, Rec2020, Adobe RGB 1998, ProPhoto RGB. Each registered in the conversion graph with their correct primaries and transfer functions; ProPhoto carries a Bradford D50 → D65 CAT internally.
25
+ - **Additional spaces.** HSV, HWB, CMYK (naive), HSLuv, Luv, linear sRGB, XYZ D65 and D50.
26
+ - **Channel get/set.** `c.get("oklch.l")`, `c.set("hsl.h", 120)`, `c.get("alpha")`.
27
+ - **Gamut mapping.** `c.inGamut("srgb")`, `c.toGamut({ space, method })`, with `"clip"`, `"css4"` (CSS Color 4 binary chroma reduction in OKLCh, default), and `"oklch-chroma"` (alias).
28
+ - **Tint, shade, tone.** `c.tint(0.2)`, `c.shade(0.2)`, `c.tone(0.2)` — mix toward white / black / mid-grey in OKLab.
29
+ - **W3C Compositing and Blending Level 1 blend modes.** `normal`, `multiply`, `screen`, `darken`, `lighten`, `overlay`, `color-dodge`, `color-burn`, `hard-light`, `soft-light`, `difference`, `exclusion`. Per-channel in linear sRGB, then re-encoded.
30
+ - **Color scales.** `swatch.scale([c1, c2, ...])` returns a chroma.js-style `Scale` with chainable `.domain([a, b])`, `.classes(n)`, `.padding([l, r])`, `.gamma(g)`, `.mode(spaceId)`, `.correctLightness()`, `.cache(on)`, plus `.colors(n, format?)`.
31
+ - **Built-in palettes.** Matplotlib perceptually-uniform colormaps (`viridis`, `magma`, `plasma`, `inferno`, `cividis`) and the ColorBrewer 2.0 sequential (`Blues`, `Greens`, `Reds`, `Oranges`, `Purples`, `Greys`), diverging (`RdBu`, `RdYlBu`, `PiYG`, `BrBG`, `Spectral`), and qualitative (`Set1`, `Set2`, `Set3`, `Pastel1`, `Dark2`) sets. Look up by name: `swatch.scale("viridis")`, `swatch.scale("RdBu")`, etc. List all: `swatch.palettes()`.
32
+ - **Scale interpolators.** `swatch.bezier([colors])` (de Casteljau in Lab), `swatch.cubehelix({ start, rotations, hue, gamma, lightness })` (Green 2011).
33
+ - **Color naming.** `c.name()` returns `{ name, hex, deltaE }` of the nearest CSS named color measured in ΔE2000; `c.toName()` returns just the string.
34
+ - **Temperature.** `swatch.temperature(6500)` (Krystek 1985 blackbody polynomial) and `c.temperature()` (McCamy 1992 inverse approximation). Range 1000 K – 40000 K.
35
+ - **Random color generation.** `swatch.random({ space, hue, lightness, chroma, saturation, seed })` with a seeded xorshift32 PRNG for reproducibility.
36
+ - **Extra ΔE metrics.** `"94"` (CIE94 graphic arts), `"cmc"` (CMC l:c with optional `{ l, c }` coefficients), `"hyab"` (Abasi & Fairchild HyAB). Existing `"76"`, `"2000"`, `"ok"` still supported.
37
+ - **TypeScript definitions rewritten.** `types/swatch.d.ts` now covers the full v3 surface including the `SpaceId` literal union, all per-space channel shapes, the widened `ColorInput`, every option bag, the `Scale` interface, and the `SwatchFactory` statics.
38
+ - **New docs.** [`README.md`](./README.md) rewritten for v3. [`MIGRATING.md`](./MIGRATING.md) added with the v2 → v3 cookbook.
39
+
40
+ ### Unchanged
41
+
42
+ The CVD / APCA / WCAG story is preserved end-to-end:
43
+
44
+ - `simulate(type, { severity })` — Brettel/Viénot dichromat simulation with a severity continuum
45
+ - `daltonize(type, { severity })` — Fidaner error redistribution
46
+ - `swatch.checkPalette(colors, { cvd, minDeltaE, mode })`
47
+ - `swatch.nearestDistinguishable(target, against, { cvd, minDeltaE, step })`
48
+ - `swatch.mostReadable(bg, candidates, { level, size })`
49
+ - `contrast(a, b)`, `isReadable(a, b, { level, size })`, `ensureContrast(a, b, { minRatio, direction, step })`
50
+ - `apcaContrast(text, background)`
51
+
52
+ All of these moved to new module paths internally but kept their public signatures.
53
+
54
+ ## 2.0.0-alpha.2 and earlier
55
+
56
+ See the git history.
@@ -0,0 +1,89 @@
1
+ # Contributing to Swatch
2
+
3
+ Thanks for working on Swatch. This repo contains the library, tests, TypeScript
4
+ declarations, and the Eleventy docs/playground.
5
+
6
+ ## Requirements
7
+
8
+ - Node.js 20 or newer.
9
+ - npm.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install
15
+ npm --prefix docs install
16
+ ```
17
+
18
+ ## Common commands
19
+
20
+ From the repository root:
21
+
22
+ ```bash
23
+ npm test # Run the library test suite
24
+ npm run typecheck # Type-check the public .d.ts against types/swatch.test-d.ts
25
+ npm run docs:dev # Start the docs/playground at http://localhost:8080
26
+ npm run docs:build # Build the static docs site
27
+ npm run check # Run tests, typecheck, and build docs
28
+ npm run pack:check # Show the npm package contents without publishing
29
+ ```
30
+
31
+ The docs package also has its own local scripts under `docs/package.json`.
32
+
33
+ Reference-page search is powered by [Pagefind](https://pagefind.app), whose
34
+ index is generated by `npm run docs:build` (not by `docs:dev`), so the search
35
+ box only returns results against a production build.
36
+
37
+ ## Project layout
38
+
39
+ - `src/swatch.js` is the public package entry point.
40
+ - `src/bootstrap.js` registers built-in color spaces, parsers, operations,
41
+ palettes, scales, and factory statics.
42
+ - `src/core/` contains the registry, immutable state helpers, and `Swatch`
43
+ class.
44
+ - `src/spaces/` contains color-space conversions.
45
+ - `src/parse/` contains CSS/object/named-color parsing.
46
+ - `src/operations/` contains manipulation, gamut, contrast, CVD, ΔE, palette,
47
+ naming, random, and temperature helpers.
48
+ - `src/scale/` and `src/palettes/` contain scale/interpolator and built-in
49
+ palette support.
50
+ - `types/swatch.d.ts` is hand-written and should be updated with public API
51
+ changes.
52
+ - `tests/` contains Vitest coverage for v2 compatibility and v3 APIs.
53
+ - `docs/src/` contains the Eleventy site and interactive playground.
54
+
55
+ ## API design notes
56
+
57
+ - `Swatch` instances are immutable. Operations should return a new `Swatch`.
58
+ - The canonical state shape is `{ space, coords, alpha }`.
59
+ - Space conversions route through the registry and are lazily memoized on the
60
+ instance.
61
+ - Raw space getters such as `.srgb` return mathematical coordinates and may be
62
+ out of gamut. Display helpers such as `.hex()` and `.rgb()` gamut-map to sRGB
63
+ by default.
64
+ - Public string options should have tests and helpful error messages.
65
+
66
+ ## Documentation changes
67
+
68
+ When adding or changing public API:
69
+
70
+ 1. Update `README.md`.
71
+ 2. Update or add a page in `docs/src/reference/`.
72
+ 3. Add or update playground affordances if the feature is visual.
73
+ 4. Update `types/swatch.d.ts`.
74
+ 5. Add tests that exercise the documented examples.
75
+
76
+ Run `npm run check` before opening a PR.
77
+
78
+ ## Release checklist
79
+
80
+ Before publishing:
81
+
82
+ ```bash
83
+ npm run check
84
+ npm run pack:check
85
+ ```
86
+
87
+ Then review the package contents printed by `pack:check` to make sure only the
88
+ intended source, declarations, docs, changelog, migration guide, license, and
89
+ package metadata are included.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Raine Luntta
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/MIGRATING.md ADDED
@@ -0,0 +1,189 @@
1
+ # Migrating from swatch 2.x to 3.0
2
+
3
+ Swatch 3.0 is a breaking rewrite. Storage moved to a canonical `{ space, coords, alpha }` state, conversions are lazy and memoized, manipulation became OKLCh-based by default, and the library gained CSS Color 4 parsing, wide-gamut spaces, color scales, built-in palettes, and more.
4
+
5
+ Most existing code will work with only small changes. The sections below cover the breakages, from most visible to most obscure.
6
+
7
+ ## 1. Manipulation amounts and space (the big one)
8
+
9
+ In v2 `lighten`/`darken`/`saturate`/`desaturate` operated in HSL with amounts in `0..100` (percentage-ish). In v3 they operate in OKLCh with amounts in `0..1` (OKLCh L and C units).
10
+
11
+ ```js
12
+ // v2
13
+ swatch("#ff0000").lighten(20); // +20 HSL L
14
+ swatch("#ff0000").saturate(10); // +10 HSL S
15
+
16
+ // v3
17
+ swatch("#ff0000").lighten(0.1); // +0.1 OKLCh L
18
+ swatch("#ff0000").saturate(0.05); // +0.05 OKLCh C
19
+ ```
20
+
21
+ **Why the change?** HSL lightness isn't perceptually uniform — `#ffff00` barely moves when you lighten it in HSL, because yellow already has near-maximum HSL L. OKLCh L is perceptually uniform, so `swatch("#ffff00").lighten(0.05)` and `swatch("#0000ff").lighten(0.05)` look equally brighter.
22
+
23
+ **Rough conversion:** v2 HSL amounts divide by about 200 to get a comparable v3 OKLCh amount, but the results are not numerically equivalent — they're perceptually better. Re-test visually.
24
+
25
+ `spin(degrees)` is unchanged (still degrees). `greyscale`, `complement`, and `invert` keep their v2 behavior.
26
+
27
+ ## 2. Space conversions are getters, not methods
28
+
29
+ ```js
30
+ // v2
31
+ c.toRGB();
32
+ c.toLab();
33
+ c.toOklch();
34
+
35
+ // v3
36
+ c.srgb;
37
+ c.lab;
38
+ c.oklch;
39
+ ```
40
+
41
+ v3 also adds a large set of new space getters: `c.hsv`, `c.hwb`, `c.cmyk`, `c.hsluv`, `c.luv`, `c.displayP3`, `c.rec2020`, `c.a98`, `c.prophoto`, `c.linearSrgb`, `c.xyz`.
42
+
43
+ Use `c.to("<spaceId>")` to move the canonical space itself (not just read in another space):
44
+
45
+ ```js
46
+ const p3 = swatch("#ff0000").to("display-p3");
47
+ p3.space; // "display-p3"
48
+ p3.coords; // [r, g, b] in Display P3, not sRGB
49
+ ```
50
+
51
+ ## 3. Wide-gamut inputs are no longer clamped at parse
52
+
53
+ v2 parsed `color(display-p3 1 0 0)` by immediately projecting into sRGB (which clipped the chromaticity). v3 preserves the original Display P3 coordinates losslessly in the canonical state.
54
+
55
+ ```js
56
+ const p3red = swatch("color(display-p3 1 0 0)");
57
+ p3red.space; // "display-p3"
58
+ p3red.inGamut("srgb"); // false
59
+ p3red.displayP3; // { r: 1, g: 0, b: 0 }
60
+ p3red.srgb; // { r: 1.093, g: -0.227, b: -0.150 } — raw conversion, out of range
61
+ p3red.toString({ format: "hex" }); // "#ff0000" (naive clip for presentation)
62
+ ```
63
+
64
+ The `.srgb` / `.linearSrgb` / `.hsl` getters no longer gamut-map. For a wide-gamut source, they will return out-of-range coordinates. Call `.toGamut({ space: "srgb", method: "css4" })` explicitly to get a properly chroma-reduced in-gamut Swatch, then read its `.srgb` / `.hex`.
65
+
66
+ ## 4. New `toJSON()` shape
67
+
68
+ ```js
69
+ // v2
70
+ c.toJSON();
71
+ // { hex: "#3366cc", rgb: { r, g, b }, hsl: { h, s, l }, isValid: true, format: "HEX" }
72
+
73
+ // v3
74
+ c.toJSON();
75
+ // { space: "srgb", coords: [0.2, 0.4, 0.8], alpha: 1 }
76
+ ```
77
+
78
+ The new shape round-trips cleanly: `swatch(c.toJSON()).equals(c)` is true.
79
+
80
+ If you stored v2 JSON blobs, read them through an adapter that extracts `hex` and passes it to `swatch()`.
81
+
82
+ ## 5. `equals()` signature changed
83
+
84
+ ```js
85
+ // v2
86
+ c.equals(other);
87
+ c.equals(other, { tolerance: 1 });
88
+ c.equals(other, { space: "oklab", tolerance: 0.01 });
89
+
90
+ // v3
91
+ c.equals(other); // default epsilon 1e-6 in the source space
92
+ c.equals(other, 1e-4); // custom epsilon
93
+ ```
94
+
95
+ `other` must be a `Swatch` instance in v3 (wrap strings with `swatch(...)` first).
96
+
97
+ ## 6. Removed: `isValid`, `hasAlpha`, `_original`, `_originalFormat`
98
+
99
+ In v2, invalid input produced a swatch with `isValid: false`. In v3, invalid input throws. Use `try`/`catch` to validate:
100
+
101
+ ```js
102
+ // v2
103
+ if (swatch(input).isValid) { ... }
104
+
105
+ // v3
106
+ try {
107
+ const c = swatch(input);
108
+ ...
109
+ } catch {
110
+ // invalid
111
+ }
112
+ ```
113
+
114
+ For alpha presence, check the numeric channel directly:
115
+
116
+ ```js
117
+ c.alpha < 1 // v3 replacement for v2's `c.hasAlpha`
118
+ ```
119
+
120
+ `_original` and `_originalFormat` (v2 internals) are gone; use `c.space` and `c.coords` to introspect the canonical state.
121
+
122
+ ## 7. `mix()` takes an options bag for the space
123
+
124
+ ```js
125
+ // v2
126
+ a.mix(b, 0.5, "lab");
127
+ a.mix(b, 0.5, "rgb");
128
+
129
+ // v3
130
+ a.mix(b, 0.5, { space: "lab" });
131
+ a.mix(b, 0.5, { space: "srgb" });
132
+ ```
133
+
134
+ Default space is still `oklab`.
135
+
136
+ ## 8. Harmonies are not yet ported
137
+
138
+ v2's `complementary()`, `triad()`, `tetrad()`, `splitComplement()`, `analogous()`, `monochromatic()` are not in v3.0. They will return in a follow-up release. As a workaround, `spin()` + an array literal covers most cases:
139
+
140
+ ```js
141
+ // v2
142
+ c.triad();
143
+
144
+ // v3 workaround
145
+ const s = swatch(c);
146
+ [s, s.spin(120), s.spin(240)];
147
+ ```
148
+
149
+ Tracked for follow-up. If you rely on harmonies, pin to v2 or file an issue.
150
+
151
+ ## 9. Named color list moved
152
+
153
+ v2 exported `named-colors.js` directly. v3 moved it to `src/data/named-colors.js`. If you imported the raw table, update the path. For most users, `c.toName()` / `c.name()` are the preferred API.
154
+
155
+ ## 10. New APIs worth learning
156
+
157
+ Things v2 didn't have at all:
158
+
159
+ | Feature | API |
160
+ |---|---|
161
+ | CSS Color 4 parsing | `swatch("oklch(0.7 0.15 240)")`, `swatch("color(display-p3 1 0 0)")` |
162
+ | Channel get/set | `c.get("oklch.l")`, `c.set("oklch.h", 120)` |
163
+ | Gamut mapping | `c.inGamut("srgb")`, `c.toGamut({ space, method })` |
164
+ | Tint / shade / tone | `c.tint(0.2)`, `c.shade(0.2)`, `c.tone(0.2)` |
165
+ | Blend modes | `c.blend(other, "multiply")` — all W3C Level 1 modes |
166
+ | Color scales | `swatch.scale([...])`, `.domain`, `.classes`, `.padding`, `.gamma`, `.mode`, `.correctLightness`, `.cache`, `.colors(n)` |
167
+ | Built-in palettes | `swatch.scale("viridis")`, `swatch.scale("RdBu")`, `swatch.palettes()` |
168
+ | Interpolators | `swatch.bezier([...])`, `swatch.cubehelix({...})` |
169
+ | Color naming | `c.name()`, `c.toName()` |
170
+ | Temperature | `swatch.temperature(6500)`, `c.temperature()` |
171
+ | Random | `swatch.random({ space, hue, lightness, chroma, seed })` |
172
+ | Extra ΔE | `"94"`, `"cmc"`, `"hyab"` on top of `"76"`, `"2000"`, `"ok"` |
173
+ | New spaces | HSV, HWB, CMYK, HSLuv, Luv, Display P3, Rec2020, A98, ProPhoto |
174
+
175
+ See [README.md](./README.md) for examples of each.
176
+
177
+ ## 11. Unchanged
178
+
179
+ The CVD/APCA/WCAG story — the heart of swatch — is unchanged:
180
+
181
+ - `simulate(type, { severity })` — Brettel/Viénot dichromat simulation
182
+ - `daltonize(type, { severity })` — Fidaner error redistribution
183
+ - `swatch.checkPalette(colors, { cvd, minDeltaE, mode })`
184
+ - `swatch.nearestDistinguishable(target, against, { cvd, minDeltaE, step })`
185
+ - `swatch.mostReadable(bg, candidates, { level, size })`
186
+ - `contrast(a, b)`, `isReadable(a, b, { level, size })`, `ensureContrast(a, b, { minRatio, direction, step })`
187
+ - `apcaContrast(text, background)`
188
+
189
+ All of these moved to new module paths internally but kept their public signatures.