@weasel-js/geom 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/dist/index.d.ts CHANGED
@@ -1,3 +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
4
  export { P as PORT_REACH } from './portCurve-BBr7eHAL.js';
2
5
 
3
6
  /**
@@ -34,6 +37,7 @@ declare function sign(n: number): -1 | 0 | 1;
34
37
  */
35
38
  declare function approxEq(a: number, b: number, eps?: number): boolean;
36
39
 
40
+ /** `[a, b, c, d, e, f]`: `x' = a·x + c·y + e`, `y' = b·x + d·y + f`. */
37
41
  type Mat3 = readonly [number, number, number, number, number, number];
38
42
  /** The transform that leaves a point where it is. */
39
43
  declare function identity(): Mat3;
@@ -73,6 +77,9 @@ declare function boundsOfCoords(coords: ArrayLike<number>): Box | null;
73
77
  declare function unionBox(a: Box, b: Box): Box;
74
78
  /** Inclusive point-in-box test. */
75
79
  declare function boxContainsPoint(b: Box, x: number, y: number): boolean;
80
+ /** Whether `outer` wholly holds `inner`, edges inclusive. Two boxes that merely
81
+ * overlap answer false. */
82
+ declare function boxContainsBox(outer: Box, inner: Box): boolean;
76
83
  /** Interleaved corner ring for a rect at (x,y,w,h), wound clockwise from the
77
84
  * origin corner. The closing edge is implicit — the same unclosed shape
78
85
  * `pointInPolygon` takes, and what a repeated first vertex would leave as a
@@ -81,7 +88,7 @@ declare function rectToContour(x: number, y: number, w: number, h: number): Floa
81
88
 
82
89
  /**
83
90
  * SVG-style command-stream encoding — the kit's single declaration of the path
84
- * opcodes. `Path` in @weasel-js/core wraps this with `kind` + `fillRule`.
91
+ * opcodes. `Path` (`./path`) wraps this with `kind` + `fillRule`.
85
92
  *
86
93
  * The codes index a `Uint8Array` command stream whose coords live in a
87
94
  * parallel float array, so a code declared anywhere but `PATH_COMMANDS` makes
@@ -121,10 +128,15 @@ declare const PATH_COMMANDS: {
121
128
  type PathCommandName = keyof typeof PATH_COMMANDS;
122
129
  /** Numeric code of a declared command. */
123
130
  type PathCommandCode = (typeof PATH_COMMANDS)[PathCommandName]['code'];
131
+ /** Command code of `M` (moveTo). */
124
132
  declare const PATH_M: 0;
133
+ /** Command code of `L` (lineTo). */
125
134
  declare const PATH_L: 1;
135
+ /** Command code of `C` (cubic bezier). */
126
136
  declare const PATH_C: 2;
137
+ /** Command code of `Q` (quadratic bezier). */
127
138
  declare const PATH_Q: 3;
139
+ /** Command code of `Z` (close subpath). */
128
140
  declare const PATH_Z: 4;
129
141
  /** Float coords consumed by each command, indexed by command code. */
130
142
  declare const PATH_CMD_LENGTHS: readonly number[];
@@ -137,6 +149,9 @@ declare function pathCommandCoordCount(cmd: number): number;
137
149
  * `false`. The pen advances to the command's last coord pair afterward; `Z`
138
150
  * returns it to the subpath's opening `M`, so a command following a `Z`
139
151
  * without an intervening `M` starts where SVG says it does.
152
+ *
153
+ * A code `PATH_COMMANDS` does not declare throws once the visitor has seen it,
154
+ * since the walker cannot tell how many coords it consumes.
140
155
  */
141
156
  declare function forEachSegment(commands: ArrayLike<number>, coords: ArrayLike<number>, visit: (cmd: number, coordIndex: number, penX: number, penY: number, commandIndex: number) => void | boolean): void;
142
157
 
@@ -150,6 +165,58 @@ declare function cubicEvalAt(x0: number, y0: number, x1: number, y1: number, x2:
150
165
  declare function elevateQuadraticToCubic(q0x: number, q0y: number, cx: number, cy: number, q1x: number, q1y: number): [number, number, number, number];
151
166
  /** Tight AABB of a cubic, evaluating only extrema that lie on the curve. */
152
167
  declare function cubicBounds(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): Box;
168
+ /** Quadratic Bezier point at parameter t (Bernstein form). */
169
+ declare function quadraticEvalAt(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, t: number): [number, number];
170
+ /** A line segment's coords: start, end. */
171
+ type LineCoords = [number, number, number, number];
172
+ /** A quadratic Bezier's coords: start, control, end. */
173
+ type QuadraticCoords = [number, number, number, number, number, number];
174
+ /** A cubic Bezier's coords: start, two controls, end. */
175
+ type CubicCoords = [number, number, number, number, number, number, number, number];
176
+ /**
177
+ * Split a cubic at parameter t (de Casteljau). The two halves share the point
178
+ * at t and together trace the original exactly. A t outside [0, 1] splits the
179
+ * curve's polynomial extension.
180
+ */
181
+ declare function splitCubicAt(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, t: number): [CubicCoords, CubicCoords];
182
+ /** Split a quadratic at parameter t (de Casteljau). See {@link splitCubicAt}. */
183
+ declare function splitQuadraticAt(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, t: number): [QuadraticCoords, QuadraticCoords];
184
+ /** Split a line segment at parameter t. See {@link splitCubicAt}. */
185
+ declare function splitLineAt(x0: number, y0: number, x1: number, y1: number, t: number): [LineCoords, LineCoords];
186
+
187
+ /** The point on one segment nearest a probe. */
188
+ interface CurveNearest {
189
+ x: number;
190
+ y: number;
191
+ /** Curve parameter of the point, in [0, 1]. */
192
+ t: number;
193
+ /** Euclidean distance from the probe. */
194
+ dist: number;
195
+ }
196
+ /** The point on a path nearest a probe, and the command whose segment holds it. */
197
+ interface PathNearest extends CurveNearest {
198
+ /** Index of the segment's command in the command stream (`L`, `Q`, `C` or `Z`). */
199
+ commandIndex: number;
200
+ /** Offset of that command's first coord; for a `Z`, where its coords would begin. */
201
+ coordIndex: number;
202
+ }
203
+ /** Nearest point on segment (x0,y0)-(x1,y1) to (px,py). */
204
+ declare function nearestOnLine(px: number, py: number, x0: number, y0: number, x1: number, y1: number): CurveNearest;
205
+ /**
206
+ * Nearest point on the cubic (x0,y0)…(x3,y3) to (px,py). Samples the curve,
207
+ * then refines every sampled local minimum with bracketed Newton on the
208
+ * distance derivative, so a loop or cusp cannot capture it in the wrong basin.
209
+ */
210
+ declare function nearestOnCubic(px: number, py: number, x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): CurveNearest;
211
+ /** Nearest point on the quadratic (x0,y0)(x1,y1)(x2,y2) to (px,py). */
212
+ declare function nearestOnQuadratic(px: number, py: number, x0: number, y0: number, x1: number, y1: number, x2: number, y2: number): CurveNearest;
213
+ /**
214
+ * Nearest point on a command-stream path to (px,py), over every `L`, `Q`, `C`
215
+ * and the closing edge each `Z` draws. The earliest segment wins a tie.
216
+ * Returns `null` when the path has no segment, and throws on a command code
217
+ * `PATH_COMMANDS` does not declare.
218
+ */
219
+ declare function nearestOnPath(commands: ArrayLike<number>, coords: ArrayLike<number>, px: number, py: number): PathNearest | null;
153
220
 
154
221
  /**
155
222
  * The port-curve rule in the 2D kernel's currency: loose scalars, the way
@@ -228,6 +295,379 @@ declare function segmentsCross(ax: number, ay: number, bx: number, by: number, c
228
295
  /** Squared distance from (px,py) to segment (ax,ay)-(bx,by), endpoint-clamped. */
229
296
  declare function pointSegmentDist2(px: number, py: number, ax: number, ay: number, bx: number, by: number): number;
230
297
 
298
+ /**
299
+ * Fluent builder for `PolygonPath`. Hides the `Uint8Array` / `Float32Array`
300
+ * encoding behind move/line/curve/close calls and a final `build()`. Use
301
+ * this to construct paths in tests and demos; production callers that need
302
+ * to mutate large paths in place should reach for the raw arrays directly.
303
+ *
304
+ * Numeric capacity grows by doubling — typical for amortized O(1) push.
305
+ *
306
+ * Also exposes `rectPath` / `polygonFromPoints` shortcuts for the common
307
+ * cases. `rectPath` returns the lighter `RectPath` subtype, not a polygon.
308
+ */
309
+
310
+ /** Fluent builder for `PolygonPath`; hides the `Uint8Array`/`Float32Array` encoding behind move/line/curve/close calls. */
311
+ declare class PathBuilder {
312
+ private cmds;
313
+ private xs;
314
+ private fillRule;
315
+ /** Seed a builder with an existing `PolygonPath`. Useful for extending
316
+ * an in-flight path with another segment (e.g. appending a cubic to
317
+ * the end of a curve in response to a user action) without hand-
318
+ * reaching into the `commands` / `coords` typed arrays.
319
+ *
320
+ * ```ts
321
+ * const next = PathBuilder.fromPath(current).curveTo(...).build();
322
+ * ```
323
+ */
324
+ static fromPath(path: PolygonPath): PathBuilder;
325
+ setFillRule(rule: PathFillRule): this;
326
+ moveTo(x: number, y: number): this;
327
+ lineTo(x: number, y: number): this;
328
+ /** Cubic bezier to (x, y) with control points (x1, y1) and (x2, y2). */
329
+ curveTo(x1: number, y1: number, x2: number, y2: number, x: number, y: number): this;
330
+ /** Quadratic bezier to (x, y) with control point (x1, y1). */
331
+ quadTo(x1: number, y1: number, x: number, y: number): this;
332
+ close(): this;
333
+ build(): PolygonPath;
334
+ }
335
+ /** Construct a `RectPath` (the fast-path subtype). */
336
+ declare function rectPath(x: number, y: number, width: number, height: number): RectPath;
337
+ /** Build an open polyline from a flat list of points — the same geometry as
338
+ * {@link polygonFromPoints} without the closing edge. A freehand stroke and a
339
+ * measurement line want this; a region wants the closed one. */
340
+ declare function polylineFromPoints(points: readonly {
341
+ x: number;
342
+ y: number;
343
+ }[]): PolygonPath | RectPath;
344
+ /** Build a closed polygon from a flat list of points. */
345
+ declare function polygonFromPoints(points: readonly {
346
+ x: number;
347
+ y: number;
348
+ }[], opts?: {
349
+ fillRule?: PathFillRule;
350
+ }): PolygonPath;
351
+ /** Closed ellipse inscribed in `bounds`, as a 4-cubic-Bezier `PolygonPath`.
352
+ * Matches the geometry `useEllipseTool`'s overlay paints. */
353
+ declare function ellipsePath(bounds: {
354
+ x: number;
355
+ y: number;
356
+ width: number;
357
+ height: number;
358
+ }): PolygonPath;
359
+ /** Closed regular n-gon centered at `center`, circumscribed by `radius`.
360
+ * `rotation` is in radians; default 0 puts the first vertex on the +x axis. */
361
+ declare function regularPolygonPath(center: {
362
+ x: number;
363
+ y: number;
364
+ }, radius: number, sides: number, rotation?: number): PolygonPath;
365
+ /** Closed n-pointed star centered at `center`, alternating `outerRadius` and
366
+ * `innerRadius` (default `outerRadius / 2`). `rotation` is in radians. */
367
+ declare function starPath(center: {
368
+ x: number;
369
+ y: number;
370
+ }, outerRadius: number, points?: number, innerRadius?: number, rotation?: number): PolygonPath;
371
+ /** Open 2-vertex polyline from `a` to `b` — strokeable, not fillable. */
372
+ declare function linePath(a: {
373
+ x: number;
374
+ y: number;
375
+ }, b: {
376
+ x: number;
377
+ y: number;
378
+ }): PolygonPath;
379
+
380
+ /**
381
+ * AABB bounds of a `Path`. Returned as `RectPath` for direct reuse with the
382
+ * rect fast path machinery (selection AABB, area-select intersection).
383
+ *
384
+ * `RectPath` is its own bounds — O(1). For `PolygonPath`, walk segment by
385
+ * segment, computing the tight bound per segment:
386
+ *
387
+ * - `M` / `L`: just the endpoint.
388
+ * - `Q`: quadratic Bezier — endpoints plus axis-aligned extrema (one
389
+ * possible inflection per axis).
390
+ * - `C`: cubic Bezier — endpoints plus axis-aligned extrema (up to two
391
+ * possible inflections per axis, found via the quadratic formula on
392
+ * the derivative).
393
+ *
394
+ * Control points are NOT included directly; they're used only to compute
395
+ * extrema that actually lie on the curve. This avoids the classic "AABB
396
+ * extends past where the curve visibly reaches" bug for curved paths whose
397
+ * control points poke outside the visible extent.
398
+ *
399
+ * Empty paths (no commands) return a zero-size rect anchored at the
400
+ * origin — the convention used elsewhere in the kit for missing geometry.
401
+ */
402
+
403
+ /** AABB of a `Path`, returned as a `RectPath` for direct reuse with rect-fast-path machinery. */
404
+ declare function boundsOfPath(path: Path): RectPath;
405
+
406
+ /**
407
+ * AABB union over a heterogeneous set of `Path` poses. Returns the
408
+ * envelope as a `RectPath`, or `null` for empty input — analog of
409
+ * `unionBounds` for the rect-only model.
410
+ */
411
+
412
+ /** AABB envelope over a set of `Path` instances; returns `null` for empty input. */
413
+ declare function unionBoundsPath(paths: Iterable<Path>): RectPath | null;
414
+
415
+ /**
416
+ * In-place and copy-out path transforms. Translation is the most common —
417
+ * called every pointermove during a drag — so the polygon variant mutates
418
+ * the float buffer directly to keep allocation pressure off the GC.
419
+ *
420
+ * `scalePathToBounds` is for the resize interaction: given the path's
421
+ * current AABB and the desired new AABB, scales every coordinate
422
+ * proportionally.
423
+ */
424
+
425
+ /**
426
+ * Translate a path by (dx, dy). Returns a new instance — the kit's pose
427
+ * model treats poses as immutable to keep React state-update semantics
428
+ * predictable. Polygon coords are copied into a fresh `Float32Array`.
429
+ */
430
+ declare function translatePath(path: Path, dx: number, dy: number): Path;
431
+ /**
432
+ * Scale a path's coords so its current AABB maps to `target`. Resize
433
+ * interactions use this to make a polygon follow a corner-handle drag.
434
+ *
435
+ * A degenerate source axis (zero width or height) has no ratio to scale by,
436
+ * so `boxToBox` translates that axis instead — a zero scale is not
437
+ * invertible and would discard what is left on it.
438
+ */
439
+ declare function scalePathToBounds(path: Path, target: RectPath): Path;
440
+
441
+ /** Apply an affine `Mat3` to a path's geometry.
442
+ *
443
+ * Axis-aligned maps (no rotation/shear, i.e. `m[1] === 0 && m[2] === 0`) keep a
444
+ * `RectPath` a rect — the four corners stay axis-aligned, so we transform the
445
+ * two diagonal corners and normalize negative extent (mirror). Rotation or
446
+ * shear promotes the rect's four corners to a `PolygonPath`. Polygon paths map
447
+ * every coord via the kernel's `transformCoords`, preserving the command stream
448
+ * and `fillRule`. Never mutates the input.
449
+ *
450
+ * `Mat3` here is the 6-tuple `number[]` from `@weasel-js/geom` (DOMMatrix order:
451
+ * `[a, b, c, d, e, f]` where `x' = a·x + c·y + e`, `y' = b·x + d·y + f`),
452
+ * not the renderer's 9-element `Float32Array`. */
453
+ declare function transformPath(path: Path, m: Mat3): Path;
454
+
455
+ /**
456
+ * Translation-only compose/decompose for `Path` poses, the analog of
457
+ * `composeRectPose` / `decomposeRectPose` for the rect-only model. Pair
458
+ * with `composeWorldPose` / `rebaseLocalPose` when an adapter uses `Path`
459
+ * as its `TPose`.
460
+ *
461
+ * Only translation is folded — the kit's hierarchy contract is
462
+ * translation-only, same as for rects. Parent rotation/scale would require
463
+ * a richer compose; that's out of scope here.
464
+ */
465
+
466
+ /** Express `child` (in `parent`'s local frame) in the next frame up. */
467
+ declare function composePath(parent: Path, child: Path): Path;
468
+ /** Inverse of `composePath` — undo `parent`'s translation from a world pose. */
469
+ declare function decomposePath(parent: Path, world: Path): Path;
470
+
471
+ /**
472
+ * Split a `PolygonPath` at each `M` command, returning one `PolygonPath` per
473
+ * subpath. Inverse-ish of compound-path construction: a multi-region
474
+ * (compound) path becomes N independent paths.
475
+ *
476
+ * `fillRule` is propagated unchanged to every output. Even-odd compound paths
477
+ * with interior "holes" lose the hole semantics — each subpath becomes its
478
+ * own filled region. (Same behavior as Illustrator's Release Compound Path.)
479
+ *
480
+ * If the input has zero `M` commands (which would already be malformed) the
481
+ * input is returned wrapped in a single-element array. A path with exactly
482
+ * one subpath is also returned as a single-element array — a trivial pass.
483
+ */
484
+
485
+ /** Split a path into one path per subpath, cutting at each `M`. A path with a
486
+ * single subpath comes back as a one-element array. */
487
+ declare function splitSubpaths(path: PolygonPath): PolygonPath[];
488
+
489
+ /**
490
+ * Contour orientation: which way a path winds, and the same path wound the
491
+ * other way. Under `'nonzero'` two overlapping contours fill their overlap
492
+ * only when they wind the same way, so composing shapes from different
493
+ * sources into one compound path first needs them to agree.
494
+ */
495
+
496
+ /**
497
+ * Signed area enclosed by `path`, summed over its contours. Positive for a
498
+ * contour that turns clockwise on a y-down screen (the shoelace sign), so a
499
+ * hole wound against its outer contour subtracts. An open contour counts as
500
+ * closed by a straight edge back to its start, the way a fill closes it.
501
+ * Curved segments are integrated exactly, not through their control polygon.
502
+ * A `RectPath` has no direction and counts as positive.
503
+ */
504
+ declare function pathSignedArea(path: Path): number;
505
+ /**
506
+ * `path` with every contour traversed backwards: same region, same curves,
507
+ * opposite winding. A closed contour keeps its starting point; an open one
508
+ * starts from where it used to end.
509
+ */
510
+ declare function reversePath(path: PolygonPath): PolygonPath;
511
+
512
+ /**
513
+ * `pathFromD` — build a weasel `Path` from an **SVG path-data string** (the
514
+ * value of SVG's `d` attribute, e.g. `"M0 0 L100 0 Z"`).
515
+ *
516
+ * This is the terse, declarative composition surface for geometry: a
517
+ * consumer authors a shape as `d` and hands it straight to a scene/op API,
518
+ * instead of chaining imperative builder calls. SVG `d` is deliberately the
519
+ * language — it's a standard every consumer already knows, so the kit gets
520
+ * path-language expressiveness without minting a new one. See
521
+ * `docs/conventions.md` ("Compose scenes in a terse path language").
522
+ *
523
+ * Lowers every supported command (M/m L/l H/h V/v C/c S/s Q/q T/t A/a Z/z)
524
+ * into weasel's `PathBuilder` primitives (move, line, cubic, quadratic,
525
+ * close). Smooth (`S`/`s`/`T`/`t`) commands resolve their implicit reflected
526
+ * control point from the previous cubic / quadratic. Arc commands (`A`/`a`)
527
+ * convert to a series of cubic Bezier curves using the standard
528
+ * endpoint-parameterization formulas (F.6.5 in the SVG spec): we reconstruct
529
+ * the center, sweep angle, and a fixed number of (≤ 90°) cubic segments per
530
+ * arc.
531
+ *
532
+ * No runtime dependency — a small hand-rolled parser. `@weasel-js/svg`'s
533
+ * document parser (`parseSvg`) calls this for `<path d=…>` elements, so the
534
+ * `d` grammar coverage is shared between the two entry points.
535
+ */
536
+
537
+ /**
538
+ * Build a weasel `PolygonPath` from an SVG path-data (`d`) string. Unknown
539
+ * command letters are skipped (and reported via `onWarn` when provided); the
540
+ * builder still returns whatever valid commands preceded them.
541
+ */
542
+ declare function pathFromD(d: string, onWarn?: (message: string) => void): ReturnType<PathBuilder['build']>;
543
+
544
+ /**
545
+ * A station along a path: where it is at a fraction of its length, and which
546
+ * way it is heading there.
547
+ *
548
+ * For anything positioned *along* geometry rather than beside it — a label on a
549
+ * routed edge, a tick on a curve, a badge near an arrowhead. Curves are
550
+ * flattened first, so the fraction is arc length along the drawn shape rather
551
+ * than a curve parameter, which is what makes 0.5 look like the middle.
552
+ */
553
+
554
+ /** The answer `pointAlongPath` gives: a point on the path and its heading there. */
555
+ interface PathStation {
556
+ point: Point;
557
+ /** Unit vector along the path at `point`, pointing toward the end. */
558
+ tangent: Point;
559
+ }
560
+ /** Options for `pointAlongPath`. */
561
+ interface PointAlongPathOptions {
562
+ /** Curve flattening tolerance, in world units. Default 0.5. */
563
+ flattenTolerance?: number;
564
+ }
565
+ /**
566
+ * Where `path` is at `t` of its total length, and its heading there.
567
+ *
568
+ * `t` is clamped to 0..1. Subpaths are measured in order and treated as one
569
+ * run, the way a browser measures a whole `<path>`. Returns `null` for a path
570
+ * with no points at all; a path of zero length answers at its single point,
571
+ * heading along +X.
572
+ */
573
+ declare function pointAlongPath(path: Path, t: number, opts?: PointAlongPathOptions): PathStation | null;
574
+
575
+ /**
576
+ * Pure-geometry distance from a point to a path's boundary (stroke), with
577
+ * no fill-side logic. Used by pickers that want to know "how close is this
578
+ * click to the visible edge of the shape?" Callers combine this with
579
+ * `pathContainsPoint` from `pathHitTest.ts` to get a closed-region
580
+ * pick distance (0 inside, stroke-distance outside).
581
+ *
582
+ * A polygon path defers to geom's `nearestOnPath`; a RectPath short-circuits
583
+ * to AABB-perimeter math.
584
+ */
585
+
586
+ /** Closest Euclidean distance from (px, py) to the boundary of `path`.
587
+ * Pure stroke distance — does *not* consult fill rule or interior. For
588
+ * closed-region pick distance ("0 inside, stroke-distance outside"),
589
+ * combine with `pathContainsPoint` at the call site. */
590
+ declare function pathDistanceToPoint(path: Path, px: number, py: number): number;
591
+
592
+ /**
593
+ * Schneider (1990, Graphics Gems I) adaptive cubic-Bezier fitter.
594
+ * Given a sequence of sample points, returns a `PolygonPath` whose `C`
595
+ * segments approximate the samples within `errorTolerance` world units.
596
+ *
597
+ * Output shape: an initial `M` to the first sample, followed by N
598
+ * `C` cubic segments. For colinear / two-point inputs, returns a single
599
+ * degenerate cubic. For empty input, returns an empty polygon path.
600
+ */
601
+ declare function schneiderFit(samples: ReadonlyArray<Point>, errorTolerance: number): PolygonPath;
602
+
603
+ /**
604
+ * Path hit-testing: path-vs-point (filled region and stroke distance),
605
+ * path-vs-rect, and path-vs-polygon in both directions.
606
+ *
607
+ * A `rect` path short-circuits to AABB arithmetic. A `polygon` path is its
608
+ * filled region: beziers are flattened, `fillRule` is honored (default
609
+ * `nonzero`), and every closed subpath counts — the hole of a donut is not
610
+ * part of the shape under `evenodd`. Open subpaths enclose no area, so the
611
+ * filled-region tests ignore them.
612
+ */
613
+
614
+ type XY = {
615
+ x: number;
616
+ y: number;
617
+ };
618
+ /** Options for the path hit-tests. */
619
+ interface PointInPathOptions {
620
+ /** Bezier flattening tolerance in world units. Default 0.5. */
621
+ tolerance?: number;
622
+ }
623
+ /** Options for {@link strokeHitTest}. */
624
+ interface StrokeHitTestOptions {
625
+ /** Bezier flattening tolerance in world units. Default 0.5. */
626
+ tolerance?: number;
627
+ /** Extra reach past the band measured in screen pixels rather than world
628
+ * units: `px` pixels, after `transform` carries the path's frame to the
629
+ * screen (only its linear part matters). A pointer's forgiveness is a
630
+ * screen distance, and under a non-uniform or rotated-then-squished
631
+ * transform no world distance equals it. */
632
+ slop?: {
633
+ px: number;
634
+ transform: Mat3;
635
+ };
636
+ }
637
+ /** Filled-region hit-test for a path. Rect short-circuits to AABB; polygons run ray-cast / winding per `fillRule`. */
638
+ declare function pointInPath(path: Path, x: number, y: number, opts?: PointInPathOptions): boolean;
639
+ /**
640
+ * Stroke-distance hit-test. True when (x, y) lies within `threshold` world
641
+ * units of the path's outline — when a stroke of total width `2 * threshold`
642
+ * drawn along the path would cover the point. Works for open and closed
643
+ * subpaths alike; OR it with {@link pointInPath} for fill-plus-stroke picking.
644
+ * Every flattened segment is treated as a capsule of radius `threshold`.
645
+ */
646
+ declare function strokeHitTest(path: Path, x: number, y: number, threshold: number, opts?: StrokeHitTestOptions): boolean;
647
+ /** Returns true if (x, y) lies within the filled region of `path`. */
648
+ declare function pathContainsPoint(path: Path, x: number, y: number, opts?: PointInPathOptions): boolean;
649
+ /** Returns true if `rect` is entirely contained within `path`. */
650
+ declare function pathContainsRect(path: Path, rect: Rect, opts?: PointInPathOptions): boolean;
651
+ /** Returns true if `rect` overlaps (intersects or contains) `path`. */
652
+ declare function pathIntersectsRect(path: Path, rect: Rect, opts?: PointInPathOptions): boolean;
653
+ /** Returns true if every vertex of `polygon` lies inside `path`. */
654
+ declare function pathContainsPolygon(path: Path, polygon: readonly XY[], opts?: PointInPathOptions): boolean;
655
+ /** Returns true if `polygon` overlaps (intersects or is contained by) `path`. */
656
+ declare function pathIntersectsPolygon(path: Path, polygon: readonly XY[], opts?: PointInPathOptions): boolean;
657
+ /**
658
+ * Returns true if all of `path` — every subpath, open ones included, beziers
659
+ * flattened — lies inside the closed `polygon`: the inverse of
660
+ * {@link pathContainsPolygon}. A lasso enclosing a shape asks this.
661
+ */
662
+ declare function polygonContainsPath(polygon: readonly XY[], path: Path, opts?: PointInPathOptions): boolean;
663
+ /**
664
+ * Returns true if any of `path` meets the closed `polygon`: its filled region,
665
+ * or the line of an open subpath, which encloses nothing. Beziers are
666
+ * flattened, so a control point off the curve never counts. The companion of
667
+ * {@link polygonContainsPath}; a lasso touching a shape asks this.
668
+ */
669
+ declare function polygonIntersectsPath(polygon: readonly XY[], path: Path, opts?: PointInPathOptions): boolean;
670
+
231
671
  /**
232
672
  * Apply an affine to an interleaved coord stream, returning a fresh f64
233
673
  * buffer. Command codes are unaffected — for a Bezier the transformed control
@@ -273,6 +713,158 @@ interface PlacedRect {
273
713
  * size. A rect too big to fit pins to the boundary's leading edge.
274
714
  */
275
715
  declare function clampRectWithin(rect: Rect, boundary: Rect, padding?: number): Rect;
716
+ /**
717
+ * Position an overlay beside `anchor` at the requested placement. With `flip`,
718
+ * a side that overflows the boundary is swapped for the opposite one when that
719
+ * fits. The result then slides along the alignment axis to stay inside the
720
+ * boundary; along the side axis it is left where it is, even if it overflows.
721
+ */
276
722
  declare function placeRect(options: PlaceRectOptions): PlacedRect;
277
723
 
278
- export { type Box, DEFAULT_FLATTEN_TOLERANCE, EPS, type Mat3, PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, type PathCommandCode, type PathCommandName, type PlaceRectOptions, type PlacedRect, type Placement, type PlacementAlign, type PlacementSide, type Rect, applyToPoint, approxEq, boundsOfCoords, boxContainsPoint, boxToBox, clampRectWithin, cross, cubicBounds, cubicEvalAt, dot, elevateQuadraticToCubic, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, forEachSegment, identity, invert, len2, multiply, pathCommandCoordCount, placeRect, pointInPolygon, pointSegmentDist2, portControls, portCurvePoints, rectToContour, rotate, rotateAboutPoint, scale, segmentsCross, sign, sub, transformCoords, translate, unionBox };
724
+ /** An easing curve: maps normalized progress `t ∈ [0, 1]` to eased progress.
725
+ * Curves may leave the 0–1 range in the middle (back, elastic) but should
726
+ * pass through 0 at 0 and 1 at 1. */
727
+ type EasingFn = (t: number) => number;
728
+ /** A spring's physical parameters. Higher stiffness settles faster, higher
729
+ * damping overshoots less, higher mass makes both sluggish. */
730
+ interface SpringPreset {
731
+ stiffness: number;
732
+ damping: number;
733
+ mass: number;
734
+ }
735
+ /** One of the tunings in `SPRING_PRESETS`. */
736
+ type SpringPresetName = 'gentle' | 'wobbly' | 'stiff' | 'slow';
737
+ /** No easing: constant rate from start to finish. */
738
+ declare const linear: EasingFn;
739
+ /** Accelerates from a standstill, gently. */
740
+ declare const easeInQuad: EasingFn;
741
+ /** Decelerates to a stop, gently. The safe default for UI motion. */
742
+ declare const easeOutQuad: EasingFn;
743
+ /** Accelerates then decelerates, gently. */
744
+ declare const easeInOutQuad: EasingFn;
745
+ /** Accelerates from a standstill, moderately. */
746
+ declare const easeInCubic: EasingFn;
747
+ /** Decelerates to a stop, moderately. */
748
+ declare const easeOutCubic: EasingFn;
749
+ /** Accelerates then decelerates, moderately. */
750
+ declare const easeInOutCubic: EasingFn;
751
+ /** Accelerates from a standstill, sharply. */
752
+ declare const easeInQuart: EasingFn;
753
+ /** Decelerates to a stop, sharply. */
754
+ declare const easeOutQuart: EasingFn;
755
+ /** Accelerates then decelerates, sharply. */
756
+ declare const easeInOutQuart: EasingFn;
757
+ /** Accelerates from a standstill, very sharply. */
758
+ declare const easeInQuint: EasingFn;
759
+ /** Decelerates to a stop, very sharply. */
760
+ declare const easeOutQuint: EasingFn;
761
+ /** Accelerates then decelerates, very sharply. */
762
+ declare const easeInOutQuint: EasingFn;
763
+ /** Accelerates from a standstill along a sine curve — the mildest
764
+ * acceleration of the built-ins. */
765
+ declare const easeInSine: EasingFn;
766
+ /** Decelerates to a stop along a sine curve — the mildest
767
+ * deceleration of the built-ins. */
768
+ declare const easeOutSine: EasingFn;
769
+ /** Accelerates then decelerates along a sine curve. */
770
+ declare const easeInOutSine: EasingFn;
771
+ /** Accelerates exponentially: barely moves at first, then rushes. */
772
+ declare const easeInExpo: EasingFn;
773
+ /** Decelerates exponentially: leaps away, then creeps in. */
774
+ declare const easeOutExpo: EasingFn;
775
+ /** Exponential at both ends — a very fast middle between two
776
+ * near-still extremes. */
777
+ declare const easeInOutExpo: EasingFn;
778
+ /** Accelerates along a circular arc: slow start, abrupt arrival. */
779
+ declare const easeInCirc: EasingFn;
780
+ /** Decelerates along a circular arc: abrupt start, slow arrival. */
781
+ declare const easeOutCirc: EasingFn;
782
+ /** Circular arcs at both ends. */
783
+ declare const easeInOutCirc: EasingFn;
784
+ /** Pulls back past the start before moving forward. Overshoots below 0. */
785
+ declare const easeInBack: EasingFn;
786
+ /** Overshoots the target, then settles back onto it. Exceeds 1. */
787
+ declare const easeOutBack: EasingFn;
788
+ /** Overshoots at both ends. Leaves the 0–1 range on each side. */
789
+ declare const easeInOutBack: EasingFn;
790
+ /** Oscillates around the start with growing amplitude, then snaps away. */
791
+ declare const easeInElastic: EasingFn;
792
+ /** Springs past the target and wobbles into it. Exceeds 1. */
793
+ declare const easeOutElastic: EasingFn;
794
+ /** Wobbles at both ends. Leaves the 0–1 range on each side. */
795
+ declare const easeInOutElastic: EasingFn;
796
+ /** Lands on the target and bounces, in hops of decreasing height. */
797
+ declare const easeOutBounce: EasingFn;
798
+ /** Bounces up to the start before departing — `easeOutBounce` reversed. */
799
+ declare const easeInBounce: EasingFn;
800
+ /** Bounces at both ends. */
801
+ declare const easeInOutBounce: EasingFn;
802
+ /** Alias for `easeInQuad`, kept for call sites that predate the
803
+ * named-curve library. */
804
+ declare const easeIn: EasingFn;
805
+ /** Alias for `easeOutQuad`, kept for call sites that predate the
806
+ * named-curve library. */
807
+ declare const easeOut: EasingFn;
808
+ /** Alias for `easeInOutQuad`, kept for call sites that predate the
809
+ * named-curve library. */
810
+ declare const easeInOut: EasingFn;
811
+ /** All easings in one bag — useful for demos / pickers. */
812
+ declare const EASINGS: {
813
+ readonly linear: EasingFn;
814
+ readonly easeInQuad: EasingFn;
815
+ readonly easeOutQuad: EasingFn;
816
+ readonly easeInOutQuad: EasingFn;
817
+ readonly easeInCubic: EasingFn;
818
+ readonly easeOutCubic: EasingFn;
819
+ readonly easeInOutCubic: EasingFn;
820
+ readonly easeInQuart: EasingFn;
821
+ readonly easeOutQuart: EasingFn;
822
+ readonly easeInOutQuart: EasingFn;
823
+ readonly easeInQuint: EasingFn;
824
+ readonly easeOutQuint: EasingFn;
825
+ readonly easeInOutQuint: EasingFn;
826
+ readonly easeInSine: EasingFn;
827
+ readonly easeOutSine: EasingFn;
828
+ readonly easeInOutSine: EasingFn;
829
+ readonly easeInExpo: EasingFn;
830
+ readonly easeOutExpo: EasingFn;
831
+ readonly easeInOutExpo: EasingFn;
832
+ readonly easeInCirc: EasingFn;
833
+ readonly easeOutCirc: EasingFn;
834
+ readonly easeInOutCirc: EasingFn;
835
+ readonly easeInBack: EasingFn;
836
+ readonly easeOutBack: EasingFn;
837
+ readonly easeInOutBack: EasingFn;
838
+ readonly easeInElastic: EasingFn;
839
+ readonly easeOutElastic: EasingFn;
840
+ readonly easeInOutElastic: EasingFn;
841
+ readonly easeInBounce: EasingFn;
842
+ readonly easeOutBounce: EasingFn;
843
+ readonly easeInOutBounce: EasingFn;
844
+ };
845
+ /** The name of one of the built-in easing curves. */
846
+ type EasingName = keyof typeof EASINGS;
847
+ /** Named spring tunings, from softest to firmest. Springs settle on a target
848
+ * rather than running for a fixed duration, so these are an alternative to an
849
+ * easing curve, not a modifier on one. */
850
+ declare const SPRING_PRESETS: Record<SpringPresetName, SpringPreset>;
851
+
852
+ /** Cubic-bezier control points, CSS `cubic-bezier()` order. The curve's two
853
+ * endpoints are implicit at (0,0) and (1,1). */
854
+ interface BezierEasing {
855
+ /** `readonly` so an `as const` preset is assignable; nothing ever writes it. */
856
+ bezier: readonly [number, number, number, number];
857
+ }
858
+ /** An easing curve as a value: a function, the name of a built-in, or control
859
+ * points. Anything an editor has to name, show or serialize must not be a bare
860
+ * function, which is why the union exists. */
861
+ type EasingSpec = EasingFn | EasingName | BezierEasing;
862
+ /** Build the easing curve for four cubic-bezier control points. `x1`/`x2` are
863
+ * clamped to [0,1] — CSS `cubic-bezier()`'s constraint for a monotone x(t),
864
+ * which both `solveForX` root-finders assume. `y1`/`y2` are unclamped: an
865
+ * overshoot easing (back, elastic) needs them outside 0..1. */
866
+ declare function cubicBezierEasing(x1: number, y1: number, x2: number, y2: number): EasingFn;
867
+ /** Resolve a spec to the function that shapes progress. `undefined` is linear. */
868
+ declare function resolveEasing(spec?: EasingSpec): EasingFn;
869
+
870
+ 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, applyToPoint, approxEq, boundsOfCoords, boundsOfPath, boxContainsBox, boxContainsPoint, boxToBox, 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, 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 };