@weasel-js/core 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +501 -0
  2. package/dist/autoPoseDescriptor-Dr6CwNZK.d.ts +26 -0
  3. package/dist/{chunk-BDWAA634.js → chunk-44EWMJV2.js} +3 -3
  4. package/dist/{chunk-BDWAA634.js.map → chunk-44EWMJV2.js.map} +1 -1
  5. package/dist/{chunk-MQI4PIX3.js → chunk-H6N2JSZ3.js} +3 -3
  6. package/dist/{chunk-MQI4PIX3.js.map → chunk-H6N2JSZ3.js.map} +1 -1
  7. package/dist/chunk-HPFJUUTF.js +167 -0
  8. package/dist/chunk-HPFJUUTF.js.map +1 -0
  9. package/dist/{chunk-UCPV7JXC.js → chunk-L5YNZYEG.js} +9 -169
  10. package/dist/chunk-L5YNZYEG.js.map +1 -0
  11. package/dist/chunk-PNNZSYRD.js +318 -0
  12. package/dist/chunk-PNNZSYRD.js.map +1 -0
  13. package/dist/{chunk-MG7OXCAI.js → chunk-QEZL53V6.js} +2493 -1580
  14. package/dist/chunk-QEZL53V6.js.map +1 -0
  15. package/dist/clipboard.d.ts +1 -1
  16. package/dist/clone.d.ts +2 -2
  17. package/dist/{depSchema-nMqj_qTM.d.ts → depSchema-FKQBEfg7.d.ts} +116 -125
  18. package/dist/{grid-BrIa38gG.d.ts → grid-CuxXjaQV.d.ts} +22 -6
  19. package/dist/index.d.ts +780 -408
  20. package/dist/index.js +6 -4
  21. package/dist/insert.d.ts +3 -3
  22. package/dist/insert.js +2 -1
  23. package/dist/insert.js.map +1 -1
  24. package/dist/math-CeGmGPy8.d.ts +267 -0
  25. package/dist/math.d.ts +5 -0
  26. package/dist/math.js +4 -0
  27. package/dist/math.js.map +1 -0
  28. package/dist/move.d.ts +4 -4
  29. package/dist/move.js +3 -2
  30. package/dist/move.js.map +1 -1
  31. package/dist/{options-BDyCnrp8.d.ts → options-BPcmwYk7.d.ts} +1 -1
  32. package/dist/{autoPoseDescriptor-CvjflWJK.d.ts → pointSnapToGrid-CgcK2R_I.d.ts} +2 -26
  33. package/dist/{poseDescriptor-CGOgIgf8.d.ts → poseDescriptor-PgfVKfa0.d.ts} +1 -1
  34. package/dist/renderer.d.ts +7 -8
  35. package/dist/renderer.js +6 -4
  36. package/dist/resize.d.ts +5 -4
  37. package/dist/resize.js +3 -2
  38. package/dist/{types-DMyo7dnM.d.ts → types-BHGdrOcu.d.ts} +1 -1
  39. package/dist/{types-DtjCJA5r.d.ts → types-BdaK9PcP.d.ts} +1 -1
  40. package/package.json +14 -10
  41. package/dist/chunk-MG7OXCAI.js.map +0 -1
  42. package/dist/chunk-UCPV7JXC.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { NodeId } from '@weasel-js/routing';
2
- import { C as ClipboardSnapshot, I as InsertAdapter } from './types-DtjCJA5r.js';
2
+ import { C as ClipboardSnapshot, I as InsertAdapter } from './types-BdaK9PcP.js';
3
3
  import '@weasel-js/history';
4
4
 
5
5
  type Replacer$1 = (key: string, value: unknown) => unknown;
package/dist/clone.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { C as CloneBehavior } from './types-DMyo7dnM.js';
1
+ import { C as CloneBehavior } from './types-BHGdrOcu.js';
2
2
  import '@weasel-js/history';
3
- import './types-DtjCJA5r.js';
3
+ import './types-BdaK9PcP.js';
4
4
  import '@weasel-js/routing';
5
5
 
6
6
  /** Clone-on-alt-drag behavior for `useClone`; activates when Alt/Option is held at drag start. */
@@ -1,14 +1,13 @@
1
- import { GradStop, TextureHandle, FillStyle, Stroke } from '@weasel-js/paint';
2
- import { a as Path, P as PoseDescriptor } from './poseDescriptor-CGOgIgf8.js';
1
+ import { GradStop, ColorSpace, TextureHandle, FillStyle, Stroke, ScreenLength } from '@weasel-js/paint';
2
+ import { NodeId, Bounds, View, SelectionApi, ActionDeps, IngestItem, DragSample, Point2 } from '@weasel-js/routing';
3
+ import { a as Path, P as PoseDescriptor } from './poseDescriptor-PgfVKfa0.js';
3
4
  import { ResolvedRun, TextStyle, TextVerticalAlign } from '@weasel-js/text';
5
+ import { Mat3 } from '@weasel-js/geom';
4
6
  import * as _weasel_js_history from '@weasel-js/history';
5
7
  import { Op, History, SerializedHistory } from '@weasel-js/history';
6
- import { NodeId, Bounds, View as View$1, SelectionApi, ActionDeps, IngestItem, DragSample, Point2 } from '@weasel-js/routing';
7
- import { a as SceneAdapter, L as LayoutStrategy, I as InsertAdapter } from './types-DtjCJA5r.js';
8
- import { MutableRefObject, ReactNode } from 'react';
8
+ import { a as SceneAdapter, L as LayoutStrategy, I as InsertAdapter } from './types-BdaK9PcP.js';
9
9
  import { ActiveToolContextValue } from '@weasel-js/routing/react';
10
- import { B as BoundsConstraint, P as PointSnapBehavior } from './types-DMyo7dnM.js';
11
- import { Mat3 as Mat3$1 } from '@weasel-js/geom';
10
+ import { B as BoundsConstraint, P as PointSnapBehavior } from './types-BHGdrOcu.js';
12
11
 
13
12
  /**
14
13
  * Axis-aligned rectangle pose with optional rotation. The canonical pose
@@ -366,6 +365,12 @@ interface Scene<TData, TLayer extends string, TPose = RectPose> {
366
365
  * structural edit, so repeat calls hand back the same array — a snapshot,
367
366
  * not a live view, and not yours to mutate. */
368
367
  renderOrderNodes(): readonly Node<TData, TLayer, TPose>[];
368
+ /** The nodes on one layer, in render order. Cached alongside
369
+ * {@link Scene.renderOrderNodes} until a structural edit, so a caller that
370
+ * only cares about one layer pays the tree walk once rather than once per
371
+ * call. A snapshot, not a live view, and not yours to mutate. An unknown
372
+ * layer id yields an empty array. */
373
+ nodesOnLayer(layer: TLayer): readonly Node<TData, TLayer, TPose>[];
369
374
  add(spec: AddNodeSpec<TData, TLayer, TPose>): NodeId;
370
375
  /** Delete `id`, its **entire subtree**, and **everything that derives from**
371
376
  * any of those nodes — a node listing one of them in `dependsOn` goes too,
@@ -510,6 +515,15 @@ interface Scene<TData, TLayer extends string, TPose = RectPose> {
510
515
  canUndo(): boolean;
511
516
  canRedo(): boolean;
512
517
  batch<T>(label: string, fn: () => T): T;
518
+ /** Run `fn` with every mutation applied but none recorded — for writes
519
+ * that are not edits, such as a simulation stepping poses each frame.
520
+ * Undo and redo move between recorded states and never restore an
521
+ * untracked write; the next recorded change starts from whatever the
522
+ * untracked writes left, so undoing it lands there. A `batch` inside
523
+ * records nothing; inside a `batch`, these writes stay out of its entry.
524
+ * Notifies once, reverts `fn`'s writes if it throws, and throws on
525
+ * `applyBatch` and `history.apply` / `applyOps`, which exist to record. */
526
+ untracked<T>(fn: () => T): T;
513
527
  /** Read-only snapshot of every history entry currently reachable from
514
528
  * the present state. Oldest applied first, then redoable entries in
515
529
  * the order they'd be re-applied. Each entry id is stable. */
@@ -613,7 +627,7 @@ interface FitViewToBoundsOptions {
613
627
  * returns `currentView` unchanged and logs a `console.warn`. Callers that
614
628
  * want to no-op silently can detect zero area themselves before calling.
615
629
  */
616
- declare function fitViewToBounds(bounds: Bounds, viewportDims: ViewportDims, currentView: View$1, opts?: FitViewToBoundsOptions): View$1;
630
+ declare function fitViewToBounds(bounds: Bounds, viewportDims: ViewportDims, currentView: View, opts?: FitViewToBoundsOptions): View;
617
631
 
618
632
  /**
619
633
  * Minimal compile/link/lookup wrapper for a GL program. Throws
@@ -878,8 +892,9 @@ declare class GLImageCache {
878
892
  */
879
893
 
880
894
  /** Bake gradient stops into a 256-entry RGBA lookup strip, which the shader
881
- * samples instead of evaluating stops per fragment. */
882
- declare function buildGradientRamp(stops: GradStop[]): Uint8ClampedArray;
895
+ * samples instead of evaluating stops per fragment. `space` is the gradient's
896
+ * `interpolate` — the ramp is where a non-sRGB blend is paid for, once. */
897
+ declare function buildGradientRamp(stops: GradStop[], space?: ColorSpace): Uint8ClampedArray;
883
898
  declare class GradientRampAtlas {
884
899
  private readonly gl;
885
900
  /** Row per stop list, in least-recently-used order: a hit re-inserts, so the
@@ -905,7 +920,7 @@ declare class GradientRampAtlas {
905
920
  * its draw past this call may hold a row across another `upload` without
906
921
  * arranging to be flushed first.
907
922
  */
908
- upload(stops: GradStop[]): number;
923
+ upload(stops: GradStop[], space?: ColorSpace): number;
909
924
  /**
910
925
  * Whether uploading `stops` would move where existing rows sit — by growing
911
926
  * the atlas, which changes every row's `v`, or by recycling one, which
@@ -914,7 +929,7 @@ declare class GradientRampAtlas {
914
929
  * Anything holding a row past this call asks first and gets itself out of
915
930
  * the way, because neither can be undone once it has happened.
916
931
  */
917
- wouldReshape(stops: GradStop[]): boolean;
932
+ wouldReshape(stops: GradStop[], space?: ColorSpace): boolean;
918
933
  /**
919
934
  * The `v` a row is sampled at — its center.
920
935
  *
@@ -955,37 +970,51 @@ declare class GradientRampAtlas {
955
970
  * `apply(m, x, y)` returns `[m * (x, y, 1)] = [m00*x + m01*y + tx,
956
971
  * m10*x + m11*y + ty]`.
957
972
  */
958
- type Mat3 = Float32Array;
959
- declare function identity(): Mat3;
960
- declare function multiply(out: Mat3, m: Mat3): Mat3;
961
- declare function translate(m: Mat3, tx: number, ty: number): Mat3;
962
- declare function scale(m: Mat3, sx: number, sy: number): Mat3;
973
+
974
+ type GlMat3 = Float32Array;
975
+ declare function identity(): GlMat3;
976
+ declare function multiply(out: GlMat3, m: GlMat3): GlMat3;
977
+ /** `m · T(tx, ty)`: composes onto `m`, where `@weasel-js/geom`'s `translate`
978
+ * constructs a fresh matrix. */
979
+ declare function translated(m: GlMat3, tx: number, ty: number): GlMat3;
980
+ /** `m · S(sx, sy)`: composes onto `m`, where geom's `scale` constructs one. */
981
+ declare function scaled(m: GlMat3, sx: number, sy: number): GlMat3;
982
+ /** This layout read as the kernel's 6-element affine. The two carry the same
983
+ * logical order, so the conversion is a repack and nothing else — it exists
984
+ * so the repack has a name instead of appearing inline at each crossing. */
985
+ declare function toAffine(m: GlMat3): Mat3;
986
+ /** The kernel's affine in this layout. The inverse of {@link toAffine}, and
987
+ * what an `SvgGroupNode.transform` (also a kernel affine) becomes on its way
988
+ * to a `GroupDrawCommand`. */
989
+ declare function fromAffine(a: Mat3): GlMat3;
963
990
  /** Inverse of an affine matrix, or `null` when `@weasel-js/geom`'s `invert`
964
991
  * finds it singular — the same rule, read through this layout. */
965
- declare function invert(m: Mat3): Mat3 | null;
966
- declare function apply(m: Mat3, x: number, y: number): [number, number];
992
+ declare function invert(m: GlMat3): GlMat3 | null;
993
+ declare function apply(m: GlMat3, x: number, y: number): [number, number];
967
994
  /**
968
995
  * Map screen pixel coords (0..width on X, 0..height on Y, top-left origin)
969
996
  * into clip space (-1..1 on X, 1..-1 on Y — note Y flip so screen-down
970
997
  * matches clip-down).
971
998
  */
972
- declare function screenToClip(width: number, height: number): Mat3;
999
+ declare function screenToClip(width: number, height: number): GlMat3;
973
1000
  /**
974
1001
  * Uniform-equivalent scale factor: the square root of the absolute
975
1002
  * determinant of the linear part, i.e. the geometric mean of the two axis
976
1003
  * scales. Rotation-invariant. Under non-uniform scale it is between the two
977
1004
  * axes and exact on neither — the same compromise `meanScale` documents.
978
1005
  */
979
- declare function meanScaleOf(m: Mat3): number;
1006
+ declare function meanScaleOf(m: GlMat3): number;
980
1007
  /** The renderer's 3x3 matrix operations, as one namespace. These work on the
981
1008
  * 9-element `Float32Array` form the GL uniform upload wants — distinct from
982
- * `@weasel-js/geom`'s 6-element affine `Mat3`, though the logical element
1009
+ * `@weasel-js/geom`'s 6-element affine `GlMat3`, though the logical element
983
1010
  * order is the same. */
984
1011
  declare const mat3: {
985
1012
  identity: typeof identity;
1013
+ toAffine: typeof toAffine;
1014
+ fromAffine: typeof fromAffine;
986
1015
  multiply: typeof multiply;
987
- translate: typeof translate;
988
- scale: typeof scale;
1016
+ translated: typeof translated;
1017
+ scaled: typeof scaled;
989
1018
  invert: typeof invert;
990
1019
  apply: typeof apply;
991
1020
  screenToClip: typeof screenToClip;
@@ -995,7 +1024,7 @@ declare const mat3: {
995
1024
  /** Row-major 4×5 color matrix identity. */
996
1025
  declare const IDENTITY_COLOR_MATRIX: Float32Array<ArrayBuffer>;
997
1026
  interface GroupFrame {
998
- transform?: Mat3;
1027
+ transform?: GlMat3;
999
1028
  alpha?: number;
1000
1029
  /** Row-major 4×5 color matrix (20 floats). Absent leaves the stack unchanged. */
1001
1030
  colorMatrix?: Float32Array | number[];
@@ -1004,7 +1033,7 @@ declare class GroupState {
1004
1033
  private transformStack;
1005
1034
  private alphaStack;
1006
1035
  private colorMatrixStack;
1007
- get transform(): Mat3;
1036
+ get transform(): GlMat3;
1008
1037
  get alpha(): number;
1009
1038
  get colorMatrix(): Float32Array;
1010
1039
  push(frame: GroupFrame): void;
@@ -1162,7 +1191,7 @@ interface PathDrawCommand {
1162
1191
  * is how a container node's transform reaches its descendants. */
1163
1192
  interface GroupDrawCommand {
1164
1193
  kind: 'group';
1165
- transform?: Mat3;
1194
+ transform?: GlMat3;
1166
1195
  alpha?: number;
1167
1196
  /**
1168
1197
  * Optional 4×5 color matrix (row-major, 20 numbers) — `out = M₄ₓ₄ * in + bias`.
@@ -1384,7 +1413,7 @@ declare class DrawBatch {
1384
1413
  * alpha). An affine maps a rect to a parallelogram, so two triangles still
1385
1414
  * cover it and the batch draws at `u_model` identity.
1386
1415
  */
1387
- pushRect(x: number, y: number, w: number, h: number, m: Mat3, r: number, g: number, b: number, a: number): void;
1416
+ pushRect(x: number, y: number, w: number, h: number, m: GlMat3, r: number, g: number, b: number, a: number): void;
1388
1417
  /**
1389
1418
  * Append one image quad: the destination rect `(x, y, w, h)` mapped through
1390
1419
  * `m`, sampling `(u0, v0)`-`(u1, v1)`, every corner carrying `post` as the
@@ -1398,7 +1427,7 @@ declare class DrawBatch {
1398
1427
  * `slot` is the texture unit the corners sample, which `draw.ts` assigns per
1399
1428
  * bitmap within the run.
1400
1429
  */
1401
- pushQuad(x: number, y: number, w: number, h: number, m: Mat3, u0: number, v0: number, u1: number, v1: number, post: number, slot: number): void;
1430
+ pushQuad(x: number, y: number, w: number, h: number, m: GlMat3, u0: number, v0: number, u1: number, v1: number, post: number, slot: number): void;
1402
1431
  /**
1403
1432
  * Append one glyph quad: the box `(x0, y0)`-`(x1, y1)` mapped through `m`,
1404
1433
  * sampling `(u0, v0)`-`(u1, v1)` of the font atlas at `slot`, painted in
@@ -1420,7 +1449,7 @@ declare class DrawBatch {
1420
1449
  * winding, which is what lets a run of mixed rects, image quads and glyphs
1421
1450
  * keep the canonical index pattern.
1422
1451
  */
1423
- pushGlyph(x0: number, y0: number, x1: number, y1: number, baselineY: number, tanItalic: number, m: Mat3, u0: number, v0: number, u1: number, v1: number, r: number, g: number, b: number, a: number, slot: number, mode: number): void;
1452
+ pushGlyph(x0: number, y0: number, x1: number, y1: number, baselineY: number, tanItalic: number, m: GlMat3, u0: number, v0: number, u1: number, v1: number, r: number, g: number, b: number, a: number, slot: number, mode: number): void;
1424
1453
  /**
1425
1454
  * Append one rect filled by a gradient: the corners of `(x, y, w, h)` mapped
1426
1455
  * through `m`, sampling the ramp atlas at `slot`.
@@ -1437,16 +1466,16 @@ declare class DrawBatch {
1437
1466
  * Values outside 0..1 are the sampler's business; the atlas clamps to the
1438
1467
  * edge texel, which is what the gradient shader's own `clamp` did.
1439
1468
  */
1440
- pushGradientRect(x: number, y: number, w: number, h: number, m: Mat3, uv: GradientUV, post: number, slot: number, mode: number, r: number, g: number, b: number, a: number): void;
1469
+ pushGradientRect(x: number, y: number, w: number, h: number, m: GlMat3, uv: GradientUV, post: number, slot: number, mode: number, r: number, g: number, b: number, a: number): void;
1441
1470
  /** `pushMesh` for a mesh filled by a gradient — see `pushGradientRect` for
1442
1471
  * what `uv`, `post` and `mode` carry. */
1443
- pushGradientMesh(mesh: Mesh, m: Mat3, uv: GradientUV, post: number, slot: number, mode: number, r: number, g: number, b: number, a: number): void;
1472
+ pushGradientMesh(mesh: Mesh, m: GlMat3, uv: GradientUV, post: number, slot: number, mode: number, r: number, g: number, b: number, a: number): void;
1444
1473
  /**
1445
1474
  * Append a tessellated mesh through `m`, all vertices carrying `rgba`. The
1446
1475
  * mesh's own indices are rebased onto the staged vertices, which is why the
1447
1476
  * index buffer is uploaded per flush rather than written once.
1448
1477
  */
1449
- pushMesh(mesh: Mesh, m: Mat3, r: number, g: number, b: number, a: number): void;
1478
+ pushMesh(mesh: Mesh, m: GlMat3, r: number, g: number, b: number, a: number): void;
1450
1479
  /** Upload the staged geometry into the next set of buffers and bind its VAO.
1451
1480
  * Returns the index count for the caller's `drawElements`. */
1452
1481
  uploadAndBind(): number;
@@ -1554,7 +1583,7 @@ declare class WeaselRenderer {
1554
1583
  * with effects asks, so a canvas without them pays no memory. */
1555
1584
  private readonly effectTargets;
1556
1585
  private readonly imageMinification;
1557
- private readonly flattenTolerance?;
1586
+ private flattenTolerance?;
1558
1587
  private readonly bakeBudget;
1559
1588
  private readonly textOutlineMinScreenSize;
1560
1589
  private contextLost;
@@ -1630,7 +1659,10 @@ declare class WeaselRenderer {
1630
1659
  * it — every other command carries its own transform in the stream, so
1631
1660
  * callers with no view concept can keep calling `render(commands)`.
1632
1661
  */
1633
- render(commands: DrawCommand[], viewMatrix?: Mat3): void;
1662
+ render(commands: DrawCommand[], viewMatrix?: GlMat3): void;
1663
+ /** Change the curve-flattening tolerance after construction. `undefined`
1664
+ * restores the cached `DEFAULT_FLATTEN_TOLERANCE` route. */
1665
+ setFlattenTolerance(tolerance: number | undefined): void;
1634
1666
  resize(dims: {
1635
1667
  width: number;
1636
1668
  height: number;
@@ -1687,23 +1719,14 @@ declare function frameRect(sheet: SpriteSheet, index: number): {
1687
1719
  };
1688
1720
 
1689
1721
  /**
1690
- * View → Mat3 helper for layer `draw` implementations on world-space layers.
1722
+ * View → GlMat3 helper for layer `draw` implementations on world-space layers.
1691
1723
  *
1692
- * The kit's main package ships a `View` type at
1693
- * `src/core/viewport/view.ts`; we re-declare a structurally compatible
1694
- * shape here to avoid a runtime cross-package import. Exported as
1695
- * `ViewLike` from the package barrel.
1724
+ * `View` is `@weasel-js/routing`'s, the one every viewport action is typed
1725
+ * in. A type-only import emits no runtime edge, so there is no reason for the
1726
+ * renderer to hold a second structurally-identical declaration and put it in
1727
+ * the emitted `.d.ts` anonymously.
1696
1728
  */
1697
1729
 
1698
- /** A weasel View — `{x, y, scale: {x, y}}`. Local type to avoid a cross-package import. */
1699
- interface View {
1700
- x: number;
1701
- y: number;
1702
- scale: {
1703
- x: number;
1704
- y: number;
1705
- };
1706
- }
1707
1730
  /**
1708
1731
  * Build the world→screen transform matrix for a `View`.
1709
1732
  * Use as the `transform` field of a `kind: 'group'` DrawCommand to wrap
@@ -1714,7 +1737,32 @@ interface View {
1714
1737
  * Column-major layout (matches `mat3.identity()`):
1715
1738
  * `[scale.x, 0, 0, 0, scale.y, 0, -view.x*scale.x, -view.y*scale.y, 1]`.
1716
1739
  */
1717
- declare function viewToMat3(view: View): Mat3;
1740
+ declare function viewToMat3(view: View): GlMat3;
1741
+
1742
+ /** A screen-space rectangle, CSS pixels. */
1743
+ interface CullRect {
1744
+ x: number;
1745
+ y: number;
1746
+ width: number;
1747
+ height: number;
1748
+ }
1749
+ /**
1750
+ * `cmds` without the commands that cannot put a pixel inside `rect`, where
1751
+ * `transform` maps the commands' space to screen space — `viewToMat3(view)`
1752
+ * for a world-space layer.
1753
+ *
1754
+ * Conservative by construction: a command is dropped only when a bound that
1755
+ * encloses everything it can paint misses `rect`. Paths are bounded by their
1756
+ * control hull plus the farthest a stroke can reach (miter spikes and square
1757
+ * caps included), images and sprites by their quads, and every bound is taken
1758
+ * through the accumulated transform as the AABB of its corners, so rotation
1759
+ * only enlarges it. Text and shader commands are always kept, and so is a
1760
+ * group with `effects` — an effect may move pixels. Clips are ignored, which
1761
+ * can only keep more. A group whose children all go is dropped.
1762
+ *
1763
+ * Returns `cmds` itself when nothing was dropped.
1764
+ */
1765
+ declare function cullDrawCommands(cmds: DrawCommand[], transform: GlMat3, rect: CullRect): DrawCommand[];
1718
1766
 
1719
1767
  /** Options for stroke tessellation. */
1720
1768
  interface StrokeOptions {
@@ -1731,9 +1779,7 @@ interface StrokeOptions {
1731
1779
  /** Resolve a stroke width to world units. A number is already world units;
1732
1780
  * `{ px }` is screen pixels divided by the accumulated scale, so it holds its
1733
1781
  * on-screen thickness as the view zooms. */
1734
- declare function resolveStrokeWidth(width: number | {
1735
- px: number;
1736
- }, scale: number): number;
1782
+ declare function resolveStrokeWidth(width: ScreenLength, scale: number): number;
1737
1783
  /**
1738
1784
  * Build a triangle-mesh ribbon from a stroked Path.
1739
1785
  *
@@ -2473,7 +2519,7 @@ interface ViewAnimationOptions {
2473
2519
  /** Easing curve. Default `easeOutCubic`. */
2474
2520
  easing?: EasingSpec;
2475
2521
  /** Replace the kit's log-scale / fixed-anchor curve. */
2476
- interpolator?: InterpolatorFactory<View$1>;
2522
+ interpolator?: InterpolatorFactory<View>;
2477
2523
  /** Fires when the target is reached. Not called on cancel. */
2478
2524
  onDone?: () => void;
2479
2525
  }
@@ -2484,28 +2530,29 @@ interface AnimateToBoundsOptions extends FitViewToBoundsOptions, ViewAnimationOp
2484
2530
  * channel `view.set` uses, so a camera animation on an uncontrolled canvas
2485
2531
  * costs no React render. */
2486
2532
  interface ViewChannel {
2487
- get(): View$1;
2488
- set(v: View$1): void;
2533
+ get(): View;
2534
+ set(v: View): void;
2489
2535
  }
2490
2536
  /** The camera animation surface. One animation at a time. */
2491
2537
  interface ViewAnimationApi {
2492
2538
  /** Glide from the live view to `to`. A thunk receives the pending target when
2493
2539
  * one is in flight, so successive discrete steps compound. */
2494
- animate(to: View$1 | ((base: View$1) => View$1), opts?: ViewAnimationOptions): void;
2540
+ animate(to: View | ((base: View) => View), opts?: ViewAnimationOptions): void;
2495
2541
  /** `fitViewToBounds` composed with `animate`. */
2496
2542
  animateToBounds(bounds: Bounds, dims: ViewportDims, opts?: AnimateToBoundsOptions): void;
2497
2543
  /** Cancel. The view stays where it is — no jump to the target. */
2498
2544
  stop(): void;
2499
2545
  isAnimating(): boolean;
2500
2546
  /** Where the in-flight animation is heading, or null when none is. */
2501
- target(): View$1 | null;
2547
+ target(): View | null;
2502
2548
  /** Cancel unless the write that prompted this came from the runner's own
2503
2549
  * per-frame write. Feed it from every channel that can move the camera. */
2504
2550
  stopIfExternal(): void;
2505
2551
  }
2506
2552
  /**
2507
2553
  * Animate the viewport `View`. Runs on the kit's {@link Animator} — pass one to
2508
- * share a canvas's animator, or omit it and the hook makes its own.
2554
+ * share a canvas's animator, or omit it and the hook makes its own. A caller
2555
+ * that always has one should use {@link useViewAnimationOn}, which builds none.
2509
2556
  *
2510
2557
  * Every animation from one instance registers under that instance's cancel key,
2511
2558
  * so starting one cancels whatever *it* had in flight, and each starts from the
@@ -2513,6 +2560,9 @@ interface ViewAnimationApi {
2513
2560
  * Two instances on one animator are independent.
2514
2561
  */
2515
2562
  declare function useViewAnimation(view: ViewChannel, animator?: Animator): ViewAnimationApi;
2563
+ /** {@link useViewAnimation} on an animator the caller owns. Constructs no
2564
+ * animator of its own, so the camera runs on exactly the one passed. */
2565
+ declare function useViewAnimationOn(view: ViewChannel, animator: Animator): ViewAnimationApi;
2516
2566
 
2517
2567
  /**
2518
2568
  * Pose composition for hierarchical scene graphs.
@@ -2779,58 +2829,6 @@ interface ContentHandlerEntry {
2779
2829
  /** Register a content handler. Returns a disposer that removes it. */
2780
2830
  declare function registerContentHandler(entry: ContentHandlerEntry): () => void;
2781
2831
 
2782
- /**
2783
- * @experimental
2784
- * PointerContext — a tiny ambient context that publishes the world-space
2785
- * position of the canvas pointer, refreshed on every `pointermove` over
2786
- * the canvas. Cleared (set to `null`) on `pointerleave`.
2787
- *
2788
- * Why ref-based and not state-based: cursor moves fire dozens of times per
2789
- * second; routing those through React state would re-render every consumer
2790
- * in the tree. The context exposes a stable `pointerRef` whose `.current`
2791
- * is mutated directly by the publisher, plus a thunk `getDropPoint()` that
2792
- * reads it on demand. Consumers (e.g. `useClipboard`) pull via the thunk
2793
- * inside their callbacks — no subscription, no re-render.
2794
- *
2795
- * `<SceneCanvas>` publishes automatically. `useClipboardOps` consumes when
2796
- * the caller didn't pass an explicit `getDropPoint` option. Other future
2797
- * hit-on-cursor consumers (drop-zone hover, context-menu anchor) can reuse
2798
- * the same context.
2799
- */
2800
-
2801
- /** @experimental World-space pointer position, or `null` when the pointer
2802
- * isn't over the publishing canvas. */
2803
- type PointerWorldPos = {
2804
- worldX: number;
2805
- worldY: number;
2806
- } | null;
2807
- /** @experimental */
2808
- interface PointerContextValue {
2809
- /** Live ref — mutate to publish, read for the latest snapshot. The
2810
- * identity is stable for the lifetime of the provider. */
2811
- readonly pointerRef: MutableRefObject<PointerWorldPos>;
2812
- /** Convenience thunk equivalent to `() => pointerRef.current`. Stable
2813
- * identity for the lifetime of the provider; safe to pass to hooks. */
2814
- readonly getDropPoint: () => PointerWorldPos;
2815
- }
2816
- /**
2817
- * @experimental
2818
- * Wrap the part of the React tree that should share a pointer-position
2819
- * context. Usually placed at the demo / app root, alongside
2820
- * `<ActionsProvider>` and `<SelectionContextProvider>`.
2821
- *
2822
- * Most consumers don't need to mount this directly — `<SceneCanvas>` mounts
2823
- * an internal provider when no parent provider is in scope, so child hooks
2824
- * (`useClipboard` without an explicit `getDropPoint`) read the canvas's
2825
- * tracked pointer for free.
2826
- */
2827
- declare function PointerContextProvider({ children }: {
2828
- children: ReactNode;
2829
- }): ReactNode;
2830
- /** @experimental Read the surrounding pointer-context value, or `null` when
2831
- * no provider is in scope. */
2832
- declare function usePointerContext(): PointerContextValue | null;
2833
-
2834
2832
  /** Optional consumer seam: given a node and the affine `m` that a pose-transform
2835
2833
  * action applied to the node's POSE, return updated `data` with the node's
2836
2834
  * data-held geometry transformed by `m`, or `null` if this node has no
@@ -2840,19 +2838,19 @@ interface GeometryProjection {
2840
2838
  id?: string;
2841
2839
  data: unknown;
2842
2840
  pose: unknown;
2843
- }, m: Mat3$1): unknown | null;
2841
+ }, m: Mat3): unknown | null;
2844
2842
  }
2845
2843
 
2846
2844
  /** Minimal view API the action layer consumes. */
2847
2845
  interface ViewApi {
2848
- get(): View$1;
2849
- set(v: View$1): void;
2846
+ get(): View;
2847
+ set(v: View): void;
2850
2848
  /** Optional recenter callback. When wired, `viewportZoomAction`'s `reset`
2851
2849
  * branch (Cmd-0) calls this instead of resetting to identity — letting
2852
2850
  * consumers re-fit the page (or other reference bounds) into the workspace.
2853
2851
  * Return the target `View` to let the action animate there; return nothing
2854
2852
  * to keep dispatching the view yourself. */
2855
- recenter?(): View$1 | void;
2853
+ recenter?(): View | void;
2856
2854
  /** Optional canvas-local host dimensions (CSS px). When wired,
2857
2855
  * `viewportZoomAction`'s keyboard branches (Cmd+= / Cmd+-) anchor at the
2858
2856
  * host center instead of the top-left origin. Null when the host isn't
@@ -2863,11 +2861,11 @@ interface ViewApi {
2863
2861
  } | null;
2864
2862
  /** Optional camera animation. `<SceneCanvas>` wires these three; a consumer
2865
2863
  * publishing their own `view` dep need not, and actions fall back to `set`. */
2866
- animate?(to: View$1, opts?: ViewAnimationOptions): void;
2864
+ animate?(to: View, opts?: ViewAnimationOptions): void;
2867
2865
  stopAnimation?(): void;
2868
2866
  /** Where an in-flight camera animation is heading, or null. Compute the next
2869
2867
  * discrete step from this so repeated presses compound. */
2870
- animationTarget?(): View$1 | null;
2868
+ animationTarget?(): View | null;
2871
2869
  /** Optional momentum decay. `<SceneCanvas>` wires this from `useDecayLoop`;
2872
2870
  * a consumer publishing their own `view` dep need not, and `viewport.dragPan`
2873
2871
  * simply lands the pan without coasting. */
@@ -3318,13 +3316,6 @@ declare module '@weasel-js/routing' {
3318
3316
  scene: Scene<unknown, string, unknown>;
3319
3317
  /** Undo/redo history bound to the current scene. */
3320
3318
  history: History;
3321
- /**
3322
- * Canvas pointer position in world space.
3323
- *
3324
- * Exposes `pointerRef` (mutable live ref) and `getDropPoint()` thunk.
3325
- * Marked `@experimental` in the source.
3326
- */
3327
- pointer: PointerContextValue;
3328
3319
  /** Currently active tool id + hotkey-hold stack. */
3329
3320
  activeTool: ActiveToolContextValue;
3330
3321
  /**
@@ -3487,4 +3478,4 @@ declare module '@weasel-js/routing' {
3487
3478
  }
3488
3479
  }
3489
3480
 
3490
- export { type ViewportDims as $, type SliceDep as A, type VertexColorChannel as B, type InsertExtras as C, type DrawCommand as D, type Effect as E, type SerializedScene as F, type GroupDrawCommand as G, type GeometryProjection as H, IDENTITY_COLOR_MATRIX as I, type ContentHandlerEntry as J, type SvgIngestOptions as K, type PanBounds as L, type Mesh as M, type Node as N, type Animator as O, type PathDrawCommand as P, ColorOverrideRegistry as Q, type RenderTarget as R, SPRITE_STRIDE as S, type TextDrawCommand as T, type UseSceneOptions as U, type View as V, WeaselRenderer as W, type SceneRegistry as X, type RegisteredOp as Y, type PoseOverrides as Z, type DerivedDep as _, type ImageDrawCommand as a, type StaggerOptions as a$, ShaderProgram as a0, type BooleansAdapter as a1, type UseAnimatorOptions as a2, type SpringPresetName as a3, type EasingSpec as a4, type AnimationHandle as a5, type SampledTrack as a6, type AddLayerSpec as a7, type AddNodeSpec as a8, type AnimateToBoundsOptions as a9, type LassoSelectDep as aA, type LayerRecord as aB, type LayoutDep as aC, type LeafNode as aD, type LoopFactory as aE, type LoopOptions as aF, type NestedTimeline as aG, type NodeAtPointDep as aH, type PhysicsHandle as aI, type PhysicsOptions as aJ, PointerContextProvider as aK, type PointerContextValue as aL, type PointerWorldPos as aM, type PoseAdapter as aN, type PoseClosure as aO, type PoseOverride as aP, RECT_POSE_COMPOSITION as aQ, RIGID_POSE_COMPOSITION as aR, type ResizePolicy as aS, SPRING_PRESETS as aT, type SerializedNode as aU, type SnapDep as aV, type SpringOptions as aW, type SpringPreset as aX, type StaggerBuilder as aY, type StaggerDelay as aZ, type StaggerFactory as a_, type AreaSelectDep as aa, type BezierEasing as ab, type BooleanOp as ac, type BooleanOpResult as ad, type ClipboardDep as ae, type ClipboardIngestCtx as af, type ColorOverride as ag, type ColorOverrideFn as ah, type ContainerNode as ai, type DecayLoopConfig as aj, type DecayOptions as ak, EASINGS as al, type EasingFn as am, type EasingName as an, type EditAnchorsDep as ao, type EventBooking as ap, type EventBookingHandle as aq, type EventTrack as ar, type FitViewToBoundsOptions as as, IDENTITY_POSE_COMPOSITION as at, type IngestCtx as au, type IngestionDep as av, type InsertDep as aw, type Interpolate as ax, type InterpolatorFactory as ay, type Keyframe as az, type ImageMinification as b, rebaseLocalPose as b$, type StaggerPerItem as b0, type StaggerSpringPoseOptions as b1, type StaggerTweenOptions as b2, type SvgUnpacker as b3, type SystemLayerRecord as b4, type SystemLayerSpec as b5, type TextEditDep as b6, type TimelineClock as b7, type TimelineEvent as b8, type TimelineHandle as b9, easeInOutBack as bA, easeInOutBounce as bB, easeInOutCirc as bC, easeInOutCubic as bD, easeInOutElastic as bE, easeInOutExpo as bF, easeInOutQuad as bG, easeInOutQuart as bH, easeInOutQuint as bI, easeInOutSine as bJ, easeInQuad as bK, easeInQuart as bL, easeInQuint as bM, easeInSine as bN, easeOut as bO, easeOutBack as bP, easeOutBounce as bQ, easeOutCirc as bR, easeOutCubic as bS, easeOutElastic as bT, easeOutExpo as bU, easeOutQuad as bV, easeOutQuart as bW, easeOutQuint as bX, easeOutSine as bY, fitViewToBounds as bZ, linear as b_, type TimelineOptions as ba, type TimelineTrack as bb, type Track as bc, type TweenLoopOptions as bd, type TweenOptions as be, type UserLayerRecord as bf, VIEW_ANIMATION_KEY as bg, type ViewAnimationApi as bh, type ViewApi as bi, type ViewChannel as bj, applyBooleanOp as bk, asNodeId as bl, composeRectPose as bm, composeRigidPose as bn, composeWorldPose as bo, cubicBezierEasing as bp, decomposeRectPose as bq, decomposeRigidPose as br, easeIn as bs, easeInBack as bt, easeInBounce as bu, easeInCirc as bv, easeInCubic as bw, easeInElastic as bx, easeInExpo as by, easeInOut as bz, type Mat3 as c, registerContentHandler as c0, resolveEasing as c1, resolveStrokeWidth as c2, translateRectPose as c3, useDecayLoop as c4, usePointerContext as c5, useViewAnimation as c6, worldPoseLookup as c7, ShaderCompileError as d, type ShaderDrawCommand as e, type ShaderProgramHandle as f, type ShaderUniform as g, type SolidPaint as h, type SpriteSheet as i, type SpritesDrawCommand as j, type StrokeOptions as k, type WeaselRendererOptions as l, blur as m, buildGradientRamp as n, frameRect as o, mat3 as p, registerProgram as q, registerEffect as r, vignette as s, tessellateStroke as t, type Scene as u, viewToMat3 as v, type RectPose as w, type InertiaConfig as x, type ViewAnimationOptions as y, type PoseComposition as z };
3481
+ export { type DerivedDep as $, type SliceDep as A, type VertexColorChannel as B, type CullRect as C, type DrawCommand as D, type Effect as E, type InsertExtras as F, type GlMat3 as G, type SerializedScene as H, IDENTITY_COLOR_MATRIX as I, type GeometryProjection as J, type ContentHandlerEntry as K, type SvgIngestOptions as L, type Mesh as M, type Node as N, type PanBounds as O, type PathDrawCommand as P, type Animator as Q, type RenderTarget as R, SPRITE_STRIDE as S, type TextDrawCommand as T, ColorOverrideRegistry as U, type ViewAnimationOptions as V, WeaselRenderer as W, type UseSceneOptions as X, type SceneRegistry as Y, type RegisteredOp as Z, type PoseOverrides as _, type GroupDrawCommand as a, type StaggerSpringPoseOptions as a$, type ViewportDims as a0, ShaderProgram as a1, type BooleansAdapter as a2, type UseAnimatorOptions as a3, type SpringPresetName as a4, type EasingSpec as a5, type AnimationHandle as a6, type SampledTrack as a7, type AddLayerSpec as a8, type AddNodeSpec as a9, type Keyframe as aA, type LassoSelectDep as aB, type LayerRecord as aC, type LayoutDep as aD, type LeafNode as aE, type LoopFactory as aF, type LoopOptions as aG, type NestedTimeline as aH, type NodeAtPointDep as aI, type PhysicsHandle as aJ, type PhysicsOptions as aK, type PoseAdapter as aL, type PoseClosure as aM, type PoseOverride as aN, RECT_POSE_COMPOSITION as aO, RIGID_POSE_COMPOSITION as aP, type ResizePolicy as aQ, SPRING_PRESETS as aR, type SerializedNode as aS, type SnapDep as aT, type SpringOptions as aU, type SpringPreset as aV, type StaggerBuilder as aW, type StaggerDelay as aX, type StaggerFactory as aY, type StaggerOptions as aZ, type StaggerPerItem as a_, type AnimateToBoundsOptions as aa, type AreaSelectDep as ab, type BezierEasing as ac, type BooleanOp as ad, type BooleanOpResult as ae, type ClipboardDep as af, type ClipboardIngestCtx as ag, type ColorOverride as ah, type ColorOverrideFn as ai, type ContainerNode as aj, type DecayLoopConfig as ak, type DecayOptions as al, EASINGS as am, type EasingFn as an, type EasingName as ao, type EditAnchorsDep as ap, type EventBooking as aq, type EventBookingHandle as ar, type EventTrack as as, type FitViewToBoundsOptions as at, IDENTITY_POSE_COMPOSITION as au, type IngestCtx as av, type IngestionDep as aw, type InsertDep as ax, type Interpolate as ay, type InterpolatorFactory as az, type ImageDrawCommand as b, resolveEasing as b$, type StaggerTweenOptions as b0, type SvgUnpacker as b1, type SystemLayerRecord as b2, type SystemLayerSpec as b3, type TextEditDep as b4, type TimelineClock as b5, type TimelineEvent as b6, type TimelineHandle as b7, type TimelineOptions as b8, type TimelineTrack as b9, easeInOutCirc as bA, easeInOutCubic as bB, easeInOutElastic as bC, easeInOutExpo as bD, easeInOutQuad as bE, easeInOutQuart as bF, easeInOutQuint as bG, easeInOutSine as bH, easeInQuad as bI, easeInQuart as bJ, easeInQuint as bK, easeInSine as bL, easeOut as bM, easeOutBack as bN, easeOutBounce as bO, easeOutCirc as bP, easeOutCubic as bQ, easeOutElastic as bR, easeOutExpo as bS, easeOutQuad as bT, easeOutQuart as bU, easeOutQuint as bV, easeOutSine as bW, fitViewToBounds as bX, linear as bY, rebaseLocalPose as bZ, registerContentHandler as b_, type Track as ba, type TweenLoopOptions as bb, type TweenOptions as bc, type UserLayerRecord as bd, VIEW_ANIMATION_KEY as be, type ViewAnimationApi as bf, type ViewApi as bg, type ViewChannel as bh, applyBooleanOp as bi, asNodeId as bj, composeRectPose as bk, composeRigidPose as bl, composeWorldPose as bm, cubicBezierEasing as bn, decomposeRectPose as bo, decomposeRigidPose as bp, easeIn as bq, easeInBack as br, easeInBounce as bs, easeInCirc as bt, easeInCubic as bu, easeInElastic as bv, easeInExpo as bw, easeInOut as bx, easeInOutBack as by, easeInOutBounce as bz, type ImageMinification as c, resolveStrokeWidth as c0, translateRectPose as c1, useDecayLoop as c2, useViewAnimation as c3, useViewAnimationOn as c4, worldPoseLookup as c5, ShaderCompileError as d, type ShaderDrawCommand as e, type ShaderProgramHandle as f, type ShaderUniform as g, type SolidPaint as h, type SpriteSheet as i, type SpritesDrawCommand as j, type StrokeOptions as k, type WeaselRendererOptions as l, blur as m, buildGradientRamp as n, cullDrawCommands as o, frameRect as p, mat3 as q, registerEffect as r, registerProgram as s, tessellateStroke as t, vignette as u, viewToMat3 as v, type Scene as w, type RectPose as x, type InertiaConfig as y, type PoseComposition as z };
@@ -1,4 +1,4 @@
1
- import { M as MoveBehavior, S as SnapStrategy } from './types-DMyo7dnM.js';
1
+ import { M as MoveBehavior, S as SnapStrategy } from './types-BHGdrOcu.js';
2
2
  import { DebugSink } from '@weasel-js/routing';
3
3
 
4
4
  /**
@@ -10,17 +10,33 @@ import { DebugSink } from '@weasel-js/routing';
10
10
  * as base units) or a `{ value, unit }` tag that's resolved against a
11
11
  * `UnitSystem` at the API boundary. Internals never see units.
12
12
  *
13
- * Linear factors only. No per-axis units. No mixed-unit arithmetic.
13
+ * An entry is affine — `base = value * factor + offset` — so a scale that
14
+ * puts zero somewhere else (degC against K) is expressible. No per-axis
15
+ * units. No mixed-unit arithmetic.
14
16
  */
15
17
  /** A unit name (e.g. `'in'`, `'ft'`, `'mm'`). Looked up in a `UnitSystem`. */
16
18
  type Unit = string;
17
- /** Conversion table mapping unit names to factors against a base unit. */
19
+ /** What one unit is worth in base units: `base = value * factor + offset`. */
20
+ interface UnitScale {
21
+ factor: number;
22
+ /** Where this unit puts zero, in base units. Absent is 0 — a pure scale. */
23
+ offset?: number;
24
+ }
25
+ /** One unit's conversion. A bare number is the `{ factor }` shorthand. */
26
+ type UnitEntry = number | UnitScale;
27
+ /** Conversion table mapping unit names to their scale against a base unit. */
18
28
  interface UnitSystem {
19
29
  /** Name of the base unit, e.g. 'in'. All conversions resolve to this. */
20
30
  base: Unit;
21
- /** Factor to multiply a value in `unit` by to get base units. base unit's factor is 1. */
22
- units: Record<Unit, number>;
31
+ /** How to reach base units from each unit. The base unit's entry is 1. */
32
+ units: Record<Unit, UnitEntry>;
23
33
  }
34
+ /**
35
+ * One unit's scale, with the bare-number shorthand widened and the offset
36
+ * defaulted — what every conversion in the kit reads. Throws if the system
37
+ * does not carry the unit.
38
+ */
39
+ declare function unitScale(unitSystem: UnitSystem, unit: Unit): Required<UnitScale>;
24
40
  /** Value at a unit-aware API boundary: bare number (in base units) or `{ value, unit }` tag. */
25
41
  type UnitValue = number | {
26
42
  value: number;
@@ -139,4 +155,4 @@ declare function pointToGridCell(point: {
139
155
  row: number;
140
156
  };
141
157
 
142
- export { ANGLE_RADIANS as A, IMPERIAL_INCHES as I, METRIC_MM as M, type OriginProjection as O, PIXELS as P, RECT_ORIGIN_PROJECTION as R, type UseMoveOptions as U, type UnitValue as a, type UnitSystem as b, type Unit as c, formatUnit as f, gridSnapStrategy as g, pointToGridCell as p, resolveUnit as r };
158
+ export { ANGLE_RADIANS as A, IMPERIAL_INCHES as I, METRIC_MM as M, type OriginProjection as O, PIXELS as P, RECT_ORIGIN_PROJECTION as R, type UseMoveOptions as U, type UnitValue as a, type UnitSystem as b, type UnitEntry as c, type Unit as d, type UnitScale as e, formatUnit as f, gridSnapStrategy as g, pointToGridCell as p, resolveUnit as r, unitScale as u };