@weasel-js/paint 1.6.1 → 1.7.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/README.md +35 -0
- package/dist/index.d.ts +42 -5
- package/dist/index.js +27 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,3 +21,38 @@ import type { FillStyle, Stroke } from '@weasel-js/paint';
|
|
|
21
21
|
const fill: FillStyle = { color: '#c0ffee' };
|
|
22
22
|
const stroke: Stroke = { paint: { color: '#000' }, width: 2, join: 'round' };
|
|
23
23
|
```
|
|
24
|
+
|
|
25
|
+
## Stroke markers
|
|
26
|
+
|
|
27
|
+
Arrowheads and other line terminators are stroke style — `markerStart`,
|
|
28
|
+
`markerMid` and `markerEnd` on `Stroke`, beside `cap` and `dash`, as SVG has
|
|
29
|
+
them. They are not a `@weasel-js/diagram` feature because `@weasel-js/svg` has
|
|
30
|
+
to round-trip them: living in diagram would either make svg depend on diagram
|
|
31
|
+
or lose every diagram edge's head on export.
|
|
32
|
+
|
|
33
|
+
A stroke names a marker by key — a built-in such as `'arrow'`, or an entry
|
|
34
|
+
registered with `registerMarker` from `@weasel-js/core` — and may give it a
|
|
35
|
+
size:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const edge: Stroke = { paint: { color: '#000' }, width: 2, markerEnd: 'arrow' };
|
|
39
|
+
const pinned: Stroke = { ...edge, markerEnd: { key: 'arrow', size: { px: 6 } } };
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
An entry's geometry, outline width and inset are all in **marker units**. One
|
|
43
|
+
unit is the resolved stroke width, so one entry is right at any line weight.
|
|
44
|
+
A `size` replaces the stroke width rather than multiplying it: a number is
|
|
45
|
+
world units, and `{ px }` is screen pixels resolved against the view scale at
|
|
46
|
+
draw time, as a `{ px }` stroke width is.
|
|
47
|
+
|
|
48
|
+
### The line stops short of the head
|
|
49
|
+
|
|
50
|
+
This is where the kit departs from SVG on purpose. SVG paints a marker over a
|
|
51
|
+
line that still runs to its endpoint, so a hollow, translucent or narrow head
|
|
52
|
+
is speared by its own line, and the usual fix — nudging `refX` — moves the tip
|
|
53
|
+
off the thing it points at. Here each entry declares an `inset`, in marker
|
|
54
|
+
units, and the stroke stops that far short of each open end while the head
|
|
55
|
+
stays on the authored endpoint. It belongs to the shape, not the stroke: a
|
|
56
|
+
filled triangle needs its full length or the line shows through, and an open
|
|
57
|
+
V needs 0 or its arms stop meeting the line. `markerMid` never trims, and the
|
|
58
|
+
trim happens before dashing so the pattern fits the visible line.
|
package/dist/index.d.ts
CHANGED
|
@@ -115,6 +115,34 @@ type Rgb = readonly [number, number, number];
|
|
|
115
115
|
*/
|
|
116
116
|
declare function interpolateSrgb(from: Rgb, to: Rgb, t: number, space?: ColorInterpolationSpace, hue?: HueInterpolation): [number, number, number];
|
|
117
117
|
|
|
118
|
+
/**
|
|
119
|
+
* A pattern tile's linear map into paint space: `[a, b, c, d]`, the first
|
|
120
|
+
* four entries of SVG's `matrix(a b c d e f)`. A tile point `(u, v)` lands at
|
|
121
|
+
* `origin + (a·u + c·v, b·u + d·v)`. Translation is the paint's `origin`, so
|
|
122
|
+
* it has no slot here.
|
|
123
|
+
*/
|
|
124
|
+
type PatternTransform = readonly [a: number, b: number, c: number, d: number];
|
|
125
|
+
/**
|
|
126
|
+
* A {@link PatternTransform} as the parts an editor shows. Angles are radians.
|
|
127
|
+
* Applied in the order scale, then skew, then rotation — rotation outermost,
|
|
128
|
+
* so turning a skewed tile turns it whole.
|
|
129
|
+
*/
|
|
130
|
+
interface PatternTransformParts {
|
|
131
|
+
rotation: number;
|
|
132
|
+
scaleX: number;
|
|
133
|
+
scaleY: number;
|
|
134
|
+
/** Shear of the tile's y axis toward x, as SVG `skewX()`. */
|
|
135
|
+
skewX: number;
|
|
136
|
+
}
|
|
137
|
+
/** `R(rotation) · K(skewX) · S(scaleX, scaleY)`. Omitted parts are identity. */
|
|
138
|
+
declare function composePatternTransform(parts: Partial<PatternTransformParts>): PatternTransform;
|
|
139
|
+
/**
|
|
140
|
+
* Inverse of {@link composePatternTransform}. Any 2×2 matrix decomposes this
|
|
141
|
+
* way; a reflection comes back as a negative `scaleY`. `undefined` reads as the
|
|
142
|
+
* identity, which is what an absent `transform` means.
|
|
143
|
+
*/
|
|
144
|
+
declare function decomposePatternTransform(t: PatternTransform | undefined): PatternTransformParts;
|
|
145
|
+
|
|
118
146
|
/**
|
|
119
147
|
* FillStyle and Stroke types — the unified shape for "what color or texture
|
|
120
148
|
* paints these pixels," modeled on SVG's paint-server concept.
|
|
@@ -157,6 +185,9 @@ declare function interpolateSrgb(from: Rgb, to: Rgb, t: number, space?: ColorInt
|
|
|
157
185
|
* node and a resize reveals more tiles rather than stretching them;
|
|
158
186
|
* `fillInPoseFrame` resolves that to a `'local'` paint with an explicit
|
|
159
187
|
* `origin` before the renderer sees it.
|
|
188
|
+
*
|
|
189
|
+
* `transform` on a pattern rotates, scales or skews the tile about `origin`
|
|
190
|
+
* (SVG's `patternTransform`, less its translation). See `PatternTransform`.
|
|
160
191
|
*/
|
|
161
192
|
type FillStyle = {
|
|
162
193
|
fill?: 'solid';
|
|
@@ -170,6 +201,7 @@ type FillStyle = {
|
|
|
170
201
|
x: number;
|
|
171
202
|
y: number;
|
|
172
203
|
};
|
|
204
|
+
transform?: PatternTransform;
|
|
173
205
|
opacity?: number;
|
|
174
206
|
} | {
|
|
175
207
|
fill: 'linear-gradient';
|
|
@@ -288,14 +320,16 @@ type StrokeAlign = 'center' | 'inner' | 'outer';
|
|
|
288
320
|
* `PaintKind` is so a consumer's registered key typechecks.
|
|
289
321
|
*/
|
|
290
322
|
type KitMarkerKey = 'arrow' | 'arrow-open' | 'arrow-concave' | 'diamond' | 'diamond-hollow' | 'circle' | 'square' | 'bar';
|
|
323
|
+
/** A marker shape's key: a built-in {@link KitMarkerKey} or a consumer-registered name. */
|
|
291
324
|
type MarkerKey = KitMarkerKey | (string & {});
|
|
292
325
|
/**
|
|
293
326
|
* A marker on one end (or every interior vertex) of a stroke.
|
|
294
327
|
*
|
|
295
|
-
* `size`
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
328
|
+
* `size` is the length of one marker unit, and replaces the stroke width
|
|
329
|
+
* rather than multiplying it: a bare number is world units, however wide the
|
|
330
|
+
* line. Omitted, one unit is the resolved stroke width — SVG's
|
|
331
|
+
* `markerUnits="strokeWidth"`; given, it is `userSpaceOnUse`. A `{ px }` size
|
|
332
|
+
* holds its screen size through a zoom, as a `{ px }` stroke width does.
|
|
299
333
|
*/
|
|
300
334
|
type MarkerRef = MarkerKey | {
|
|
301
335
|
key: MarkerKey;
|
|
@@ -483,11 +517,13 @@ interface ColorFnContext {
|
|
|
483
517
|
}
|
|
484
518
|
/** A color computed at resolve time — typically derived from another entry. */
|
|
485
519
|
type ColorFn = (ctx: ColorFnContext) => ColorSource | null | undefined;
|
|
520
|
+
/** Anything that resolves to a color: a literal, a named reference, or a function computing one. */
|
|
486
521
|
type ColorSource = ColorLiteral | ColorRef | ColorFn;
|
|
487
522
|
/** A sequence of colors, read lazily, so it may be endless. A factory rather
|
|
488
523
|
* than an iterable because a generator object can be iterated only once:
|
|
489
524
|
* pass the `function*` itself. */
|
|
490
525
|
type ColorSeqFn = (ctx: ColorFnContext) => Iterable<ColorSource>;
|
|
526
|
+
/** A named palette slot holding either one color (`color`) or a sequence (`colors`) that refs index into. */
|
|
491
527
|
type PaletteEntry = {
|
|
492
528
|
readonly name: string;
|
|
493
529
|
readonly color: ColorSource;
|
|
@@ -495,6 +531,7 @@ type PaletteEntry = {
|
|
|
495
531
|
readonly name: string;
|
|
496
532
|
readonly colors: ColorSeqFn;
|
|
497
533
|
};
|
|
534
|
+
/** A set of named colors that {@link ColorRef}s resolve against. When two entries share a name, the first wins. */
|
|
498
535
|
interface Palette {
|
|
499
536
|
readonly entries: readonly PaletteEntry[];
|
|
500
537
|
}
|
|
@@ -519,4 +556,4 @@ declare function colorLiteralToHex(color: ColorLiteral): string | null;
|
|
|
519
556
|
/** `#rrggbb` or `#rrggbbaa` as an `srgb` literal; `null` for anything else. */
|
|
520
557
|
declare function hexToColorLiteral(hex: string): ColorLiteral | null;
|
|
521
558
|
|
|
522
|
-
export { type ColorFn, type ColorFnContext, type ColorInterpolationSpace, type ColorLiteral, type ColorRef, type ColorSeqFn, type ColorSource, type ColorSpace, type ExternalColors, type FillStyle, type GradStop, type GradientFill, type GradientKind, type GradientUnits, type HueInterpolation, type KitMarkerKey, type MarkerKey, type MarkerRef, type OklchDeg, type Palette, type PaletteEntry, type Region, STROKE_DASH_RATIOS, type ScreenLength, type Stroke, type StrokeAlign, type StrokeDashStyle, type TextureHandle, type TilePatternSpec, alignedStrokeRect, colorLiteralToHex, contrastLineColor, dashForStrokeStyle, hexToColorLiteral, hexToOklchDeg, hslToSrgb, interpolateSrgb, lerpColorArray, lerpOklab, lerpOklch, linearSrgbToOklab, linearToSrgb, mixOklab, oklabToLinearSrgb, oklabToOklch, oklabToSrgbU8, oklchDegToHex, oklchToOklab, resolvePaletteColor, resolvePaletteColors, resolveScreenLength, srgbFloatToOklab, srgbToHsl, srgbToLinear, srgbU8ToOklab, strokeDashStyleOf };
|
|
559
|
+
export { type ColorFn, type ColorFnContext, type ColorInterpolationSpace, type ColorLiteral, type ColorRef, type ColorSeqFn, type ColorSource, type ColorSpace, type ExternalColors, type FillStyle, type GradStop, type GradientFill, type GradientKind, type GradientUnits, type HueInterpolation, type KitMarkerKey, type MarkerKey, type MarkerRef, type OklchDeg, type Palette, type PaletteEntry, type PatternTransform, type PatternTransformParts, type Region, STROKE_DASH_RATIOS, type ScreenLength, type Stroke, type StrokeAlign, type StrokeDashStyle, type TextureHandle, type TilePatternSpec, alignedStrokeRect, colorLiteralToHex, composePatternTransform, contrastLineColor, dashForStrokeStyle, decomposePatternTransform, hexToColorLiteral, hexToOklchDeg, hslToSrgb, interpolateSrgb, lerpColorArray, lerpOklab, lerpOklch, linearSrgbToOklab, linearToSrgb, mixOklab, oklabToLinearSrgb, oklabToOklch, oklabToSrgbU8, oklchDegToHex, oklchToOklab, resolvePaletteColor, resolvePaletteColors, resolveScreenLength, srgbFloatToOklab, srgbToHsl, srgbToLinear, srgbU8ToOklab, strokeDashStyleOf };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
// src/patternTransform.ts
|
|
2
|
+
function composePatternTransform(parts) {
|
|
3
|
+
const { rotation = 0, scaleX = 1, scaleY = 1, skewX = 0 } = parts;
|
|
4
|
+
const cos = Math.cos(rotation);
|
|
5
|
+
const sin = Math.sin(rotation);
|
|
6
|
+
const shear = Math.tan(skewX) * scaleY;
|
|
7
|
+
return [
|
|
8
|
+
cos * scaleX,
|
|
9
|
+
sin * scaleX,
|
|
10
|
+
cos * shear - sin * scaleY,
|
|
11
|
+
sin * shear + cos * scaleY
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
function decomposePatternTransform(t) {
|
|
15
|
+
if (!t) return { rotation: 0, scaleX: 1, scaleY: 1, skewX: 0 };
|
|
16
|
+
const [a, b, c, d] = t;
|
|
17
|
+
const scaleX = Math.hypot(a, b);
|
|
18
|
+
const rotation = scaleX === 0 ? 0 : Math.atan2(b, a);
|
|
19
|
+
const cos = Math.cos(rotation);
|
|
20
|
+
const sin = Math.sin(rotation);
|
|
21
|
+
const shear = c * cos + d * sin;
|
|
22
|
+
const scaleY = d * cos - c * sin;
|
|
23
|
+
const skewX = scaleY === 0 ? 0 : Math.atan(shear / scaleY);
|
|
24
|
+
return { rotation, scaleX, scaleY, skewX };
|
|
25
|
+
}
|
|
26
|
+
|
|
1
27
|
// src/paint.ts
|
|
2
28
|
function resolveScreenLength(value, scale) {
|
|
3
29
|
if (typeof value === "number") return value;
|
|
@@ -395,6 +421,6 @@ function hexToColorLiteral(hex) {
|
|
|
395
421
|
return hex.length === 9 ? { space: "srgb", coords, alpha: byte(7) } : { space: "srgb", coords };
|
|
396
422
|
}
|
|
397
423
|
|
|
398
|
-
export { STROKE_DASH_RATIOS, alignedStrokeRect, colorLiteralToHex, contrastLineColor, dashForStrokeStyle, hexToColorLiteral, hexToOklchDeg, hslToSrgb, interpolateSrgb, lerpColorArray, lerpOklab, lerpOklch, linearSrgbToOklab, linearToSrgb, mixOklab, oklabToLinearSrgb, oklabToOklch, oklabToSrgbU8, oklchDegToHex, oklchToOklab, resolvePaletteColor, resolvePaletteColors, resolveScreenLength, srgbFloatToOklab, srgbToHsl, srgbToLinear, srgbU8ToOklab, strokeDashStyleOf };
|
|
424
|
+
export { STROKE_DASH_RATIOS, alignedStrokeRect, colorLiteralToHex, composePatternTransform, contrastLineColor, dashForStrokeStyle, decomposePatternTransform, hexToColorLiteral, hexToOklchDeg, hslToSrgb, interpolateSrgb, lerpColorArray, lerpOklab, lerpOklch, linearSrgbToOklab, linearToSrgb, mixOklab, oklabToLinearSrgb, oklabToOklch, oklabToSrgbU8, oklchDegToHex, oklchToOklab, resolvePaletteColor, resolvePaletteColors, resolveScreenLength, srgbFloatToOklab, srgbToHsl, srgbToLinear, srgbU8ToOklab, strokeDashStyleOf };
|
|
399
425
|
//# sourceMappingURL=index.js.map
|
|
400
426
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/paint.ts","../src/colorSpaces.ts","../src/contrast.ts","../src/palette.ts"],"names":["L","C","h","s","l","hex2"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * FillStyle and Stroke types — the unified shape for \"what color or texture\n * paints these pixels,\" modeled on SVG's paint-server concept.\n *\n * - `FillStyle` is a tagged union: solid color, pattern, or gradient. Used\n * wherever a kit option previously took `fillStyle: string`.\n * - `Stroke` pairs a `FillStyle` with structural stroke parameters (width, dash,\n * line cap/join, alignment).\n * - These types are consumed by the GL renderer's DrawCommand path fills\n * and strokes.\n *\n * The 2D `applyPaint` / `applyStroke` / `renderFilledRegion` helpers that\n * formerly lived alongside these types were deleted with the 2D backend in\n * Step 10. `alignedStrokeRect` survives as a pure geometry helper used by\n * path tessellation and the selection overlay.\n */\n\nimport type { TextureHandle } from './texture';\nimport type { ColorSpace } from './colorSpaces';\n\n/**\n * Color/texture strategy for fills (and, via `Stroke.paint`, strokes).\n *\n * `fill` is optional and defaults to `'solid'` — `{ color: '#abc' }` is\n * equivalent to `{ fill: 'solid', color: '#abc' }`. Pattern paints must set\n * `fill: 'pattern'` explicitly.\n *\n * The `'pattern'` variant's payload is either a `TilePatternSpec` — plain\n * data naming one of the built-in tiles, which survives serialization — or a\n * `TextureHandle` for a tile the consumer built itself via\n * `createTilePattern()`. A handle is a session-scoped registry key, so a\n * paint carrying one cannot be persisted or exported; prefer the spec.\n *\n * `interpolate` on a gradient names the space its stops blend through, and\n * defaults to `'rgb'` — the channel-wise sRGB lerp every other vector format\n * means by a gradient. `'oklab'` spaces the blend perceptually; `'oklch'`\n * additionally travels around the hue wheel, so red to blue stays saturated\n * instead of passing through a muddy purple. Alpha is linear in every space.\n *\n * `units` on a pattern names the space the tile's origin and scale live in,\n * not the space of any geometry (a pattern has none). Under `'bounds'` the\n * tile anchors to the painted node's box, so the pattern travels with the\n * node and a resize reveals more tiles rather than stretching them;\n * `fillInPoseFrame` resolves that to a `'local'` paint with an explicit\n * `origin` before the renderer sees it.\n */\nexport type FillStyle =\n | { fill?: 'solid'; color: string; opacity?: number }\n | { fill: 'pattern'; pattern: TextureHandle | TilePatternSpec; units?: GradientUnits; origin?: { x: number; y: number }; opacity?: number }\n | { fill: 'linear-gradient'; from: { x: number; y: number }; to: { x: number; y: number }; stops: GradStop[]; units?: GradientUnits; interpolate?: ColorSpace; opacity?: number }\n | { fill: 'radial-gradient'; center: { x: number; y: number }; radius: number; stops: GradStop[]; units?: GradientUnits; interpolate?: ColorSpace; opacity?: number }\n | { fill: 'conic-gradient'; center: { x: number; y: number }; angle: number; stops: GradStop[]; units?: GradientUnits; interpolate?: ColorSpace; opacity?: number };\n\n/**\n * Which coordinate space a gradient's geometry (`from`/`to`, `center`,\n * `radius`) is expressed in. SVG's `gradientUnits`, plus an option for\n * paints that are themselves viewport furniture.\n *\n * - `'bounds'`: fractions of the painted node's bounding box, `0..1` on each\n * axis — SVG `objectBoundingBox`. Resolved by the node painter, before the\n * renderer sees it, so the paint follows the node through moves, resizes\n * and rotation. What a gradient on a scene node wants.\n * - `'local'`: the coordinate space the geometry was handed to the renderer\n * in — the enclosing group's frame. For draw commands a consumer builds\n * itself, where \"the coordinates I just wrote\" is the useful frame.\n * - `'world'`: scene coordinates. The paint stays put under pan and zoom\n * while the geometry moves through it. SVG `userSpaceOnUse`. Requires the\n * renderer to have been handed a view matrix; falls back to `'screen'`\n * when it has not.\n * - `'screen'`: CSS pixels of the drawing surface. For overlays and\n * viewport-fixed washes that should not move with the content at all.\n *\n * Defaults to `'screen'`, which is the behavior every gradient had before\n * this field existed.\n */\nexport type GradientUnits = 'bounds' | 'local' | 'world' | 'screen';\n\n/**\n * A built-in tile, described as plain data. The serializable half of the\n * pattern paint: `resolvePatternSpec()` turns one into a `TextureHandle`\n * at paint time, memoized so identical specs share a texture.\n *\n * `size` is the tile's edge length, and doubles as its extent in paint\n * space — a bigger `size` rasterizes a bigger tile rather than magnifying\n * a small one, which is why there is no separate scale field.\n */\nexport interface TilePatternSpec {\n tile: 'hatch' | 'crosshatch' | 'dots' | 'chunks';\n color: string;\n /** `chunks` only — omit for a transparent tile background. */\n bg?: string;\n size?: number;\n /** `hatch` / `crosshatch`. */\n lineWidth?: number;\n /** `dots`. */\n radius?: number;\n /** `chunks`. */\n density?: number;\n chunkSize?: number;\n seed?: number;\n}\n\n/** A single color stop within a gradient. `offset` is in 0..1. */\nexport interface GradStop {\n offset: number;\n color: string;\n}\n\n/** The gradient members of `FillStyle`, as one type. What a gradient editor\n * edits, and what the gradient-specific helpers accept. */\nexport type GradientFill = Extract<\n FillStyle,\n { fill: 'linear-gradient' | 'radial-gradient' | 'conic-gradient' }\n>;\n\n/** `GradientFill['fill']` — the three gradient discriminants on their own. */\nexport type GradientKind = GradientFill['fill'];\n\n/**\n * Where a stroke sits relative to the geometric edge it strokes.\n *\n * - `'center'` (default): canvas-native — half the stroke width sits inside\n * the geometry, half outside.\n * - `'inner'`: the entire stroke lies inside the geometry. The outer edge of\n * the stroke coincides with the geometric edge.\n * - `'outer'`: the entire stroke lies outside the geometry. The inner edge\n * of the stroke coincides with the geometric edge.\n *\n * Mirrors the (proposed) SVG `stroke-alignment` property. Honoring `inner`\n * or `outer` is the renderer's responsibility — for axis-aligned rects, the\n * kit shifts coordinates by `width / 2`. For arbitrary paths, renderers\n * typically use a stencil mask of the stroked path against the geometry.\n */\nexport type StrokeAlign = 'center' | 'inner' | 'outer';\n\n/**\n * The kit's built-in marker vocabulary, open on the string the way\n * `PaintKind` is so a consumer's registered key typechecks.\n */\nexport type KitMarkerKey =\n | 'arrow' | 'arrow-open' | 'arrow-concave'\n | 'diamond' | 'diamond-hollow'\n | 'circle' | 'square' | 'bar';\nexport type MarkerKey = KitMarkerKey | (string & {});\n\n/**\n * A marker on one end (or every interior vertex) of a stroke.\n *\n * `size` reuses `Stroke.width`'s unit system: a bare number scales with the\n * resolved stroke width, `{ px }` pins screen pixels. That is SVG's\n * `markerUnits` in the idiom this codebase already resolves at draw time.\n * Omitted, the marker is one stroke width per unit.\n */\nexport type MarkerRef = MarkerKey | { key: MarkerKey; size?: ScreenLength };\n\n/**\n * A length the author states either in world units (a plain number) or in\n * screen pixels (`{ px }`), resolved against the accumulated transform scale\n * wherever it is consumed — so a `{ px }` length holds its on-screen size as\n * the view zooms, with no call-site arithmetic.\n */\nexport type ScreenLength = number | { px: number };\n\n/**\n * Resolve a {@link ScreenLength} to world units. A non-finite or zero scale\n * has no world to divide into, so the pixel count passes through unchanged\n * rather than becoming `Infinity`.\n */\nexport function resolveScreenLength(value: ScreenLength, scale: number): number {\n if (typeof value === 'number') return value;\n if (!Number.isFinite(scale) || scale === 0) return value.px;\n return value.px / scale;\n}\n\n/** Stroke style: a FillStyle plus structural line parameters. */\nexport interface Stroke {\n /**\n * Omitted, the stroke paints nothing — the same \"no paint\" a `fill: null`\n * says for a node's fill. Documents written before mid-2026 can hold a\n * stroke whose other fields were seeded without one, and the type is\n * optional so every reader has to answer for that rather than throw on it.\n */\n paint?: FillStyle;\n /** World units, or `{ px }` for screen pixels — resolved against the\n * accumulated transform scale at draw time, so it holds its on-screen\n * thickness as the view zooms. */\n width?: ScreenLength;\n /** Per `CanvasRenderingContext2D.setLineDash` — empty/omitted = solid. */\n dash?: number[];\n /** Marker at the first vertex of each open subpath, rotated to point back\n * along the line (SVG's `auto-start-reverse`, as the only behavior). */\n markerStart?: MarkerRef;\n /** Marker at every interior authored vertex, on the bisector of the\n * incoming and outgoing directions. Never insets the stroke. */\n markerMid?: MarkerRef;\n /** Marker at the last vertex of each open subpath. */\n markerEnd?: MarkerRef;\n cap?: 'butt' | 'round' | 'square';\n join?: 'miter' | 'round' | 'bevel';\n /**\n * Miter join fallback threshold. When the miter length exceeds\n * `miterLimit * width / 2`, the join falls back to a bevel. Default 4,\n * matching SVG — which is also what the kit's own serializer implies when\n * it omits the attribute for an unset field. Canvas2D's 10 lets an acute\n * corner throw a spike four times the half-width.\n */\n miterLimit?: number;\n /** Where the stroke sits relative to the geometric edge. Default `'center'`. */\n align?: StrokeAlign;\n /**\n * Per-anchor RGBA, flat (length = 4 × countPathAnchors(path)). Each\n * value in 0..1. Arc-length interpolated across the tessellated ribbon\n * between consecutive anchors. When set, `paint` is still required —\n * its `opacity` (and color, as a placeholder) flow through the shader.\n */\n vertexColors?: number[];\n /**\n * Per-anchor stroke width (length = `countPathAnchors(path)`). When set,\n * the tessellator interpolates half-widths along each segment to produce\n * a tapered ribbon. `width` is used as the fallback for any anchor whose\n * entry is missing or non-finite. Pressure-driven pencil strokes use\n * this; pair with `pressureToWidth` to derive widths from stylus input.\n *\n * Joins between adjacent segments whose widths differ by more than\n * `varyingWidthJoinThreshold` (default 1.5×) are forced to bevel\n * regardless of the `join` setting — miter math is unstable when widths\n * vary across the corner; smooth round joins with mismatched widths\n * are a future enhancement.\n */\n vertexWidths?: number[];\n /**\n * Max width ratio (greater / lesser) at which a non-bevel join is\n * preserved when `vertexWidths` causes adjacent segments to differ.\n * Beyond this ratio the join falls back to bevel. Default 1.5. Ignored\n * when `vertexWidths` is absent.\n */\n varyingWidthJoinThreshold?: number;\n}\n\n/**\n * Inflate (positive) or deflate (negative) a rect to honor `align` when\n * stroking it. Returns the rect to pass to a stroked-rect renderer. `width`\n * is the stroke width (defaults to 1 to match canvas).\n *\n * Pure geometry helper — no rendering side effects. Used by path\n * tessellation and the selection overlay to produce a rect whose\n * center-aligned stroke visually coincides with the requested\n * inner/outer-aligned stroke of the original rect.\n */\nexport function alignedStrokeRect(\n rect: { x: number; y: number; width: number; height: number },\n align: StrokeAlign,\n width = 1,\n): { x: number; y: number; width: number; height: number } {\n if (align === 'center') return rect;\n // For 'inner', shift inward by width/2 so the stroke's outer edge coincides\n // with the geometric edge. For 'outer', shift outward.\n const sign = align === 'inner' ? -1 : 1;\n const d = (sign * width) / 2;\n return {\n x: rect.x - d,\n y: rect.y - d,\n width: rect.width + 2 * d,\n height: rect.height + 2 * d,\n };\n}\n\n/**\n * The named line styles a `Stroke.dash` array reads as.\n *\n * `custom` is what an imported array that matches no preset reads as — it is\n * reportable, not authorable: there is no array it maps back to.\n */\nexport type StrokeDashStyle = 'solid' | 'dashed' | 'dotted' | 'custom';\n\n/**\n * Dash and gap lengths of the presets, **as multiples of the stroke width**.\n *\n * SVG dash lengths are absolute, so a fixed pattern is a different style at\n * every width: `[6, 3]` is dots on a hairline and a railroad on a 20px\n * stroke. Scaling by the width is what makes \"dashed\" one style.\n */\nexport const STROKE_DASH_RATIOS = {\n dashed: [3, 2],\n dotted: [1, 2],\n} as const satisfies Record<'dashed' | 'dotted', readonly [number, number]>;\n\n/** `width` as a plain number — a `{ px }` width is read at scale 1, matching\n * what an unresolved stroke reaching the tessellator gets. */\nfunction dashWidth(width: number | { px: number } | undefined): number {\n const w = typeof width === 'object' ? width.px : (width ?? 1);\n return Number.isFinite(w) && w > 0 ? w : 1;\n}\n\n/**\n * The `Stroke.dash` array for a named style at `width`, or `undefined` for\n * `solid` — which is stored as no dash at all, not as an empty pattern.\n *\n * `custom` has no array of its own and returns `undefined`; a caller that\n * offers it as a choice should refuse the choice rather than call this.\n */\nexport function dashForStrokeStyle(\n style: StrokeDashStyle,\n width: number | { px: number } | undefined,\n): number[] | undefined {\n if (style !== 'dashed' && style !== 'dotted') return undefined;\n const w = dashWidth(width);\n return STROKE_DASH_RATIOS[style].map((r) => r * w);\n}\n\n/**\n * The style a stored `dash` reads as at `width`. Absent or empty is `solid`;\n * an array matching neither preset is `custom`.\n */\nexport function strokeDashStyleOf(\n dash: readonly number[] | undefined,\n width: number | { px: number } | undefined,\n): StrokeDashStyle {\n if (dash === undefined || dash.length === 0 || dash.every((v) => v === 0)) return 'solid';\n const w = dashWidth(width);\n for (const style of ['dashed', 'dotted'] as const) {\n const preset = STROKE_DASH_RATIOS[style];\n // Tolerance is relative to the width: the presets are multiples of it, and\n // a round-tripped array carries the serializer's decimal trimming.\n if (dash.length === preset.length && preset.every((r, i) => Math.abs(dash[i] - r * w) <= w * 1e-3)) {\n return style;\n }\n }\n return 'custom';\n}\n\n/** Region a fill is clipped to. */\nexport interface Region {\n x: number;\n y: number;\n w: number;\n h: number;\n shape: 'rectangle' | 'circle';\n}\n","// sRGB ↔ OKLab conversion. Reference: https://bottosson.github.io/posts/oklab/\n\nconst SRGB_TO_LINEAR: Float64Array = (() => {\n const lut = new Float64Array(256);\n for (let i = 0; i < 256; i++) {\n const c = i / 255;\n lut[i] = c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n }\n return lut;\n})();\n\nfunction linearToSrgbByte(c: number): number {\n if (c <= 0) return 0;\n if (c >= 1) return 255;\n const v = c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;\n return Math.round(v * 255);\n}\n\n/** 0..1 float channel to the 8-bit index the LUTs are cut for. Rounds and\n * clamps; `& 0xff` would truncate, and wrap anything out of range. */\nconst f2u = (v: number): number => Math.max(0, Math.min(255, Math.round(v * 255)));\n\n/**\n * Convert a 0..1 float sRGB triple to OKLab — the renderer's own color space,\n * and what a caller holding a `resolveColor` result has. Rounds into the u8\n * grid the way every other float→u8 crossing in this file does, rather than\n * leaving each caller to pick a convention.\n */\nexport function srgbFloatToOklab(r: number, g: number, b: number): [number, number, number] {\n return srgbU8ToOklab(f2u(r), f2u(g), f2u(b));\n}\n\n/** Convert an 8-bit sRGB triple to OKLab. Channels are indices into a 256-entry\n * LUT: pass integers, or `srgbFloatToOklab` for 0..1 floats. */\nexport function srgbU8ToOklab(r: number, g: number, b: number): [number, number, number] {\n return linearSrgbToOklab(SRGB_TO_LINEAR[r & 0xff], SRGB_TO_LINEAR[g & 0xff], SRGB_TO_LINEAR[b & 0xff]);\n}\n\n/** Linear-light sRGB (0..1 floats, unclamped) to OKLab. */\nexport function linearSrgbToOklab(rl: number, gl: number, bl: number): [number, number, number] {\n const l = 0.4122214708 * rl + 0.5363325363 * gl + 0.0514459929 * bl;\n const m = 0.2119034982 * rl + 0.6806995451 * gl + 0.1073969566 * bl;\n const s = 0.0883024619 * rl + 0.2817188376 * gl + 0.6299787005 * bl;\n const lp = Math.cbrt(l);\n const mp = Math.cbrt(m);\n const sp = Math.cbrt(s);\n return [\n 0.2104542553 * lp + 0.7936177850 * mp - 0.0040720468 * sp,\n 1.9779984951 * lp - 2.4285922050 * mp + 0.4505937099 * sp,\n 0.0259040371 * lp + 0.7827717662 * mp - 0.8086757660 * sp,\n ];\n}\n\n/** OKLab to linear-light sRGB. Not gamut-clipped: out-of-gamut colors come\n * back with channels outside 0..1. */\nexport function oklabToLinearSrgb(L: number, A: number, B: number): [number, number, number] {\n const lp = L + 0.3963377774 * A + 0.2158037573 * B;\n const mp = L - 0.1055613458 * A - 0.0638541728 * B;\n const sp = L - 0.0894841775 * A - 1.2914855480 * B;\n const l = lp * lp * lp;\n const m = mp * mp * mp;\n const s = sp * sp * sp;\n return [\n +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s,\n ];\n}\n\nfunction inGamut(rl: number, gl: number, bl: number): boolean {\n // Small epsilon absorbs float-roundtrip noise on pure-primary colors.\n const eps = 1e-6;\n return (\n rl >= -eps && rl <= 1 + eps &&\n gl >= -eps && gl <= 1 + eps &&\n bl >= -eps && bl <= 1 + eps\n );\n}\n\nfunction clipToGamut(L: number, A: number, B: number): [number, number, number] {\n let [rl, gl, bl] = oklabToLinearSrgb(L, A, B);\n if (inGamut(rl, gl, bl)) return [rl, gl, bl];\n let lo = 0;\n let hi = 1;\n // 5 iterations → ~3% chroma precision; sufficient for u8 output.\n for (let i = 0; i < 5; i++) {\n const t = (lo + hi) / 2;\n [rl, gl, bl] = oklabToLinearSrgb(L, A * t, B * t);\n if (inGamut(rl, gl, bl)) lo = t; else hi = t;\n }\n [rl, gl, bl] = oklabToLinearSrgb(L, A * lo, B * lo);\n return [rl, gl, bl];\n}\n\n/** Convert OKLab back to an 8-bit sRGB triple, clamped into gamut. */\nexport function oklabToSrgbU8(L: number, A: number, B: number): [number, number, number] {\n const [rl, gl, bl] = clipToGamut(L, A, B);\n return [linearToSrgbByte(rl), linearToSrgbByte(gl), linearToSrgbByte(bl)];\n}\n\n/** Blend two 8-bit sRGB colors through OKLab. Perceptually even, and it does\n * not pass through the muddy midpoints an sRGB blend produces between\n * complementary hues. */\nexport function lerpOklab(\n from: readonly [number, number, number],\n to: readonly [number, number, number],\n t: number,\n): [number, number, number] {\n return [\n from[0] + (to[0] - from[0]) * t,\n from[1] + (to[1] - from[1]) * t,\n from[2] + (to[2] - from[2]) * t,\n ];\n}\n\n/**\n * `color-mix(in oklab, a p%, b)` for two 0..1 sRGBA colors, `p` as 0..1: the\n * channels mix premultiplied by alpha, as CSS does, so a transparent side\n * lends the result its opacity and none of its color.\n */\nexport function mixOklab(\n a: readonly [number, number, number, number],\n b: readonly [number, number, number, number],\n p: number,\n): [number, number, number, number] {\n const alpha = a[3] * p + b[3] * (1 - p);\n if (alpha === 0) return [0, 0, 0, 0];\n const la = srgbFloatToOklab(a[0], a[1], a[2]);\n const lb = srgbFloatToOklab(b[0], b[1], b[2]);\n const mix = (i: number) => (la[i] * a[3] * p + lb[i] * b[3] * (1 - p)) / alpha;\n const [r, g, bl] = oklabToSrgbU8(mix(0), mix(1), mix(2));\n return [r / 255, g / 255, bl / 255, alpha];\n}\n\n/** Convert OKLab (L, a, b) to OKLCh (L, C, h). h is in radians, range [-π, π]. */\nexport function oklabToOklch(L: number, A: number, B: number): [number, number, number] {\n const C = Math.hypot(A, B);\n const h = Math.atan2(B, A);\n return [L, C, h];\n}\n\n/** Convert OKLCh (L, C, h) to OKLab (L, a, b). h is in radians. */\nexport function oklchToOklab(L: number, C: number, h: number): [number, number, number] {\n return [L, C * Math.cos(h), C * Math.sin(h)];\n}\n\n/** Lerp OKLCh values with shortest-arc hue interpolation. Lightness and\n * chroma lerp linearly. When chroma is near zero on either endpoint, hue\n * is taken from the other endpoint (avoids hue snap-from-undefined).\n * h inputs are in radians. */\nexport function lerpOklch(\n from: readonly [number, number, number],\n to: readonly [number, number, number],\n t: number,\n): [number, number, number] {\n const [L1, C1, h1Raw] = from;\n const [L2, C2, h2Raw] = to;\n const C_EPS = 1e-4;\n // When one endpoint is near-achromatic, take hue from the other endpoint\n // to avoid spurious arc rotation through undefined hue space.\n const h1 = C1 < C_EPS ? h2Raw : h1Raw;\n const h2 = C2 < C_EPS ? h1Raw : h2Raw;\n const TWO_PI = Math.PI * 2;\n // Shortest-arc delta in [-π, π].\n let dh = h2 - h1;\n while (dh > Math.PI) dh -= TWO_PI;\n while (dh < -Math.PI) dh += TWO_PI;\n return [\n L1 + (L2 - L1) * t,\n C1 + (C2 - C1) * t,\n h1 + dh * t,\n ];\n}\n\n/** Which space a color blend is computed in. `'rgb'` is cheapest; `'oklab'`\n * is perceptually even; `'oklch'` additionally travels around the hue wheel\n * rather than through it. */\nexport type ColorSpace = 'rgb' | 'oklab' | 'oklch';\n\nconst u2f = (v: number): number => v / 255;\n\n/** Lerp a flat RGBA color array `from` toward `to`. Inputs are 0..1\n * floats (the renderer's color space); outputs are 0..1 floats too.\n * Alpha is always linearly lerped; RGB channels are lerped in the\n * requested color space. OKLab / OKLCh paths bounce through u8 because\n * the gamma-correction LUT and gamut-clip routines are byte-keyed —\n * the round-trip is lossy at <1% per channel, well under the visible\n * threshold for these animations. */\nexport function lerpColorArray(\n from: readonly number[],\n to: readonly number[],\n t: number,\n space: ColorSpace = 'rgb',\n): number[] {\n if (from.length !== to.length) {\n throw new Error(`lerpColorArray: length mismatch (from=${from.length}, to=${to.length})`);\n }\n if (from.length % 4 !== 0) {\n throw new Error(`lerpColorArray: length ${from.length} not divisible by 4`);\n }\n const out = new Array<number>(from.length);\n const n = from.length / 4;\n if (space === 'rgb') {\n // Pure float lerp — no rounding (which previously discretized 0..1\n // inputs to 0/1, giving the cycle its 'choppy 8-corner' look).\n for (let i = 0; i < from.length; i++) {\n out[i] = from[i] + (to[i] - from[i]) * t;\n }\n return out;\n }\n if (space === 'oklch') {\n for (let i = 0; i < n; i++) {\n const k = i * 4;\n const fLab = srgbU8ToOklab(f2u(from[k]), f2u(from[k + 1]), f2u(from[k + 2]));\n const tLab = srgbU8ToOklab(f2u(to[k]), f2u(to[k + 1]), f2u(to[k + 2]));\n const fLch = oklabToOklch(fLab[0], fLab[1], fLab[2]);\n const tLch = oklabToOklch(tLab[0], tLab[1], tLab[2]);\n const midLch = lerpOklch(fLch, tLch, t);\n const midLab = oklchToOklab(midLch[0], midLch[1], midLch[2]);\n const [r, g, b] = oklabToSrgbU8(midLab[0], midLab[1], midLab[2]);\n out[k] = u2f(r);\n out[k + 1] = u2f(g);\n out[k + 2] = u2f(b);\n out[k + 3] = from[k + 3] + (to[k + 3] - from[k + 3]) * t;\n }\n return out;\n }\n for (let i = 0; i < n; i++) {\n const k = i * 4;\n const fLab = srgbU8ToOklab(f2u(from[k]), f2u(from[k + 1]), f2u(from[k + 2]));\n const tLab = srgbU8ToOklab(f2u(to[k]), f2u(to[k + 1]), f2u(to[k + 2]));\n const mid = lerpOklab(fLab, tLab, t);\n const [r, g, b] = oklabToSrgbU8(mid[0], mid[1], mid[2]);\n out[k] = u2f(r);\n out[k + 1] = u2f(g);\n out[k + 2] = u2f(b);\n out[k + 3] = from[k + 3] + (to[k + 3] - from[k + 3]) * t;\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// OKLCh in degrees\n// ---------------------------------------------------------------------------\n\n/**\n * OKLCh with the hue in **degrees**, and `#rrggbb` on the other side.\n *\n * The helpers above take radians, because that is what the math wants. Every\n * consumer that authors colors — a theme ramp, a palette generator — wants\n * degrees and a hex string, and two packages independently built the same\n * wrapper before this existed.\n */\nexport interface OklchDeg {\n readonly L: number;\n readonly C: number;\n /** 0..360. */\n readonly H: number;\n}\n\nconst hex2 = (v: number): string => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, '0');\n\n/**\n * OKLCh (hue in degrees) to `#rrggbb`. Over-saturated requests come back at\n * the gamut boundary: `oklabToSrgbU8` clips chroma at constant lightness, which\n * is what lets a caller find a hue's ceiling by asking for far more than exists.\n */\nexport function oklchDegToHex(L: number, C: number, hueDeg: number): string {\n const [l, a, b] = oklchToOklab(L, C, (hueDeg * Math.PI) / 180);\n const [r, g, bl] = oklabToSrgbU8(l, a, b);\n return `#${hex2(r)}${hex2(g)}${hex2(bl)}`;\n}\n\n/** `#rrggbb` to OKLCh with the hue wrapped into 0..360. */\nexport function hexToOklchDeg(hex: string): OklchDeg {\n const n = Number.parseInt(hex.slice(1), 16);\n const [L, A, B] = srgbU8ToOklab((n >> 16) & 255, (n >> 8) & 255, n & 255);\n const [l, c, h] = oklabToOklch(L, A, B);\n return { L: l, C: c, H: ((((h * 180) / Math.PI) % 360) + 360) % 360 };\n}\n\n// ---------------------------------------------------------------------------\n// Float sRGB transfer, HSL, and interpolation across spaces\n// ---------------------------------------------------------------------------\n\n/** sRGB-encoded channel (0..1) to linear light. Unclamped; odd-symmetric\n * below zero, as CSS `srgb-linear` extends it. */\nexport function srgbToLinear(c: number): number {\n const a = Math.abs(c);\n const v = a <= 0.04045 ? a / 12.92 : Math.pow((a + 0.055) / 1.055, 2.4);\n return c < 0 ? -v : v;\n}\n\n/** Linear-light channel to sRGB encoding (0..1). Unclamped. */\nexport function linearToSrgb(c: number): number {\n const a = Math.abs(c);\n const v = a <= 0.0031308 ? a * 12.92 : 1.055 * Math.pow(a, 1 / 2.4) - 0.055;\n return c < 0 ? -v : v;\n}\n\n/** HSL to sRGB. Hue in degrees, saturation, lightness and output all 0..1. */\nexport function hslToSrgb(h: number, s: number, l: number): [number, number, number] {\n if (s === 0) return [l, l, l];\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n const hk = h / 360;\n return [hueToChannel(p, q, hk + 1 / 3), hueToChannel(p, q, hk), hueToChannel(p, q, hk - 1 / 3)];\n}\n\nfunction hueToChannel(p: number, q: number, t: number): number {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n}\n\n/** sRGB (0..1) to HSL: `[hue°, saturation, lightness]`, hue in 0..360. An\n * achromatic color reports hue 0 and saturation 0. */\nexport function srgbToHsl(r: number, g: number, b: number): [number, number, number] {\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n const d = max - min;\n if (d === 0) return [0, 0, l];\n const s = d / (1 - Math.abs(2 * l - 1));\n let h: number;\n if (max === r) h = ((g - b) / d) % 6;\n else if (max === g) h = (b - r) / d + 2;\n else h = (r - g) / d + 4;\n return [(((h * 60) % 360) + 360) % 360, s, l];\n}\n\n/**\n * The space a color interpolation runs in, spelled as CSS `color-mix()` spells\n * them. `'srgb'` and `'srgb-linear'` blend gamma-encoded and linear-light\n * channels; `'oklab'` blends perceptual coordinates; `'oklch'` and `'hsl'` are\n * polar, so their hue travels around the wheel rather than through it.\n *\n * Distinct from {@link ColorSpace}, the gradient and animation vocabulary,\n * which keeps its `'rgb'` spelling and its byte-precision paths.\n */\nexport type ColorInterpolationSpace = 'oklch' | 'oklab' | 'hsl' | 'srgb' | 'srgb-linear';\n\n/** Which way a polar space's hue goes between two endpoints, as CSS\n * `hue-interpolation-method`: the arc of at most 180°, or the other one. */\nexport type HueInterpolation = 'shorter' | 'longer';\n\n/** An endpoint with less chroma (OKLCH) or saturation (HSL) than this has no\n * hue of its own. */\nconst ACHROMATIC_EPS = 1e-4;\n\nfunction lerpHueDeg(h1: number, h2: number, t: number, method: HueInterpolation): number {\n let dh = (((h2 - h1) % 360) + 360) % 360;\n if (method === 'shorter') {\n if (dh > 180) dh -= 360;\n } else if (dh > 0 && dh < 180) {\n dh -= 360;\n }\n return (((h1 + dh * t) % 360) + 360) % 360;\n}\n\ntype Polar = readonly [radius: number, hueDeg: number, axis: number];\n\nfunction lerpPolar(a: Polar, b: Polar, t: number, method: HueInterpolation): [number, number, number] {\n const h1 = a[0] < ACHROMATIC_EPS ? b[1] : a[1];\n const h2 = b[0] < ACHROMATIC_EPS ? a[1] : b[1];\n return [a[0] + (b[0] - a[0]) * t, lerpHueDeg(h1, h2, t, method), a[2] + (b[2] - a[2]) * t];\n}\n\ntype Rgb = readonly [number, number, number];\n\nconst lerp3 = (a: Rgb, b: Rgb, t: number): [number, number, number] => [\n a[0] + (b[0] - a[0]) * t,\n a[1] + (b[1] - a[1]) * t,\n a[2] + (b[2] - a[2]) * t,\n];\n\nconst clamp01 = (v: number): number => (v < 0 ? 0 : v > 1 ? 1 : v);\n\nconst srgbToOklabFloat = (c: Rgb): [number, number, number] =>\n linearSrgbToOklab(srgbToLinear(c[0]), srgbToLinear(c[1]), srgbToLinear(c[2]));\n\nfunction oklabToSrgbClipped(L: number, A: number, B: number): [number, number, number] {\n const [rl, gl, bl] = clipToGamut(L, A, B);\n return [clamp01(linearToSrgb(rl)), clamp01(linearToSrgb(gl)), clamp01(linearToSrgb(bl))];\n}\n\n/**\n * Interpolate between two sRGB colors (0..1 floats) in `space`, at `t` in 0..1.\n * Float precision throughout, with no byte round-trip. The result is sRGB;\n * only OKLab and OKLCH blends can leave gamut, and those come back\n * chroma-clipped at constant OKLab lightness.\n *\n * `hue` applies to the polar spaces only. An endpoint with no chroma (OKLCH)\n * or no saturation (HSL) borrows the other endpoint's hue, so a ramp to white\n * or black holds its hue instead of sweeping from red.\n */\nexport function interpolateSrgb(\n from: Rgb,\n to: Rgb,\n t: number,\n space: ColorInterpolationSpace = 'oklch',\n hue: HueInterpolation = 'shorter',\n): [number, number, number] {\n switch (space) {\n case 'srgb':\n return lerp3(from, to, t);\n case 'srgb-linear': {\n const lin = (c: Rgb): Rgb => [srgbToLinear(c[0]), srgbToLinear(c[1]), srgbToLinear(c[2])];\n const [r, g, b] = lerp3(lin(from), lin(to), t);\n return [linearToSrgb(r), linearToSrgb(g), linearToSrgb(b)];\n }\n case 'oklab': {\n const [L, A, B] = lerp3(srgbToOklabFloat(from), srgbToOklabFloat(to), t);\n return oklabToSrgbClipped(L, A, B);\n }\n case 'oklch': {\n const polar = (c: Rgb): Polar => {\n const [L, C, h] = oklabToOklch(...srgbToOklabFloat(c));\n return [C, (((h * 180) / Math.PI) % 360 + 360) % 360, L];\n };\n const [C, H, L] = lerpPolar(polar(from), polar(to), t, hue);\n const [l, a, b] = oklchToOklab(L, C, (H * Math.PI) / 180);\n return oklabToSrgbClipped(l, a, b);\n }\n case 'hsl': {\n const polar = (c: Rgb): Polar => {\n const [h, s, l] = srgbToHsl(c[0], c[1], c[2]);\n return [s, h, l];\n };\n const [s, h, l] = lerpPolar(polar(from), polar(to), t, hue);\n return hslToSrgb(h, s, l);\n }\n }\n}\n","import { oklabToSrgbU8, srgbU8ToOklab } from './colorSpaces';\n\nconst hex2 = (v: number): string => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, '0');\n\nfunction readHex(color: string): [number, number, number] | null {\n const m = /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(color.trim());\n if (!m) return null;\n let h = m[1];\n if (h.length === 3) h = h.replace(/./g, (c) => c + c);\n const n = Number.parseInt(h.slice(0, 6), 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\n/**\n * A line color that reads against `background` — a grid, a rule, a guide\n * drawn over a surface whose color the document chooses, where theme tokens\n * would be keyed to the chrome instead.\n *\n * The line is the background moved `strength` in OKLab lightness (0..1) away\n * from its nearer end: darker over light, lighter over dark, with its hue and\n * chroma kept. Returns `#rrggbb`; the background's alpha is ignored. A color\n * that is not hex comes back as black at `strength` alpha.\n */\nexport function contrastLineColor(background: string, strength: number): string {\n const rgb = readHex(background);\n if (!rgb) return `rgba(0, 0, 0, ${strength})`;\n const [L, A, B] = srgbU8ToOklab(rgb[0], rgb[1], rgb[2]);\n const next = L > 0.5 ? Math.max(0, L - strength) : Math.min(1, L + strength);\n const [r, g, b] = oklabToSrgbU8(next, A, B);\n return `#${hex2(r)}${hex2(g)}${hex2(b)}`;\n}\n","import { oklabToSrgbU8, oklchToOklab } from './colorSpaces';\n\n/**\n * A color given directly. `coords` are in the order CSS Color 4 uses for\n * `space` — `srgb` as 0..1 r, g, b; `oklab` as L, a, b; `oklch` as L, C and a\n * hue in degrees. `space` is open: a palette may carry colors in spaces the kit\n * cannot convert, and `colorLiteralToHex` answers `null` for those.\n */\nexport interface ColorLiteral {\n readonly space: string;\n readonly coords: readonly number[];\n /** 0..1. Omitted means opaque. */\n readonly alpha?: number;\n}\n\n/** A color named rather than given: a palette entry, or whatever the resolver's\n * `external` callback answers to. `index` picks from a sequence entry; a\n * single-color entry answers only to 0. */\nexport interface ColorRef {\n readonly ref: string;\n readonly index?: number;\n}\n\n/** What a {@link ColorFn} or {@link ColorSeqFn} is handed. */\nexport interface ColorFnContext {\n /** Resolve any source against the same palette and external lookup. */\n resolve(source: ColorSource): ColorLiteral | null;\n}\n\n/** A color computed at resolve time — typically derived from another entry. */\nexport type ColorFn = (ctx: ColorFnContext) => ColorSource | null | undefined;\n\nexport type ColorSource = ColorLiteral | ColorRef | ColorFn;\n\n/** A sequence of colors, read lazily, so it may be endless. A factory rather\n * than an iterable because a generator object can be iterated only once:\n * pass the `function*` itself. */\nexport type ColorSeqFn = (ctx: ColorFnContext) => Iterable<ColorSource>;\n\nexport type PaletteEntry =\n | { readonly name: string; readonly color: ColorSource }\n | { readonly name: string; readonly colors: ColorSeqFn };\n\nexport interface Palette {\n readonly entries: readonly PaletteEntry[];\n}\n\n/** Answers a ref the palette has no entry for. */\nexport type ExternalColors = (ref: ColorRef) => ColorSource | null | undefined;\n\ntype Visit = (s: ColorSource | null | undefined, visiting: ReadonlySet<string>) => ColorLiteral | null;\n\nfunction nth<T>(items: Iterable<T>, n: number): T | undefined {\n if (!Number.isInteger(n) || n < 0) return undefined;\n let i = 0;\n for (const item of items) if (i++ === n) return item;\n return undefined;\n}\n\nconst refKey = (name: string, index: number): string => `${index}:${name}`;\n\nfunction resolver(palette: Palette, external?: ExternalColors) {\n const byName = new Map<string, PaletteEntry>();\n for (const e of palette.entries) if (!byName.has(e.name)) byName.set(e.name, e);\n\n const ctx = (visiting: ReadonlySet<string>): ColorFnContext => ({ resolve: (s) => visit(s, visiting) });\n\n const visit: Visit = (s, visiting) => {\n if (s == null) return null;\n if (typeof s === 'function') return visit(s(ctx(visiting)), visiting);\n if ('space' in s) return s;\n const index = s.index ?? 0;\n const key = refKey(s.ref, index);\n if (visiting.has(key)) return null;\n const next = new Set(visiting).add(key);\n const entry = byName.get(s.ref);\n if (!entry) return visit(external?.(s), next);\n if ('color' in entry) return index === 0 ? visit(entry.color, next) : null;\n return visit(nth(entry.colors(ctx(next)), index), next);\n };\n\n return { byName, ctx, visit };\n}\n\n/**\n * Resolve `source` to a literal. A ref names a palette entry first, then goes\n * to `external`; whatever either answers is resolved in turn. A name nothing\n * answers, an index past a sequence's end, or a chain that comes back to a ref\n * it is already resolving gives `null`.\n */\nexport function resolvePaletteColor(\n palette: Palette,\n source: ColorSource,\n external?: ExternalColors,\n): ColorLiteral | null {\n return resolver(palette, external).visit(source, new Set());\n}\n\n/**\n * Every color under `name`, resolved lazily in order — one for a single-color\n * entry, as many as the sequence yields for a `colors` entry, nothing for a\n * name the palette lacks. Stop early to read an endless sequence.\n */\nexport function* resolvePaletteColors(\n palette: Palette,\n name: string,\n external?: ExternalColors,\n): Generator<ColorLiteral | null> {\n const { byName, ctx, visit } = resolver(palette, external);\n const entry = byName.get(name);\n if (!entry) return;\n if ('color' in entry) {\n yield visit(entry.color, new Set([refKey(name, 0)]));\n return;\n }\n let i = 0;\n for (const item of entry.colors(ctx(new Set()))) {\n yield visit(item, new Set([refKey(name, i++)]));\n }\n}\n\nconst hex2 = (v: number): string => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, '0');\n\n/** `#rrggbb`, or `#rrggbbaa` below full opacity. `null` for a space the kit\n * cannot convert, or fewer than three coordinates. */\nexport function colorLiteralToHex(color: ColorLiteral): string | null {\n const [x, y, z] = color.coords;\n if (z === undefined) return null;\n let rgb: readonly number[];\n switch (color.space) {\n case 'srgb':\n rgb = [x * 255, y * 255, z * 255];\n break;\n case 'oklab':\n rgb = oklabToSrgbU8(x, y, z);\n break;\n case 'oklch':\n rgb = oklabToSrgbU8(...oklchToOklab(x, y, (z * Math.PI) / 180));\n break;\n default:\n return null;\n }\n const a = color.alpha ?? 1;\n return `#${rgb.map(hex2).join('')}${a < 1 ? hex2(a * 255) : ''}`;\n}\n\n/** `#rrggbb` or `#rrggbbaa` as an `srgb` literal; `null` for anything else. */\nexport function hexToColorLiteral(hex: string): ColorLiteral | null {\n if (!/^#(?:[0-9a-f]{6}|[0-9a-f]{8})$/i.test(hex)) return null;\n const byte = (i: number): number => Number.parseInt(hex.slice(i, i + 2), 16) / 255;\n const coords = [byte(1), byte(3), byte(5)];\n return hex.length === 9 ? { space: 'srgb', coords, alpha: byte(7) } : { space: 'srgb', coords };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/patternTransform.ts","../src/paint.ts","../src/colorSpaces.ts","../src/contrast.ts","../src/palette.ts"],"names":["L","C","h","s","l","hex2"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * A pattern tile's linear map into paint space: `[a, b, c, d]`, the first\n * four entries of SVG's `matrix(a b c d e f)`. A tile point `(u, v)` lands at\n * `origin + (a·u + c·v, b·u + d·v)`. Translation is the paint's `origin`, so\n * it has no slot here.\n */\nexport type PatternTransform = readonly [a: number, b: number, c: number, d: number];\n\n/**\n * A {@link PatternTransform} as the parts an editor shows. Angles are radians.\n * Applied in the order scale, then skew, then rotation — rotation outermost,\n * so turning a skewed tile turns it whole.\n */\nexport interface PatternTransformParts {\n rotation: number;\n scaleX: number;\n scaleY: number;\n /** Shear of the tile's y axis toward x, as SVG `skewX()`. */\n skewX: number;\n}\n\n/** `R(rotation) · K(skewX) · S(scaleX, scaleY)`. Omitted parts are identity. */\nexport function composePatternTransform(parts: Partial<PatternTransformParts>): PatternTransform {\n const { rotation = 0, scaleX = 1, scaleY = 1, skewX = 0 } = parts;\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const shear = Math.tan(skewX) * scaleY;\n return [\n cos * scaleX,\n sin * scaleX,\n cos * shear - sin * scaleY,\n sin * shear + cos * scaleY,\n ];\n}\n\n/**\n * Inverse of {@link composePatternTransform}. Any 2×2 matrix decomposes this\n * way; a reflection comes back as a negative `scaleY`. `undefined` reads as the\n * identity, which is what an absent `transform` means.\n */\nexport function decomposePatternTransform(t: PatternTransform | undefined): PatternTransformParts {\n if (!t) return { rotation: 0, scaleX: 1, scaleY: 1, skewX: 0 };\n const [a, b, c, d] = t;\n const scaleX = Math.hypot(a, b);\n const rotation = scaleX === 0 ? 0 : Math.atan2(b, a);\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const shear = c * cos + d * sin;\n const scaleY = d * cos - c * sin;\n const skewX = scaleY === 0 ? 0 : Math.atan(shear / scaleY);\n return { rotation, scaleX, scaleY, skewX };\n}\n","/**\n * FillStyle and Stroke types — the unified shape for \"what color or texture\n * paints these pixels,\" modeled on SVG's paint-server concept.\n *\n * - `FillStyle` is a tagged union: solid color, pattern, or gradient. Used\n * wherever a kit option previously took `fillStyle: string`.\n * - `Stroke` pairs a `FillStyle` with structural stroke parameters (width, dash,\n * line cap/join, alignment).\n * - These types are consumed by the GL renderer's DrawCommand path fills\n * and strokes.\n *\n * The 2D `applyPaint` / `applyStroke` / `renderFilledRegion` helpers that\n * formerly lived alongside these types were deleted with the 2D backend in\n * Step 10. `alignedStrokeRect` survives as a pure geometry helper used by\n * path tessellation and the selection overlay.\n */\n\nimport type { TextureHandle } from './texture';\nimport type { ColorSpace } from './colorSpaces';\nimport type { PatternTransform } from './patternTransform';\n\n/**\n * Color/texture strategy for fills (and, via `Stroke.paint`, strokes).\n *\n * `fill` is optional and defaults to `'solid'` — `{ color: '#abc' }` is\n * equivalent to `{ fill: 'solid', color: '#abc' }`. Pattern paints must set\n * `fill: 'pattern'` explicitly.\n *\n * The `'pattern'` variant's payload is either a `TilePatternSpec` — plain\n * data naming one of the built-in tiles, which survives serialization — or a\n * `TextureHandle` for a tile the consumer built itself via\n * `createTilePattern()`. A handle is a session-scoped registry key, so a\n * paint carrying one cannot be persisted or exported; prefer the spec.\n *\n * `interpolate` on a gradient names the space its stops blend through, and\n * defaults to `'rgb'` — the channel-wise sRGB lerp every other vector format\n * means by a gradient. `'oklab'` spaces the blend perceptually; `'oklch'`\n * additionally travels around the hue wheel, so red to blue stays saturated\n * instead of passing through a muddy purple. Alpha is linear in every space.\n *\n * `units` on a pattern names the space the tile's origin and scale live in,\n * not the space of any geometry (a pattern has none). Under `'bounds'` the\n * tile anchors to the painted node's box, so the pattern travels with the\n * node and a resize reveals more tiles rather than stretching them;\n * `fillInPoseFrame` resolves that to a `'local'` paint with an explicit\n * `origin` before the renderer sees it.\n *\n * `transform` on a pattern rotates, scales or skews the tile about `origin`\n * (SVG's `patternTransform`, less its translation). See `PatternTransform`.\n */\nexport type FillStyle =\n | { fill?: 'solid'; color: string; opacity?: number }\n | { fill: 'pattern'; pattern: TextureHandle | TilePatternSpec; units?: GradientUnits; origin?: { x: number; y: number }; transform?: PatternTransform; opacity?: number }\n | { fill: 'linear-gradient'; from: { x: number; y: number }; to: { x: number; y: number }; stops: GradStop[]; units?: GradientUnits; interpolate?: ColorSpace; opacity?: number }\n | { fill: 'radial-gradient'; center: { x: number; y: number }; radius: number; stops: GradStop[]; units?: GradientUnits; interpolate?: ColorSpace; opacity?: number }\n | { fill: 'conic-gradient'; center: { x: number; y: number }; angle: number; stops: GradStop[]; units?: GradientUnits; interpolate?: ColorSpace; opacity?: number };\n\n/**\n * Which coordinate space a gradient's geometry (`from`/`to`, `center`,\n * `radius`) is expressed in. SVG's `gradientUnits`, plus an option for\n * paints that are themselves viewport furniture.\n *\n * - `'bounds'`: fractions of the painted node's bounding box, `0..1` on each\n * axis — SVG `objectBoundingBox`. Resolved by the node painter, before the\n * renderer sees it, so the paint follows the node through moves, resizes\n * and rotation. What a gradient on a scene node wants.\n * - `'local'`: the coordinate space the geometry was handed to the renderer\n * in — the enclosing group's frame. For draw commands a consumer builds\n * itself, where \"the coordinates I just wrote\" is the useful frame.\n * - `'world'`: scene coordinates. The paint stays put under pan and zoom\n * while the geometry moves through it. SVG `userSpaceOnUse`. Requires the\n * renderer to have been handed a view matrix; falls back to `'screen'`\n * when it has not.\n * - `'screen'`: CSS pixels of the drawing surface. For overlays and\n * viewport-fixed washes that should not move with the content at all.\n *\n * Defaults to `'screen'`, which is the behavior every gradient had before\n * this field existed.\n */\nexport type GradientUnits = 'bounds' | 'local' | 'world' | 'screen';\n\n/**\n * A built-in tile, described as plain data. The serializable half of the\n * pattern paint: `resolvePatternSpec()` turns one into a `TextureHandle`\n * at paint time, memoized so identical specs share a texture.\n *\n * `size` is the tile's edge length, and doubles as its extent in paint\n * space — a bigger `size` rasterizes a bigger tile rather than magnifying\n * a small one, which is why there is no separate scale field.\n */\nexport interface TilePatternSpec {\n tile: 'hatch' | 'crosshatch' | 'dots' | 'chunks';\n color: string;\n /** `chunks` only — omit for a transparent tile background. */\n bg?: string;\n size?: number;\n /** `hatch` / `crosshatch`. */\n lineWidth?: number;\n /** `dots`. */\n radius?: number;\n /** `chunks`. */\n density?: number;\n chunkSize?: number;\n seed?: number;\n}\n\n/** A single color stop within a gradient. `offset` is in 0..1. */\nexport interface GradStop {\n offset: number;\n color: string;\n}\n\n/** The gradient members of `FillStyle`, as one type. What a gradient editor\n * edits, and what the gradient-specific helpers accept. */\nexport type GradientFill = Extract<\n FillStyle,\n { fill: 'linear-gradient' | 'radial-gradient' | 'conic-gradient' }\n>;\n\n/** `GradientFill['fill']` — the three gradient discriminants on their own. */\nexport type GradientKind = GradientFill['fill'];\n\n/**\n * Where a stroke sits relative to the geometric edge it strokes.\n *\n * - `'center'` (default): canvas-native — half the stroke width sits inside\n * the geometry, half outside.\n * - `'inner'`: the entire stroke lies inside the geometry. The outer edge of\n * the stroke coincides with the geometric edge.\n * - `'outer'`: the entire stroke lies outside the geometry. The inner edge\n * of the stroke coincides with the geometric edge.\n *\n * Mirrors the (proposed) SVG `stroke-alignment` property. Honoring `inner`\n * or `outer` is the renderer's responsibility — for axis-aligned rects, the\n * kit shifts coordinates by `width / 2`. For arbitrary paths, renderers\n * typically use a stencil mask of the stroked path against the geometry.\n */\nexport type StrokeAlign = 'center' | 'inner' | 'outer';\n\n/**\n * The kit's built-in marker vocabulary, open on the string the way\n * `PaintKind` is so a consumer's registered key typechecks.\n */\nexport type KitMarkerKey =\n | 'arrow' | 'arrow-open' | 'arrow-concave'\n | 'diamond' | 'diamond-hollow'\n | 'circle' | 'square' | 'bar';\n/** A marker shape's key: a built-in {@link KitMarkerKey} or a consumer-registered name. */\nexport type MarkerKey = KitMarkerKey | (string & {});\n\n/**\n * A marker on one end (or every interior vertex) of a stroke.\n *\n * `size` is the length of one marker unit, and replaces the stroke width\n * rather than multiplying it: a bare number is world units, however wide the\n * line. Omitted, one unit is the resolved stroke width — SVG's\n * `markerUnits=\"strokeWidth\"`; given, it is `userSpaceOnUse`. A `{ px }` size\n * holds its screen size through a zoom, as a `{ px }` stroke width does.\n */\nexport type MarkerRef = MarkerKey | { key: MarkerKey; size?: ScreenLength };\n\n/**\n * A length the author states either in world units (a plain number) or in\n * screen pixels (`{ px }`), resolved against the accumulated transform scale\n * wherever it is consumed — so a `{ px }` length holds its on-screen size as\n * the view zooms, with no call-site arithmetic.\n */\nexport type ScreenLength = number | { px: number };\n\n/**\n * Resolve a {@link ScreenLength} to world units. A non-finite or zero scale\n * has no world to divide into, so the pixel count passes through unchanged\n * rather than becoming `Infinity`.\n */\nexport function resolveScreenLength(value: ScreenLength, scale: number): number {\n if (typeof value === 'number') return value;\n if (!Number.isFinite(scale) || scale === 0) return value.px;\n return value.px / scale;\n}\n\n/** Stroke style: a FillStyle plus structural line parameters. */\nexport interface Stroke {\n /**\n * Omitted, the stroke paints nothing — the same \"no paint\" a `fill: null`\n * says for a node's fill. Documents written before mid-2026 can hold a\n * stroke whose other fields were seeded without one, and the type is\n * optional so every reader has to answer for that rather than throw on it.\n */\n paint?: FillStyle;\n /** World units, or `{ px }` for screen pixels — resolved against the\n * accumulated transform scale at draw time, so it holds its on-screen\n * thickness as the view zooms. */\n width?: ScreenLength;\n /** Per `CanvasRenderingContext2D.setLineDash` — empty/omitted = solid. */\n dash?: number[];\n /** Marker at the first vertex of each open subpath, rotated to point back\n * along the line (SVG's `auto-start-reverse`, as the only behavior). */\n markerStart?: MarkerRef;\n /** Marker at every interior authored vertex, on the bisector of the\n * incoming and outgoing directions. Never insets the stroke. */\n markerMid?: MarkerRef;\n /** Marker at the last vertex of each open subpath. */\n markerEnd?: MarkerRef;\n cap?: 'butt' | 'round' | 'square';\n join?: 'miter' | 'round' | 'bevel';\n /**\n * Miter join fallback threshold. When the miter length exceeds\n * `miterLimit * width / 2`, the join falls back to a bevel. Default 4,\n * matching SVG — which is also what the kit's own serializer implies when\n * it omits the attribute for an unset field. Canvas2D's 10 lets an acute\n * corner throw a spike four times the half-width.\n */\n miterLimit?: number;\n /** Where the stroke sits relative to the geometric edge. Default `'center'`. */\n align?: StrokeAlign;\n /**\n * Per-anchor RGBA, flat (length = 4 × countPathAnchors(path)). Each\n * value in 0..1. Arc-length interpolated across the tessellated ribbon\n * between consecutive anchors. When set, `paint` is still required —\n * its `opacity` (and color, as a placeholder) flow through the shader.\n */\n vertexColors?: number[];\n /**\n * Per-anchor stroke width (length = `countPathAnchors(path)`). When set,\n * the tessellator interpolates half-widths along each segment to produce\n * a tapered ribbon. `width` is used as the fallback for any anchor whose\n * entry is missing or non-finite. Pressure-driven pencil strokes use\n * this; pair with `pressureToWidth` to derive widths from stylus input.\n *\n * Joins between adjacent segments whose widths differ by more than\n * `varyingWidthJoinThreshold` (default 1.5×) are forced to bevel\n * regardless of the `join` setting — miter math is unstable when widths\n * vary across the corner; smooth round joins with mismatched widths\n * are a future enhancement.\n */\n vertexWidths?: number[];\n /**\n * Max width ratio (greater / lesser) at which a non-bevel join is\n * preserved when `vertexWidths` causes adjacent segments to differ.\n * Beyond this ratio the join falls back to bevel. Default 1.5. Ignored\n * when `vertexWidths` is absent.\n */\n varyingWidthJoinThreshold?: number;\n}\n\n/**\n * Inflate (positive) or deflate (negative) a rect to honor `align` when\n * stroking it. Returns the rect to pass to a stroked-rect renderer. `width`\n * is the stroke width (defaults to 1 to match canvas).\n *\n * Pure geometry helper — no rendering side effects. Used by path\n * tessellation and the selection overlay to produce a rect whose\n * center-aligned stroke visually coincides with the requested\n * inner/outer-aligned stroke of the original rect.\n */\nexport function alignedStrokeRect(\n rect: { x: number; y: number; width: number; height: number },\n align: StrokeAlign,\n width = 1,\n): { x: number; y: number; width: number; height: number } {\n if (align === 'center') return rect;\n // For 'inner', shift inward by width/2 so the stroke's outer edge coincides\n // with the geometric edge. For 'outer', shift outward.\n const sign = align === 'inner' ? -1 : 1;\n const d = (sign * width) / 2;\n return {\n x: rect.x - d,\n y: rect.y - d,\n width: rect.width + 2 * d,\n height: rect.height + 2 * d,\n };\n}\n\n/**\n * The named line styles a `Stroke.dash` array reads as.\n *\n * `custom` is what an imported array that matches no preset reads as — it is\n * reportable, not authorable: there is no array it maps back to.\n */\nexport type StrokeDashStyle = 'solid' | 'dashed' | 'dotted' | 'custom';\n\n/**\n * Dash and gap lengths of the presets, **as multiples of the stroke width**.\n *\n * SVG dash lengths are absolute, so a fixed pattern is a different style at\n * every width: `[6, 3]` is dots on a hairline and a railroad on a 20px\n * stroke. Scaling by the width is what makes \"dashed\" one style.\n */\nexport const STROKE_DASH_RATIOS = {\n dashed: [3, 2],\n dotted: [1, 2],\n} as const satisfies Record<'dashed' | 'dotted', readonly [number, number]>;\n\n/** `width` as a plain number — a `{ px }` width is read at scale 1, matching\n * what an unresolved stroke reaching the tessellator gets. */\nfunction dashWidth(width: number | { px: number } | undefined): number {\n const w = typeof width === 'object' ? width.px : (width ?? 1);\n return Number.isFinite(w) && w > 0 ? w : 1;\n}\n\n/**\n * The `Stroke.dash` array for a named style at `width`, or `undefined` for\n * `solid` — which is stored as no dash at all, not as an empty pattern.\n *\n * `custom` has no array of its own and returns `undefined`; a caller that\n * offers it as a choice should refuse the choice rather than call this.\n */\nexport function dashForStrokeStyle(\n style: StrokeDashStyle,\n width: number | { px: number } | undefined,\n): number[] | undefined {\n if (style !== 'dashed' && style !== 'dotted') return undefined;\n const w = dashWidth(width);\n return STROKE_DASH_RATIOS[style].map((r) => r * w);\n}\n\n/**\n * The style a stored `dash` reads as at `width`. Absent or empty is `solid`;\n * an array matching neither preset is `custom`.\n */\nexport function strokeDashStyleOf(\n dash: readonly number[] | undefined,\n width: number | { px: number } | undefined,\n): StrokeDashStyle {\n if (dash === undefined || dash.length === 0 || dash.every((v) => v === 0)) return 'solid';\n const w = dashWidth(width);\n for (const style of ['dashed', 'dotted'] as const) {\n const preset = STROKE_DASH_RATIOS[style];\n // Tolerance is relative to the width: the presets are multiples of it, and\n // a round-tripped array carries the serializer's decimal trimming.\n if (dash.length === preset.length && preset.every((r, i) => Math.abs(dash[i] - r * w) <= w * 1e-3)) {\n return style;\n }\n }\n return 'custom';\n}\n\n/** Region a fill is clipped to. */\nexport interface Region {\n x: number;\n y: number;\n w: number;\n h: number;\n shape: 'rectangle' | 'circle';\n}\n","// sRGB ↔ OKLab conversion. Reference: https://bottosson.github.io/posts/oklab/\n\nconst SRGB_TO_LINEAR: Float64Array = (() => {\n const lut = new Float64Array(256);\n for (let i = 0; i < 256; i++) {\n const c = i / 255;\n lut[i] = c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n }\n return lut;\n})();\n\nfunction linearToSrgbByte(c: number): number {\n if (c <= 0) return 0;\n if (c >= 1) return 255;\n const v = c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;\n return Math.round(v * 255);\n}\n\n/** 0..1 float channel to the 8-bit index the LUTs are cut for. Rounds and\n * clamps; `& 0xff` would truncate, and wrap anything out of range. */\nconst f2u = (v: number): number => Math.max(0, Math.min(255, Math.round(v * 255)));\n\n/**\n * Convert a 0..1 float sRGB triple to OKLab — the renderer's own color space,\n * and what a caller holding a `resolveColor` result has. Rounds into the u8\n * grid the way every other float→u8 crossing in this file does, rather than\n * leaving each caller to pick a convention.\n */\nexport function srgbFloatToOklab(r: number, g: number, b: number): [number, number, number] {\n return srgbU8ToOklab(f2u(r), f2u(g), f2u(b));\n}\n\n/** Convert an 8-bit sRGB triple to OKLab. Channels are indices into a 256-entry\n * LUT: pass integers, or `srgbFloatToOklab` for 0..1 floats. */\nexport function srgbU8ToOklab(r: number, g: number, b: number): [number, number, number] {\n return linearSrgbToOklab(SRGB_TO_LINEAR[r & 0xff], SRGB_TO_LINEAR[g & 0xff], SRGB_TO_LINEAR[b & 0xff]);\n}\n\n/** Linear-light sRGB (0..1 floats, unclamped) to OKLab. */\nexport function linearSrgbToOklab(rl: number, gl: number, bl: number): [number, number, number] {\n const l = 0.4122214708 * rl + 0.5363325363 * gl + 0.0514459929 * bl;\n const m = 0.2119034982 * rl + 0.6806995451 * gl + 0.1073969566 * bl;\n const s = 0.0883024619 * rl + 0.2817188376 * gl + 0.6299787005 * bl;\n const lp = Math.cbrt(l);\n const mp = Math.cbrt(m);\n const sp = Math.cbrt(s);\n return [\n 0.2104542553 * lp + 0.7936177850 * mp - 0.0040720468 * sp,\n 1.9779984951 * lp - 2.4285922050 * mp + 0.4505937099 * sp,\n 0.0259040371 * lp + 0.7827717662 * mp - 0.8086757660 * sp,\n ];\n}\n\n/** OKLab to linear-light sRGB. Not gamut-clipped: out-of-gamut colors come\n * back with channels outside 0..1. */\nexport function oklabToLinearSrgb(L: number, A: number, B: number): [number, number, number] {\n const lp = L + 0.3963377774 * A + 0.2158037573 * B;\n const mp = L - 0.1055613458 * A - 0.0638541728 * B;\n const sp = L - 0.0894841775 * A - 1.2914855480 * B;\n const l = lp * lp * lp;\n const m = mp * mp * mp;\n const s = sp * sp * sp;\n return [\n +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s,\n ];\n}\n\nfunction inGamut(rl: number, gl: number, bl: number): boolean {\n // Small epsilon absorbs float-roundtrip noise on pure-primary colors.\n const eps = 1e-6;\n return (\n rl >= -eps && rl <= 1 + eps &&\n gl >= -eps && gl <= 1 + eps &&\n bl >= -eps && bl <= 1 + eps\n );\n}\n\nfunction clipToGamut(L: number, A: number, B: number): [number, number, number] {\n let [rl, gl, bl] = oklabToLinearSrgb(L, A, B);\n if (inGamut(rl, gl, bl)) return [rl, gl, bl];\n let lo = 0;\n let hi = 1;\n // 5 iterations → ~3% chroma precision; sufficient for u8 output.\n for (let i = 0; i < 5; i++) {\n const t = (lo + hi) / 2;\n [rl, gl, bl] = oklabToLinearSrgb(L, A * t, B * t);\n if (inGamut(rl, gl, bl)) lo = t; else hi = t;\n }\n [rl, gl, bl] = oklabToLinearSrgb(L, A * lo, B * lo);\n return [rl, gl, bl];\n}\n\n/** Convert OKLab back to an 8-bit sRGB triple, clamped into gamut. */\nexport function oklabToSrgbU8(L: number, A: number, B: number): [number, number, number] {\n const [rl, gl, bl] = clipToGamut(L, A, B);\n return [linearToSrgbByte(rl), linearToSrgbByte(gl), linearToSrgbByte(bl)];\n}\n\n/** Blend two 8-bit sRGB colors through OKLab. Perceptually even, and it does\n * not pass through the muddy midpoints an sRGB blend produces between\n * complementary hues. */\nexport function lerpOklab(\n from: readonly [number, number, number],\n to: readonly [number, number, number],\n t: number,\n): [number, number, number] {\n return [\n from[0] + (to[0] - from[0]) * t,\n from[1] + (to[1] - from[1]) * t,\n from[2] + (to[2] - from[2]) * t,\n ];\n}\n\n/**\n * `color-mix(in oklab, a p%, b)` for two 0..1 sRGBA colors, `p` as 0..1: the\n * channels mix premultiplied by alpha, as CSS does, so a transparent side\n * lends the result its opacity and none of its color.\n */\nexport function mixOklab(\n a: readonly [number, number, number, number],\n b: readonly [number, number, number, number],\n p: number,\n): [number, number, number, number] {\n const alpha = a[3] * p + b[3] * (1 - p);\n if (alpha === 0) return [0, 0, 0, 0];\n const la = srgbFloatToOklab(a[0], a[1], a[2]);\n const lb = srgbFloatToOklab(b[0], b[1], b[2]);\n const mix = (i: number) => (la[i] * a[3] * p + lb[i] * b[3] * (1 - p)) / alpha;\n const [r, g, bl] = oklabToSrgbU8(mix(0), mix(1), mix(2));\n return [r / 255, g / 255, bl / 255, alpha];\n}\n\n/** Convert OKLab (L, a, b) to OKLCh (L, C, h). h is in radians, range [-π, π]. */\nexport function oklabToOklch(L: number, A: number, B: number): [number, number, number] {\n const C = Math.hypot(A, B);\n const h = Math.atan2(B, A);\n return [L, C, h];\n}\n\n/** Convert OKLCh (L, C, h) to OKLab (L, a, b). h is in radians. */\nexport function oklchToOklab(L: number, C: number, h: number): [number, number, number] {\n return [L, C * Math.cos(h), C * Math.sin(h)];\n}\n\n/** Lerp OKLCh values with shortest-arc hue interpolation. Lightness and\n * chroma lerp linearly. When chroma is near zero on either endpoint, hue\n * is taken from the other endpoint (avoids hue snap-from-undefined).\n * h inputs are in radians. */\nexport function lerpOklch(\n from: readonly [number, number, number],\n to: readonly [number, number, number],\n t: number,\n): [number, number, number] {\n const [L1, C1, h1Raw] = from;\n const [L2, C2, h2Raw] = to;\n const C_EPS = 1e-4;\n // When one endpoint is near-achromatic, take hue from the other endpoint\n // to avoid spurious arc rotation through undefined hue space.\n const h1 = C1 < C_EPS ? h2Raw : h1Raw;\n const h2 = C2 < C_EPS ? h1Raw : h2Raw;\n const TWO_PI = Math.PI * 2;\n // Shortest-arc delta in [-π, π].\n let dh = h2 - h1;\n while (dh > Math.PI) dh -= TWO_PI;\n while (dh < -Math.PI) dh += TWO_PI;\n return [\n L1 + (L2 - L1) * t,\n C1 + (C2 - C1) * t,\n h1 + dh * t,\n ];\n}\n\n/** Which space a color blend is computed in. `'rgb'` is cheapest; `'oklab'`\n * is perceptually even; `'oklch'` additionally travels around the hue wheel\n * rather than through it. */\nexport type ColorSpace = 'rgb' | 'oklab' | 'oklch';\n\nconst u2f = (v: number): number => v / 255;\n\n/** Lerp a flat RGBA color array `from` toward `to`. Inputs are 0..1\n * floats (the renderer's color space); outputs are 0..1 floats too.\n * Alpha is always linearly lerped; RGB channels are lerped in the\n * requested color space. OKLab / OKLCh paths bounce through u8 because\n * the gamma-correction LUT and gamut-clip routines are byte-keyed —\n * the round-trip is lossy at <1% per channel, well under the visible\n * threshold for these animations. */\nexport function lerpColorArray(\n from: readonly number[],\n to: readonly number[],\n t: number,\n space: ColorSpace = 'rgb',\n): number[] {\n if (from.length !== to.length) {\n throw new Error(`lerpColorArray: length mismatch (from=${from.length}, to=${to.length})`);\n }\n if (from.length % 4 !== 0) {\n throw new Error(`lerpColorArray: length ${from.length} not divisible by 4`);\n }\n const out = new Array<number>(from.length);\n const n = from.length / 4;\n if (space === 'rgb') {\n // Pure float lerp — no rounding (which previously discretized 0..1\n // inputs to 0/1, giving the cycle its 'choppy 8-corner' look).\n for (let i = 0; i < from.length; i++) {\n out[i] = from[i] + (to[i] - from[i]) * t;\n }\n return out;\n }\n if (space === 'oklch') {\n for (let i = 0; i < n; i++) {\n const k = i * 4;\n const fLab = srgbU8ToOklab(f2u(from[k]), f2u(from[k + 1]), f2u(from[k + 2]));\n const tLab = srgbU8ToOklab(f2u(to[k]), f2u(to[k + 1]), f2u(to[k + 2]));\n const fLch = oklabToOklch(fLab[0], fLab[1], fLab[2]);\n const tLch = oklabToOklch(tLab[0], tLab[1], tLab[2]);\n const midLch = lerpOklch(fLch, tLch, t);\n const midLab = oklchToOklab(midLch[0], midLch[1], midLch[2]);\n const [r, g, b] = oklabToSrgbU8(midLab[0], midLab[1], midLab[2]);\n out[k] = u2f(r);\n out[k + 1] = u2f(g);\n out[k + 2] = u2f(b);\n out[k + 3] = from[k + 3] + (to[k + 3] - from[k + 3]) * t;\n }\n return out;\n }\n for (let i = 0; i < n; i++) {\n const k = i * 4;\n const fLab = srgbU8ToOklab(f2u(from[k]), f2u(from[k + 1]), f2u(from[k + 2]));\n const tLab = srgbU8ToOklab(f2u(to[k]), f2u(to[k + 1]), f2u(to[k + 2]));\n const mid = lerpOklab(fLab, tLab, t);\n const [r, g, b] = oklabToSrgbU8(mid[0], mid[1], mid[2]);\n out[k] = u2f(r);\n out[k + 1] = u2f(g);\n out[k + 2] = u2f(b);\n out[k + 3] = from[k + 3] + (to[k + 3] - from[k + 3]) * t;\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// OKLCh in degrees\n// ---------------------------------------------------------------------------\n\n/**\n * OKLCh with the hue in **degrees**, and `#rrggbb` on the other side.\n *\n * The helpers above take radians, because that is what the math wants. Every\n * consumer that authors colors — a theme ramp, a palette generator — wants\n * degrees and a hex string, and two packages independently built the same\n * wrapper before this existed.\n */\nexport interface OklchDeg {\n readonly L: number;\n readonly C: number;\n /** 0..360. */\n readonly H: number;\n}\n\nconst hex2 = (v: number): string => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, '0');\n\n/**\n * OKLCh (hue in degrees) to `#rrggbb`. Over-saturated requests come back at\n * the gamut boundary: `oklabToSrgbU8` clips chroma at constant lightness, which\n * is what lets a caller find a hue's ceiling by asking for far more than exists.\n */\nexport function oklchDegToHex(L: number, C: number, hueDeg: number): string {\n const [l, a, b] = oklchToOklab(L, C, (hueDeg * Math.PI) / 180);\n const [r, g, bl] = oklabToSrgbU8(l, a, b);\n return `#${hex2(r)}${hex2(g)}${hex2(bl)}`;\n}\n\n/** `#rrggbb` to OKLCh with the hue wrapped into 0..360. */\nexport function hexToOklchDeg(hex: string): OklchDeg {\n const n = Number.parseInt(hex.slice(1), 16);\n const [L, A, B] = srgbU8ToOklab((n >> 16) & 255, (n >> 8) & 255, n & 255);\n const [l, c, h] = oklabToOklch(L, A, B);\n return { L: l, C: c, H: ((((h * 180) / Math.PI) % 360) + 360) % 360 };\n}\n\n// ---------------------------------------------------------------------------\n// Float sRGB transfer, HSL, and interpolation across spaces\n// ---------------------------------------------------------------------------\n\n/** sRGB-encoded channel (0..1) to linear light. Unclamped; odd-symmetric\n * below zero, as CSS `srgb-linear` extends it. */\nexport function srgbToLinear(c: number): number {\n const a = Math.abs(c);\n const v = a <= 0.04045 ? a / 12.92 : Math.pow((a + 0.055) / 1.055, 2.4);\n return c < 0 ? -v : v;\n}\n\n/** Linear-light channel to sRGB encoding (0..1). Unclamped. */\nexport function linearToSrgb(c: number): number {\n const a = Math.abs(c);\n const v = a <= 0.0031308 ? a * 12.92 : 1.055 * Math.pow(a, 1 / 2.4) - 0.055;\n return c < 0 ? -v : v;\n}\n\n/** HSL to sRGB. Hue in degrees, saturation, lightness and output all 0..1. */\nexport function hslToSrgb(h: number, s: number, l: number): [number, number, number] {\n if (s === 0) return [l, l, l];\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n const hk = h / 360;\n return [hueToChannel(p, q, hk + 1 / 3), hueToChannel(p, q, hk), hueToChannel(p, q, hk - 1 / 3)];\n}\n\nfunction hueToChannel(p: number, q: number, t: number): number {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n}\n\n/** sRGB (0..1) to HSL: `[hue°, saturation, lightness]`, hue in 0..360. An\n * achromatic color reports hue 0 and saturation 0. */\nexport function srgbToHsl(r: number, g: number, b: number): [number, number, number] {\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n const d = max - min;\n if (d === 0) return [0, 0, l];\n const s = d / (1 - Math.abs(2 * l - 1));\n let h: number;\n if (max === r) h = ((g - b) / d) % 6;\n else if (max === g) h = (b - r) / d + 2;\n else h = (r - g) / d + 4;\n return [(((h * 60) % 360) + 360) % 360, s, l];\n}\n\n/**\n * The space a color interpolation runs in, spelled as CSS `color-mix()` spells\n * them. `'srgb'` and `'srgb-linear'` blend gamma-encoded and linear-light\n * channels; `'oklab'` blends perceptual coordinates; `'oklch'` and `'hsl'` are\n * polar, so their hue travels around the wheel rather than through it.\n *\n * Distinct from {@link ColorSpace}, the gradient and animation vocabulary,\n * which keeps its `'rgb'` spelling and its byte-precision paths.\n */\nexport type ColorInterpolationSpace = 'oklch' | 'oklab' | 'hsl' | 'srgb' | 'srgb-linear';\n\n/** Which way a polar space's hue goes between two endpoints, as CSS\n * `hue-interpolation-method`: the arc of at most 180°, or the other one. */\nexport type HueInterpolation = 'shorter' | 'longer';\n\n/** An endpoint with less chroma (OKLCH) or saturation (HSL) than this has no\n * hue of its own. */\nconst ACHROMATIC_EPS = 1e-4;\n\nfunction lerpHueDeg(h1: number, h2: number, t: number, method: HueInterpolation): number {\n let dh = (((h2 - h1) % 360) + 360) % 360;\n if (method === 'shorter') {\n if (dh > 180) dh -= 360;\n } else if (dh > 0 && dh < 180) {\n dh -= 360;\n }\n return (((h1 + dh * t) % 360) + 360) % 360;\n}\n\ntype Polar = readonly [radius: number, hueDeg: number, axis: number];\n\nfunction lerpPolar(a: Polar, b: Polar, t: number, method: HueInterpolation): [number, number, number] {\n const h1 = a[0] < ACHROMATIC_EPS ? b[1] : a[1];\n const h2 = b[0] < ACHROMATIC_EPS ? a[1] : b[1];\n return [a[0] + (b[0] - a[0]) * t, lerpHueDeg(h1, h2, t, method), a[2] + (b[2] - a[2]) * t];\n}\n\ntype Rgb = readonly [number, number, number];\n\nconst lerp3 = (a: Rgb, b: Rgb, t: number): [number, number, number] => [\n a[0] + (b[0] - a[0]) * t,\n a[1] + (b[1] - a[1]) * t,\n a[2] + (b[2] - a[2]) * t,\n];\n\nconst clamp01 = (v: number): number => (v < 0 ? 0 : v > 1 ? 1 : v);\n\nconst srgbToOklabFloat = (c: Rgb): [number, number, number] =>\n linearSrgbToOklab(srgbToLinear(c[0]), srgbToLinear(c[1]), srgbToLinear(c[2]));\n\nfunction oklabToSrgbClipped(L: number, A: number, B: number): [number, number, number] {\n const [rl, gl, bl] = clipToGamut(L, A, B);\n return [clamp01(linearToSrgb(rl)), clamp01(linearToSrgb(gl)), clamp01(linearToSrgb(bl))];\n}\n\n/**\n * Interpolate between two sRGB colors (0..1 floats) in `space`, at `t` in 0..1.\n * Float precision throughout, with no byte round-trip. The result is sRGB;\n * only OKLab and OKLCH blends can leave gamut, and those come back\n * chroma-clipped at constant OKLab lightness.\n *\n * `hue` applies to the polar spaces only. An endpoint with no chroma (OKLCH)\n * or no saturation (HSL) borrows the other endpoint's hue, so a ramp to white\n * or black holds its hue instead of sweeping from red.\n */\nexport function interpolateSrgb(\n from: Rgb,\n to: Rgb,\n t: number,\n space: ColorInterpolationSpace = 'oklch',\n hue: HueInterpolation = 'shorter',\n): [number, number, number] {\n switch (space) {\n case 'srgb':\n return lerp3(from, to, t);\n case 'srgb-linear': {\n const lin = (c: Rgb): Rgb => [srgbToLinear(c[0]), srgbToLinear(c[1]), srgbToLinear(c[2])];\n const [r, g, b] = lerp3(lin(from), lin(to), t);\n return [linearToSrgb(r), linearToSrgb(g), linearToSrgb(b)];\n }\n case 'oklab': {\n const [L, A, B] = lerp3(srgbToOklabFloat(from), srgbToOklabFloat(to), t);\n return oklabToSrgbClipped(L, A, B);\n }\n case 'oklch': {\n const polar = (c: Rgb): Polar => {\n const [L, C, h] = oklabToOklch(...srgbToOklabFloat(c));\n return [C, (((h * 180) / Math.PI) % 360 + 360) % 360, L];\n };\n const [C, H, L] = lerpPolar(polar(from), polar(to), t, hue);\n const [l, a, b] = oklchToOklab(L, C, (H * Math.PI) / 180);\n return oklabToSrgbClipped(l, a, b);\n }\n case 'hsl': {\n const polar = (c: Rgb): Polar => {\n const [h, s, l] = srgbToHsl(c[0], c[1], c[2]);\n return [s, h, l];\n };\n const [s, h, l] = lerpPolar(polar(from), polar(to), t, hue);\n return hslToSrgb(h, s, l);\n }\n }\n}\n","import { oklabToSrgbU8, srgbU8ToOklab } from './colorSpaces';\n\nconst hex2 = (v: number): string => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, '0');\n\nfunction readHex(color: string): [number, number, number] | null {\n const m = /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(color.trim());\n if (!m) return null;\n let h = m[1];\n if (h.length === 3) h = h.replace(/./g, (c) => c + c);\n const n = Number.parseInt(h.slice(0, 6), 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\n/**\n * A line color that reads against `background` — a grid, a rule, a guide\n * drawn over a surface whose color the document chooses, where theme tokens\n * would be keyed to the chrome instead.\n *\n * The line is the background moved `strength` in OKLab lightness (0..1) away\n * from its nearer end: darker over light, lighter over dark, with its hue and\n * chroma kept. Returns `#rrggbb`; the background's alpha is ignored. A color\n * that is not hex comes back as black at `strength` alpha.\n */\nexport function contrastLineColor(background: string, strength: number): string {\n const rgb = readHex(background);\n if (!rgb) return `rgba(0, 0, 0, ${strength})`;\n const [L, A, B] = srgbU8ToOklab(rgb[0], rgb[1], rgb[2]);\n const next = L > 0.5 ? Math.max(0, L - strength) : Math.min(1, L + strength);\n const [r, g, b] = oklabToSrgbU8(next, A, B);\n return `#${hex2(r)}${hex2(g)}${hex2(b)}`;\n}\n","import { oklabToSrgbU8, oklchToOklab } from './colorSpaces';\n\n/**\n * A color given directly. `coords` are in the order CSS Color 4 uses for\n * `space` — `srgb` as 0..1 r, g, b; `oklab` as L, a, b; `oklch` as L, C and a\n * hue in degrees. `space` is open: a palette may carry colors in spaces the kit\n * cannot convert, and `colorLiteralToHex` answers `null` for those.\n */\nexport interface ColorLiteral {\n readonly space: string;\n readonly coords: readonly number[];\n /** 0..1. Omitted means opaque. */\n readonly alpha?: number;\n}\n\n/** A color named rather than given: a palette entry, or whatever the resolver's\n * `external` callback answers to. `index` picks from a sequence entry; a\n * single-color entry answers only to 0. */\nexport interface ColorRef {\n readonly ref: string;\n readonly index?: number;\n}\n\n/** What a {@link ColorFn} or {@link ColorSeqFn} is handed. */\nexport interface ColorFnContext {\n /** Resolve any source against the same palette and external lookup. */\n resolve(source: ColorSource): ColorLiteral | null;\n}\n\n/** A color computed at resolve time — typically derived from another entry. */\nexport type ColorFn = (ctx: ColorFnContext) => ColorSource | null | undefined;\n\n/** Anything that resolves to a color: a literal, a named reference, or a function computing one. */\nexport type ColorSource = ColorLiteral | ColorRef | ColorFn;\n\n/** A sequence of colors, read lazily, so it may be endless. A factory rather\n * than an iterable because a generator object can be iterated only once:\n * pass the `function*` itself. */\nexport type ColorSeqFn = (ctx: ColorFnContext) => Iterable<ColorSource>;\n\n/** A named palette slot holding either one color (`color`) or a sequence (`colors`) that refs index into. */\nexport type PaletteEntry =\n | { readonly name: string; readonly color: ColorSource }\n | { readonly name: string; readonly colors: ColorSeqFn };\n\n/** A set of named colors that {@link ColorRef}s resolve against. When two entries share a name, the first wins. */\nexport interface Palette {\n readonly entries: readonly PaletteEntry[];\n}\n\n/** Answers a ref the palette has no entry for. */\nexport type ExternalColors = (ref: ColorRef) => ColorSource | null | undefined;\n\ntype Visit = (s: ColorSource | null | undefined, visiting: ReadonlySet<string>) => ColorLiteral | null;\n\nfunction nth<T>(items: Iterable<T>, n: number): T | undefined {\n if (!Number.isInteger(n) || n < 0) return undefined;\n let i = 0;\n for (const item of items) if (i++ === n) return item;\n return undefined;\n}\n\nconst refKey = (name: string, index: number): string => `${index}:${name}`;\n\nfunction resolver(palette: Palette, external?: ExternalColors) {\n const byName = new Map<string, PaletteEntry>();\n for (const e of palette.entries) if (!byName.has(e.name)) byName.set(e.name, e);\n\n const ctx = (visiting: ReadonlySet<string>): ColorFnContext => ({ resolve: (s) => visit(s, visiting) });\n\n const visit: Visit = (s, visiting) => {\n if (s == null) return null;\n if (typeof s === 'function') return visit(s(ctx(visiting)), visiting);\n if ('space' in s) return s;\n const index = s.index ?? 0;\n const key = refKey(s.ref, index);\n if (visiting.has(key)) return null;\n const next = new Set(visiting).add(key);\n const entry = byName.get(s.ref);\n if (!entry) return visit(external?.(s), next);\n if ('color' in entry) return index === 0 ? visit(entry.color, next) : null;\n return visit(nth(entry.colors(ctx(next)), index), next);\n };\n\n return { byName, ctx, visit };\n}\n\n/**\n * Resolve `source` to a literal. A ref names a palette entry first, then goes\n * to `external`; whatever either answers is resolved in turn. A name nothing\n * answers, an index past a sequence's end, or a chain that comes back to a ref\n * it is already resolving gives `null`.\n */\nexport function resolvePaletteColor(\n palette: Palette,\n source: ColorSource,\n external?: ExternalColors,\n): ColorLiteral | null {\n return resolver(palette, external).visit(source, new Set());\n}\n\n/**\n * Every color under `name`, resolved lazily in order — one for a single-color\n * entry, as many as the sequence yields for a `colors` entry, nothing for a\n * name the palette lacks. Stop early to read an endless sequence.\n */\nexport function* resolvePaletteColors(\n palette: Palette,\n name: string,\n external?: ExternalColors,\n): Generator<ColorLiteral | null> {\n const { byName, ctx, visit } = resolver(palette, external);\n const entry = byName.get(name);\n if (!entry) return;\n if ('color' in entry) {\n yield visit(entry.color, new Set([refKey(name, 0)]));\n return;\n }\n let i = 0;\n for (const item of entry.colors(ctx(new Set()))) {\n yield visit(item, new Set([refKey(name, i++)]));\n }\n}\n\nconst hex2 = (v: number): string => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, '0');\n\n/** `#rrggbb`, or `#rrggbbaa` below full opacity. `null` for a space the kit\n * cannot convert, or fewer than three coordinates. */\nexport function colorLiteralToHex(color: ColorLiteral): string | null {\n const [x, y, z] = color.coords;\n if (z === undefined) return null;\n let rgb: readonly number[];\n switch (color.space) {\n case 'srgb':\n rgb = [x * 255, y * 255, z * 255];\n break;\n case 'oklab':\n rgb = oklabToSrgbU8(x, y, z);\n break;\n case 'oklch':\n rgb = oklabToSrgbU8(...oklchToOklab(x, y, (z * Math.PI) / 180));\n break;\n default:\n return null;\n }\n const a = color.alpha ?? 1;\n return `#${rgb.map(hex2).join('')}${a < 1 ? hex2(a * 255) : ''}`;\n}\n\n/** `#rrggbb` or `#rrggbbaa` as an `srgb` literal; `null` for anything else. */\nexport function hexToColorLiteral(hex: string): ColorLiteral | null {\n if (!/^#(?:[0-9a-f]{6}|[0-9a-f]{8})$/i.test(hex)) return null;\n const byte = (i: number): number => Number.parseInt(hex.slice(i, i + 2), 16) / 255;\n const coords = [byte(1), byte(3), byte(5)];\n return hex.length === 9 ? { space: 'srgb', coords, alpha: byte(7) } : { space: 'srgb', coords };\n}\n"]}
|