@weasel-js/geom 1.9.4 → 1.10.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/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { a as PolygonPath, b as PathFillRule, R as RectPath, P as Path } from './path-D0CoudGM.js';
2
- import { P as Point } from './cubicMath-CpCvuEl8.js';
3
- export { c as cubicPointAt, f as fitCubicThroughDeletion, s as splitCubicAtT } from './cubicMath-CpCvuEl8.js';
1
+ import { b as PathOpenFill, a as PolygonPath, c as PathFillRule, R as RectPath, P as Path } from './path-ljHxobyu.js';
2
+ import { P as Point$1 } from './cubicMath-BW-HJrCE.js';
3
+ export { c as cubicPointAt, s as splitCubicAtT } from './cubicMath-BW-HJrCE.js';
4
4
  export { PORT_REACH } from './nd/index.js';
5
5
 
6
6
  /**
@@ -8,8 +8,7 @@ export { PORT_REACH } from './nd/index.js';
8
8
  *
9
9
  * Points are scalar pairs (px, py); there is no point struct. All math is
10
10
  * f64 (JS-native). Epsilons are f32-SCALE and magnitude-relative, because
11
- * stored coords are quantized to Float32 (~7 significant digits) — see the
12
- * geometry-kernel spec.
11
+ * stored coords are quantized to Float32 (~7 significant digits).
13
12
  */
14
13
  /** Base relative epsilon, sized for Float32 storage (~1 part in 1e-6). */
15
14
  declare const EPS = 0.000001;
@@ -33,9 +32,8 @@ declare function sign(n: number): -1 | 0 | 1;
33
32
  *
34
33
  * The exception is a guard against an exact algebraic value that a formula
35
34
  * produces bit-for-bit: a homogeneous `w === 1`, a ray's `d === 0`. Those are
36
- * testing a branch, not comparing coordinates, and `geom/3d` has two of them
37
- * (`mat4.ts`, `ray3.ts`). Widening one to `approxEq` would change which branch
38
- * runs, not how precisely it runs.
35
+ * testing a branch, not comparing coordinates. Widening one to `approxEq`
36
+ * would change which branch runs, not how precisely it runs.
39
37
  */
40
38
  declare function approxEq(a: number, b: number, eps?: number): boolean;
41
39
 
@@ -72,28 +70,35 @@ declare const ZOOM_FLOOR = 1e-9;
72
70
  declare function normalizeZoom(zoom: number): number;
73
71
 
74
72
  /** `[a, b, c, d, e, f]`: `x' = a·x + c·y + e`, `y' = b·x + d·y + f`. */
75
- type Mat3 = readonly [number, number, number, number, number, number];
73
+ type Affine = readonly [number, number, number, number, number, number];
76
74
  /** The transform that leaves a point where it is. */
77
- declare function identity(): Mat3;
75
+ declare function identity$1(): Affine;
78
76
  /** A pure translation by `(tx, ty)`. */
79
- declare function translate(tx: number, ty: number): Mat3;
77
+ declare function translate(tx: number, ty: number): Affine;
80
78
  /** A pure scale about the origin. Scale about another point by composing
81
79
  * translate → scale → inverse translate with `multiply`. */
82
- declare function scale(sx: number, sy: number): Mat3;
80
+ declare function scale(sx: number, sy: number): Affine;
83
81
  /** A pure rotation about the origin, in radians, clockwise in canvas
84
82
  * coordinates (y down). */
85
- declare function rotate(rad: number): Mat3;
83
+ declare function rotate(rad: number): Affine;
86
84
  /** Compose: result applies `n` first, then `m` (m·n). */
87
- declare function multiply(m: Mat3, n: Mat3): Mat3;
85
+ declare function multiply$1(m: Affine, n: Affine): Affine;
88
86
  /** Inverse, or null when the matrix is singular, non-finite, or too
89
87
  * ill-conditioned to invert meaningfully at its own scale. */
90
- declare function invert(m: Mat3): Mat3 | null;
88
+ declare function invert$1(m: Affine): Affine | null;
91
89
  /** Apply to a point, returning a tuple. Cold-path use; hot loops inline. */
92
- declare function applyToPoint(m: Mat3, x: number, y: number): [number, number];
90
+ declare function applyToPoint(m: Affine, x: number, y: number): [number, number];
93
91
  /** Affine that maps source box (sx,sy,sw,sh) onto destination box (dx,dy,dw,dh). */
94
- declare function boxToBox(sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): Mat3;
92
+ declare function boxToBox(sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): Affine;
95
93
  /** Rotation by `rad` about pivot (cx,cy): translate(c)·rotate·translate(-c). */
96
- declare function rotateAboutPoint(cx: number, cy: number, rad: number): Mat3;
94
+ declare function rotateAboutPoint(cx: number, cy: number, rad: number): Affine;
95
+ /**
96
+ * Apply an affine to an interleaved coord stream, returning a fresh f64
97
+ * buffer. Command codes are unaffected — for a Bezier the transformed control
98
+ * points define the transformed curve exactly (affine invariance), so callers
99
+ * pass `path.coords` straight through and keep `path.commands` as-is.
100
+ */
101
+ declare function transformCoords(coords: ArrayLike<number>, m: Affine): Float64Array;
97
102
 
98
103
  /** Axis-aligned box as [minX, minY, maxX, maxY]. */
99
104
  type Box = readonly [number, number, number, number];
@@ -122,12 +127,12 @@ declare function rectToContour(x: number, y: number, w: number, h: number): Floa
122
127
 
123
128
  /**
124
129
  * SVG-style command-stream encoding — the kit's single declaration of the path
125
- * opcodes. `Path` (`./path`) wraps this with `kind` + `fillRule`.
130
+ * opcodes.
126
131
  *
127
132
  * The codes index a `Uint8Array` command stream whose coords live in a
128
133
  * parallel float array, so a code declared anywhere but `PATH_COMMANDS` makes
129
134
  * every walker that doesn't know it misread the coord stream from that command
130
- * on — silently, for every path. Derive, never restate.
135
+ * on — silently, for every path.
131
136
  */
132
137
  /** Opcode table: command code and the float coords it consumes. */
133
138
  declare const PATH_COMMANDS: {
@@ -178,18 +183,15 @@ declare const PATH_CMD_LENGTHS: readonly number[];
178
183
  declare function pathCommandCoordCount(cmd: number): number;
179
184
  /**
180
185
  * Visit each command with its coord offset and the pen position BEFORE the
181
- * command consumes its coords (the segment start). The callback receives
182
- * (cmd, coordIndex, penX, penY, commandIndex) and stops the walk by returning
183
- * `false`. The pen advances to the command's last coord pair afterward; `Z`
184
- * returns it to the subpath's opening `M`, so a command following a `Z`
185
- * without an intervening `M` starts where SVG says it does.
186
+ * command consumes its coords (the segment start). The callback stops the
187
+ * walk by returning `false`. `Z` returns the pen to the subpath's opening `M`.
186
188
  *
187
- * Such a command opens a new subpath at the pen, as does a drawing command
188
- * no `M` precedes at all. The visitor is told with `opensSubpath`, and has to
189
- * start its contour at `(penX, penY)` then: there is no `M` to do it.
189
+ * A command following a `Z` without an intervening `M` opens a new subpath at
190
+ * the pen, as does a drawing command no `M` precedes at all. The visitor is
191
+ * told with `opensSubpath`, and has to start its contour at `(penX, penY)`
192
+ * then: there is no `M` to do it.
190
193
  *
191
- * A code `PATH_COMMANDS` does not declare throws once the visitor has seen it,
192
- * since the walker cannot tell how many coords it consumes.
194
+ * A code `PATH_COMMANDS` does not declare throws once the visitor has seen it.
193
195
  */
194
196
  declare function forEachSegment(commands: ArrayLike<number>, coords: ArrayLike<number>, visit: (cmd: number, coordIndex: number, penX: number, penY: number, commandIndex: number, opensSubpath: boolean) => void | boolean): void;
195
197
 
@@ -274,13 +276,10 @@ declare function portCurvePoints(ax: number, ay: number, bx: number, by: number,
274
276
 
275
277
  /**
276
278
  * Bezier flattening — subdivide cubic and quadratic segments into polyline
277
- * approximations within a flatness tolerance. Used by hit-testing and
278
- * (eventually) any kernel that doesn't want to special-case curves.
279
+ * approximations within a flatness tolerance.
279
280
  *
280
- * The flatness metric is the maximum perpendicular distance from any
281
- * control point to the chord between endpoints. When that distance falls
282
- * below `tolerance`, the segment is "flat enough" and emitted as a single
283
- * line segment.
281
+ * The flatness metric is the maximum distance from any control point to the
282
+ * chord between endpoints.
284
283
  *
285
284
  * Tolerance is in world units. 0.5 is a sensible default for screen-rate
286
285
  * rendering at 1× zoom; consumers that zoom in heavily should pass a
@@ -296,23 +295,18 @@ declare function flattenCubic(x0: number, y0: number, x1: number, y1: number, x2
296
295
  /** Recursively subdivide a quadratic bezier (P0, P1, P2). */
297
296
  declare function flattenQuadratic(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, tolerance: number, out: number[]): void;
298
297
  /**
299
- * Like `flattenCubic` but also appends, for each new flattened point, its
300
- * arc-length fraction `t` (relative to the polyline distance accumulated so
301
- * far inside this curve) to `arcOut`. Caller then post-processes the segment's
302
- * `arcOut` range by dividing each by the segment's total flattened arc length
303
- * to yield t ∈ (0, 1].
304
- *
305
- * The returned values are *cumulative distance from the segment start*, not
306
- * normalized fractions. Two-pass design (accumulate, then divide) keeps the
307
- * recursive splitter simple — it doesn't need to know the total length up
308
- * front.
298
+ * Like `flattenCubic` but also appends to `arcOut`, for each new flattened
299
+ * point, its *cumulative distance from the segment start* — not a normalized
300
+ * fraction. The caller divides each by the segment's total flattened arc
301
+ * length to yield t ∈ (0, 1]. `maxTurn`, in radians, also bounds how far each
302
+ * piece's control polygon may turn.
309
303
  */
310
- declare function flattenCubicWithArcLen(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, tolerance: number, out: number[], arcOut: number[]): number;
304
+ declare function flattenCubicWithArcLen(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, tolerance: number, out: number[], arcOut: number[], maxTurn?: number): number;
311
305
  /** Flatten a quadratic bezier into line segments within `tolerance`, appending
312
306
  * points to `out` and their cumulative arc lengths to `arcOut`. The arc
313
307
  * lengths are what lets per-anchor color and dash phase be interpolated
314
308
  * evenly along the curve rather than per segment. */
315
- declare function flattenQuadraticWithArcLen(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, tolerance: number, out: number[], arcOut: number[]): number;
309
+ declare function flattenQuadraticWithArcLen(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, tolerance: number, out: number[], arcOut: number[], maxTurn?: number): number;
316
310
 
317
311
  /**
318
312
  * Even-odd ray-cast point-in-polygon over an interleaved, unclosed contour
@@ -333,6 +327,15 @@ declare function segmentsCross(ax: number, ay: number, bx: number, by: number, c
333
327
  /** Squared distance from (px,py) to segment (ax,ay)-(bx,by), endpoint-clamped. */
334
328
  declare function pointSegmentDist2(px: number, py: number, ax: number, ay: number, bx: number, by: number): number;
335
329
 
330
+ /** Set whether a fill closes an open subpath, for every path that names no
331
+ * `openFill` of its own. Starts at `'close'`. */
332
+ declare function setDefaultOpenFill(rule: PathOpenFill): void;
333
+ /** The rule a path with no `openFill` of its own follows. */
334
+ declare function defaultOpenFill(): PathOpenFill;
335
+ /** Whether `path`'s open subpaths fill, each closed by a straight edge back to
336
+ * its start. What painting, area, and the filled-region hit tests all ask. */
337
+ declare function fillsOpenSubpaths(path: PolygonPath): boolean;
338
+
336
339
  /**
337
340
  * Fluent builder for `PolygonPath`. Hides the `Uint8Array` / `Float32Array`
338
341
  * encoding behind move/line/curve/close calls and a final `build()`. Use
@@ -416,29 +419,10 @@ declare function linePath(a: {
416
419
  }): PolygonPath;
417
420
 
418
421
  /**
419
- * AABB bounds of a `Path`. Returned as `RectPath` for direct reuse with the
420
- * rect fast path machinery (selection AABB, area-select intersection).
421
- *
422
- * `RectPath` is its own bounds — O(1). For `PolygonPath`, walk segment by
423
- * segment, computing the tight bound per segment:
424
- *
425
- * - `M` / `L`: just the endpoint.
426
- * - `Q`: quadratic Bezier — endpoints plus axis-aligned extrema (one
427
- * possible inflection per axis).
428
- * - `C`: cubic Bezier — endpoints plus axis-aligned extrema (up to two
429
- * possible inflections per axis, found via the quadratic formula on
430
- * the derivative).
431
- *
432
- * Control points are NOT included directly; they're used only to compute
433
- * extrema that actually lie on the curve. This avoids the classic "AABB
434
- * extends past where the curve visibly reaches" bug for curved paths whose
435
- * control points poke outside the visible extent.
436
- *
437
- * Empty paths (no commands) return a zero-size rect anchored at the
438
- * origin — the convention used elsewhere in the kit for missing geometry.
422
+ * AABB of a `Path`, returned as a `RectPath` for direct reuse with rect-fast-path machinery.
423
+ * Control points are NOT included directly; they're used only to compute extrema that actually
424
+ * lie on the curve. Empty paths (no commands) return a zero-size rect anchored at the origin.
439
425
  */
440
-
441
- /** AABB of a `Path`, returned as a `RectPath` for direct reuse with rect-fast-path machinery. */
442
426
  declare function boundsOfPath(path: Path): RectPath;
443
427
 
444
428
  /**
@@ -476,19 +460,12 @@ declare function translatePath(path: Path, dx: number, dy: number): Path;
476
460
  */
477
461
  declare function scalePathToBounds(path: Path, target: RectPath): Path;
478
462
 
479
- /** Apply an affine `Mat3` to a path's geometry.
463
+ /** Apply an `Affine` to a path's geometry. Never mutates the input.
480
464
  *
481
465
  * Axis-aligned maps (no rotation/shear: `m[1]` and `m[2]` within 1e-9 of 0) keep a
482
- * `RectPath` a rect — the four corners stay axis-aligned, so we transform the
483
- * two diagonal corners and normalize negative extent (mirror). Rotation or
484
- * shear promotes the rect's four corners to a `PolygonPath`. Polygon paths map
485
- * every coord via the kernel's `transformCoords`, preserving the command stream
486
- * and `fillRule`. Never mutates the input.
487
- *
488
- * `Mat3` here is the 6-tuple `number[]` from `@weasel-js/geom` (DOMMatrix order:
489
- * `[a, b, c, d, e, f]` where `x' = a·x + c·y + e`, `y' = b·x + d·y + f`),
490
- * not the renderer's 9-element `Float32Array`. */
491
- declare function transformPath(path: Path, m: Mat3): Path;
466
+ * `RectPath` a rect, normalizing negative extent (mirror). Rotation or
467
+ * shear promotes the rect's four corners to a `PolygonPath`. */
468
+ declare function transformPath(path: Path, m: Affine): Path;
492
469
 
493
470
  /**
494
471
  * Translation-only compose/decompose for `Path` poses, the analog of
@@ -506,24 +483,24 @@ declare function composePath(parent: Path, child: Path): Path;
506
483
  /** Inverse of `composePath` — undo `parent`'s translation from a world pose. */
507
484
  declare function decomposePath(parent: Path, world: Path): Path;
508
485
 
509
- /**
510
- * Split a `PolygonPath` at each `M` command, returning one `PolygonPath` per
511
- * subpath. Inverse-ish of compound-path construction: a multi-region
512
- * (compound) path becomes N independent paths.
513
- *
514
- * `fillRule` is propagated unchanged to every output. Even-odd compound paths
515
- * with interior "holes" lose the hole semantics — each subpath becomes its
516
- * own filled region. (Same behavior as Illustrator's Release Compound Path.)
517
- *
518
- * If the input has zero `M` commands (which would already be malformed) the
519
- * input is returned wrapped in a single-element array. A path with exactly
520
- * one subpath is also returned as a single-element array — a trivial pass.
521
- */
522
-
523
486
  /** Split a path into one path per subpath, cutting at each `M`. A path with a
524
- * single subpath comes back as a one-element array. */
487
+ * single subpath comes back as a one-element array. `fillRule` is propagated
488
+ * unchanged, so even-odd compound paths with interior "holes" lose the hole
489
+ * semantics — each subpath becomes its own filled region. */
525
490
  declare function splitSubpaths(path: PolygonPath): PolygonPath[];
526
491
 
492
+ /** Whether any subpath of `path` lacks the `Z` that closes it. */
493
+ declare function hasOpenSubpath(path: Path): boolean;
494
+ /**
495
+ * `path` as two paths: the subpaths a `Z` closes, and those left open, each in
496
+ * the order `path` holds them and with its fill rules. A side with no subpaths
497
+ * is `null`. A fill that does not close an open subpath covers `closed` alone.
498
+ */
499
+ declare function splitByClosure(path: PolygonPath): {
500
+ closed: PolygonPath | null;
501
+ open: PolygonPath | null;
502
+ };
503
+
527
504
  /**
528
505
  * Contour orientation: which way a path winds, and the same path wound the
529
506
  * other way. Under `'nonzero'` two overlapping contours fill their overlap
@@ -535,7 +512,8 @@ declare function splitSubpaths(path: PolygonPath): PolygonPath[];
535
512
  * Signed area enclosed by `path`, summed over its contours. Positive for a
536
513
  * contour that turns clockwise on a y-down screen (the shoelace sign), so a
537
514
  * hole wound against its outer contour subtracts. An open contour counts as
538
- * closed by a straight edge back to its start, the way a fill closes it.
515
+ * closed by a straight edge back to its start where a fill closes it, and as
516
+ * nothing where one does not: see `fillsOpenSubpaths`.
539
517
  * Curved segments are integrated exactly, not through their control polygon.
540
518
  * A `RectPath` has no direction and counts as positive.
541
519
  */
@@ -551,25 +529,11 @@ declare function reversePath(path: PolygonPath): PolygonPath;
551
529
  * `pathFromD` — build a weasel `Path` from an **SVG path-data string** (the
552
530
  * value of SVG's `d` attribute, e.g. `"M0 0 L100 0 Z"`).
553
531
  *
554
- * This is the terse, declarative composition surface for geometry: a
555
- * consumer authors a shape as `d` and hands it straight to a scene/op API,
556
- * instead of chaining imperative builder calls. SVG `d` is deliberately the
557
- * language — it's a standard every consumer already knows, so the kit gets
558
- * path-language expressiveness without minting a new one. See
559
- * `docs/conventions.md` ("Compose scenes in a terse path language").
560
- *
561
532
  * Lowers every supported command (M/m L/l H/h V/v C/c S/s Q/q T/t A/a Z/z)
562
533
  * into weasel's `PathBuilder` primitives (move, line, cubic, quadratic,
563
- * close). Smooth (`S`/`s`/`T`/`t`) commands resolve their implicit reflected
564
- * control point from the previous cubic / quadratic. Arc commands (`A`/`a`)
565
- * convert to a series of cubic Bezier curves using the standard
566
- * endpoint-parameterization formulas (F.6.5 in the SVG spec): we reconstruct
567
- * the center, sweep angle, and a fixed number of (≤ 90°) cubic segments per
568
- * arc.
569
- *
570
- * No runtime dependency — a small hand-rolled parser. `@weasel-js/svg`'s
571
- * document parser (`parseSvg`) calls this for `<path d=…>` elements, so the
572
- * `d` grammar coverage is shared between the two entry points.
534
+ * close). Arc commands (`A`/`a`) convert to a series of cubic Bezier curves
535
+ * using the standard endpoint-parameterization formulas (F.6.5 in the SVG
536
+ * spec).
573
537
  */
574
538
 
575
539
  /**
@@ -593,9 +557,9 @@ declare function pathFromD(d: string, onWarn?: (message: string) => void): Retur
593
557
 
594
558
  /** The answer `pointAlongPath` gives: a point on the path and its heading there. */
595
559
  interface PathStation {
596
- point: Point;
560
+ point: Point$1;
597
561
  /** Unit vector along the path at `point`, pointing toward the end. */
598
- tangent: Point;
562
+ tangent: Point$1;
599
563
  }
600
564
  /** Options for `pointAlongPath`. */
601
565
  interface PointAlongPathOptions {
@@ -629,6 +593,102 @@ declare function pointAlongPath(path: Path, t: number, opts?: PointAlongPathOpti
629
593
  * combine with `pathContainsPoint` at the call site. */
630
594
  declare function pathDistanceToPoint(path: Path, px: number, py: number): number;
631
595
 
596
+ /**
597
+ * Counts the path anchors used by the per-anchor coloring surface. An
598
+ * "anchor" is the destination point of a path command: M, L, C, Q each
599
+ * contribute one (the (x, y) where the pen ends up); Z contributes none
600
+ * (it closes back to the subpath's first M). RectPath has four implicit
601
+ * anchors — the corners — matching its M/L/L/L/Z stroke tessellation.
602
+ *
603
+ * Consumers use this to size their per-anchor color array; the renderer
604
+ * uses it to validate the array length in dev builds.
605
+ */
606
+
607
+ /** One anchor of an editable path: its on-curve point plus the two control
608
+ * handles that shape the segments either side of it. Handles are in the same
609
+ * space as the point, and absent when the adjoining segment is straight. */
610
+ interface PenAnchor {
611
+ x: number;
612
+ y: number;
613
+ inHandle?: {
614
+ x: number;
615
+ y: number;
616
+ };
617
+ outHandle?: {
618
+ x: number;
619
+ y: number;
620
+ };
621
+ }
622
+ /**
623
+ * Derive a per-subpath anchor model from a PolygonPath. Subpaths split on
624
+ * every `M` command; a subpath is closed iff it ends with `Z`.
625
+ *
626
+ * Cubic-segment control points become the outHandle of the previous anchor
627
+ * and the inHandle of the next anchor. A closed subpath whose last curve ends
628
+ * exactly on its first point holds that point twice; the two are one anchor,
629
+ * and the curve's second control is that anchor's inHandle. Quadratic segments are upgraded to
630
+ * cubics (each control reused for both adjacent handles) — this loses no
631
+ * geometry. Linear segments produce anchors with no handles.
632
+ */
633
+ declare function pathToAnchors(path: PolygonPath): {
634
+ anchors: PenAnchor[][];
635
+ closed: boolean[];
636
+ };
637
+ /**
638
+ * Serialize the per-subpath anchor model back to a PolygonPath. Inverse of
639
+ * `pathToAnchors`. Curve-vs-line decision per segment:
640
+ * - Both adjacent handles absent → straight L segment.
641
+ * - Either handle present → C segment, with missing handles defaulting to
642
+ * the anchor point itself (degenerate but valid; renders as a near-line).
643
+ * Given `like`, the path being reshaped, the result keeps its fill rules.
644
+ */
645
+ declare function anchorsToPath(anchors: PenAnchor[][], closed: boolean[], like?: PolygonPath): PolygonPath;
646
+ /**
647
+ * Returns true if the anchor's in-handle and out-handle are collinear with
648
+ * the anchor point, indicating "smooth" (mirror-drag) behavior. Detected via
649
+ * the magnitude of the normalized cross product of the two handle vectors.
650
+ *
651
+ * Edge cases:
652
+ * - Missing in or out handle → false (corner by definition).
653
+ * - Either handle at zero distance from anchor → false.
654
+ */
655
+ declare function isAnchorSmooth(a: PenAnchor): boolean;
656
+ /** How many anchors a path has. Matches the per-anchor arrays the renderer
657
+ * expects for `vertexColors`. */
658
+ declare function countPathAnchors(path: Path): number;
659
+ /** The segment `(sub, segIdx)` as its two end anchors, or null when it
660
+ * doesn't exist. `segIdx === sub.length - 1` names a closed subpath's
661
+ * closing segment, which runs from the last anchor back to the first. */
662
+ declare function segmentEnds(anchors: readonly PenAnchor[][], closed: readonly boolean[] | undefined, sub: number, segIdx: number): {
663
+ a: PenAnchor;
664
+ b: PenAnchor;
665
+ } | null;
666
+ /** Whether the segment from `a` to `b` is a straight line (no handles). */
667
+ declare function isStraightSegment(a: PenAnchor, b: PenAnchor): boolean;
668
+ /** The segment of a decoded path nearest `(wx, wy)`, and the parameter `t`
669
+ * on it closest to that point. Pass `closed` (from `pathToAnchors`) to
670
+ * include each closed subpath's closing segment, reported as
671
+ * `segIdx === sub.length - 1`. `t` spans `[0, 1]`, endpoints included.
672
+ * Returns `null` only when there are no segments. */
673
+ declare function nearestSegmentT(anchors: PenAnchor[][], wx: number, wy: number, closed?: readonly boolean[]): {
674
+ sub: number;
675
+ segIdx: number;
676
+ t: number;
677
+ } | null;
678
+
679
+ /**
680
+ * Controls for the one cubic that replaces `prev → removed → next` when
681
+ * `removed` is deleted. The new controls keep the directions the curve leaves
682
+ * `prev` and arrives at `next` with, and their lengths are least-squares fitted
683
+ * to samples of the two segments being replaced, so the curve keeps its shape
684
+ * as closely as one cubic can. Where `removed` was inserted by splitting a
685
+ * cubic, the original cubic comes back.
686
+ */
687
+ declare function fitCubicThroughDeletion(prev: PenAnchor, removed: PenAnchor, next: PenAnchor): {
688
+ c1: Point$1;
689
+ c2: Point$1;
690
+ };
691
+
632
692
  /**
633
693
  * Schneider (1990, Graphics Gems I) adaptive cubic-Bezier fitter.
634
694
  * Given a sequence of sample points, returns a `PolygonPath` whose `C`
@@ -638,7 +698,273 @@ declare function pathDistanceToPoint(path: Path, px: number, py: number): number
638
698
  * `C` cubic segments. For colinear / two-point inputs, returns a single
639
699
  * degenerate cubic. For empty input, returns an empty polygon path.
640
700
  */
641
- declare function schneiderFit(samples: ReadonlyArray<Point>, errorTolerance: number): PolygonPath;
701
+ declare function schneiderFit(samples: ReadonlyArray<Point$1>, errorTolerance: number): PolygonPath;
702
+ /**
703
+ * The single cubic from the first sample to the last that best fits the
704
+ * samples between, with its control points held to the given unit tangents:
705
+ * `tStart` leaving the first sample, `tEnd` leaving the last one backward.
706
+ * Only the two handle lengths are solved for.
707
+ *
708
+ * `params` is the curve parameter each sample starts at, chord length when
709
+ * omitted; `passes` is how many times those are refined and the lengths
710
+ * solved again.
711
+ */
712
+ declare function fitCubicWithTangents(samples: ReadonlyArray<Point$1>, tStart: Point$1, tEnd: Point$1, opts?: {
713
+ params?: ReadonlyArray<number>;
714
+ passes?: number;
715
+ }): {
716
+ cp1: Point$1;
717
+ cp2: Point$1;
718
+ };
719
+
720
+ /** Options for {@link simplifyPath}. */
721
+ interface SimplifyPathOptions {
722
+ /**
723
+ * An anchor whose path turns by more than this many degrees is a corner:
724
+ * it is kept, and the curve is refitted on either side of it. Default 40.
725
+ */
726
+ cornerAngle?: number;
727
+ }
728
+ /**
729
+ * `path` refitted with as few anchors as hold it within `tolerance`: every
730
+ * point sampled along the original lies within `tolerance` of the result.
731
+ * Corners (see {@link SimplifyPathOptions.cornerAngle}) and the ends of open
732
+ * subpaths stay where they are; the runs between them are refitted as smooth
733
+ * cubics, Schneider-style, and a run that lies within `tolerance` of a line
734
+ * becomes one straight segment. Fill rules carry over.
735
+ */
736
+ declare function simplifyPath(path: PolygonPath, tolerance: number, opts?: SimplifyPathOptions): PolygonPath;
737
+
738
+ /**
739
+ * Screen-pixel lengths in world units, per axis.
740
+ *
741
+ * Chrome declares its hit zones in screen pixels — an 8px handle stays 8px at
742
+ * every zoom, because it paints in screen space. Converting one such length to
743
+ * world units with a single scalar (see `meanScale`) is exact only under
744
+ * uniform zoom; per-axis it is too generous on one axis and too mean on the
745
+ * other, so the pickable region stops matching the painted one.
746
+ *
747
+ * Prefer {@link withinPxBox} / {@link withinPxRadius}, which compare in screen
748
+ * space and so can't drift from the paint at all. {@link pxExtent} is for the
749
+ * cases that must stay in world units — a tolerance handed to geometry that
750
+ * doesn't know about the view.
751
+ */
752
+ interface Scale2 {
753
+ x: number;
754
+ y: number;
755
+ }
756
+ /** One screen-pixel length as world-space extents, per axis. `scale` is a
757
+ * view's, so neither axis is zero (see `View`).
758
+ *
759
+ * With `rotation`, the axes are a frame turned that far from world, and each
760
+ * extent is how far along it an edge across it must move to move `px` on
761
+ * screen — which, under non-uniform zoom, is not the extent along the screen
762
+ * axis nearest to it. */
763
+ declare function pxExtent(px: number, scale: Scale2, rotation?: number): {
764
+ x: number;
765
+ y: number;
766
+ };
767
+ /** World delta → screen delta. Only the scale participates: translation
768
+ * cancels in a difference, and the kit's views carry no skew. */
769
+ declare function scaleDelta(dx: number, dy: number, scale: Scale2): {
770
+ x: number;
771
+ y: number;
772
+ };
773
+ /**
774
+ * Is a world-space delta inside a screen-space square of half-extent `px`?
775
+ *
776
+ * The square is axis-aligned **on screen**, which is what a handle painted in
777
+ * screen space actually is — so this stays true under non-uniform zoom and
778
+ * under a rotated target, where an axis-aligned world-space test is a rotated
779
+ * rectangle on screen.
780
+ */
781
+ declare function withinPxBox(dx: number, dy: number, px: number, scale: Scale2): boolean;
782
+ /** Is a world-space delta inside a screen-space circle of radius `px`? */
783
+ declare function withinPxRadius(dx: number, dy: number, px: number, scale: Scale2): boolean;
784
+ /**
785
+ * A world point pushed `px` screen pixels off an edge, along the edge's normal
786
+ * as it lands on screen. `normal` is the edge's outward normal in world space.
787
+ *
788
+ * Scaling the world normal by the view is not the same thing: under
789
+ * non-uniform zoom the image of a normal is no longer perpendicular to the
790
+ * image of its edge, so chrome placed that way drifts sideways and sits closer
791
+ * than `px`. Returns the point in world coords and the on-screen unit normal.
792
+ */
793
+ declare function standoff(anchor: {
794
+ x: number;
795
+ y: number;
796
+ }, normal: {
797
+ x: number;
798
+ y: number;
799
+ }, px: number, scale: Scale2): {
800
+ x: number;
801
+ y: number;
802
+ nx: number;
803
+ ny: number;
804
+ };
805
+ /** The screen angle a frame turned `rotation` from world lands its x axis at.
806
+ * Equals `rotation` under uniform zoom; non-uniform zoom bends it. */
807
+ declare function screenAngleOf(rotation: number, scale: Scale2): number;
808
+
809
+ /**
810
+ * Pure anchor-set edits on the model `pathToAnchors` produces: subpath-major
811
+ * `PenAnchor[][]` plus a parallel `closed: boolean[]`. Every function here
812
+ * mutates that structure in place; callers decode with `pathToAnchors`,
813
+ * apply, and re-encode with `anchorsToPath` (see {@link editAnchorSet}).
814
+ *
815
+ * Callers address anchors by flat index — the sequential position in walk
816
+ * order across all subpaths, which is what `enumerateAnchors` reports.
817
+ * {@link locateAnchor} and {@link flatAnchorIndex} convert to and from the
818
+ * `(sub, idx)` pair.
819
+ *
820
+ * The two orders agree because `pathToAnchors` and `enumerateAnchors`
821
+ * walk the same command stream and emit one anchor per M/L/C/Q, less the
822
+ * end of a closing curve that lands on its subpath's first point.
823
+ * `countPathAnchors`, which sizes the renderer's per-anchor arrays, counts
824
+ * that end too and so can be one higher per closed subpath.
825
+ */
826
+
827
+ /** Subpath-major anchor model — the decoded form of a `PolygonPath`. */
828
+ interface AnchorSet {
829
+ anchors: PenAnchor[][];
830
+ closed: boolean[];
831
+ }
832
+ /** A world-space rectangle, as produced by a drag-rect gesture. */
833
+ interface AnchorRect {
834
+ x: number;
835
+ y: number;
836
+ width: number;
837
+ height: number;
838
+ }
839
+ /** Total anchors across every subpath. */
840
+ declare function anchorCount(set: AnchorSet): number;
841
+ /** Flat index → `(sub, idx)`. Returns null when out of range. */
842
+ declare function locateAnchor(set: AnchorSet, flatIndex: number): {
843
+ sub: number;
844
+ idx: number;
845
+ } | null;
846
+ /** `(sub, idx)` → flat index. Returns -1 when out of range. */
847
+ declare function flatAnchorIndex(set: AnchorSet, sub: number, idx: number): number;
848
+ /** Resolve a flat index to the anchor itself. Null when out of range. */
849
+ declare function anchorAt(set: AnchorSet, flatIndex: number): PenAnchor | null;
850
+ /**
851
+ * Decode `path`, hand the mutable anchor set to `edit`, and re-encode.
852
+ * Returns null when `edit` returns `false` (it changed nothing), so callers
853
+ * can skip a no-op commit.
854
+ */
855
+ declare function editAnchorSet(path: PolygonPath, edit: (set: AnchorSet) => boolean | void): PolygonPath | null;
856
+ /** Translate an anchor and both of its handles by `(dx, dy)`. */
857
+ declare function translateAnchorBy(set: AnchorSet, flatIndex: number, dx: number, dy: number): boolean;
858
+ /**
859
+ * Move one control handle to an absolute world position. When the anchor was
860
+ * smooth (handles collinear through the anchor) and `breakSmoothness` is
861
+ * false, the opposite handle is mirrored so the curve stays smooth.
862
+ */
863
+ declare function moveHandleTo(set: AnchorSet, flatIndex: number, side: 'in' | 'out', toX: number, toY: number, breakSmoothness: boolean): boolean;
864
+ /**
865
+ * Split the segment `(sub, segIdx) → (sub, segIdx + 1)` at parameter `t`,
866
+ * inserting a new anchor there. On a closed subpath `segIdx` may also name
867
+ * the closing segment (`sub.length - 1`); its new anchor is appended.
868
+ *
869
+ * A straight segment stays straight — the new anchor has no handles. A curved
870
+ * one splits by de Casteljau, so the two halves trace the original path.
871
+ *
872
+ * Returns the new anchor's flat index, or -1 when the segment doesn't
873
+ * exist.
874
+ */
875
+ declare function insertAnchorOnSegment(set: AnchorSet, args: {
876
+ sub: number;
877
+ segIdx: number;
878
+ t: number;
879
+ }): number;
880
+ /** A point on a segment, as {@link segmentAt} reports it. */
881
+ interface SegmentHit {
882
+ sub: number;
883
+ segIdx: number;
884
+ /** Parameter on the segment — what {@link insertAnchorOnSegment} takes. */
885
+ t: number;
886
+ /** The point on the path at `t`, in the set's own space. */
887
+ x: number;
888
+ y: number;
889
+ }
890
+ /**
891
+ * The segment point under `(x, y)`, when it lies within `tolerancePx` of
892
+ * the path on screen and no nearer than that to either of the segment's
893
+ * own anchors — a press on an anchor is about the anchor, not the segment
894
+ * beside it.
895
+ *
896
+ * `scale` is the view's, so the tolerance holds per axis under
897
+ * non-uniform zoom. The search runs in screen-scaled space: scaling is
898
+ * affine, so the curve's parameterization, and therefore `t`, carries
899
+ * straight back to world space.
900
+ */
901
+ declare function segmentAt(set: AnchorSet, x: number, y: number, opts: {
902
+ tolerancePx: number;
903
+ scale?: Scale2;
904
+ }): SegmentHit | null;
905
+ /**
906
+ * Delete the anchors at `flatIndexes`. Where a deleted anchor had
907
+ * neighbors on both sides — across the seam too, on a closed subpath — the
908
+ * surviving segment is refitted to the two it replaces (`fitCubicThroughDeletion`)
909
+ * so the path keeps its shape; a gap between two straight segments closes straight.
910
+ *
911
+ * Subpaths left with fewer than two anchors are dropped entirely. If that
912
+ * would leave the path with no subpaths at all, the whole deletion is refused
913
+ * (returns false, `set` untouched): an empty path leaves the node selected
914
+ * and in the scene with nothing on screen and no anchors to grab it by.
915
+ */
916
+ declare function deleteAnchorsAt(set: AnchorSet, flatIndexes: Iterable<number>): boolean;
917
+ /**
918
+ * Scissors: open a closed subpath at the given anchor. The anchor list is
919
+ * rotated to start there and a second anchor at the same point ends it, so
920
+ * every segment survives and the two ends can be pulled apart. No-ops on an
921
+ * already-open subpath — there's nothing to cut.
922
+ */
923
+ declare function openSubpathAt(set: AnchorSet, flatIndex: number): boolean;
924
+ /** Flat indices of every anchor whose on-curve point falls inside `rect`. */
925
+ declare function anchorsInRect(set: AnchorSet, rect: AnchorRect): number[];
926
+
927
+ /**
928
+ * Average and Join: anchor-set edits that bring anchors together. Both mutate
929
+ * the model `pathToAnchors` produces in place, like the edits in
930
+ * `anchorEdits`, and address anchors by flat index.
931
+ */
932
+
933
+ /** Which coordinates {@link averageAnchorsAt} averages: `'x'` lines the
934
+ * anchors up on one vertical, `'y'` on one horizontal, `'both'` stacks them
935
+ * on one point. */
936
+ type AverageAxis = 'x' | 'y' | 'both';
937
+ /** One end of an open subpath. */
938
+ interface SubpathEnd {
939
+ sub: number;
940
+ end: 'first' | 'last';
941
+ }
942
+ /**
943
+ * Move each anchor in `flatIndexes` to their mean position, along `axis`.
944
+ * Each anchor carries its handles with it. Returns false, changing nothing,
945
+ * when fewer than two of the indexes name anchors.
946
+ */
947
+ declare function averageAnchorsAt(set: AnchorSet, flatIndexes: Iterable<number>, axis?: AverageAxis): boolean;
948
+ /** The open-subpath end anchor `flatIndex` names, or null for an interior
949
+ * anchor or one on a closed subpath. A lone anchor reads as `'last'`. */
950
+ declare function subpathEndAt(set: AnchorSet, flatIndex: number): SubpathEnd | null;
951
+ /**
952
+ * Join the two open-subpath ends `a` and `b`. The two ends of one subpath
953
+ * close it; ends of two subpaths make one subpath, `a`'s run followed by
954
+ * `b`'s, in the slot of whichever came first. Ends that coincide merge into
955
+ * one anchor, keeping the handle on either side; ends apart are bridged by a
956
+ * straight segment. Returns false, changing nothing, when the ends are not
957
+ * two distinct ends of open subpaths.
958
+ */
959
+ declare function joinSubpathEnds(set: AnchorSet, a: SubpathEnd, b: SubpathEnd): boolean;
960
+ /** {@link joinSubpathEnds} for two anchors named by flat index, each the end
961
+ * of an open subpath. */
962
+ declare function joinAnchorsAt(set: AnchorSet, flatA: number, flatB: number): boolean;
963
+ /**
964
+ * The two open-subpath ends nearest each other that `accept` allows, on two
965
+ * different subpaths. Null when there are no two such subpaths.
966
+ */
967
+ declare function closestOpenEnds(set: AnchorSet, accept?: (a: SubpathEnd, b: SubpathEnd) => boolean): [SubpathEnd, SubpathEnd] | null;
642
968
 
643
969
  /**
644
970
  * Path hit-testing: path-vs-point (filled region and stroke distance),
@@ -647,19 +973,22 @@ declare function schneiderFit(samples: ReadonlyArray<Point>, errorTolerance: num
647
973
  * A `rect` path short-circuits to AABB arithmetic. A `polygon` path is its
648
974
  * filled region: beziers are flattened, `fillRule` is honored (default
649
975
  * `nonzero`), and every closed subpath counts — the hole of a donut is not
650
- * part of the shape under `evenodd`. Open subpaths enclose no area, so the
651
- * filled-region tests ignore them.
976
+ * part of the shape under `evenodd`. An open subpath counts as closed where a
977
+ * fill closes it and encloses nothing where one does not: see
978
+ * `fillsOpenSubpaths`.
652
979
  */
653
980
 
654
- type XY = {
655
- x: number;
656
- y: number;
657
- };
658
981
  /** Options for the path hit-tests. */
659
982
  interface PointInPathOptions {
660
983
  /** Bezier flattening tolerance in world units. Default 0.5. */
661
984
  tolerance?: number;
662
985
  }
986
+ /** Options for {@link polygonIntersectsPath}. */
987
+ interface PolygonIntersectsPathOptions extends PointInPathOptions {
988
+ /** False when nothing paints the path's interior: only its outline can meet
989
+ * the polygon, and a polygon lying wholly inside meets nothing. Default true. */
990
+ filled?: boolean;
991
+ }
663
992
  /** Options for {@link strokeHitTest}. */
664
993
  interface StrokeHitTestOptions {
665
994
  /** Bezier flattening tolerance in world units. Default 0.5. */
@@ -671,7 +1000,7 @@ interface StrokeHitTestOptions {
671
1000
  * transform no world distance equals it. */
672
1001
  slop?: {
673
1002
  px: number;
674
- transform: Mat3;
1003
+ transform: Affine;
675
1004
  };
676
1005
  }
677
1006
  /** Filled-region hit-test for a path. Rect short-circuits to AABB; polygons run ray-cast / winding per `fillRule`. */
@@ -691,30 +1020,132 @@ declare function pathContainsRect(path: Path, rect: Rect, opts?: PointInPathOpti
691
1020
  /** Returns true if `rect` overlaps (intersects or contains) `path`. */
692
1021
  declare function pathIntersectsRect(path: Path, rect: Rect, opts?: PointInPathOptions): boolean;
693
1022
  /** Returns true if every vertex of `polygon` lies inside `path`. */
694
- declare function pathContainsPolygon(path: Path, polygon: readonly XY[], opts?: PointInPathOptions): boolean;
1023
+ declare function pathContainsPolygon(path: Path, polygon: readonly Point$1[], opts?: PointInPathOptions): boolean;
695
1024
  /** Returns true if `polygon` overlaps (intersects or is contained by) `path`. */
696
- declare function pathIntersectsPolygon(path: Path, polygon: readonly XY[], opts?: PointInPathOptions): boolean;
1025
+ declare function pathIntersectsPolygon(path: Path, polygon: readonly Point$1[], opts?: PointInPathOptions): boolean;
697
1026
  /**
698
1027
  * Returns true if all of `path` — every subpath, open ones included, beziers
699
1028
  * flattened — lies inside the closed `polygon`: the inverse of
700
1029
  * {@link pathContainsPolygon}. A lasso enclosing a shape asks this.
701
1030
  */
702
- declare function polygonContainsPath(polygon: readonly XY[], path: Path, opts?: PointInPathOptions): boolean;
1031
+ declare function polygonContainsPath(polygon: readonly Point$1[], path: Path, opts?: PointInPathOptions): boolean;
703
1032
  /**
704
1033
  * Returns true if any of `path` meets the closed `polygon`: its filled region,
705
- * or the line of an open subpath, which encloses nothing. Beziers are
1034
+ * or the line of an open subpath, which encloses nothing. With `filled: false`
1035
+ * a closed subpath is a line too. Beziers are
706
1036
  * flattened, so a control point off the curve never counts. The companion of
707
1037
  * {@link polygonContainsPath}; a lasso touching a shape asks this.
708
1038
  */
709
- declare function polygonIntersectsPath(polygon: readonly XY[], path: Path, opts?: PointInPathOptions): boolean;
1039
+ declare function polygonIntersectsPath(polygon: readonly Point$1[], path: Path, opts?: PolygonIntersectsPathOptions): boolean;
710
1040
 
711
1041
  /**
712
- * Apply an affine to an interleaved coord stream, returning a fresh f64
713
- * buffer. Command codes are unaffected — for a Bezier the transformed control
714
- * points define the transformed curve exactly (affine invariance), so callers
715
- * pass `path.coords` straight through and keep `path.commands` as-is.
1042
+ * Ergonomic builders for tiny shape paths used by chrome / overlays / markers.
1043
+ * They all return `PolygonPath`.
1044
+ *
1045
+ * Not appropriate for *user-drawn* shapes (those have a pose and live in the
1046
+ * scene).
1047
+ */
1048
+
1049
+ /**
1050
+ * N-segment polygon approximation of a circle. Default 32 segments → max
1051
+ * radial deviation of ≈0.005·r (≈0.05 px at r=10). Bump higher for large
1052
+ * filled circles where the facets become visible.
1053
+ */
1054
+ declare function circlePath(cx: number, cy: number, r: number, segments?: number): PolygonPath;
1055
+ /** Axis-aligned square centred at (cx, cy) with side length `size`. */
1056
+ declare function squarePath(cx: number, cy: number, size: number): PolygonPath;
1057
+ /** Axis-aligned rectangle. Top-left at (x, y), width/height as given. */
1058
+ declare function rectMarkerPath(x: number, y: number, width: number, height: number): PolygonPath;
1059
+ /**
1060
+ * Axis-aligned rounded rectangle. Top-left at (x, y); `r` is clamped to half
1061
+ * the shorter side. Each corner is `cornerSamples` line segments — the
1062
+ * default 8 gives the same angular resolution as `circlePath`'s 32.
1063
+ */
1064
+ declare function roundRectPath(x: number, y: number, width: number, height: number, r: number, cornerSamples?: number): PolygonPath;
1065
+
1066
+ /**
1067
+ * 2D affine matrix utilities. Column-major 9 elements, matching
1068
+ * `WebGL2RenderingContext.uniformMatrix3fv` element order so an upload needs
1069
+ * no transpose flag.
1070
+ *
1071
+ * Layout (column-major):
1072
+ * [m00, m10, 0,
1073
+ * m01, m11, 0,
1074
+ * tx, ty, 1]
716
1075
  */
717
- declare function transformCoords(coords: ArrayLike<number>, m: Mat3): Float64Array;
1076
+
1077
+ /**
1078
+ * A 2D affine transform as a column-major 9-element array, laid out as above.
1079
+ *
1080
+ * Every matrix the kit builds is a `Float64Array`: a view translation far
1081
+ * from the origin at high zoom needs more than a float32's 24 bits to hold a
1082
+ * fraction of a pixel. A `Float32Array` is accepted wherever one is read.
1083
+ * `mat3.toUniform` makes the float32 copy a GL uniform upload wants.
1084
+ */
1085
+ type GlMat3 = Float32Array | Float64Array;
1086
+ declare function identity(): GlMat3;
1087
+ declare function multiply(out: GlMat3, m: GlMat3): GlMat3;
1088
+ /** `m · T(tx, ty)`: composes onto `m`, where `@weasel-js/geom`'s `translate`
1089
+ * constructs a fresh matrix. */
1090
+ declare function translated(m: GlMat3, tx: number, ty: number): GlMat3;
1091
+ /** `m · S(sx, sy)`: composes onto `m`, where geom's `scale` constructs one. */
1092
+ declare function scaled(m: GlMat3, sx: number, sy: number): GlMat3;
1093
+ /** This layout read as the kernel's 6-element affine. The two carry the same
1094
+ * logical order, so the conversion is a repack and nothing else. */
1095
+ declare function toAffine(m: GlMat3): Affine;
1096
+ /** The kernel's affine in this layout. The inverse of {@link toAffine}. */
1097
+ declare function fromAffine(a: Affine): GlMat3;
1098
+ /** Inverse of an affine matrix, or `null` when `@weasel-js/geom`'s `invert`
1099
+ * finds it singular — the same rule, read through this layout. */
1100
+ declare function invert(m: GlMat3): GlMat3 | null;
1101
+ /** A float32 copy of `m`, for `uniformMatrix3fv` or a shader uniform value. */
1102
+ declare function toUniform(m: GlMat3): Float32Array;
1103
+ declare function apply(m: GlMat3, x: number, y: number): [number, number];
1104
+ /**
1105
+ * Map screen pixel coords (0..width on X, 0..height on Y, top-left origin)
1106
+ * into clip space (-1..1 on X, 1..-1 on Y — note Y flip so screen-down
1107
+ * matches clip-down).
1108
+ */
1109
+ declare function screenToClip(width: number, height: number): GlMat3;
1110
+ /**
1111
+ * Uniform-equivalent scale factor: the square root of the absolute
1112
+ * determinant of the linear part, i.e. the geometric mean of the two axis
1113
+ * scales. Rotation-invariant. Under non-uniform scale it is between the two
1114
+ * axes and exact on neither — the same compromise `meanScale` documents.
1115
+ */
1116
+ declare function meanScaleOf(m: GlMat3): number;
1117
+ /** The least any direction is scaled by the linear part — its smaller singular
1118
+ * value. What a screen length is worth in world units, at most. */
1119
+ declare function minScaleOf(m: GlMat3): number;
1120
+ /** The renderer's 3x3 matrix operations, as one namespace. These work on the
1121
+ * 9-element form the GL uniform upload wants — distinct from the 6-element
1122
+ * `Affine`, though the logical element order is the same. */
1123
+ declare const mat3: {
1124
+ identity: typeof identity;
1125
+ toAffine: typeof toAffine;
1126
+ fromAffine: typeof fromAffine;
1127
+ multiply: typeof multiply;
1128
+ translated: typeof translated;
1129
+ scaled: typeof scaled;
1130
+ invert: typeof invert;
1131
+ toUniform: typeof toUniform;
1132
+ apply: typeof apply;
1133
+ screenToClip: typeof screenToClip;
1134
+ meanScaleOf: typeof meanScaleOf;
1135
+ minScaleOf: typeof minScaleOf;
1136
+ };
1137
+
1138
+ /**
1139
+ * Build the world→screen transform matrix for a `View`.
1140
+ * Use as the `transform` field of a `kind: 'group'` DrawCommand to wrap
1141
+ * world-space content emitted from a layer `draw` implementation.
1142
+ *
1143
+ * Mapping: `screen = (world − {view.x, view.y}) × {view.scale.x, view.scale.y}`.
1144
+ *
1145
+ * Column-major layout (matches `mat3.identity()`):
1146
+ * `[scale.x, 0, 0, 0, scale.y, 0, -view.x*scale.x, -view.y*scale.y, 1]`.
1147
+ */
1148
+ declare function viewToMat3(view: View): GlMat3;
718
1149
 
719
1150
  /** Which side of the anchor the overlay sits on. */
720
1151
  type PlacementSide = 'top' | 'bottom' | 'left' | 'right';
@@ -907,4 +1338,337 @@ declare function cubicBezierEasing(x1: number, y1: number, x2: number, y2: numbe
907
1338
  /** Resolve a spec to the function that shapes progress. `undefined` is linear. */
908
1339
  declare function resolveEasing(spec?: EasingSpec): EasingFn;
909
1340
 
910
- export { type BezierEasing, type Box, type CubicCoords, type CurveNearest, DEFAULT_FLATTEN_TOLERANCE, EASINGS, EPS, type EasingFn, type EasingName, type EasingSpec, type LineCoords, type Mat3, PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, Path, PathBuilder, type PathCommandCode, type PathCommandName, PathFillRule, type PathNearest, type PathStation, type PlaceRectOptions, type PlacedRect, type Placement, type PlacementAlign, type PlacementSide, Point, type PointAlongPathOptions, type PointInPathOptions, PolygonPath, type QuadraticCoords, type Rect, RectPath, SPRING_PRESETS, type SpringPreset, type SpringPresetName, type StrokeHitTestOptions, type View, ZOOM_FLOOR, applyToPoint, approxEq, boundsOfCoords, boundsOfPath, boxContainsBox, boxContainsPoint, boxToBox, clamp, clampRectWithin, composePath, cross, cubicBezierEasing, cubicBounds, cubicEvalAt, decomposePath, dot, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, elevateQuadraticToCubic, ellipsePath, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, forEachSegment, identity, invert, len2, linePath, linear, multiply, nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic, normalizeZoom, pathCommandCoordCount, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathFromD, pathIntersectsPolygon, pathIntersectsRect, pathSignedArea, placeRect, pointAlongPath, pointInPath, pointInPolygon, pointSegmentDist2, polygonContainsPath, polygonFromPoints, polygonIntersectsPath, polylineFromPoints, portControls, portCurvePoints, quadraticEvalAt, rectPath, rectToContour, regularPolygonPath, resolveEasing, reversePath, rotate, rotateAboutPoint, scale, scalePathToBounds, schneiderFit, segmentsCross, sign, splitCubicAt, splitLineAt, splitQuadraticAt, splitSubpaths, starPath, strokeHitTest, sub, transformCoords, transformPath, translate, translatePath, unionBoundsPath, unionBox };
1341
+ /**
1342
+ * Geometric mean of a per-axis scale's magnitudes, so a flipped (negative)
1343
+ * axis counts by its size.
1344
+ *
1345
+ * **Not for hit-testing.** A screen-pixel length is not one world distance
1346
+ * under non-uniform zoom, and collapsing it to a scalar makes a pickable
1347
+ * region too generous on one axis and too mean on the other. Use `pxExtent`
1348
+ * for a per-axis world length, or `withinPxBox` / `withinPxRadius` to compare
1349
+ * in screen space directly. Nor for placing chrome or measuring a pick slop:
1350
+ * `standoff` and `strokeHitTest`'s `slop` work on screen.
1351
+ *
1352
+ * What legitimately remains is a stroke width for a line that is not
1353
+ * axis-aligned: the renderer resolves a `{ px }` width through this same
1354
+ * mean, so a picker reading ink widths must too.
1355
+ */
1356
+ declare function meanScale(s: {
1357
+ x: number;
1358
+ y: number;
1359
+ }): number;
1360
+
1361
+ /** Pivot (`cx`, `cy`) and angle resolved from a pose's rotation convention. */
1362
+ interface PoseRotation {
1363
+ cx: number;
1364
+ cy: number;
1365
+ rotation: number;
1366
+ }
1367
+ /**
1368
+ * Resolve a pose's rotation transform, or `null` when the pose carries no
1369
+ * effective rotation. Non-null requires a nonzero `rotation` **and** all four
1370
+ * AABB fields (`x`, `y`, `width`, `height`) — the pivot is the unrotated AABB
1371
+ * center.
1372
+ */
1373
+ declare function poseRotationOf(pose: unknown): PoseRotation | null;
1374
+ /**
1375
+ * Rotate every coordinate of `path` about `(cx, cy)` by `rotation` radians.
1376
+ * A `rect` promotes to a four-corner polygon (axis-aligned rects can't encode
1377
+ * rotation). Returns a fresh `PolygonPath`; never mutates the input.
1378
+ */
1379
+ declare function rotatePathAround(path: Path, cx: number, cy: number, rotation: number): PolygonPath;
1380
+
1381
+ /**
1382
+ * The one composition of a box pose into the matrix that carries its own
1383
+ * frame to its parent's: the rotation convention of `poseRotationOf`, and the
1384
+ * pose's residual `transform` inside it. Painting, culling, silhouettes, and
1385
+ * picking all read a pose through `poseFrameOf` so they agree on where the
1386
+ * node is.
1387
+ */
1388
+
1389
+ /**
1390
+ * The linear part of a box pose that its box, rotation, and flips cannot
1391
+ * hold: a skew, or a scale that differs by axis. `[a, b, c, d]` in
1392
+ * `Affine` order (`x' = a·x + c·y`, `y' = b·x + d·y`), applied about the
1393
+ * box center to what the node draws in its unrotated box, before the
1394
+ * rotation. Absent is the identity.
1395
+ */
1396
+ type PoseLinear = readonly [a: number, b: number, c: number, d: number];
1397
+ /** `transform` when it changes anything, `null` for absent or the identity. */
1398
+ declare function poseLinearOf(pose: unknown): PoseLinear | null;
1399
+ /**
1400
+ * The matrix taking a point in the pose's own unrotated box frame to where
1401
+ * the node draws it: `rotate(rotation) · transform`, about the box center.
1402
+ * `null` when the pose has neither, or is not a box, so a caller can skip
1403
+ * the step.
1404
+ */
1405
+ declare function poseFrameOf(pose: unknown): Affine | null;
1406
+ /**
1407
+ * The inverse of {@link poseFrameOf}: where a parent-frame point falls in the
1408
+ * pose's unrotated box frame. `null` when there is no frame to undo, or when
1409
+ * the `transform` is singular and nothing maps back.
1410
+ */
1411
+ declare function poseFrameInverseOf(pose: unknown): Affine | null;
1412
+ /** `path`, given in the pose's unrotated box frame, as the node draws it. */
1413
+ declare function pathThroughPoseFrame(path: Path, pose: unknown): Path;
1414
+
1415
+ type Side = 'in' | 'out';
1416
+ /**
1417
+ * How a path maps onto itself under one transform `m`: `partners[i]` is the
1418
+ * flat index of the anchor that anchor `i` lands on, and `flips[i]` whether
1419
+ * its in-handle lands on that anchor's out-handle — a mirror reverses which
1420
+ * way a path runs, a rotation does not. An anchor `m` fixes is its own
1421
+ * partner.
1422
+ */
1423
+ interface AnchorSymmetry {
1424
+ readonly m: Affine;
1425
+ readonly partners: readonly number[];
1426
+ readonly flips: readonly boolean[];
1427
+ }
1428
+ /**
1429
+ * The pairing that makes `set` its own image under `m`, or `null` when it is
1430
+ * not one: every anchor, handles included, must land on a distinct anchor
1431
+ * within `tolerance` on each axis.
1432
+ */
1433
+ declare function anchorSymmetry(set: AnchorSet, m: Affine, tolerance?: number): AnchorSymmetry | null;
1434
+ /** Every transform in `group` that `set` is its own image under, paired. */
1435
+ declare function anchorSymmetries(set: AnchorSet, group: readonly Affine[], tolerance?: number): AnchorSymmetry[];
1436
+ /**
1437
+ * Translate the anchors `flats` by `(dx, dy)` the way `translateAnchorBy`
1438
+ * does, and every image of each under `syms` by the transformed delta, so a
1439
+ * path that was its own image under each of them still is. `syms` should be
1440
+ * the whole symmetry group less its identity, as `anchorSymmetries` gives it
1441
+ * for a group; with a part of one, the anchors it fixes are only partly held.
1442
+ * An anchor that is itself being dragged moves as dragged.
1443
+ */
1444
+ declare function translateAnchorsSymmetric(set: AnchorSet, flats: readonly number[], dx: number, dy: number, syms: readonly AnchorSymmetry[]): boolean;
1445
+ /**
1446
+ * Move one handle to `(toX, toY)` and every image of it under `syms` to the
1447
+ * image of that point, so a path that was its own image under each of them
1448
+ * still is. A handle a transform maps onto itself keeps to where that
1449
+ * transform allows; one mapped onto its own anchor's opposite handle drives
1450
+ * that handle.
1451
+ *
1452
+ * Otherwise a smooth anchor keeps the opposite handle opposite, as
1453
+ * `moveHandleTo` does, unless `breakSmoothness`, and that handle's images
1454
+ * follow it. Every handle is written once, from its target, so no anchor
1455
+ * re-aims a handle another image already placed.
1456
+ */
1457
+ declare function moveHandleSymmetric(set: AnchorSet, flat: number, side: Side, toX: number, toY: number, breakSmoothness: boolean, syms: readonly AnchorSymmetry[]): boolean;
1458
+
1459
+ /** Where on a segment a bend is held, as `segmentAt` reports it. */
1460
+ interface BendGrip {
1461
+ sub: number;
1462
+ segIdx: number;
1463
+ /** Curve parameter of the held point. */
1464
+ t: number;
1465
+ }
1466
+ /**
1467
+ * Bend one segment so the point held at `grip.t` moves by `(dx, dy)`, by
1468
+ * moving its two control handles: each by an amount weighted toward the end it
1469
+ * belongs to, together exactly enough to carry the held point along. A straight
1470
+ * segment becomes a curve. Where an end anchor was smooth, its other handle
1471
+ * turns to stay in line, keeping its length, so the neighboring segment bends
1472
+ * with it rather than kinking.
1473
+ *
1474
+ * Returns false when the segment doesn't exist.
1475
+ */
1476
+ declare function bendSegment(set: AnchorSet, grip: BendGrip, dx: number, dy: number): boolean;
1477
+
1478
+ type Point = {
1479
+ x: number;
1480
+ y: number;
1481
+ };
1482
+ /**
1483
+ * Collapse the handles of the anchors at `flatIndexes` onto their anchors,
1484
+ * leaving sharp corners. A segment whose ends both lose their handles turns
1485
+ * straight.
1486
+ *
1487
+ * Returns false when every handle was already on its anchor. A segment that
1488
+ * stays curved because its far end keeps a handle still encodes a control at
1489
+ * this end, so it decodes as a handle sitting on the anchor: retracted.
1490
+ */
1491
+ declare function retractHandles(set: AnchorSet, flatIndexes: Iterable<number>): boolean;
1492
+ /**
1493
+ * Give each anchor at `flatIndexes` two handles of equal length pointing in
1494
+ * opposite directions, so the curve passes through it smoothly. The shared
1495
+ * direction splits the difference between the two handles' own directions,
1496
+ * and the shared length is their mean; an anchor with one handle mirrors it.
1497
+ *
1498
+ * Skipped: an anchor with no handles, and the ends of an open subpath, which
1499
+ * have only one segment to shape. Returns false when nothing changed.
1500
+ */
1501
+ declare function makeHandlesSymmetric(set: AnchorSet, flatIndexes: Iterable<number>): boolean;
1502
+ /**
1503
+ * Where a handle lands when dragged toward `to` but held to its current
1504
+ * direction from `anchor`: `to` projected onto that ray. The length never
1505
+ * goes below zero, so the handle can shrink onto the anchor but not flip
1506
+ * through it. A handle already sitting on its anchor has no direction to
1507
+ * keep and follows `to` freely.
1508
+ */
1509
+ declare function handleAlongItsAngle(anchor: Point, handle: Point, to: Point): Point;
1510
+
1511
+ /**
1512
+ * Where each point of an edited path came from, so an array kept per point (a skin's
1513
+ * weights) can follow an edit that inserts, deletes, or reorders points.
1514
+ */
1515
+
1516
+ /** The anchor model `pathToAnchors` produces; `AnchorSet` in `anchorEdits`. */
1517
+ interface Anchors {
1518
+ anchors: PenAnchor[][];
1519
+ closed: boolean[];
1520
+ }
1521
+ /**
1522
+ * Where a point of an edited path came from: point `a` of the path before the edit, or for a
1523
+ * point the edit made, a blend `t` of the way from point `a` to point `b`.
1524
+ */
1525
+ interface PointOrigin {
1526
+ a: number;
1527
+ b: number;
1528
+ t: number;
1529
+ }
1530
+ /**
1531
+ * `editAnchorSet`, answering also where each point of the new path came from.
1532
+ *
1533
+ * An anchor the edit kept, moved or not, keeps its points. One the edit put exactly where an
1534
+ * anchor was takes that anchor's, each handle by where it is, so a subpath turned around
1535
+ * keeps its weights. A handle an edit gave an anchor that had none takes the anchor's point. An anchor the edit made is a blend of the nearest kept anchors either side
1536
+ * of it in its subpath, by its distance to each, or a copy of the one it has; its origin is
1537
+ * `null` when its subpath has none.
1538
+ */
1539
+ declare function editAnchorSetTracked(path: PolygonPath, edit: (set: Anchors) => boolean | void): {
1540
+ path: PolygonPath;
1541
+ origins: (PointOrigin | null)[];
1542
+ } | null;
1543
+ /**
1544
+ * An array kept per point of a path, carried through an edit: `origins` is what
1545
+ * {@link editAnchorSetTracked} answered. A point with no origin, and an origin past the
1546
+ * array's end, read 0.
1547
+ */
1548
+ declare function remapPointValues(values: ArrayLike<number>, origins: readonly (PointOrigin | null)[]): number[];
1549
+
1550
+ /**
1551
+ * Anchor lookup across several paths, measured on screen: which existing
1552
+ * anchor is nearest a point, and whether it ends an open subpath. Feeds the
1553
+ * pen's anchor snapping and its pick-up of an open path's endpoint.
1554
+ */
1555
+
1556
+ /** An existing anchor found near a point. */
1557
+ interface PathAnchorHit {
1558
+ /** The id the path was supplied under. */
1559
+ id: string;
1560
+ /** Subpath index, then anchor index within that subpath. */
1561
+ sub: number;
1562
+ idx: number;
1563
+ x: number;
1564
+ y: number;
1565
+ /** Which end of an open subpath this anchor is, or null when it is an
1566
+ * interior anchor or its subpath is closed. A lone anchor reads `'last'`. */
1567
+ end: 'first' | 'last' | null;
1568
+ }
1569
+ /**
1570
+ * The anchor nearest `point` within a screen-space circle of radius `px`,
1571
+ * across every subpath of every path in `paths`. Paths and `point` share one
1572
+ * world frame; `scale` is the view's, so the radius stays round under
1573
+ * non-uniform zoom. `accept` narrows the candidates (endpoints only, say).
1574
+ * Ties go to the earlier path, so pass paths front-to-back.
1575
+ */
1576
+ declare function nearestPathAnchor(paths: Iterable<{
1577
+ id: string;
1578
+ path: PolygonPath;
1579
+ }>, point: {
1580
+ x: number;
1581
+ y: number;
1582
+ }, px: number, scale: Scale2, accept?: (hit: PathAnchorHit) => boolean): PathAnchorHit | null;
1583
+ /** Reverse a subpath's direction without changing its shape: the anchor
1584
+ * order flips and each anchor's in and out handles trade places. */
1585
+ declare function reverseAnchors<A extends PenAnchor>(anchors: readonly A[]): A[];
1586
+
1587
+ /**
1588
+ * Project a leaf path from its source frame into world coordinates given a
1589
+ * `{x, y, width, height, rotation?}` pose.
1590
+ *
1591
+ * RectPaths can't carry rotation as-is (they're axis-aligned by definition);
1592
+ * a non-zero `pose.rotation` on a rect promotes the result to a polygon so
1593
+ * the four corners are baked into world coords.
1594
+ */
1595
+
1596
+ /** Subset of pose fields this helper consumes: `x/y/width/height` define an
1597
+ * AABB whose unrotated center is the rotation pivot. */
1598
+ interface PathInWorldPose {
1599
+ x: number;
1600
+ y: number;
1601
+ width: number;
1602
+ height: number;
1603
+ rotation?: number;
1604
+ transform?: PoseLinear;
1605
+ }
1606
+ /**
1607
+ * Project a stored path into the pose's **local frame**: rebase its AABB onto
1608
+ * the pose box. It does NOT apply `pose.rotation`; `pathInWorld` composes
1609
+ * this with the rotation wrap.
1610
+ *
1611
+ * Rects rebase onto the pose's `width`/`height` because resize updates the pose,
1612
+ * not the stored `RectPath` — so the live size lives on the pose.
1613
+ */
1614
+ declare function pathInPoseFrame(path: Path, pose: PathInWorldPose): Path;
1615
+ /**
1616
+ * Bake `pose` into `path`'s coordinates so the returned path is positioned
1617
+ * in world space. Returns a fresh `Path` instance; never mutates inputs.
1618
+ */
1619
+ declare function pathInWorld(path: Path, pose: PathInWorldPose): Path;
1620
+ /**
1621
+ * Inverse of `pathInWorld` for a path in **world** space: the stored path
1622
+ * in the pose's own frame plus the pose that draws it there. The pose's
1623
+ * `rotation` and `transform` are preserved, and its AABB fields are fit to
1624
+ * the result. The new box's center is placed where the old frame carries it,
1625
+ * since the pivot moves with the box: `pathInWorld(result.path, result.pose)`
1626
+ * reproduces `worldPath` whether or not its bounds changed.
1627
+ */
1628
+ declare function worldEditToStorage<P extends PathInWorldPose>(pose: P, worldPath: PolygonPath): {
1629
+ pose: P;
1630
+ path: PolygonPath;
1631
+ };
1632
+ declare function worldEditToStorage<P extends PathInWorldPose>(pose: P, worldPath: Path): {
1633
+ pose: P;
1634
+ path: Path;
1635
+ };
1636
+
1637
+ /** The constructor of each typed array of numbers, under the tag its type is written by. */
1638
+ declare const TYPED_ARRAY_CONSTRUCTORS: {
1639
+ readonly i8: Int8ArrayConstructor;
1640
+ readonly u8: Uint8ArrayConstructor;
1641
+ readonly u8c: Uint8ClampedArrayConstructor;
1642
+ readonly i16: Int16ArrayConstructor;
1643
+ readonly u16: Uint16ArrayConstructor;
1644
+ readonly i32: Int32ArrayConstructor;
1645
+ readonly u32: Uint32ArrayConstructor;
1646
+ readonly f32: Float32ArrayConstructor;
1647
+ readonly f64: Float64ArrayConstructor;
1648
+ };
1649
+ /** The name a typed array's type is written under. */
1650
+ type TypedArrayTag = keyof typeof TYPED_ARRAY_CONSTRUCTORS;
1651
+ /** A typed array of numbers: what a `Path` keeps its commands and coords in. */
1652
+ type NumberTypedArray = InstanceType<(typeof TYPED_ARRAY_CONSTRUCTORS)[TypedArrayTag]>;
1653
+ /** A typed array as JSON holds it: its type's tag and its numbers. */
1654
+ interface TaggedTypedArray {
1655
+ __ta: TypedArrayTag;
1656
+ data: number[];
1657
+ }
1658
+ /** `value` as a tag and its numbers where it is a typed array of numbers, else `undefined`. */
1659
+ declare function tagTypedArray(value: unknown): TaggedTypedArray | undefined;
1660
+ /** The typed array a `TaggedTypedArray` describes, or `undefined` for anything else. */
1661
+ declare function untagTypedArray(value: unknown): NumberTypedArray | undefined;
1662
+ /**
1663
+ * A copy of `value` that `JSON.stringify` writes whole: every typed array in it, at any
1664
+ * depth of arrays and plain objects, becomes a `TaggedTypedArray`. A `Path` goes through it
1665
+ * to be saved, and `reviveTypedArrays` reads it back.
1666
+ */
1667
+ declare function tagTypedArrays(value: unknown): unknown;
1668
+ /** A copy of `value` with every `TaggedTypedArray` in it a typed array again: what
1669
+ * `JSON.parse` answered for something `tagTypedArrays` or `typedArrayReplacer` wrote. */
1670
+ declare function reviveTypedArrays(value: unknown): unknown;
1671
+ /** `tagTypedArrays` as a `JSON.stringify` replacer. */
1672
+ declare function typedArrayReplacer(_key: string, value: unknown): unknown;
1673
+
1674
+ export { type Affine, type AnchorRect, type AnchorSet, type AnchorSymmetry, type AverageAxis, type BendGrip, type BezierEasing, type Box, type CubicCoords, type CurveNearest, DEFAULT_FLATTEN_TOLERANCE, EASINGS, EPS, type EasingFn, type EasingName, type EasingSpec, type GlMat3, type LineCoords, type NumberTypedArray, PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, Path, type PathAnchorHit, PathBuilder, type PathCommandCode, type PathCommandName, PathFillRule, type PathInWorldPose, type PathNearest, PathOpenFill, type PathStation, type PenAnchor, type PlaceRectOptions, type PlacedRect, type Placement, type PlacementAlign, type PlacementSide, Point$1 as Point, type PointAlongPathOptions, type PointInPathOptions, type PointOrigin, type PolygonIntersectsPathOptions, PolygonPath, type PoseLinear, type PoseRotation, type QuadraticCoords, type Rect, RectPath, SPRING_PRESETS, type Scale2, type SegmentHit, type SimplifyPathOptions, type SpringPreset, type SpringPresetName, type StrokeHitTestOptions, type SubpathEnd, TYPED_ARRAY_CONSTRUCTORS, type TaggedTypedArray, type TypedArrayTag, type View, ZOOM_FLOOR, anchorAt, anchorCount, anchorSymmetries, anchorSymmetry, anchorsInRect, anchorsToPath, applyToPoint, approxEq, averageAnchorsAt, bendSegment, boundsOfCoords, boundsOfPath, boxContainsBox, boxContainsPoint, boxToBox, circlePath, clamp, clampRectWithin, closestOpenEnds, composePath, countPathAnchors, cross, cubicBezierEasing, cubicBounds, cubicEvalAt, decomposePath, defaultOpenFill, deleteAnchorsAt, dot, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorSet, editAnchorSetTracked, elevateQuadraticToCubic, ellipsePath, fillsOpenSubpaths, fitCubicThroughDeletion, fitCubicWithTangents, flatAnchorIndex, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, forEachSegment, handleAlongItsAngle, hasOpenSubpath, identity$1 as identity, insertAnchorOnSegment, invert$1 as invert, isAnchorSmooth, isStraightSegment, joinAnchorsAt, joinSubpathEnds, len2, linePath, linear, locateAnchor, makeHandlesSymmetric, mat3, meanScale, moveHandleSymmetric, moveHandleTo, multiply$1 as multiply, nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic, nearestPathAnchor, nearestSegmentT, normalizeZoom, openSubpathAt, pathCommandCoordCount, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSignedArea, pathThroughPoseFrame, pathToAnchors, placeRect, pointAlongPath, pointInPath, pointInPolygon, pointSegmentDist2, polygonContainsPath, polygonFromPoints, polygonIntersectsPath, polylineFromPoints, portControls, portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, pxExtent, quadraticEvalAt, rectMarkerPath, rectPath, rectToContour, regularPolygonPath, remapPointValues, resolveEasing, retractHandles, reverseAnchors, reversePath, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roundRectPath, scale, scaleDelta, scalePathToBounds, schneiderFit, screenAngleOf, segmentAt, segmentEnds, segmentsCross, setDefaultOpenFill, sign, simplifyPath, splitByClosure, splitCubicAt, splitLineAt, splitQuadraticAt, splitSubpaths, squarePath, standoff, starPath, strokeHitTest, sub, subpathEndAt, tagTypedArray, tagTypedArrays, transformCoords, transformPath, translate, translateAnchorBy, translateAnchorsSymmetric, translatePath, typedArrayReplacer, unionBoundsPath, unionBox, untagTypedArray, viewToMat3, withinPxBox, withinPxRadius, worldEditToStorage };