@mkbabb/value.js 0.5.0 → 0.10.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 (43) hide show
  1. package/README.md +38 -56
  2. package/dist/easing.d.ts +49 -0
  3. package/dist/index.d.ts +19 -8
  4. package/dist/math.d.ts +1 -1
  5. package/dist/parsing/animation-shorthand.d.ts +19 -0
  6. package/dist/parsing/color.d.ts +10 -3
  7. package/dist/parsing/extract.d.ts +48 -0
  8. package/dist/parsing/index.d.ts +5 -20
  9. package/dist/parsing/serialize.d.ts +24 -0
  10. package/dist/parsing/stylesheet.d.ts +44 -0
  11. package/dist/parsing/units.d.ts +24 -6
  12. package/dist/parsing/utils.d.ts +5 -0
  13. package/dist/postcss-CRluLK2m.js +6400 -0
  14. package/dist/quantize/cluster.d.ts +45 -0
  15. package/dist/quantize/index.d.ts +14 -0
  16. package/dist/quantize/types.d.ts +39 -0
  17. package/dist/standalone-Ck3UyY5I.js +3458 -0
  18. package/dist/units/color/constants.d.ts +21 -0
  19. package/dist/units/color/contrast.d.ts +35 -0
  20. package/dist/units/color/conversions/cylindrical.d.ts +13 -0
  21. package/dist/units/color/conversions/direct.d.ts +41 -0
  22. package/dist/units/color/conversions/hex.d.ts +3 -0
  23. package/dist/units/color/conversions/index.d.ts +17 -0
  24. package/dist/units/color/conversions/kelvin.d.ts +5 -0
  25. package/dist/units/color/conversions/lab.d.ts +8 -0
  26. package/dist/units/color/conversions/oklab.d.ts +11 -0
  27. package/dist/units/color/conversions/transfer.d.ts +22 -0
  28. package/dist/units/color/conversions/xyz-extended.d.ts +13 -0
  29. package/dist/units/color/dispatch.d.ts +26 -0
  30. package/dist/units/color/gamut.d.ts +6 -0
  31. package/dist/units/color/index.d.ts +220 -116
  32. package/dist/units/color/mix.d.ts +16 -0
  33. package/dist/units/color/normalize.d.ts +3 -3
  34. package/dist/units/index.d.ts +39 -1
  35. package/dist/units/interpolate.d.ts +47 -0
  36. package/dist/units/normalize.d.ts +47 -7
  37. package/dist/units/utils.d.ts +1 -1
  38. package/dist/utils.d.ts +3 -2
  39. package/dist/value.js +4229 -5229
  40. package/package.json +62 -30
  41. package/scripts/migrate-keyframes-js-lerp.mjs +257 -0
  42. package/dist/units/color/utils.d.ts +0 -77
  43. package/dist/value.cjs +0 -20
package/README.md CHANGED
@@ -1,15 +1,16 @@
1
- # value.js ![image](demo/color-picker/cube.png)
1
+ # `value.js` <img src="demo/color-picker/favicon.svg" style="vertical-align: middle" width="48">
2
2
 
3
- CSS value parsing, color theory, and unit conversion. Typed values with units—`deg`, `px`, `rem`, `oklch()`—the core CSS value vocabulary.
3
+ CSS value parsing, color theory, and unit conversion. Typed values with units—`deg`, `px`, `rem`, `oklch()`—the CSS value vocabulary.
4
4
 
5
- [demo](https://color.babb.dev)
5
+ [demo](https://color.babb.dev) & [app guide](docs/colors/app.md)
6
6
 
7
7
  ## Features
8
8
 
9
9
  - Parse any CSS value: lengths, angles, times, colors, `calc()`, `var()`, gradients, transforms
10
+ - CSS Color Level 4 support: `color()`, `color-mix()`, relative color syntax
10
11
  - **15 color spaces**: RGB, HSL, HSV, HWB, Lab, LCh, OKLab, OKLCh, XYZ, Kelvin, sRGB-linear, Display P3, Adobe RGB, ProPhoto RGB, Rec. 2020
11
12
  - Color space conversion via **XYZ hub** with analytical gamut mapping (Ottosson's algorithm)
12
- - CSS Color Level 4 support: `color()`, `color-mix()`, relative color syntax
13
+ - **Color quantization**: OKLab-native palette extraction (MMCQ + k-means++) with chroma-weighted clustering and JND deduplication
13
14
  - CSS math functions: `calc()`, `min()`, `max()`, `clamp()`, trig, exponential
14
15
  - 30+ easing functions: cubic-bezier, stepped, linear(), bounce, sine, expo
15
16
  - 2D/3D matrix decomposition with quaternion slerp interpolation
@@ -32,14 +33,23 @@ import {
32
33
  } from "@mkbabb/value.js";
33
34
  ```
34
35
 
36
+ ## Upgrading
37
+
38
+ If you are upgrading across a major-feature bump, see [`CHANGELOG.md`](CHANGELOG.md) for the full per-version breaking-change list. The two migrations to be aware of:
39
+
40
+ - **v0.7.0** — the 51 individual `<from>2<to>` color-conversion functions were removed from the barrel. Replace `import { rgb2hsl } from "@mkbabb/value.js"` with the unified `color2(rgb, "rgb", "hsl")`.
41
+ - **v0.8.0** — `lerpLegacy` was removed; `lerp` takes canonical `(a, b, t)` ordering. The published codemod `scripts/migrate-keyframes-js-lerp.mjs` rewrites the legacy call shape automatically; manual migration is a straightforward argument swap (first argument moves to last).
42
+
43
+ v0.9.0 carries no breaking changes.
44
+
35
45
  ## Build
36
46
 
37
47
  ```bash
38
48
  npm run build # library → dist/value.js + value.cjs + value.d.ts
39
49
  npm run gh-pages # demo → dist/
40
50
  npm run dev # dev server (Vite default port)
41
- npm test # vitest (1372 tests)
42
- npm run test:e2e # playwright (desktop + mobile)
51
+ npm test # vitest unit suite
52
+ npm run test:e2e # playwright smoke suite (5 projects)
43
53
  ```
44
54
 
45
55
  ## Structure
@@ -66,77 +76,53 @@ src/
66
76
  │ ├── index.ts # Color<T> base + space classes
67
77
  │ ├── constants.ts # ranges, matrices, white points, named colors
68
78
  │ ├── matrix.ts # Vec3/Mat3 (row-major, replaces gl-matrix)
69
- │ ├── utils.ts # conversions via XYZ, mixColors, gamutMap
79
+ │ ├── conversions/ # focused per-family converters (hex, kelvin, lab, …)
80
+ │ ├── dispatch.ts # color2(), DIRECT_PATHS, gamutMap dispatch
70
81
  │ ├── normalize.ts # color normalization to [0,1], space conversion
71
82
  │ ├── gamut.ts # Ottosson analytical sRGB gamut mapping
72
83
  │ └── colorFilter.ts # CSS filter solver (SPSA)
84
+ ├── quantize/ # image color quantization
85
+ │ ├── index.ts # quantizePixels, dominantColor (public API)
86
+ │ ├── cluster.ts # MMCQ median cut, k-means++, JND dedup
87
+ │ └── types.ts # QuantizeOptions, QuantizedColor
73
88
  └── transform/
74
89
  └── decompose.ts # 2D/3D matrix decomposition, quaternion slerp
75
-
76
- test/ # vitest unit tests (24 files)
77
- e2e/ # playwright E2E (14 specs)
78
- demo/ # Vue 3.5 color picker (reka-ui, Tailwind)
79
- api/ # Hono + MongoDB palette API (Docker)
80
- docs/ # color-theory.md, gamut-mapping.md
81
- assets/docs/ # 10 color space reference pages
82
90
  ```
83
91
 
84
92
  ## Color Spaces
85
93
 
86
94
  All conversions route through the **XYZ D65** hub, enabling any-to-any conversion. Perceptual spaces (OKLab, Lab) use D50 natively with Bradford chromatic adaptation where needed.
87
95
 
88
- Each color space is documented in [`assets/docs/`](assets/docs/)historical context, component ranges, conversion functions, and practical applications.
96
+ Each color space is documented in [`assets/docs/`](assets/docs/), therein with historical context, component ranges, conversion functions, and practical applications.
89
97
 
90
98
  ### Gamut Mapping
91
99
 
92
100
  Out-of-gamut colors are mapped using Björn Ottosson's analytical sRGB algorithm: a polynomial initial guess refined by a single Halley's method step (cubic convergence). Significantly faster than CSS Color 4's iterative binary search. Hue is preserved exactly; an adaptive `L0` formula blends between chroma reduction and mid-gray anchoring.
93
101
 
94
- See [`docs/gamut-mapping.md`](docs/gamut-mapping.md) for the full treatment.
95
-
96
- ## Easing
97
-
98
- 30+ timing functions covering the CSS `<easing-function>` grammar plus bounce and back. `CSSCubicBezier` solves via Newton-Raphson with bisection fallback; `cssLinear()` implements CSS Easing Level 2 piecewise-linear with gap filling per spec; stepped easings support all four jump terms.
99
-
100
- ## Transforms
101
-
102
- CSS `matrix()` and `matrix3d()` decomposition per the CSSOM View and CSS Transforms specs. 3D uses Gram-Schmidt orthogonalization + quaternion extraction. `slerp` for rotation interpolation. `interpolateDecomposed()` for full transform blending.
103
-
104
- ## Palette API
102
+ See [`docs/colors/gamut-mapping.md`](docs/colors/gamut-mapping.md) for the full treatment.
105
103
 
106
- The [demo](https://color.babb.dev) is backed by a palette API for saving, sharing, and voting on color palettes. Users register via `POST /sessions`, which mints a UUID token and a four-word slug—no accounts required. Palettes are slug-addressed, votable (atomic toggle), and sortable by popularity or recency. A color name registry lets users propose names for CSS colors; admins approve or reject through a moderation queue.
104
+ ### Color Quantization
107
105
 
108
- Hono + MongoDB, Dockerized. See [`api/README.md`](api/README.md) for endpoints, schema, and deployment.
106
+ `quantizePixels()` extracts a perceptual palette from raw image data. The pipeline operates natively in OKLab—MMCQ pre-clustering, k-means++ with chroma-weighted distance, JND deduplication.
109
107
 
110
- | Feature | Mechanism |
111
- | ----------------- | ------------------------------------------------------------------------------------------------------------ |
112
- | **Sessions** | `POST /sessions` → UUID token + user slug; stored with hashed IP; 30-day TTL |
113
- | **Palettes** | CRUD by slug; 1–50 color stops with CSS string + optional name + position |
114
- | **Voting** | `POST /palettes/:slug/vote` — idempotent toggle; unique composite index on `{userSlug, paletteSlug}` |
115
- | **Color names** | `POST /colors/propose` → admin approval queue → `GET /colors/approved` feeds the demo's custom name registry |
116
- | **Rate limiting** | 60 reads/min, 10 writes/min per IP (in-memory, rightmost X-Forwarded-For) |
108
+ ```ts
109
+ import { quantizePixels, dominantColor } from "@mkbabb/value.js";
117
110
 
118
- ### Palette System Flow (Frontend + API)
111
+ const palette = quantizePixels(pixels, width, height, { k: 6 });
112
+ const dominant = dominantColor(pixels, width, height);
113
+ ```
119
114
 
120
- 1. **Save locally** (`PaletteForm` / `usePaletteStore`): stores palettes in browser storage (`color-palettes`) for instant local recall.
121
- 2. **Publish** (`PaletteDialog`): ensures a session (`POST /sessions`), then publishes via `POST /palettes` with `X-Session-Token`.
122
- 3. **Browse + vote** (`Browse` tab): fetches `GET /palettes` and toggles votes with `POST /palettes/:slug/vote` (server maintains atomic vote counts).
123
- 4. **Suggest color names** (`ColorInput` propose form): ensures session, then submits `POST /colors/propose` for moderation.
124
- 5. **Admin moderation** (`AdminPanel`): token login (`Authorization: Bearer ...`), queue from `GET /admin/queue`, actions for approve/reject + feature/delete.
115
+ See [`docs/colors/quantization.md`](docs/colors/quantization.md) for the full pipeline.
125
116
 
126
- ### Validation
117
+ ## Easing
127
118
 
128
- - **API smoke (live backend)**: session creation, publish/list/get, vote toggle, rename, propose, admin queue, approve, feature, delete.
129
- - **Playwright live integration**: [`e2e/palette-api-live.spec.ts`](e2e/palette-api-live.spec.ts) validates save/publish/vote/propose/admin end-to-end against a real API.
119
+ 30+ timing functions covering the CSS `<easing-function>` grammar plus bounce and back. `CSSCubicBezier` solves via Newton-Raphson with bisection fallback; `cssLinear()` implements CSS Easing Level 2 piecewise-linear with gap filling per spec; stepped easings support all four jump terms.
130
120
 
131
- ```bash
132
- # 1) Start API (example)
133
- MONGODB_URI=mongodb://127.0.0.1:27019/palette-e2e ADMIN_TOKEN=test-admin-token PORT=3100 npm --prefix api run dev
121
+ ## Transforms
134
122
 
135
- # 2) Run live frontend + backend integration
136
- PALETTE_API_E2E=1 VITE_API_URL=http://127.0.0.1:3100 npx playwright test e2e/palette-api-live.spec.ts --project=desktop
137
- ```
123
+ CSS `matrix()` and `matrix3d()` decomposition per the CSSOM View and CSS Transforms specs. 3D uses Gram-Schmidt orthogonalization + quaternion extraction. `slerp` for rotation interpolation. `interpolateDecomposed()` for full transform blending.
138
124
 
139
- ## Sources, acknowledgements, &c.
125
+ ## Sources, acknowledgements, & c.
140
126
 
141
127
  - Ottosson, B. (2020). [A perceptual color space for image processing](https://bottosson.github.io/posts/oklab/). — OKLab: the perceptual color space used for `color-mix()` and gamut mapping.
142
128
  - Ottosson, B. (2021). [sRGB gamut clipping](https://bottosson.github.io/posts/gamutclipping/). — Analytical gamut mapping algorithm (cubic boundary + Halley's method).
@@ -145,8 +131,4 @@ PALETTE_API_E2E=1 VITE_API_URL=http://127.0.0.1:3100 npx playwright test e2e/pal
145
131
  - Lindbloom, B. [XYZ to Correlated Color Temperature](http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_T.html). — CCT conversion reference.
146
132
  - [`@mkbabb/parse-that`](https://github.com/mkbabb/parse-that) — Parser combinators powering the CSS value grammar.
147
133
 
148
- See [`docs/color-theory.md`](docs/color-theory.md) for the full bibliography.
149
-
150
- ## License
151
-
152
- GPL-3.0-only
134
+ See [`docs/colors/theory.md`](docs/colors/theory.md) for the full bibliography.
package/dist/easing.d.ts CHANGED
@@ -1,3 +1,10 @@
1
+ /**
2
+ * A timing function (a.k.a. easing function): maps progress
3
+ * `t ∈ [0, 1]` to an eased output (typically `∈ [0, 1]`, but easings
4
+ * such as `bounceInEase` overshoot). Canonical home for the type
5
+ * (keyframes.js parallel-declares the same shape — keep parity here).
6
+ */
7
+ export type TimingFunction = (t: number) => number;
1
8
  export declare function linear(t: number): number;
2
9
  /**
3
10
  * CSS Easing Level 2 `linear()` — piecewise-linear timing function.
@@ -24,6 +31,11 @@ export declare function easeInCubic(t: number): number;
24
31
  export declare function easeOutCubic(t: number): number;
25
32
  export declare function easeInOutCubic(t: number): number;
26
33
  export declare function smoothStep3(t: number): number;
34
+ /**
35
+ * Solve X(t) = x for t using Newton-Raphson with bisection fallback.
36
+ * X(t) = 3(1-t)^2*t*x1 + 3(1-t)*t^2*x2 + t^3
37
+ */
38
+ export declare function solveCubicBezierX(x: number, x1: number, x2: number, epsilon?: number): number;
27
39
  export declare const CSSCubicBezier: (x1: number, y1: number, x2: number, y2: number) => (x: number) => number;
28
40
  export declare function easeInBounce(t: number): number;
29
41
  export declare function bounceInEase(t: number): number;
@@ -44,15 +56,52 @@ export declare const jumpTerms: readonly ["jump-start", "jump-end", "jump-none",
44
56
  export declare function steppedEase(steps: number, jumpTerm?: (typeof jumpTerms)[number]): (t: number) => number;
45
57
  export declare function stepStart(): (t: number) => number;
46
58
  export declare function stepEnd(): (t: number) => number;
59
+ /**
60
+ * Canonical cubic-bezier control-point tables for every CSS timing
61
+ * function expressible as a bezier curve. The CSS spec only defines the
62
+ * four "standard" keywords (ease, ease-in, ease-out, ease-in-out), but
63
+ * the sine/quad/cubic/expo/circ/back families used throughout the
64
+ * animation ecosystem have well-known bezier approximations — these are
65
+ * the values popularised by Robert Penner and shipped by libraries like
66
+ * GSAP, anime.js, and the Material Design curves.
67
+ *
68
+ * Keeping all of these in value.js means every consumer (keyframes.js,
69
+ * bbnf-buddy, future editors) can ask "is this name a bezier curve?"
70
+ * and "what are its control points?" from one source of truth, rather
71
+ * than hand-rolling parallel tables.
72
+ */
47
73
  export declare const bezierPresets: {
74
+ readonly linear: readonly [0, 0, 1, 1];
48
75
  readonly ease: readonly [0.25, 0.1, 0.25, 1];
49
76
  readonly "ease-in": readonly [0.42, 0, 1, 1];
50
77
  readonly "ease-out": readonly [0, 0, 0.58, 1];
51
78
  readonly "ease-in-out": readonly [0.42, 0, 0.58, 1];
79
+ readonly "ease-in-sine": readonly [0.47, 0, 0.745, 0.715];
80
+ readonly "ease-out-sine": readonly [0.39, 0.575, 0.565, 1];
81
+ readonly "ease-in-out-sine": readonly [0.445, 0.05, 0.55, 0.95];
82
+ readonly "ease-in-quad": readonly [0.55, 0.085, 0.68, 0.53];
83
+ readonly "ease-out-quad": readonly [0.25, 0.46, 0.45, 0.94];
84
+ readonly "ease-in-out-quad": readonly [0.455, 0.03, 0.515, 0.955];
85
+ readonly "ease-in-cubic": readonly [0.55, 0.055, 0.675, 0.19];
86
+ readonly "ease-out-cubic": readonly [0.215, 0.61, 0.355, 1];
87
+ readonly "ease-in-out-cubic": readonly [0.645, 0.045, 0.355, 1];
88
+ readonly "ease-in-expo": readonly [0.95, 0.05, 0.795, 0.035];
89
+ readonly "ease-out-expo": readonly [0.19, 1, 0.22, 1];
90
+ readonly "ease-in-out-expo": readonly [1, 0, 0, 1];
91
+ readonly "ease-in-circ": readonly [0.6, 0.04, 0.98, 0.335];
92
+ readonly "ease-out-circ": readonly [0.075, 0.82, 0.165, 1];
93
+ readonly "ease-in-out-circ": readonly [0.785, 0.135, 0.15, 0.86];
52
94
  readonly "ease-in-back": readonly [0.6, -0.28, 0.735, 0.045];
53
95
  readonly "ease-out-back": readonly [0.175, 0.885, 0.32, 1.275];
54
96
  readonly "ease-in-out-back": readonly [0.68, -0.55, 0.265, 1.55];
55
97
  };
98
+ /**
99
+ * Short human descriptions for every timing-function name value.js knows
100
+ * about — bezier presets, analytic functions, and step variants. Editors
101
+ * and demos can surface these as tooltip copy without hand-maintaining a
102
+ * parallel map.
103
+ */
104
+ export declare const timingFunctionDescriptions: Record<string, string>;
56
105
  export declare const timingFunctions: {
57
106
  readonly linear: typeof linear;
58
107
  readonly easeInQuad: typeof easeInQuad;
package/dist/index.d.ts CHANGED
@@ -1,29 +1,40 @@
1
1
  export { ValueUnit, FunctionValue, ValueArray } from './units';
2
2
  export type { InterpolatedVar } from './units';
3
- export { ABSOLUTE_LENGTH_UNITS, RELATIVE_LENGTH_UNITS, LENGTH_UNITS, TIME_UNITS, ANGLE_UNITS, PERCENTAGE_UNITS, FREQUENCY_UNITS, RESOLUTION_UNITS, FLEX_UNITS, COMPUTED_UNITS, STRING_UNITS, COLOR_UNITS, UNITS, BLACKLISTED_COALESCE_UNITS, STYLE_NAMES, } from './units/constants';
3
+ export { ABSOLUTE_LENGTH_UNITS, RELATIVE_LENGTH_UNITS, LENGTH_UNITS, TIME_UNITS, ANGLE_UNITS, PERCENTAGE_UNITS, FREQUENCY_UNITS, RESOLUTION_UNITS, FLEX_UNITS, COMPUTED_UNITS, UNITS, STYLE_NAMES, } from './units/constants';
4
4
  export type { MatrixValues } from './units/constants';
5
5
  export { isColorUnit, flattenObject, unflattenObject, unflattenObjectToString, isCSSStyleName, unpackMatrixValues, convertAbsoluteUnitToPixels, convertToPixels, convertToMs, convertToDegrees, convertToHz, convertToDPI, convert2, } from './units/utils';
6
6
  export { getComputedValue, normalizeNumericUnits, normalizeValueUnits, } from './units/normalize';
7
+ export type { NormalizeValueUnitsOptions } from './units/normalize';
8
+ export { lerpValue, lerpComputedValue, lerpColorValue, lerpNumericValue, prepareInterpVar, } from './units/interpolate';
7
9
  export { Color, RGBColor, HSLColor, HSVColor, HWBColor, LABColor, LCHColor, OKLABColor, OKLCHColor, XYZColor, KelvinColor, LinearSRGBColor, DisplayP3Color, AdobeRGBColor, ProPhotoRGBColor, Rec2020Color, } from './units/color';
8
10
  export type { ColorSpaceMap } from './units/color';
9
11
  export { RGBA_MAX, ALPHA_RANGE, RGB_RANGE, UNIT_RANGE, HUE_RANGE, COLOR_SPACE_RANGES, ALPHA_DENORM_UNIT, COLOR_SPACE_DENORM_UNITS, COLOR_SPACE_NAMES, WHITE_POINT_D65, WHITE_POINT_D50, WHITE_POINT_D65_D50, WHITE_POINT_D50_D65, WHITE_POINTS, XYZ_TO_LMS_MATRIX, LMS_TO_XYZ_MATRIX, LMS_TO_OKLAB_MATRIX, OKLAB_TO_LMS_MATRIX, LMS_TO_LINEAR_SRGB, LINEAR_SRGB_TO_LMS, OKLAB_TO_LMS_COEFF, GAMUT_SECTOR_COEFFICIENTS, COLOR_NAMES, } from './units/color/constants';
10
12
  export type { ColorSpace, WhitePoint } from './units/color/constants';
11
13
  export { transformMat3, transposeMat3, multiplyMat3, invertMat3, } from './units/color/matrix';
12
14
  export type { Vec3, Mat3 } from './units/color/matrix';
13
- export { getFormattedColorSpaceRange, hex2rgb, rgb2hex, kelvin2rgb, rgb2kelvin, hsv2hsl, hsl2hsv, hwb2hsl, hsl2hwb, rgb2hsl, hsl2rgb, xyz2lab, lab2xyz, srgbToLinear, linearToSrgb, rgb2xyz, xyz2rgb, lch2lab, lab2lch, oklab2xyz, xyz2oklab, oklab2lab, lab2oklab, oklab2oklch, oklch2oklab, oklch2lab, lab2oklch, hsl2xyz, xyz2hsl, hsv2xyz, xyz2hsv, hwb2xyz, xyz2hwb, lch2xyz, xyz2lch, oklch2xyz, xyz2oklch, kelvin2xyz, xyz2kelvin, adobeRgbToLinear, linearToAdobeRgb, proPhotoToLinear, linearToProPhoto, rec2020ToLinear, linearToRec2020, linearSrgb2xyz, xyz2linearSrgb, displayP32xyz, xyz2displayP3, adobeRgb2xyz, xyz2adobeRgb, proPhoto2xyz, xyz2proPhoto, rec20202xyz, xyz2rec2020, color2, gamutMap, interpolateHue, mixColors, CYLINDRICAL_HUE_COMPONENT, } from './units/color/utils';
14
- export type { HueInterpolationMethod } from './units/color/utils';
15
+ export { getFormattedColorSpaceRange, color2, gamutMap, interpolateHue, mixColors, CYLINDRICAL_HUE_COMPONENT, computeSafeAccent, safeAccentColor, needsContrastAdjustment, getOklchLightness, } from './units/color/dispatch';
16
+ export type { HueInterpolationMethod } from './units/color/dispatch';
17
+ export { mixColorsN } from './units/color/mix';
15
18
  export { normalizeColorUnitComponent, normalizeColor, normalizeColorUnit, colorUnit2, normalizeColorUnits, } from './units/color/normalize';
16
- export { DELTA_E_OK_JND, deltaEOK, oklabToLinearSRGB, isInSRGBGamut, computeMaxSaturation, findCusp, findGamutIntersection, gamutMapOKLab, srgbToOKLab, gamutMapSRGB, } from './units/color/gamut';
19
+ export { DELTA_E_OK_JND, deltaEOK, oklabToLinearSRGB, isInSRGBGamut, computeMaxSaturation, findCusp, findGamutIntersection, gamutMapOKLab, srgbToOKLab, gamutMapSRGB, rawOklabToOklch, rawOklchToOklab, oklabToRgb255, } from './units/color/gamut';
17
20
  export { clamp, scale, lerp, logerp, deCasteljau, cubicBezier, interpBezier, cubicBezierToSVG, cubicBezierToString, } from './math';
18
21
  export { FRAME_RATE, isObject, clone, arrayEquals, sleep, waitUntil, debounce, createHash, memoize, hyphenToCamelCase, camelCaseToHyphen, seekPreviousValue, requestAnimationFrame, cancelAnimationFrame, } from './utils';
19
22
  export type { MemoizeOptions } from './utils';
20
23
  export { rgb2ColorFilter, cssFiltersToString } from './units/color/colorFilter';
21
- export { linear, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, smoothStep3, CSSCubicBezier, easeInBounce, bounceInEase, bounceInEaseHalf, bounceOutEase, bounceOutEaseHalf, bounceInOutEase, easeInSine, easeOutSine, easeInOutSine, easeInCirc, easeOutCirc, easeInOutCirc, easeInExpo, easeOutExpo, easeInOutExpo, jumpTerms, steppedEase, stepStart, stepEnd, cssLinear, bezierPresets, timingFunctions, } from './easing';
22
- export type { LinearStop } from './easing';
24
+ export { linear, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, smoothStep3, CSSCubicBezier, solveCubicBezierX, easeInBounce, bounceInEase, bounceInEaseHalf, bounceOutEase, bounceOutEaseHalf, bounceInOutEase, easeInSine, easeOutSine, easeInOutSine, easeInCirc, easeOutCirc, easeInOutCirc, easeInExpo, easeOutExpo, easeInOutExpo, jumpTerms, steppedEase, stepStart, stepEnd, cssLinear, bezierPresets, timingFunctions, timingFunctionDescriptions, } from './easing';
25
+ export type { LinearStop, TimingFunction } from './easing';
23
26
  export { CSS_WIDE_KEYWORDS, CSSString, CSSFunction, CSSJSON, CSSValues, parseCSSValue, parseCSSPercent, parseCSSTime, } from './parsing';
24
- export { CSSValueUnit, parseCSSValueUnit } from './parsing/units';
27
+ export { parseCSSStylesheet } from './parsing/stylesheet';
28
+ export type { Stylesheet, StylesheetItem, KeyframeRule, KeyframeSelector, Declaration, PropertyDescriptor, } from './parsing/stylesheet';
29
+ export { extractKeyframes, extractProperties, extractStyleRules, extractAnimationOptions, } from './parsing/extract';
30
+ export type { CSSAnimationOptions } from './parsing/extract';
31
+ export { parseAnimationShorthand, reverseAnimationShorthand, } from './parsing/animation-shorthand';
32
+ export { serializeStylesheet, serializeStylesheetItem, serializeDeclaration, serializeKeyframeSelector, formatCSS, stylesheetToString, } from './parsing/serialize';
33
+ export { CSSValueUnit, parseCSSValueUnit, reverseCSSTime, reverseCSSIterationCount, } from './parsing/units';
25
34
  export { evaluateMathFunction } from './parsing/math';
26
- export { CSSColor, parseCSSColor } from './parsing/color';
35
+ export { CSSColor, parseCSSColor, registerColorNames, clearCustomColorNames, getCustomColorNames, } from './parsing/color';
27
36
  export { istring, identifier, none, integer, number, succeed, fail, tryParse, parseResult, } from './parsing/utils';
37
+ export { quantizePixels, dominantColor } from './quantize';
38
+ export type { QuantizeOptions, QuantizedColor } from './quantize';
28
39
  export { decomposeMatrix2D, decomposeMatrix3D, recomposeMatrix3D, slerp, interpolateDecomposed, } from './transform/decompose';
29
40
  export type { DecomposedMatrix2D, DecomposedMatrix3D, Vec4, Mat4, } from './transform/decompose';
package/dist/math.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export declare function clamp(value: number, min: number, max: number): number;
2
2
  export declare function scale(value: number, fromMin: number, fromMax: number, toMin?: number, toMax?: number): number;
3
- export declare function lerp(t: number, start: number, end: number): number;
3
+ export declare function lerp(start: number, end: number, t: number): number;
4
4
  export declare function logerp(t: number, start: number, end: number): number;
5
5
  export declare function deCasteljau(t: number, points: number[]): number;
6
6
  export declare function cubicBezier(t: number, x1: number, y1: number, x2: number, y2: number): number[];
@@ -0,0 +1,19 @@
1
+ import { CSSAnimationOptions } from './extract';
2
+ /**
3
+ * Parse the value of an `animation` shorthand declaration into one
4
+ * options object per comma-segment.
5
+ *
6
+ * Per CSS Animations spec, `animation: 1s ease-in, 500ms linear`
7
+ * declares two animations. This function returns both; callers that
8
+ * only support a single animation should take `[0]`.
9
+ */
10
+ export declare const parseAnimationShorthand: import('../utils').Memoized<(input: string) => CSSAnimationOptions[]>;
11
+ /**
12
+ * Reverse: emit a single `animation` shorthand string from an options
13
+ * object. Always emits in canonical order:
14
+ * `<duration> <timing-function> <delay> <iteration-count>
15
+ * <direction> <fill-mode> <composition> <name>`.
16
+ *
17
+ * Fields that are unset are omitted entirely (no `0s` placeholders).
18
+ */
19
+ export declare const reverseAnimationShorthand: (opts: CSSAnimationOptions) => string;
@@ -13,8 +13,8 @@ type ComponentExpr = {
13
13
  type: "none";
14
14
  };
15
15
  export declare const CSSColor: {
16
- Value: Parser<ValueUnit<any, string | undefined>>;
17
- colorValue: Parser<ValueUnit<any, string | undefined>>;
16
+ Value: Parser<ValueUnit<any, string>>;
17
+ colorValue: Parser<ValueUnit<any, string>>;
18
18
  componentExpr: Parser<ComponentExpr>;
19
19
  sep: Parser<string>;
20
20
  alphaSep: Parser<string>;
@@ -23,5 +23,12 @@ export declare const CSSColor: {
23
23
  export declare function registerColorNames(names: Record<string, string>): void;
24
24
  export declare function clearCustomColorNames(): void;
25
25
  export declare function getCustomColorNames(): ReadonlyMap<string, string>;
26
- export declare function parseCSSColor(input: string): ValueUnit;
26
+ /**
27
+ * Parse a CSS color string into a `ValueUnit<Color>`. Memoised — the returned
28
+ * ValueUnit is shared across callers, so callers MUST NOT mutate it. Clone
29
+ * before mutating if a per-call instance is needed.
30
+ *
31
+ * The cache is invalidated by `registerColorNames` and `clearCustomColorNames`.
32
+ */
33
+ export declare const parseCSSColor: import('../utils').Memoized<(input: string) => ValueUnit>;
27
34
  export {};
@@ -0,0 +1,48 @@
1
+ import { Declaration, KeyframeRule, PropertyDescriptor, Stylesheet } from './stylesheet';
2
+ /**
3
+ * Animation options as expressed in CSS — a CSS-spec subset shared by
4
+ * `animation` shorthand and the individual `animation-*` longhand
5
+ * properties. Renderer-specific options (WAAPI, color space, hue
6
+ * method) are not represented here; consumers extend this type.
7
+ */
8
+ export type CSSAnimationOptions = {
9
+ name?: string;
10
+ duration?: number;
11
+ delay?: number;
12
+ iterationCount?: number;
13
+ direction?: "normal" | "reverse" | "alternate" | "alternate-reverse";
14
+ fillMode?: "none" | "forwards" | "backwards" | "both";
15
+ timingFunction?: string;
16
+ composition?: "replace" | "add" | "accumulate";
17
+ };
18
+ /**
19
+ * Group every `@keyframes` block in the stylesheet by name. Unnamed
20
+ * blocks are keyed by the empty string. When two `@keyframes` rules
21
+ * share a name, their rule lists are concatenated (CSS cascade order).
22
+ */
23
+ export declare const extractKeyframes: (s: Stylesheet) => Map<string, KeyframeRule[]>;
24
+ /**
25
+ * Index every `@property` registration by its custom property name.
26
+ * Later registrations override earlier ones.
27
+ */
28
+ export declare const extractProperties: (s: Stylesheet) => Map<string, PropertyDescriptor>;
29
+ /** Return every top-level qualified rule (`.foo { ... }`). */
30
+ export declare const extractStyleRules: (s: Stylesheet) => {
31
+ selectors: string[];
32
+ declarations: Declaration[];
33
+ }[];
34
+ /**
35
+ * Walk the stylesheet's top-level style rules and merge every
36
+ * recognised `animation-*` longhand into a single options object.
37
+ *
38
+ * Shorthand `animation: ...` is handled by `parseAnimationShorthand`
39
+ * (a separate entry) — we don't re-tokenise it here. If a style rule
40
+ * has both shorthand and longhand declarations, the consumer is
41
+ * expected to call `parseAnimationShorthand` itself and merge.
42
+ *
43
+ * Longhand declarations later in the stylesheet override earlier ones
44
+ * (CSS cascade). Cross-rule merging is intentional — most stylesheets
45
+ * keep all `animation-*` for one animation in a single rule, but the
46
+ * extractor stays robust either way.
47
+ */
48
+ export declare const extractAnimationOptions: (s: Stylesheet) => CSSAnimationOptions;
@@ -1,32 +1,17 @@
1
1
  import { Parser } from '@mkbabb/parse-that';
2
2
  import { FunctionValue, ValueArray, ValueUnit } from '../units';
3
3
  export declare const CSS_WIDE_KEYWORDS: readonly ["inherit", "initial", "unset", "revert", "revert-layer"];
4
- export declare const CSSString: Parser<ValueUnit<string, string | undefined>>;
4
+ export declare const CSSString: Parser<ValueUnit<string, string>>;
5
5
  export declare const CSSFunction: {
6
6
  Function: Parser<any>;
7
7
  Value: Parser<any>;
8
8
  FunctionArgs: Parser<ValueArray<any>>;
9
9
  };
10
- export declare const CSSJSON: Parser<ValueUnit<any, string>>;
10
+ export declare const CSSJSON: Parser<ValueUnit<any, "json">>;
11
11
  export declare const CSSValues: {
12
12
  Value: Parser<any>;
13
13
  Values: Parser<any[]>;
14
14
  };
15
- export declare const parseCSSValue: ((input: string) => ValueUnit | FunctionValue) & {
16
- cache: Map<string, {
17
- value: ValueUnit<any, string | undefined> | FunctionValue<any, string>;
18
- timestamp: number;
19
- }>;
20
- };
21
- export declare const parseCSSPercent: ((input: string | number) => number) & {
22
- cache: Map<string, {
23
- value: number;
24
- timestamp: number;
25
- }>;
26
- };
27
- export declare const parseCSSTime: ((input: string) => number) & {
28
- cache: Map<string, {
29
- value: number;
30
- timestamp: number;
31
- }>;
32
- };
15
+ export declare const parseCSSValue: import('../utils').Memoized<(input: string) => ValueUnit | FunctionValue>;
16
+ export declare const parseCSSPercent: import('../utils').Memoized<(input: string | number) => number>;
17
+ export declare const parseCSSTime: import('../utils').Memoized<(input: string) => number>;
@@ -0,0 +1,24 @@
1
+ import { Declaration, KeyframeSelector, Stylesheet, StylesheetItem } from './stylesheet';
2
+ export declare const serializeKeyframeSelector: (s: KeyframeSelector) => string;
3
+ export declare const serializeDeclaration: (d: Declaration) => string;
4
+ export declare const serializeStylesheetItem: (item: StylesheetItem) => string;
5
+ /**
6
+ * Emit a `Stylesheet` AST as a CSS string. Items are separated by a
7
+ * single blank line. The output is structurally equivalent to the
8
+ * input (modulo whitespace) when round-tripped through
9
+ * `parseCSSStylesheet`.
10
+ */
11
+ export declare const serializeStylesheet: (s: Stylesheet) => string;
12
+ /**
13
+ * Format a CSS string via Prettier's PostCSS parser. Prettier and its
14
+ * PostCSS plugin are loaded lazily via dynamic `import()` — calling
15
+ * code that never invokes `formatCSS` doesn't pay the bundle cost.
16
+ *
17
+ * Use this for human-readable output (editors, file dumps). Programs
18
+ * that read the AST directly should not need it.
19
+ */
20
+ export declare function formatCSS(css: string, printWidth?: number): Promise<string>;
21
+ /**
22
+ * Convenience: serialise + format in one call.
23
+ */
24
+ export declare function stylesheetToString(s: Stylesheet, printWidth?: number): Promise<string>;
@@ -0,0 +1,44 @@
1
+ import { ValueArray } from '../units';
2
+ export type Declaration = {
3
+ name: string;
4
+ value: ValueArray;
5
+ important: boolean;
6
+ };
7
+ export type KeyframeSelector = {
8
+ kind: "percent";
9
+ value: number;
10
+ } | {
11
+ kind: "named";
12
+ name: "entry" | "exit" | "cover" | "contain";
13
+ };
14
+ export type KeyframeRule = {
15
+ selectors: KeyframeSelector[];
16
+ declarations: Declaration[];
17
+ timingFunction?: string;
18
+ composition?: "replace" | "add" | "accumulate";
19
+ };
20
+ export type PropertyDescriptor = {
21
+ syntax?: string;
22
+ inherits?: boolean;
23
+ initialValue?: ValueArray;
24
+ };
25
+ export type StylesheetItem = {
26
+ kind: "keyframes";
27
+ name?: string;
28
+ rules: KeyframeRule[];
29
+ } | {
30
+ kind: "property";
31
+ name: string;
32
+ descriptor: PropertyDescriptor;
33
+ } | {
34
+ kind: "style";
35
+ selectors: string[];
36
+ declarations: Declaration[];
37
+ } | {
38
+ kind: "unknown";
39
+ atName: string;
40
+ prelude: string;
41
+ body: string | null;
42
+ };
43
+ export type Stylesheet = StylesheetItem[];
44
+ export declare const parseCSSStylesheet: import('../utils').Memoized<(input: string) => Stylesheet>;
@@ -6,14 +6,32 @@ export declare const CSSValueUnit: {
6
6
  Length: Parser<ValueUnit<number, string>>;
7
7
  Angle: Parser<ValueUnit<number, string>>;
8
8
  Time: Parser<ValueUnit<number, string>>;
9
- TimePercentage: Parser<ValueUnit<any, string | undefined>>;
9
+ TimePercentage: Parser<ValueUnit<any, string>>;
10
10
  Frequency: Parser<ValueUnit<number, string>>;
11
11
  Resolution: Parser<ValueUnit<number, string>>;
12
12
  Flex: Parser<ValueUnit<number, string>>;
13
- Percentage: Parser<ValueUnit<any, string | undefined>>;
14
- Color: Parser<ValueUnit<any, string | undefined>>;
15
- Slash: Parser<ValueUnit<string, string>>;
16
- Value: Parser<ValueUnit<any, string | undefined>>;
13
+ Percentage: Parser<ValueUnit<any, string>>;
14
+ Color: Parser<ValueUnit<any, string>>;
15
+ Slash: Parser<ValueUnit<string, "string">>;
16
+ Value: Parser<ValueUnit<any, string>>;
17
17
  sep: Parser<string>;
18
18
  };
19
- export declare function parseCSSValueUnit(input: string): ValueUnit;
19
+ /**
20
+ * Parse a CSS dimension/value string into a `ValueUnit`. Memoised — the
21
+ * returned `ValueUnit` is shared across callers, so callers MUST NOT mutate it.
22
+ * Mirrors the memo contract of the sibling `parseCSSValue`/`parseCSSColor`.
23
+ */
24
+ export declare const parseCSSValueUnit: import('../utils').Memoized<(input: string) => ValueUnit>;
25
+ /**
26
+ * Format a millisecond duration as a CSS time string. Emits `<n>s`
27
+ * for durations ≥ 5 s (where seconds become more readable than
28
+ * milliseconds); otherwise `<n>ms`. Threshold matches the historical
29
+ * keyframes.js convention so round-trips don't drift.
30
+ */
31
+ export declare function reverseCSSTime(time: number): string;
32
+ /**
33
+ * Format an iteration count for the `animation-iteration-count`
34
+ * property. `Infinity` becomes the keyword `infinite`; finite values
35
+ * render as their decimal representation.
36
+ */
37
+ export declare function reverseCSSIterationCount(count: number): string;
@@ -12,6 +12,11 @@ export declare function fail(message: string): Parser<never>;
12
12
  /**
13
13
  * Try to parse; return the result or throw on failure.
14
14
  * Equivalent to Parsimmon's `.tryParse()`.
15
+ *
16
+ * The thrown error includes a 16-char context window (8 before / 8 after
17
+ * the failure offset) so callers — particularly the demo's color-picker
18
+ * error toasts — can pinpoint where the parse derailed. (E.W1 Lane D /
19
+ * E-AUDIT-5 §9 item 11.)
15
20
  */
16
21
  export declare function tryParse<T>(parser: Parser<T>, input: string): T;
17
22
  /**