@weasel-js/core 1.4.3 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +1299 -2197
  2. package/README.md +118 -75
  3. package/dist/{pointSnapToGrid-D1bRdq-j.d.ts → autoPoseDescriptor-CvjflWJK.d.ts} +35 -17
  4. package/dist/{chunk-ORZNKVXM.js → chunk-BDWAA634.js} +4 -22
  5. package/dist/chunk-BDWAA634.js.map +1 -0
  6. package/dist/{chunk-WYPSGIYS.js → chunk-MG7OXCAI.js} +4149 -5316
  7. package/dist/chunk-MG7OXCAI.js.map +1 -0
  8. package/dist/{chunk-BLJNRMKB.js → chunk-MQI4PIX3.js} +3 -3
  9. package/dist/chunk-MQI4PIX3.js.map +1 -0
  10. package/dist/{chunk-SBFC6J3C.js → chunk-UCPV7JXC.js} +201 -256
  11. package/dist/chunk-UCPV7JXC.js.map +1 -0
  12. package/dist/clipboard.d.ts +2 -3
  13. package/dist/clone.d.ts +3 -2
  14. package/dist/depSchema-nMqj_qTM.d.ts +3490 -0
  15. package/dist/{grid-Bw8cSde-.d.ts → grid-BrIa38gG.d.ts} +7 -23
  16. package/dist/index.d.ts +2134 -1210
  17. package/dist/index.js +4 -5
  18. package/dist/insert.d.ts +4 -4
  19. package/dist/insert.js +1 -1
  20. package/dist/move.d.ts +5 -6
  21. package/dist/move.js +3 -6
  22. package/dist/move.js.map +1 -1
  23. package/dist/{options-DYfUlZxk.d.ts → options-BDyCnrp8.d.ts} +3 -2
  24. package/dist/poseDescriptor-CGOgIgf8.d.ts +134 -0
  25. package/dist/renderer.d.ts +10 -4
  26. package/dist/renderer.js +4 -5
  27. package/dist/resize.d.ts +10 -11
  28. package/dist/resize.js +2 -2
  29. package/dist/routing.d.ts +1 -142
  30. package/dist/routing.js +1 -1
  31. package/dist/routing.js.map +1 -1
  32. package/dist/{types-BJqsTlXl.d.ts → types-DMyo7dnM.d.ts} +12 -41
  33. package/dist/{types-CoVTbo_y.d.ts → types-DtjCJA5r.d.ts} +10 -9
  34. package/package.json +13 -10
  35. package/dist/DrawCommand-CD-ug3d9.d.ts +0 -332
  36. package/dist/builtins-CtGORLCG.d.ts +0 -740
  37. package/dist/chunk-BLJNRMKB.js.map +0 -1
  38. package/dist/chunk-LEURURX3.js +0 -561
  39. package/dist/chunk-LEURURX3.js.map +0 -1
  40. package/dist/chunk-ORZNKVXM.js.map +0 -1
  41. package/dist/chunk-SBFC6J3C.js.map +0 -1
  42. package/dist/chunk-WYPSGIYS.js.map +0 -1
  43. package/dist/geometry-CHR36Ub_.d.ts +0 -114
  44. package/dist/path-JEV2c5If.d.ts +0 -48
  45. package/dist/registry-DnoTWGED.d.ts +0 -4003
  46. package/dist/types-BHK2dkMu.d.ts +0 -172
  47. package/dist/types-H7o6MaPo.d.ts +0 -512
  48. package/dist/view-DSQgxBJB.d.ts +0 -63
package/dist/index.d.ts CHANGED
@@ -1,48 +1,40 @@
1
1
  import * as React$1 from 'react';
2
2
  import React__default, { RefObject, ReactNode, Ref, MouseEvent, ComponentType, MutableRefObject } from 'react';
3
- import { a as ViewTransform, V as View, Z as ZoomBound, b as ZoomFactor } from './view-DSQgxBJB.js';
4
- export { s as screenToWorld, v as viewToTransform, w as worldToScreen } from './view-DSQgxBJB.js';
5
- import { a as UnitValue, b as UnitSystem, U as UseMoveOptions, O as OriginProjection } from './grid-Bw8cSde-.js';
6
- export { I as IMPERIAL_INCHES, M as METRIC_MM, P as PIXELS, R as RECT_ORIGIN_PROJECTION, c as Unit, f as formatUnit, g as gridSnapStrategy, p as pointToGridCell, r as resolveUnit } from './grid-Bw8cSde-.js';
7
- import { R as RenderLayer, D as Dims, a as DeviceProfile, b as DetectedDeviceFacts, C as Condition, c as Rule, d as RuleCtx, V as VisibilityRules, e as ChromeCtx, f as ChromeId, A as Action, I as InertiaConfig, g as ViewAnimationOptions, h as DepSchema, S as SliceDep, i as ActionsRegistry, T as Tool, j as AffordanceHit, k as Dispatcher, l as ToolDef, m as ViewportToolDef, n as AnyTool, O as OverlayPosition, o as ToolKeybinding, H as HotkeyTrigger, L as LayerHit, p as OngoingOverlay, q as ChromeState, r as SelectionApi, s as LayerGroup, U as UseSelectionOptions, t as InsertExtras, B as BuiltinShapeToolId, G as GeometryProjection, u as ContentHandlerEntry, v as SvgIngestOptions, P as PanBounds, w as ActionsProp, x as Animator, y as Affordance, z as AffordanceRegion, E as AffordanceBinding, F as CommonAffordanceScratch, J as ColorOverrideRegistry, K as BooleansAdapter, M as UseAnimatorOptions, N as SpringPresetName, Q as EasingSpec, W as AnimationHandle, X as VertexColorChannel, Y as SampledTrack, Z as Eligibility, _ as BindingScope, $ as Contribution, a0 as ScopedBinding } from './registry-DnoTWGED.js';
8
- export { a1 as ALWAYS, a2 as ActionDeps, a3 as ActionDisabledReason, a4 as ActionEnabledResult, a5 as ActionEntry, a6 as ActionsProvider, a7 as ActionsScope, a8 as ActiveToolContextProvider, a9 as ActiveToolContextProviderIfRoot, aa as ActiveToolContextProviderProps, ab as ActiveToolContextValue, ac as AnimateToBoundsOptions, ad as AreaSelectDep, ae as BezierEasing, af as BindingOpts, ag as BooleanOp, ah as BooleanOpResult, ai as BoundGesture, aj as BuildRuleCtxArgs, ak as ClaimableGesture, al as ClipboardDep, am as ClipboardIngestCtx, an as ColorOverride, ao as ColorOverrideFn, ap as CustomPaintContext, aq as DecayLoopConfig, ar as DecayOptions, as as DepName, at as DepRegistry, au as DepRegistryProvider, av as DispatcherContext, aw as DragSample, ax as EASINGS, ay as EasingFn, az as EasingName, aA as EditAnchorsDep, aB as EventTrack, aC as GestureBinding, aD as IDENTITY_POSE_COMPOSITION, aE as ImmediateInvoker, aF as IngestCtx, aG as IngestionDep, aH as InsertDep, aI as Interpolate, aJ as InterpolatorFactory, aK as InvocationCtx, aL as Invoker, aM as KIT_SHAPE_KINDS, aN as Keyframe, aO as LassoSelectDep, aP as LayerCommandCache, aQ as LayerDrawFailure, aR as LayoutDep, aS as LoopFactory, aT as LoopOptions, aU as MatchResult, aV as NEVER, aW as NestedTimeline, aX as NodeAtPointDep, aY as OngoingHandle, aZ as OngoingInvoker, a_ as PhysicsHandle, a$ as PhysicsOptions, b0 as Point2, b1 as PointerContextProvider, b2 as PointerContextValue, b3 as PointerWorldPos, b4 as PoseAdapter, b5 as PoseComposition, b6 as ResizePolicy, b7 as ResolveAllOptions, b8 as ResolveOnlyResult, b9 as ResolvedCandidate, ba as SPRING_PRESETS, bb as SelectionExtendKey, bc as SelectionMode, bd as Selector, be as SnapDep, bf as SpringOptions, bg as SpringPreset, bh as StaggerBuilder, bi as StaggerDelay, bj as StaggerFactory, bk as StaggerOptions, bl as StaggerPerItem, bm as StaggerSpringPoseOptions, bn as StaggerTweenOptions, bo as SvgUnpacker, bp as TextEditDep, bq as TimelineHandle, br as TimelineOptions, bs as TimelineTrack, bt as ToolCtx, bu as ToolModifiers, bv as ToolPresentation, bw as ToolSlot, bx as Track, by as TweenLoopOptions, bz as TweenOptions, bA as UiOngoingControl, bB as VIEW_ANIMATION_KEY, bC as ViewAnimationApi, bD as ViewApi, bE as ViewChannel, bF as actionBindings, bG as applyBooleanOp, bH as buildRuleCtx, bI as clipboardCopyAction, bJ as clipboardCutAction, bK as composeRectPose, bL as composeWorldPose, bM as createDispatcher, bN as cubicBezierEasing, bO as decomposeRectPose, bP as describeRule, bQ as drawLayers, bR as drawOneLayer, bS as easeIn, bT as easeInBack, bU as easeInBounce, bV as easeInCirc, bW as easeInCubic, bX as easeInElastic, bY as easeInExpo, bZ as easeInOut, b_ as easeInOutBack, b$ as easeInOutBounce, c0 as easeInOutCirc, c1 as easeInOutCubic, c2 as easeInOutElastic, c3 as easeInOutExpo, c4 as easeInOutQuad, c5 as easeInOutQuart, c6 as easeInOutQuint, c7 as easeInOutSine, c8 as easeInQuad, c9 as easeInQuart, ca as easeInQuint, cb as easeInSine, cc as easeOut, cd as easeOutBack, ce as easeOutBounce, cf as easeOutCirc, cg as easeOutCubic, ch as easeOutElastic, ci as easeOutExpo, cj as easeOutQuad, ck as easeOutQuart, cl as easeOutQuint, cm as easeOutSine, cn as enterTextEditAction, co as evaluate, cp as evaluateEnabled, cq as isLayerPainted, cr as isLayerVisible, cs as linear, ct as rebaseLocalPose, cu as registerContentHandler, cv as resolveEasing, cw as resolveParams, cx as sliceAction, cy as specificity, cz as translateRectPose, cA as useAction, cB as useActionsRegistry, cC as useActiveToolContext, cD as useDecayLoop, cE as useDepRegistry, cF as useDepSource, cG as useOptionalActiveToolContext, cH as useOptionalDepRegistry, cI as usePointerContext, cJ as useSelection, cK as useViewAnimation, cL as worldPoseLookup } from './registry-DnoTWGED.js';
9
- import { Stroke, FillStyle, TextureHandle, TilePatternSpec, GradientKind, GradStop, GradientFill, GradientUnits, MarkerKey, MarkerRef } from '@weasel-js/paint';
3
+ import { a as UnitValue, b as UnitSystem, c as Unit, U as UseMoveOptions, O as OriginProjection } from './grid-BrIa38gG.js';
4
+ export { A as ANGLE_RADIANS, I as IMPERIAL_INCHES, M as METRIC_MM, P as PIXELS, R as RECT_ORIGIN_PROJECTION, f as formatUnit, g as gridSnapStrategy, p as pointToGridCell, r as resolveUnit } from './grid-BrIa38gG.js';
5
+ import { View, NodeId, Bounds, ModifierState, PointerSessionCancelReason, DeviceProfile, Action, SelectionMode, SelectionExtendKey, SelectionApi, DepSchema, AnyToolOf, Contribution as Contribution$1, ContributionChrome as ContributionChrome$1, Tool as Tool$1, ToolDef as ToolDef$1, ViewportToolDef as ViewportToolDef$1, HitShape, HandleKind, DebugSink, ToolKeybinding, HotkeyTrigger, RuleCtx, Rule, IngestItem, OngoingOverlay, ActionsProp, OverlayRole, ResizeAnchor } from '@weasel-js/routing';
6
+ export { ALWAYS, Action, ActionDeps, ActionDisabledReason, ActionDispatch, ActionEnabledResult, ActionEntry, ActionPresentation, ActionsProp, ActionsRegistry, AffordanceHit, BindingOpts, BindingScope, BindingSource, BoundGesture, Bounds, BuildRuleCtxArgs, COARSE_TARGET_SCALE, ContributionRouting, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, DebugSink, DepName, DepSchema, DetectedDeviceFacts, DeviceProfile, Dispatcher, DispatcherContext, DragSample, Eligibility, EligibilityState, GestureBinding, HandleKind, HitShape, HotkeyTrigger, ImmediateInvoker, IngestItem, InputEvent, InvocationCtx, Invoker, MatchResult, ModifierState, NEVER, NodeId, OngoingHandle, OngoingInvoker, OngoingOverlay, OverlayPosition, OverlayRole, Point2, PointerSession, PointerSessionCallbacks, PointerSessionCancelReason, PointerSessionOptions, ResizeAnchor, ResolveAllOptions, ResolveOnlyResult, ResolvedCandidate, Rule, RuleCtx, ScopedBinding, ScratchKey, ScratchStore, SelectionApi, SelectionExtendKey, SelectionMode, Selector, ToolCtx, ToolKeybinding, ToolModifiers, ToolPresentation, ToolSlot, UiOngoingControl, View, actionBindings, buildRuleCtx, clientToCanvas, createDispatcher, deleteScratch, describeRule, evaluate, evaluateEnabled, getScratch, isEditableTarget, liveScope, matchesKeyBinding, mergeContributions, openPointerSession, resolveDeviceProfile, resolveParams, scopeBindings, scratchKey, setScratch, specificity } from '@weasel-js/routing';
7
+ import { FillStyle, Stroke, TextureHandle, TilePatternSpec, GradientKind, GradStop, GradientFill, GradientUnits, MarkerKey, MarkerRef } from '@weasel-js/paint';
10
8
  export { FillStyle, GradStop, GradientFill, GradientKind, GradientUnits, KitMarkerKey, MarkerKey, MarkerRef, Region, STROKE_DASH_RATIOS, Stroke, StrokeAlign, StrokeDashStyle, TextureHandle, TilePatternSpec, alignedStrokeRect, dashForStrokeStyle, strokeDashStyleOf } from '@weasel-js/paint';
11
- import { R as RectPose, S as Scene, N as NodeId, a as Node$1, b as SerializedScene, U as UseSceneOptions, c as SceneRegistry, d as RegisteredOp } from './types-H7o6MaPo.js';
12
- export { A as AddLayerSpec, e as AddNodeSpec, C as ContainerNode, L as LayerRecord, f as LeafNode, P as PoseOverride, g as PoseOverrides, h as SerializedNode, i as SystemLayerRecord, j as SystemLayerSpec, k as UserLayerRecord, l as asNodeId } from './types-H7o6MaPo.js';
13
- import { B as Bounds, P as PoseProjection, V as ViewportDims } from './geometry-CHR36Ub_.js';
14
- export { F as FitViewToBoundsOptions, R as RECT_POSE_DESCRIPTOR, a as ROTATED_POSE_DESCRIPTOR, f as fitViewToBounds } from './geometry-CHR36Ub_.js';
15
- import { GestureSpec, BodyClassification, IngestItem } from '@weasel-js/gestures';
16
- export { ClickSpec, DragSpec, DropSpec, GestureSpec, IngestItem, InputEvent, KeyHeldSpec, KeySpec, ModSpec, MultiTouchSpec, PasteSpec, TargetSpec, WheelSpec } from '@weasel-js/gestures';
17
- import { M as ModifierState, R as ResizePose, B as BoundsConstraint, P as PointSnapBehavior, L as LassoSelectBehavior, a as RotatedPose, e as RotateBehavior, S as SnapStrategy, c as ResizeAnchor, b as MoveBehavior, I as InsertBehavior } from './types-BJqsTlXl.js';
18
- export { A as ActionBehavior, f as AreaSelectOverlay, g as BehaviorMoveResult, h as BehaviorResult, C as CloneBehavior, i as CloneLayer, j as ClonePose, G as GestureContext, k as GroupTransform, l as InsertMoveResult, m as InsertOverlay, n as InsertPoint, o as InsertProposed, p as LassoSelectMoveResult, q as LassoSelectOverlay, r as LassoSelectPose, s as LassoSelectProposed, t as PointSnapContext, d as PointSnapFrame, u as PointSnapResult, v as PointerState, w as ResizeMoveResult, x as ResizeOverlay, y as ResizeProposed, z as RotateMoveResult, D as RotateOverlay, E as RotateProposed } from './types-BJqsTlXl.js';
19
- import { U as UseResizeOptions } from './pointSnapToGrid-D1bRdq-j.js';
20
- export { C as CORNER_ANCHORS, a as CornerAnchor, e as CornerEdge, b as CornerHandle, c as cornerPoint, d as cornerResizeHandles, h as hitCornerHandle, p as pointSnapToGrid } from './pointSnapToGrid-D1bRdq-j.js';
21
- import { ResolvedCursor, CursorSpec } from '@weasel-js/cursor';
22
- export { BakeOptions, CursorGlyph, CursorGlyphName, CursorGlyphSpec, CursorSpec, ResolvedCursor, bakeCursor, cursorFor, resolveCursor, resolveCursorTier } from '@weasel-js/cursor';
23
- import { M as MoveAdapter, A as AreaSelectAdapter, R as RotateAdapter, b as LassoHitMode, c as LassoSelectAdapter, d as ResizeAdapter, L as LayoutStrategy, e as LayerEnumerableAdapter, I as InsertAdapter, C as ClipboardSnapshot, O as OrderedAdapter, a as SceneAdapter, f as LayoutSnap } from './types-CoVTbo_y.js';
24
- export { g as ContainerBounds, D as DropTarget, h as LayoutChild, i as LayoutContainer, j as LayoutDragged, S as SnapTarget } from './types-CoVTbo_y.js';
25
- import { D as DebugSink, a as DebugConfig, b as DebugSnapshot, c as DebugStrokes, d as DebugTheme } from './types-BHK2dkMu.js';
26
- export { e as DebugFeature, f as DebugStroke, H as HandleKind, g as HitShape, R as RecordedBounds, h as RecordedHandle, i as RecordedHitbox, j as RecordedLayer, k as RecordedOrigin, l as RecordedSnap } from './types-BHK2dkMu.js';
27
- import { a as PolygonPath, P as Path, b as PathFillRule, R as RectPath } from './path-JEV2c5If.js';
9
+ import { D as DrawCommand, E as Effect, u as Scene, w as RectPose, x as InertiaConfig, y as ViewAnimationOptions, N as Node$1, z as PoseComposition, A as SliceDep, B as VertexColorChannel, f as ShaderProgramHandle, C as InsertExtras, F as SerializedScene, H as GeometryProjection, J as ContentHandlerEntry, K as SvgIngestOptions, L as PanBounds, O as Animator, Q as ColorOverrideRegistry, U as UseSceneOptions, X as SceneRegistry, Y as RegisteredOp, Z as PoseOverrides, _ as DerivedDep, $ as ViewportDims, P as PathDrawCommand, T as TextDrawCommand, a0 as ShaderProgram, c as Mat3$1, a1 as BooleansAdapter, a2 as UseAnimatorOptions, a3 as SpringPresetName, a4 as EasingSpec, a5 as AnimationHandle, a6 as SampledTrack } from './depSchema-nMqj_qTM.js';
10
+ export { a7 as AddLayerSpec, a8 as AddNodeSpec, a9 as AnimateToBoundsOptions, aa as AreaSelectDep, ab as BezierEasing, ac as BooleanOp, ad as BooleanOpResult, ae as ClipboardDep, af as ClipboardIngestCtx, ag as ColorOverride, ah as ColorOverrideFn, ai as ContainerNode, aj as DecayLoopConfig, ak as DecayOptions, al as EASINGS, am as EasingFn, an as EasingName, ao as EditAnchorsDep, ap as EventBooking, aq as EventBookingHandle, ar as EventTrack, as as FitViewToBoundsOptions, G as GroupDrawCommand, at as IDENTITY_POSE_COMPOSITION, a as ImageDrawCommand, b as ImageMinification, au as IngestCtx, av as IngestionDep, aw as InsertDep, ax as Interpolate, ay as InterpolatorFactory, az as Keyframe, aA as LassoSelectDep, aB as LayerRecord, aC as LayoutDep, aD as LeafNode, aE as LoopFactory, aF as LoopOptions, aG as NestedTimeline, aH as NodeAtPointDep, aI as PhysicsHandle, aJ as PhysicsOptions, aK as PointerContextProvider, aL as PointerContextValue, aM as PointerWorldPos, aN as PoseAdapter, aO as PoseClosure, aP as PoseOverride, aQ as RECT_POSE_COMPOSITION, aR as RIGID_POSE_COMPOSITION, R as RenderTarget, aS as ResizePolicy, aT as SPRING_PRESETS, S as SPRITE_STRIDE, aU as SerializedNode, e as ShaderDrawCommand, g as ShaderUniform, aV as SnapDep, aW as SpringOptions, aX as SpringPreset, i as SpriteSheet, j as SpritesDrawCommand, aY as StaggerBuilder, aZ as StaggerDelay, a_ as StaggerFactory, a$ as StaggerOptions, b0 as StaggerPerItem, b1 as StaggerSpringPoseOptions, b2 as StaggerTweenOptions, b3 as SvgUnpacker, b4 as SystemLayerRecord, b5 as SystemLayerSpec, b6 as TextEditDep, b7 as TimelineClock, b8 as TimelineEvent, b9 as TimelineHandle, ba as TimelineOptions, bb as TimelineTrack, bc as Track, bd as TweenLoopOptions, be as TweenOptions, bf as UserLayerRecord, bg as VIEW_ANIMATION_KEY, bh as ViewAnimationApi, bi as ViewApi, bj as ViewChannel, bk as applyBooleanOp, bl as asNodeId, m as blur, bm as composeRectPose, bn as composeRigidPose, bo as composeWorldPose, bp as cubicBezierEasing, bq as decomposeRectPose, br as decomposeRigidPose, bs as easeIn, bt as easeInBack, bu as easeInBounce, bv as easeInCirc, bw as easeInCubic, bx as easeInElastic, by as easeInExpo, bz as easeInOut, bA as easeInOutBack, bB as easeInOutBounce, bC as easeInOutCirc, bD as easeInOutCubic, bE as easeInOutElastic, bF as easeInOutExpo, bG as easeInOutQuad, bH as easeInOutQuart, bI as easeInOutQuint, bJ as easeInOutSine, bK as easeInQuad, bL as easeInQuart, bM as easeInQuint, bN as easeInSine, bO as easeOut, bP as easeOutBack, bQ as easeOutBounce, bR as easeOutCirc, bS as easeOutCubic, bT as easeOutElastic, bU as easeOutExpo, bV as easeOutQuad, bW as easeOutQuart, bX as easeOutQuint, bY as easeOutSine, bZ as fitViewToBounds, o as frameRect, b_ as linear, p as mat3, b$ as rebaseLocalPose, c0 as registerContentHandler, r as registerEffect, c1 as resolveEasing, c2 as resolveStrokeWidth, c3 as translateRectPose, c4 as useDecayLoop, c5 as usePointerContext, c6 as useViewAnimation, v as viewToMat3, s as vignette, c7 as worldPoseLookup } from './depSchema-nMqj_qTM.js';
11
+ import { CursorSpec, PaintedCursorState } from '@weasel-js/cursor';
12
+ export { BakeOptions, CursorGlyph, CursorGlyphName, CursorGlyphSpec, CursorSpec, PaintedCursor, PaintedCursorFrame, PaintedCursorState, ResolvedCursor, bakeCursor, createPaintedCursorState, cursorFor, resolveCursor, resolveCursorTier } from '@weasel-js/cursor';
13
+ import { ClaimableGesture, GestureSpec } from '@weasel-js/gestures';
14
+ export { ClaimableGesture, ClickSpec, DragSpec, DropSpec, GestureSpec, KeyHeldSpec, KeySpec, ModSpec, MultiTouchSpec, PasteSpec, TargetSpec, WheelSpec } from '@weasel-js/gestures';
15
+ import { ToolsApi as ToolsApi$1, UseToolsOptions as UseToolsOptions$1 } from '@weasel-js/routing/react';
16
+ export { ActionsProvider, ActionsScope, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, ActiveToolContextProviderProps, ActiveToolContextValue, DepRegistry, DepRegistryProvider, UseGestureDispatcherOptions, useAction, useActionsRegistry, useActiveToolContext, useDepRegistry, useDepSource, useGestureDispatcher, useOptionalActiveToolContext, useOptionalDepRegistry } from '@weasel-js/routing/react';
17
+ import { B as BoundsConstraint, P as PointSnapBehavior, L as LassoSelectBehavior, R as RotateBehavior, S as SnapStrategy, M as MoveBehavior, I as InsertBehavior } from './types-DMyo7dnM.js';
18
+ export { A as ActionBehavior, b as AreaSelectOverlay, c as BehaviorMoveResult, d as BehaviorResult, C as CloneBehavior, e as CloneLayer, f as ClonePose, G as GestureContext, g as GroupTransform, h as InsertMoveResult, i as InsertOverlay, j as InsertPoint, k as InsertProposed, l as LassoSelectMoveResult, m as LassoSelectOverlay, n as LassoSelectPose, o as LassoSelectProposed, p as PointSnapContext, a as PointSnapFrame, q as PointSnapResult, r as PointerState, s as ResizeMoveResult, t as ResizeOverlay, u as ResizeProposed, v as RotateMoveResult, w as RotateOverlay, x as RotateProposed } from './types-DMyo7dnM.js';
19
+ import { P as PoseDescriptor, c as PolygonPath, a as Path, d as RotatedPose, e as PathFillRule, f as RectPath } from './poseDescriptor-CGOgIgf8.js';
20
+ export { R as RECT_POSE_DESCRIPTOR, b as ROTATED_POSE_DESCRIPTOR, p as poseDescriptorForNode, t as translatePoseViaDescriptor, v as visualBoundsViaDescriptor } from './poseDescriptor-CGOgIgf8.js';
21
+ import { U as UseResizeOptions } from './autoPoseDescriptor-CvjflWJK.js';
22
+ export { A as AUTO_POSE_DESCRIPTOR, C as CORNER_ANCHORS, a as CornerAnchor, g as CornerEdge, b as CornerHandle, c as cornerPoint, d as cornerResizeHandles, h as hitCornerHandle, i as isPathLike, e as isRectPose, p as pointSnapToGrid } from './autoPoseDescriptor-CvjflWJK.js';
23
+ import { M as MoveAdapter, A as AreaSelectAdapter, R as RotateAdapter, b as LassoHitMode, c as LassoSelectAdapter, d as ResizeAdapter, L as LayoutStrategy, e as LayerEnumerableAdapter, I as InsertAdapter, C as ClipboardSnapshot, O as OrderedAdapter, a as SceneAdapter, f as LayoutSnap } from './types-DtjCJA5r.js';
24
+ export { g as ContainerBounds, D as DropTarget, h as LayoutChild, i as LayoutContainer, j as LayoutDragged, S as SnapTarget } from './types-DtjCJA5r.js';
28
25
  import * as react_jsx_runtime from 'react/jsx-runtime';
29
- import { D as DrawCommand, b as ShaderProgramHandle, P as PathDrawCommand, M as Mat3$1 } from './DrawCommand-CD-ug3d9.js';
30
- export { E as Effect, G as GroupDrawCommand, I as ImageDrawCommand, S as SPRITE_STRIDE, a as ShaderDrawCommand, c as ShaderUniform, e as SpritesDrawCommand, T as TextDrawCommand, m as mat3, r as registerEffect } from './DrawCommand-CD-ug3d9.js';
31
26
  import { Op, HistorySelection, CreateHistoryOptions, History } from '@weasel-js/history';
32
27
  export * from '@weasel-js/history';
33
28
  export { Op } from '@weasel-js/history';
34
29
  import { PlacementAlign, Rect, Mat3 } from '@weasel-js/geom';
35
- export { PATH_C, PATH_CMD_LENGTHS, PATH_L, PATH_M, PATH_Q, PATH_Z, Rect, pathCommandCoordCount } from '@weasel-js/geom';
30
+ export { DEFAULT_FLATTEN_TOLERANCE, PATH_C, PATH_CMD_LENGTHS, PATH_L, PATH_M, PATH_Q, PATH_Z, Rect, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, pathCommandCoordCount } from '@weasel-js/geom';
36
31
  import { TextRenderer, TextPose, StyledRun, TextStyle, TextPaint, TextVerticalAlign } from '@weasel-js/text';
37
- export { DEFAULT_TEXT_STYLE, LaidOutDecoration, LaidOutGroup, LaidOutLineBox, LaidOutOutlineGlyph, LaidOutQuad, LaidOutRuns, LayoutLine, LayoutResult, LayoutRunsOpts, MARKDOWN_RUN_GRAMMAR, MarkdownFontOptions, MeasureFn, MeasureTextBoundsOpts, MeasuredText, PositionedRun, ResolvedRun, ResolvedTextStyle, RunFlag, RunGrammar, RunMarker, SCRIPT_METRICS, StyledRun, TextAlign, TextDirection, TextLineBoxesOpts, TextPaint, TextPose, TextRenderer, TextStyle, TextVerticalAlign, cachedLayoutRuns, createMarkdownRenderer, fontString, layoutMarkdown, layoutRuns, markdownToRuns, measureText, measureTextBounds, measuredWidth, resolveAlign, resolveRuns, resolveTextStyle, runsToMarkdown, runsToPlainText, textLineBoxes, toRuns, verticalAlignOffset } from '@weasel-js/text';
38
- import { i as ShaderProgram } from './builtins-CtGORLCG.js';
39
- export { a as ImageMinification, R as RenderTarget, b as SpriteSheet, e as blur, g as frameRect, r as resolveStrokeWidth, v as viewToMat3, h as vignette } from './builtins-CtGORLCG.js';
32
+ export { DEFAULT_TEXT_STYLE, LaidOutDecoration, LaidOutGroup, LaidOutLineBox, LaidOutOutlineGlyph, LaidOutQuad, LaidOutRuns, LayoutLine, LayoutResult, LayoutRunsOpts, MARKDOWN_RUN_GRAMMAR, MarkdownFontOptions, MeasureFn, MeasureTextBoundsOpts, MeasuredText, PositionedRun, ResolvedRun, ResolvedTextStyle, RunFlag, RunGrammar, RunMarker, SCRIPT_METRICS, StyledRun, TextAlign, TextDirection, TextLineBoxesOpts, TextPaint, TextPose, TextPoseLayout, TextPoseLayoutInput, TextRenderer, TextStyle, TextVerticalAlign, cachedLayoutRuns, createMarkdownRenderer, fontString, layoutMarkdown, layoutRuns, layoutTextPose, markdownToRuns, measureText, measureTextBounds, measuredWidth, resolveAlign, resolveRuns, resolveTextStyle, runsToMarkdown, runsToPlainText, textLineBoxes, textPoseLayoutInput, toRuns, verticalAlignOffset } from '@weasel-js/text';
40
33
  import { G as Guide } from './types-D2tTKEU0.js';
41
- export { U as UseInsertOptions } from './options-DYfUlZxk.js';
34
+ export { U as UseInsertOptions } from './options-BDyCnrp8.js';
42
35
  export { UseClipboardOpsOptions, UseClipboardOpsReturn, WEASEL_CLIPBOARD_MIME, WEASEL_CLIPBOARD_MIME_WEB, buildWeaselClipboardText, embedWeaselMetadataInSvg, extractWeaselClipboardFromSvg, parseWeaselClipboardText, sniffWeaselClipboardText, useClipboardOps } from './clipboard.js';
43
36
  export { cloneByAltDrag } from './clone.js';
44
37
  export { FontVariant, LocalFontOutlinesResult, OutlineFontStyle, OutlineSource, OutlineStatus, OutlineVariant, canQueryLocalFonts, enableLocalFontOutlines, hasFontOutlines, isCanvasFont, listFontOutlines, outlineStatus, registerCanvasFont, registerFont, registerFontOutlines, subscribeGlyphReady, unregisterCanvasFont, unregisterFontOutlines } from '@weasel-js/font';
45
- import { CapabilityTag } from '@weasel-js/modes';
46
38
 
47
39
  /**
48
40
  * The kit version a build was compiled from, so an app can report what it is
@@ -67,6 +59,20 @@ declare const VERSION: string;
67
59
  /** Round `value` to the nearest multiple of `cellSize`. Returns 0 when the result would be -0. */
68
60
  declare function roundToCell(value: number, cellSize: number): number;
69
61
 
62
+ /** Pan offset (in pixels) plus per-axis zoom (pixels per content unit). */
63
+ interface ViewTransform {
64
+ panX: number;
65
+ panY: number;
66
+ zoom: {
67
+ x: number;
68
+ y: number;
69
+ };
70
+ }
71
+ /** Project a world-space point to screen-space pixels through a `ViewTransform`. */
72
+ declare function worldToScreen(worldX: number, worldY: number, view: ViewTransform): [number, number];
73
+ /** Inverse of `worldToScreen` — recover the world-space point under a screen-space pixel. */
74
+ declare function screenToWorld(screenX: number, screenY: number, view: ViewTransform): [number, number];
75
+
70
76
  /**
71
77
  * Pointer-tracking glue that turns hover position into a grid cell, suitable
72
78
  * for dropping straight into `createCellHighlightLayer({ getCell })`. Pairs
@@ -125,6 +131,524 @@ interface UseGridCellHoverReturn {
125
131
  /** Track which grid cell the pointer is over; pairs with `createCellHighlightLayer`. */
126
132
  declare function useGridCellHover(opts: UseGridCellHoverOptions): UseGridCellHoverReturn;
127
133
 
134
+ /**
135
+ * Input convenience for zoom primitives. A `number` is treated as a
136
+ * uniform factor applied to both axes; a `{x, y}` vector applies
137
+ * per-axis factors.
138
+ */
139
+ type ZoomFactor = number | {
140
+ x: number;
141
+ y: number;
142
+ };
143
+ /**
144
+ * Input convenience for zoom-clamp ranges. A `number` is applied as the
145
+ * same bound on both axes; a `{x, y}` vector applies per-axis bounds.
146
+ */
147
+ type ZoomBound = number | {
148
+ x: number;
149
+ y: number;
150
+ };
151
+ /**
152
+ * Bridge `View` into the legacy `ViewTransform` shape so chrome can keep
153
+ * calling `worldToScreen` / `screenToWorld`. `View` and `ViewTransform`
154
+ * use opposite sign conventions for the translation half (`view.x` is
155
+ * camera position; `panX` is canvas translation), so the adapter flips
156
+ * the sign and multiplies by per-axis scale.
157
+ */
158
+ declare function viewToTransform(view: View): ViewTransform;
159
+ /**
160
+ * How far `view` is zoomed in, as one number — the geometric mean of its two
161
+ * axes, so a uniform view reports its own scale and a stretched one reports
162
+ * the scale that covers the same area.
163
+ *
164
+ * What a `RuleCtx` carries, because the only rule that asks about the
165
+ * viewport asks for a threshold rather than a camera.
166
+ */
167
+ declare function viewZoom(view: View): number;
168
+ /**
169
+ * `view` inside the invariant {@link View} documents: a zero or non-finite
170
+ * scale axis becomes `ZOOM_FLOOR`, a negative one keeps its sign, and a
171
+ * non-finite translation becomes 0. Returns `view` itself when it already
172
+ * holds, so a valid view keeps its identity.
173
+ */
174
+ declare function normalizeView(view: View): View;
175
+
176
+ interface ChromeState {
177
+ /** Currently selected ids. Live; reflects useSelection's React state. */
178
+ readonly selection: readonly NodeId[];
179
+ /** True when the canvas is in multi-mode AND >= 2 ids are selected. */
180
+ readonly multiActive: boolean;
181
+ /** Bounds for any selection member id. Honors active-tool overlay state
182
+ * (move/resize/rotate ghosts → ghost bounds; otherwise → committed
183
+ * pose bounds). Returns null for unknown ids or ids whose bounds aren't
184
+ * computable. */
185
+ boundsOf(id: string): Bounds | null;
186
+ /** Multi-union AABB when `multiActive`. Computed lazily from `boundsOf`
187
+ * over every selected id, expanding rotated members to the extent of
188
+ * their ink; null otherwise. */
189
+ readonly unionBounds: Bounds | null;
190
+ /** Active modifier state at the moment of the call. */
191
+ readonly modifiers: ModifierState;
192
+ /** True iff the node's pose-descriptor declares it can carry a rotation.
193
+ * Affordances consult this to decide whether to expose rotate cursors /
194
+ * drag-bands. Defaults to `true` when the descriptor doesn't declare
195
+ * (back-compat) or when the id is unknown — the rotation gesture will
196
+ * no-op visually for poses without AABB fields, but the affordance
197
+ * doesn't lie about the cursor. Optional on the interface so unit-test
198
+ * call sites that construct `ChromeState` by hand keep compiling;
199
+ * affordances should treat an absent predicate as "true". */
200
+ canRotate?(id: string): boolean;
201
+ }
202
+
203
+ /**
204
+ * @experimental
205
+ * A single interactive piece of chrome. Pure functions; the kit composes
206
+ * multiple affordances into a single RenderLayer per tool via
207
+ * `composeAffordanceLayer`.
208
+ *
209
+ * Affordances declare interactive regions in a target's *local* frame.
210
+ * The framework (`composeAffordanceLayer`) composes the target's bounds
211
+ * transform (rotation around the AABB center, when present) for both paint
212
+ * and hit-test, so the affordance never touches rotation, view.scale, or
213
+ * world↔screen math.
214
+ */
215
+ interface Affordance {
216
+ /** Stable id for debug overlays + visibility maps. */
217
+ id: string;
218
+ /** Enumerate this affordance's interactive regions. Each region lives in
219
+ * some target id's local frame (or in the world frame when `targetId`
220
+ * is `null`). Returning `[]` means "no chrome for this state" (no
221
+ * selection, multi-mode disabled, etc.). */
222
+ regions(state: ChromeState): readonly AffordanceRegion[];
223
+ /** Optional non-interactive decoration (e.g., a leader line drawn from
224
+ * a bounds edge to a handle — visual only, not draggable). Receives
225
+ * raw state + view because the decoration may live outside any single
226
+ * target's local frame. Most affordances leave this undefined. */
227
+ decorate?(state: ChromeState, view: View): DrawCommand[];
228
+ }
229
+ /**
230
+ * @experimental
231
+ * One interactive region produced by an affordance. The framework owns
232
+ * the local↔world transform for `targetId` (when non-null), so `shape`,
233
+ * `paint.sizePx`, and `hitRadiusPx` are always specified in coordinates
234
+ * the affordance can reason about directly.
235
+ */
236
+ interface AffordanceRegion<TScratch = unknown> {
237
+ /** Stable id, e.g. `corner-min-min`. Used for debug overlays + a11y. */
238
+ id: string;
239
+ /** Target id whose `state.boundsOf(targetId)` defines this region's
240
+ * local frame. `bounds.rotation` (if present) is the only transform
241
+ * applied — translation is the AABB origin; scale is identity. Pass
242
+ * `null` for affordances anchored to the viewport / world frame
243
+ * (identity transform). */
244
+ targetId: string | null;
245
+ /** Region geometry, expressed in the target's local frame.
246
+ *
247
+ * - `point` — circular hit (`hitRadiusPx` is screen-space).
248
+ * - `rect` — axis-aligned rect (target rotation applies).
249
+ * - `annulus` — outer ellipse minus inner rect cutout. Used for
250
+ * invisible zones that sit *around* the AABB (e.g. rotate-on-
251
+ * hover band). The outer ellipse is defined by world-space
252
+ * semi-axes `rx` / `ry` around `(cx, cy)`; the inner rect is the
253
+ * same target-local rect that defines the AABB. Hit-test:
254
+ * inside outer ellipse AND outside inner rect. */
255
+ shape: {
256
+ kind: 'point';
257
+ x: number;
258
+ y: number;
259
+ hitRadiusPx: number;
260
+ } | {
261
+ kind: 'rect';
262
+ x: number;
263
+ y: number;
264
+ width: number;
265
+ height: number;
266
+ } | {
267
+ kind: 'annulus';
268
+ /** Outer-ellipse center (target-local). */
269
+ cx: number;
270
+ cy: number;
271
+ /** Outer-ellipse semi-axes (target-local). */
272
+ rx: number;
273
+ ry: number;
274
+ /** Inner rect (target-local) — the cutout. Typically the
275
+ * selection's AABB. */
276
+ innerX: number;
277
+ innerY: number;
278
+ innerWidth: number;
279
+ innerHeight: number;
280
+ /** Minimum band thickness outside the inner rect, in **screen**
281
+ * pixels. The framework widens `rx`/`ry` to at least
282
+ * `innerHalfExtent + minBandPx / meanScale(view.scale)` for both
283
+ * paint and hit-test.
284
+ *
285
+ * This exists because the clamp has to know the view and the
286
+ * affordance doesn't: `ChromeState` carries no scale. Expressing the
287
+ * floor in world units instead (which is what the rotate ring used
288
+ * to do) makes the band shrink on screen as you zoom in, until the
289
+ * ring around a small shape is too thin to hover. */
290
+ minBandPx?: number;
291
+ };
292
+ /** Optional paint. World position is derived from `shape` + target
293
+ * transform; visual size stays in screen pixels (so handles don't
294
+ * warp under zoom or non-uniform scale). Omit for hit-only regions.
295
+ *
296
+ * - `square` — small fixed-size square (only valid over `point` shapes).
297
+ * - `annulus` — fill + stroke the annulus ring (only valid over
298
+ * `annulus` shapes). Uses even-odd fill rule to punch the inner-rect
299
+ * cutout.
300
+ * - `custom` — emit arbitrary draw commands; receives a {@link CustomPaintContext}. */
301
+ paint?: {
302
+ kind: 'square';
303
+ sizePx: number;
304
+ fill?: FillStyle;
305
+ stroke?: Stroke;
306
+ } | {
307
+ kind: 'annulus';
308
+ fill?: FillStyle;
309
+ stroke?: Stroke;
310
+ insetPx?: number;
311
+ } | {
312
+ kind: 'custom';
313
+ draw: (ctx: CustomPaintContext) => DrawCommand[];
314
+ };
315
+ /** Discriminator a press on this region reports as `AffordanceHit.kind` —
316
+ * the string routing specs match on (`'handle:top-left'`,
317
+ * `'rotate-handle'`, `'anchor:3'`). Omit for regions that only exist
318
+ * inside a consumer-registered layer, where the layer id is the
319
+ * discriminator; `buildAffordanceAt` falls back to
320
+ * `<affordanceId>:<regionId>`. */
321
+ hitKind?: string;
322
+ /** Cursor to show while hovering this region. Read by the hover-cursor
323
+ * pump in `useGestureDispatcher` via `AffordanceHit.cursor`, which
324
+ * `buildAffordanceAt` fills in from the region the walk landed on. */
325
+ cursor?: CursorSpec;
326
+ /** `'exclusive'` bars every binding whose target doesn't consult the
327
+ * affordance. Read only when the affordance is composed into a
328
+ * consumer-registered layer; kit chrome routes through
329
+ * `buildAffordanceAt`, which reports `'shared'`. */
330
+ strength?: 'exclusive' | 'shared';
331
+ /** Which gestures an exclusive claim bars. Omitted bars all of them. */
332
+ claimedKinds?: readonly ClaimableGesture[];
333
+ /** Drag binding produced when this region is hit. Lazily called so
334
+ * affordances don't pay binding-construction cost on every paint frame —
335
+ * state snapshots (e.g., capturing per-leaf poses at click time) belong
336
+ * inside `bind()`, not inside `regions()`. */
337
+ bind(): AffordanceBinding<TScratch>;
338
+ }
339
+ /** Context passed to a region's `paint.kind === 'custom'` draw callback.
340
+ * Provides both the world-space anchor (already transformed) and the
341
+ * original local shape, for affordances that want to do additional
342
+ * geometry themselves. */
343
+ interface CustomPaintContext {
344
+ /** World-space mapping of `shape`. For `point`, only `x`/`y` are set.
345
+ * For `rect`, all four fields are set. */
346
+ world: {
347
+ x: number;
348
+ y: number;
349
+ width?: number;
350
+ height?: number;
351
+ };
352
+ /** The original local shape (same object identity as `region.shape`). */
353
+ local: AffordanceRegion['shape'];
354
+ view: View;
355
+ state: ChromeState;
356
+ }
357
+ /**
358
+ * @experimental
359
+ * Result of an affordance hit — what the region computed about itself.
360
+ *
361
+ * `initialScratch` is the payload: what the region already knows (which
362
+ * corner, which target id) so the action that picks up the drag doesn't
363
+ * re-derive it. `<SceneCanvas>` reads it out of the layer hit-test and packs
364
+ * it into `AffordanceHit`, which flows to the matching action through
365
+ * `InvocationCtx.drag.affordance`.
366
+ *
367
+ * This used to also carry a `drag: DragChannel` naming the handlers the
368
+ * tool-routing dispatcher should wire up. Every implementation supplied a
369
+ * no-op stub that claimed, because the real routing had already moved to
370
+ * bindings; the field went with that dispatcher.
371
+ */
372
+ interface AffordanceBinding<TScratch = unknown> {
373
+ initialScratch?: TScratch;
374
+ }
375
+ /**
376
+ * The fields `buildAffordanceAt` lifts out of a region's `initialScratch`
377
+ * when it turns a region hit into an `AffordanceHit`.
378
+ *
379
+ * Scratch is otherwise opaque — whatever the affordance wants to hand the
380
+ * action that picks up the drag. These few names are the exception: they mean
381
+ * the same thing to every affordance, and the actions that consume them
382
+ * (`resizeAction`, `rotateAction`) read them off `AffordanceHit` rather than
383
+ * out of scratch. An affordance that doesn't set them simply produces a hit
384
+ * without those fields.
385
+ */
386
+ interface CommonAffordanceScratch {
387
+ /** The node (or `MULTI_RESIZE_TARGET_ID`) this chrome acts on. Becomes
388
+ * `AffordanceHit.targetIds`. */
389
+ targetId?: string;
390
+ /** For resize chrome: which corner stays pinned. Mirrors the kit's
391
+ * `ResizeAnchor`, spelled inline so `affordances/` doesn't take a type
392
+ * dependency on the gesture layer for one field. */
393
+ anchor?: {
394
+ x: 'min' | 'max' | 'free';
395
+ y: 'min' | 'max' | 'free';
396
+ };
397
+ /** World-space invariant point of the transform — the fixed corner for a
398
+ * resize, the pivot for a rotation. */
399
+ fixedPoint?: {
400
+ x: number;
401
+ y: number;
402
+ };
403
+ }
404
+ /**
405
+ * What a **registered layer's** `hitTest` returns. Extends `AffordanceBinding`
406
+ * so existing implementations keep typechecking; the added fields are how a
407
+ * consumer's own chrome says the things kit chrome says through
408
+ * `AffordanceRegion` — which cursor to show, and whether it owns the point
409
+ * outright.
410
+ */
411
+ interface LayerHit<TScratch = unknown> extends AffordanceBinding<TScratch> {
412
+ /** Cursor while the pointer is over this hit. Reaches the hover-cursor
413
+ * pump as `AffordanceHit.cursor`, the same path kit chrome uses. */
414
+ cursor?: CursorSpec;
415
+ /** `'exclusive'` bars every binding whose target doesn't consult the
416
+ * affordance. Omitted means `'shared'` — today's behavior. Same name and
417
+ * meaning as `AffordanceHit.strength`, which it becomes. */
418
+ strength?: 'exclusive' | 'shared';
419
+ /** Which gestures an exclusive claim bars. Omitted bars all of them. */
420
+ claimedKinds?: readonly ClaimableGesture[];
421
+ }
422
+
423
+ /**
424
+ * Canvas size in CSS pixels — passed to `draw` for layers that anchor to
425
+ * canvas edges (e.g. the debug overlay's layer-list panel). The GL backend
426
+ * supplies it explicitly so layers don't have to know about DPR.
427
+ */
428
+ interface Dims {
429
+ width: number;
430
+ height: number;
431
+ }
432
+ /**
433
+ * What a layer's `draw` threw, and which layer threw it.
434
+ *
435
+ * A `draw` runs on the frame loop, so a throw that escapes it surfaces as an
436
+ * uncaught `requestAnimationFrame` error on the window and takes the whole
437
+ * frame with it — every other layer included. One broken layer painting
438
+ * nothing, named in the console, is the lesser wrong.
439
+ */
440
+ interface LayerDrawFailure {
441
+ layerId: string;
442
+ error: unknown;
443
+ }
444
+ /**
445
+ * Several consecutive layers composited as one.
446
+ *
447
+ * A layer's own `effects` run over that layer alone, which is the wrong
448
+ * picture whenever a pass reads neighboring pixels: `blur(A over B)` is not
449
+ * `blur(A) over blur(B)`, and it costs a buffer and a pass chain per layer. A
450
+ * group draws its members into one buffer, runs one chain over it, and
451
+ * composites the result back once.
452
+ *
453
+ * Membership is by `RenderLayer.id` — the same names `layerOrder` and
454
+ * `layerVisibility` use, not the `layers` map's slot keys.
455
+ *
456
+ * Only *consecutive* members share a buffer, because anything drawn between
457
+ * two members has to land between them. A group whose members are separated in
458
+ * the render order is drawn as one bracket per run, with a warning: the
459
+ * picture is right, the declaration almost certainly is not.
460
+ *
461
+ * This is a render-stack bracket, not a scene `ContainerNode` — it holds no
462
+ * ids, survives no reload, and nothing in the scene knows about it.
463
+ */
464
+ interface LayerGroup {
465
+ /** Names the group in warnings; not a layer id and never drawn. */
466
+ id: string;
467
+ /** Member layer ids. Order here is ignored — the render order decides. */
468
+ layers: readonly string[];
469
+ /**
470
+ * Passes over the group's combined pixels, in order. A thunk is re-read on
471
+ * every frame, so an animating radius costs no React render; an array is
472
+ * read once per frame either way.
473
+ */
474
+ effects?: readonly Effect[] | ((view: View, dims: Dims) => readonly Effect[]);
475
+ /** Opacity applied to the group's composited result, not to each member. */
476
+ alpha?: number;
477
+ /** 4×5 color matrix (row-major, 20 numbers) applied to the composited
478
+ * result. See `GroupDrawCommand.colorMatrix`. */
479
+ colorMatrix?: number[];
480
+ }
481
+ /** One layer's memoized output, keyed by layer id. Owned by the canvas that
482
+ * calls `drawLayers`, not by `drawLayers` itself — the function is pure. */
483
+ type LayerCommandCache = Map<string, {
484
+ deps: readonly unknown[];
485
+ cmds: DrawCommand[];
486
+ }>;
487
+ /**
488
+ * A single named render sub-layer within a canvas renderer.
489
+ *
490
+ * @template TData - The data object passed to each draw call.
491
+ */
492
+ interface RenderLayer<TData> {
493
+ /** Unique identifier used in visibility maps and ordering arrays. When a
494
+ * cache is in use, an id must identify the same logical layer across
495
+ * frames — reusing it for a different layer can serve cross-layer commands. */
496
+ id: string;
497
+ /** Human-readable name for UI toggles. */
498
+ label: string;
499
+ /**
500
+ * Emit a DrawCommand tree for the GL backend to dispatch.
501
+ *
502
+ * For world-space layers (the default), emit commands in WORLD COORDS —
503
+ * `drawLayers` automatically wraps them in `{ kind: 'group', transform:
504
+ * viewToMat3(view), ... }` before handing them to the renderer. Do NOT
505
+ * apply the view transform yourself.
506
+ *
507
+ * For screen-space layers (`space: 'screen'`), emit commands in CSS-pixel
508
+ * coords directly; `drawLayers` passes them through unchanged. If part
509
+ * of a screen-space layer's output needs to track the view, wrap that
510
+ * subset manually with `viewToMat3(view)`.
511
+ */
512
+ draw: (data: TData, view: View, dims: Dims) => DrawCommand[];
513
+ /**
514
+ * Optional cache key. When present and a `LayerCommandCache` is supplied to
515
+ * `drawLayers`, the layer's previous `DrawCommand[]` is reused as long as
516
+ * every entry is `Object.is`-equal to the previous call's. A layer with no
517
+ * `deps` rebuilds on every frame.
518
+ *
519
+ * **The returned commands must be treated as immutable.** A cached tree is
520
+ * handed to the renderer again on later frames, so mutating a tree you
521
+ * previously returned corrupts the cache silently rather than erroring.
522
+ *
523
+ * **Screen-space layers are not protected against a stale `view`/`dims`
524
+ * the way world-space layers are** (see `space` below) — include them in
525
+ * `deps` if `draw` reads them.
526
+ */
527
+ deps?: (data: TData, view: View, dims: Dims) => readonly unknown[];
528
+ /**
529
+ * Whether the layer is shown when no explicit visibility entry exists.
530
+ * Defaults to `true` when absent.
531
+ */
532
+ defaultVisible?: boolean;
533
+ /**
534
+ * When true, the layer is always drawn regardless of the visibility map.
535
+ * Useful for layers that must never be hidden (e.g. base grid).
536
+ */
537
+ alwaysOn?: boolean;
538
+ /**
539
+ * Coordinate space the layer draws in.
540
+ *
541
+ * - `'world'` (default): the layer's `draw` returns world-space commands;
542
+ * `drawLayers` wraps them in a `kind: 'group'` with `viewToMat3(view)`
543
+ * automatically.
544
+ * - `'screen'`: the layer's `draw` returns screen-space (CSS-pixel)
545
+ * commands; `drawLayers` passes them through unchanged. World-anchored
546
+ * chrome inside a screen-space layer must call `worldToScreen` or wrap
547
+ * the relevant subset with `viewToMat3(view)` manually.
548
+ */
549
+ space?: 'world' | 'screen';
550
+ /**
551
+ * Full-screen passes run over this layer's own pixels before it joins the
552
+ * frame — a blur here blurs the world and leaves the HUD drawn above it
553
+ * sharp, which is the thing a CSS `filter` on the `<canvas>` cannot do.
554
+ *
555
+ * Costs nothing while empty: the renderer allocates no offscreen buffer
556
+ * until a layer actually declares one. See `GroupDrawCommand.effects` for
557
+ * what a pass may read, and {@link LayerGroup} to run one chain over
558
+ * several layers at once instead of one chain each.
559
+ */
560
+ effects?: readonly Effect[];
561
+ /**
562
+ * Optional hit-test for **consumer-attached** layers.
563
+ *
564
+ * Only layers registered through `CanvasExtensionApi.registerLayer` are
565
+ * hit-tested: `hitTestExtras` walks them last-registered-first on
566
+ * pointerdown, and `<SceneCanvas>` folds the result into its `affordanceAt`
567
+ * thunk ahead of the kit's own selection chrome. First non-null result
568
+ * wins; null means "I don't claim this hit, try the next layer."
569
+ *
570
+ * Layers that reach the draw stack some other way — a `Tool.overlay`, an
571
+ * entry in the `layers` map — are painted but never hit-tested, so defining
572
+ * `hitTest` on one has no effect. (The kit's own chrome doesn't need it: it
573
+ * goes through `buildAffordanceAt`.)
574
+ *
575
+ * Coordinates are world-space. The `data` arg is the layer's
576
+ * configured data slot (same as `draw`); `view` and `dims` mirror
577
+ * `draw`'s arguments.
578
+ */
579
+ hitTest?: (worldX: number, worldY: number, data: TData, view: View, dims: Dims,
580
+ /** Chrome-caps visibility predicate. When supplied, the layer must
581
+ * not return a hit from any chrome element whose id reports
582
+ * `false`. Absent → every element is hittable. */
583
+ isVisible?: (id: string) => boolean) => LayerHit | null;
584
+ /**
585
+ * Called on every pointermove when no gesture is currently captured.
586
+ * Lets layers (e.g. HUD widgets) track hover state without participating
587
+ * in the drag pipeline. Coords are world-space; the layer is responsible
588
+ * for any further conversion (e.g. world→screen for screen-space layers)
589
+ * and for its own throttling.
590
+ */
591
+ onUncapturedMove?: (worldX: number, worldY: number, evt: PointerEvent, view: View, dims: Dims) => void;
592
+ /**
593
+ * Called when the cursor leaves the canvas element. Lets layers clear
594
+ * any hover state they're holding.
595
+ */
596
+ onUncapturedLeave?: () => void;
597
+ }
598
+ /**
599
+ * Walk visible layers and concatenate their emitted DrawCommand arrays into
600
+ * one flat list, ready to feed to `WeaselRenderer.render(commands)`.
601
+ *
602
+ * Visibility resolution order:
603
+ * 1. `alwaysOn` — always drawn, ignores visibility map.
604
+ * 2. Explicit entry in `visibility` map — overrides default.
605
+ * 3. `layer.defaultVisible` — falls back to `true` when absent.
606
+ *
607
+ * Transform composition: world-space layers (the default; `space` unset or
608
+ * `'world'`) have their commands wrapped in a `kind: 'group'` with
609
+ * `viewToMat3(view)` before they reach the renderer. Screen-space layers
610
+ * (`space: 'screen'`) pass through unchanged.
611
+ *
612
+ * A layer whose `draw` throws is dropped for the frame and reported through
613
+ * `onLayerError` — the rest of the frame still paints.
614
+ *
615
+ * `groups` brackets runs of consecutive layers so they composite as one — see
616
+ * `LayerGroup`. A layer named by no group is emitted exactly as it was before
617
+ * groups existed, and a frame that declares none allocates nothing.
618
+ */
619
+ declare function drawLayers<TData>(layers: RenderLayer<TData>[], data: TData, visibility: Record<string, boolean>, order: string[] | undefined, view: View | undefined, dims: Dims, cache?: LayerCommandCache, onLayerError?: (failure: LayerDrawFailure) => void, groups?: readonly LayerGroup[]): DrawCommand[];
620
+ /**
621
+ * Resolve one layer's visibility: `alwaysOn` wins, then an explicit entry in
622
+ * `visibility`, then `defaultVisible`, defaulting to shown.
623
+ */
624
+ declare function isLayerVisible<TData>(layer: RenderLayer<TData>, visibility: Record<string, boolean>): boolean;
625
+ /**
626
+ * Does this layer reach the screen at all — both gates, in the order
627
+ * `drawLayers` applies them.
628
+ *
629
+ * **A listed `order` is the whole list**, so omission from it drops a layer
630
+ * that `visibility` would have shown, and `alwaysOn` does not rescue it.
631
+ * Hit-testing asks this, not `isLayerVisible`: a layer that is not painted
632
+ * but still claims pointer events is a pointer landing on nothing the user
633
+ * can see.
634
+ */
635
+ declare function isLayerPainted<TData>(layer: RenderLayer<TData>, visibility: Record<string, boolean>, order: string[] | undefined): boolean;
636
+ /**
637
+ * Draw one layer and put its commands in the space its `space` declares:
638
+ * world-space output wrapped in a `viewToMat3(view)` group, screen-space
639
+ * output passed through.
640
+ *
641
+ * Anything rendering layers through a view — the canvas itself, a viewport
642
+ * node's inner pass — goes through here. A second copy of this rule that
643
+ * forgets the wrap draws world content at raw world coords, which looks
644
+ * plausible at the identity view and wrong everywhere else.
645
+ *
646
+ * A `draw` that throws yields no commands, and `onLayerError` is told which
647
+ * layer it was. The layer's cache entry goes with it, so the next frame is a
648
+ * real re-attempt rather than a stale tree served under fresh deps.
649
+ */
650
+ declare function drawOneLayer<TData>(layer: RenderLayer<TData>, data: TData, view: View, dims: Dims, cache?: LayerCommandCache, onLayerError?: (failure: LayerDrawFailure) => void): DrawCommand[];
651
+
128
652
  /**
129
653
  * Grid overlay — a reusable render layer that draws a world-space grid with
130
654
  * optional finer subdivisions and accent lines every N cells.
@@ -264,6 +788,12 @@ interface CreateViewResolverOpts {
264
788
  left: number;
265
789
  top: number;
266
790
  };
791
+ /**
792
+ * Whether something painted over every view claims a canvas-local point —
793
+ * chrome on the surface's own frame. Such a point resolves to the root even
794
+ * inside a view's rect. Asked only where a view would otherwise win.
795
+ */
796
+ occluded?: (x: number, y: number) => boolean;
267
797
  }
268
798
  declare function createViewResolver(opts: CreateViewResolverOpts): ViewResolver;
269
799
 
@@ -484,23 +1014,9 @@ interface SimulationForce<TNode extends SimulationNode = SimulationNode> {
484
1014
  (alpha: number): void;
485
1015
  initialize?(nodes: TNode[], random?: () => number): void;
486
1016
  }
487
- /** Options for `useSimulation`: the nodes to move, the forces acting on them,
488
- * and the cooling schedule that decides when the simulation settles. */
489
- interface UseSimulationOptions<TNode extends SimulationNode> {
490
- /** Mutable array of nodes. Kit + forces mutate vx/vy/x/y in place. */
491
- nodes: TNode[];
492
- /** Forces applied per tick. Each may implement `initialize` for setup. */
493
- forces?: SimulationForce<TNode>[];
494
- /** Initial alpha. Default 1. */
495
- alpha?: number;
496
- /** Settle threshold. When alpha drops below and alphaTarget is 0, onEnd fires. Default 0.001. */
497
- alphaMin?: number;
498
- /** Per-tick decay rate toward alphaTarget. Default 1 - 0.001^(1/300) ≈ 0.0228. */
499
- alphaDecay?: number;
500
- /** Target alpha. Set above alphaMin to keep sim warm (e.g. during drag). Default 0. */
501
- alphaTarget?: number;
502
- /** Friction multiplier on velocity per tick: vx *= (1 - velocityDecay). Default 0.4. */
503
- velocityDecay?: number;
1017
+ /** Options for `useSimulation`: everything {@link SimulationOptions} carries,
1018
+ * plus the loop's own callbacks and clock. */
1019
+ interface UseSimulationOptions<TNode extends SimulationNode> extends SimulationOptions<TNode> {
504
1020
  /** Fired after each integration step. */
505
1021
  onTick?: (nodes: TNode[]) => void;
506
1022
  /** Fired once when the sim settles (alpha < alphaMin && alphaTarget === 0). */
@@ -510,7 +1026,7 @@ interface UseSimulationOptions<TNode extends SimulationNode> {
510
1026
  cancelFrame?: (handle: number) => void;
511
1027
  }
512
1028
  /**
513
- * A running force simulation over a set of nodes.
1029
+ * A force simulation over a set of nodes, with no clock of its own.
514
1030
  *
515
1031
  * Each tick applies every force and then integrates velocities, scaled by
516
1032
  * `alpha` — a temperature that decays toward `alphaTarget` so the layout
@@ -518,8 +1034,12 @@ interface UseSimulationOptions<TNode extends SimulationNode> {
518
1034
  * which is what a drag does.
519
1035
  *
520
1036
  * Nodes are mutated in place; the simulation holds the array, not a copy.
1037
+ *
1038
+ * Nothing here advances time. {@link Simulation} adds the frame loop; a caller
1039
+ * that wants the whole relaxation at once — a layout pass, a pre-warm, a test
1040
+ * — drives {@link SimulationCore.tick} itself.
521
1041
  */
522
- interface Simulation<TNode extends SimulationNode> {
1042
+ interface SimulationCore<TNode extends SimulationNode> {
523
1043
  readonly nodes: TNode[];
524
1044
  setNodes(nodes: TNode[]): this;
525
1045
  setForces(forces: SimulationForce<TNode>[]): this;
@@ -533,10 +1053,6 @@ interface Simulation<TNode extends SimulationNode> {
533
1053
  alphaMin(value: number): this;
534
1054
  velocityDecay(): number;
535
1055
  velocityDecay(value: number): this;
536
- /** Resume the RAF loop. If alpha < alphaMin, reset alpha to 1. */
537
- restart(): this;
538
- /** Cancel the RAF loop. Does not change alpha. */
539
- stop(): this;
540
1056
  /**
541
1057
  * Run the tick body synchronously `iterations` times. Does NOT fire
542
1058
  * onTick or onEnd (matches d3-force). Used for offscreen pre-warm and tests.
@@ -544,6 +1060,34 @@ interface Simulation<TNode extends SimulationNode> {
544
1060
  tick(iterations?: number): this;
545
1061
  isSettled(): boolean;
546
1062
  }
1063
+ /** A {@link SimulationCore} running on a frame loop. */
1064
+ interface Simulation<TNode extends SimulationNode> extends SimulationCore<TNode> {
1065
+ /** Resume the RAF loop. If alpha < alphaMin, reset alpha to 1. */
1066
+ restart(): this;
1067
+ /** Cancel the RAF loop. Does not change alpha. */
1068
+ stop(): this;
1069
+ }
1070
+ /** What {@link SimulationCore} needs: the nodes, the forces acting on them,
1071
+ * and the cooling schedule. {@link UseSimulationOptions} adds the loop's. */
1072
+ interface SimulationOptions<TNode extends SimulationNode> {
1073
+ /** Mutable array of nodes. Kit + forces mutate vx/vy/x/y in place. */
1074
+ nodes: TNode[];
1075
+ /** Forces applied per tick. Each may implement `initialize` for setup. */
1076
+ forces?: SimulationForce<TNode>[];
1077
+ /** Initial alpha. Default 1. */
1078
+ alpha?: number;
1079
+ /** Settle threshold. When alpha drops below and alphaTarget is 0, onEnd fires. Default 0.001. */
1080
+ alphaMin?: number;
1081
+ /** Per-tick decay rate toward alphaTarget. Default 1 - 0.001^(1/300) ≈ 0.0228. */
1082
+ alphaDecay?: number;
1083
+ /** Target alpha. Set above alphaMin to keep sim warm (e.g. during drag). Default 0. */
1084
+ alphaTarget?: number;
1085
+ /** Friction multiplier on velocity per tick: vx *= (1 - velocityDecay). Default 0.4. */
1086
+ velocityDecay?: number;
1087
+ /** Handed to each force's `initialize`. Default `Math.random`; pass a seeded
1088
+ * source to make a run reproducible. */
1089
+ random?: () => number;
1090
+ }
547
1091
  /** Default alpha decay: such that alpha drops from 1 to alphaMin (0.001) in 300 ticks. */
548
1092
  declare const DEFAULT_ALPHA_DECAY: number;
549
1093
  /** Alpha below which a cooling simulation is considered settled. */
@@ -553,9 +1097,24 @@ declare const DEFAULT_ALPHA_MIN = 0.001;
553
1097
  declare const DEFAULT_VELOCITY_DECAY = 0.4;
554
1098
 
555
1099
  /**
556
- * Continuous N-body simulation primitive. Owns a RAF loop and a velocity-Verlet
557
- * integrator; forces are pluggable functions matching d3-force's protocol so
558
- * d3-force's bundled forces work without translation.
1100
+ * The integrator, with no clock attached.
1101
+ *
1102
+ * Velocity-Verlet over a pluggable force list, contract-compatible with
1103
+ * d3-force so d3's own bundled forces drop in untranslated. Nothing here
1104
+ * advances time: `tick()` is the only thing that moves a node, and the caller
1105
+ * decides how often to call it. `useSimulation` calls it once a frame; a
1106
+ * layout pass calls it a few hundred times in one go and reads the result.
1107
+ *
1108
+ * Splitting it out is what lets a *pure* function run a relaxation — a React
1109
+ * hook cannot, and the alternative was a second integrator drifting away from
1110
+ * this one.
1111
+ */
1112
+
1113
+ declare function createSimulation<TNode extends SimulationNode>(opts: SimulationOptions<TNode>): SimulationCore<TNode>;
1114
+
1115
+ /**
1116
+ * Continuous N-body simulation primitive: `createSimulation`'s integrator on a
1117
+ * frame loop.
559
1118
  *
560
1119
  * The kit is adapter-agnostic — `onTick(nodes)` fires after each integration
561
1120
  * step and the consumer decides how (and whether) to write through to scene
@@ -564,6 +1123,47 @@ declare const DEFAULT_VELOCITY_DECAY = 0.4;
564
1123
  */
565
1124
  declare function useSimulation<TNode extends SimulationNode>(opts: UseSimulationOptions<TNode>): Simulation<TNode>;
566
1125
 
1126
+ /** What a producer is told before it is asked for a frame. */
1127
+ interface PoseRunCtx<TPose> {
1128
+ /** Nodes another gesture is moving, and the pose each is drawn at. The run
1129
+ * will not write these, so a producer holds them fixed. */
1130
+ pinned: ReadonlyMap<NodeId, TPose>;
1131
+ /** Frames this run has produced, starting at 0. */
1132
+ frame: number;
1133
+ }
1134
+ /** One frame of a run. */
1135
+ interface PoseRunStep<TPose> {
1136
+ /** Where the nodes it drives are this frame — the whole picture, not a
1137
+ * delta. An id the frame omits stops being published, which is how a node
1138
+ * leaves the run's hands: a producer that drops a grabbed box and its rows
1139
+ * from one frame has released them by the next. */
1140
+ poses: Iterable<readonly [NodeId, TPose]>;
1141
+ /** Whether the run is finished. The frame is published either way, and a
1142
+ * finished run commits. */
1143
+ done: boolean;
1144
+ }
1145
+ interface UsePoseRunOptions<TPose> {
1146
+ scene: Scene<unknown, string, TPose>;
1147
+ step: (ctx: PoseRunCtx<TPose>) => PoseRunStep<TPose>;
1148
+ /** The undo entry's name. Default `'Layout'`. */
1149
+ label?: string;
1150
+ /** How many nodes the commit wrote. Fires after the ops land. */
1151
+ onCommit?: (moved: number) => void;
1152
+ /** Clock injection, for tests. Defaults to `requestAnimationFrame`. */
1153
+ requestFrame?: (cb: (t: number) => void) => number;
1154
+ cancelFrame?: (handle: number) => void;
1155
+ }
1156
+ interface PoseRun {
1157
+ /** Begin, or continue where a `stop` left off. Idempotent while running. */
1158
+ start(): void;
1159
+ /** Finish now: commit what is published, then drop the overrides. */
1160
+ stop(): void;
1161
+ /** Abandon: drop the overrides and write nothing, like a canceled drag. */
1162
+ cancel(): void;
1163
+ isRunning(): boolean;
1164
+ }
1165
+ declare function usePoseRun<TPose>(opts: UsePoseRunOptions<TPose>): PoseRun;
1166
+
567
1167
  /**
568
1168
  * `useNodeOverlayFrame` — the coordinate frame a DOM overlay pinned to one
569
1169
  * scene node needs: the node's world box, the projection from that box's
@@ -600,7 +1200,8 @@ interface NodeOverlayFrame {
600
1200
  };
601
1201
  /** Node box frame → overlay pixels, rotation and view included. */
602
1202
  toScreen: (p: OverlayPoint) => OverlayPoint;
603
- /** Overlay pixels → node box frame. Inverts `toScreen`. */
1203
+ /** Overlay pixels → node box frame. Inverts `toScreen`; while a live view
1204
+ * flattens an axis, it keeps the last mapping that had an inverse. */
604
1205
  toLocal: (p: OverlayPoint) => OverlayPoint;
605
1206
  /** The container's size in CSS pixels — the overlay's own box. */
606
1207
  width: number;
@@ -820,7 +1421,8 @@ interface Scale2 {
820
1421
  x: number;
821
1422
  y: number;
822
1423
  }
823
- /** One screen-pixel length as world-space extents, per axis. */
1424
+ /** One screen-pixel length as world-space extents, per axis. `scale` is a
1425
+ * view's, so neither axis is zero (see `View`). */
824
1426
  declare function pxExtent(px: number, scale: Scale2): {
825
1427
  x: number;
826
1428
  y: number;
@@ -843,59 +1445,6 @@ declare function withinPxBox(dx: number, dy: number, px: number, scale: Scale2):
843
1445
  /** Is a world-space delta inside a screen-space circle of radius `px`? */
844
1446
  declare function withinPxRadius(dx: number, dy: number, px: number, scale: Scale2): boolean;
845
1447
 
846
- /**
847
- * The DOM half of a drag: one pointer, held down, from press to release.
848
- *
849
- * Every pointerdown-to-pointerup lifecycle in the kit used to answer capture,
850
- * pointer identity, teardown and lost-pointer recovery for itself, and each
851
- * answered them differently. This is the one place those are decided; anything
852
- * above it — thresholds, coordinate spaces, what the drag *means* — belongs to
853
- * its caller.
854
- */
855
- /** Why a session ended without the pointer being released. */
856
- type PointerSessionCancelReason =
857
- /** The browser cancelled the pointer (touch interrupted, palm rejection). */
858
- 'pointercancel'
859
- /** The origin left the document mid-gesture, taking capture with it. */
860
- | 'lostcapture'
861
- /** `cancel()` — an unmount, a window blur, Escape, a consumer's own rule. */
862
- | 'aborted'
863
- /** A new press arrived on this pointer, so the tracked one had ended. */
864
- | 'superseded';
865
- interface PointerSessionCallbacks {
866
- /** Every move belonging to this pointer, while it is still held. */
867
- onMove?: (e: PointerEvent) => void;
868
- /** The pointer was released. Fires once, before teardown completes. */
869
- onEnd?: (e: PointerEvent) => void;
870
- /** The session ended without a release. Fires once. */
871
- onCancel?: (reason: PointerSessionCancelReason) => void;
872
- }
873
- interface PointerSessionOptions {
874
- /** Ask the origin element to capture the pointer. Default `true`. Capture
875
- * keeps hover and click off everything the drag passes over; the session
876
- * does not depend on it to keep receiving events. */
877
- capture?: boolean;
878
- }
879
- interface PointerSession {
880
- readonly pointerId: number;
881
- /** False once the session has ended, by any route. */
882
- readonly active: boolean;
883
- /** End the session now, reporting `'aborted'`. Idempotent. */
884
- cancel: () => void;
885
- }
886
- /**
887
- * Open a session for the pointer that `down` belongs to.
888
- *
889
- * Listens on the origin's document rather than on the element: a captured
890
- * element that is removed mid-drag stops receiving events, and every listener
891
- * hung on it goes with it. Three recovery rules close the gaps a plain
892
- * pointerup/pointercancel pair leaves — losing capture cancels only once the
893
- * origin has left the document, a move reporting no held button is read as
894
- * the release that never arrived, and a fresh press on the same pointer says
895
- * the tracked one had already ended.
896
- */
897
- declare function openPointerSession(origin: Element, down: PointerEvent | React.PointerEvent, cb: PointerSessionCallbacks, opts?: PointerSessionOptions): PointerSession;
898
-
899
1448
  /** A 2D point in the rect element's local coordinate space. */
900
1449
  interface HandleDragPoint {
901
1450
  x: number;
@@ -1049,33 +1598,6 @@ interface CanvasSizeSnapshot extends CanvasSize {
1049
1598
  * query instead. */
1050
1599
  declare function useCanvasSize(containerRef: RefObject<HTMLElement | null>): CanvasSizeSnapshot;
1051
1600
 
1052
- /**
1053
- * Handle/hit multiplier applied on a coarse pointer.
1054
- *
1055
- * 8px handle → 14px; 24px rotation distance → 42px. Counting the
1056
- * surrounding grab zone, that lands in the Apple HIG 44pt / Material 48dp
1057
- * minimum-touch-target band. One constant so it is tunable in one place.
1058
- */
1059
- declare const COARSE_TARGET_SCALE = 1.75;
1060
- /**
1061
- * Fold consumer overrides over detected facts and derive `targetScale`.
1062
- *
1063
- * `targetScale` is re-derived AFTER the merge, so an override of
1064
- * `coarsePointer` alone scales the chrome as expected. An explicit
1065
- * `targetScale` override wins over the derivation.
1066
- */
1067
- declare function resolveDeviceProfile(detected: DetectedDeviceFacts, overrides?: Partial<DeviceProfile>): DeviceProfile;
1068
- /**
1069
- * Assumed when `matchMedia` is unavailable (SSR, jsdom) and used as the
1070
- * absent-means value for `RuleCtx.device`.
1071
- *
1072
- * Derived from `resolveDeviceProfile` rather than hand-written, so it can
1073
- * never drift from what the function would compute for the same facts. A
1074
- * mouse-like device is the safe default: it is what the kit has always
1075
- * assumed, so an absent profile changes nothing for existing consumers.
1076
- */
1077
- declare const DEFAULT_DEVICE_PROFILE: DeviceProfile;
1078
-
1079
1601
  /**
1080
1602
  * Base sizes for grabbable chrome, in CSS pixels at `targetScale = 1`, and the
1081
1603
  * one accessor that resolves them for a live pointer type.
@@ -1149,7 +1671,7 @@ interface ZoomClampOpts {
1149
1671
  min?: ZoomBound;
1150
1672
  max?: ZoomBound;
1151
1673
  }
1152
- declare function zoomAt(view: View, anchor: {
1674
+ declare function zoomAt(input: View, anchor: {
1153
1675
  x: number;
1154
1676
  y: number;
1155
1677
  }, factor: ZoomFactor, opts?: ZoomClampOpts): View;
@@ -1165,6 +1687,23 @@ declare function zoomAt(view: View, anchor: {
1165
1687
  */
1166
1688
  declare const DEFAULT_MIN_ZOOM = 0.1;
1167
1689
  declare const DEFAULT_MAX_ZOOM = 8;
1690
+ /**
1691
+ * The smallest zoom magnitude a view can hold, in `View.scale` units.
1692
+ *
1693
+ * A view's zoom is always finite and at least this far from 0. Nothing can be
1694
+ * drawn or picked through a zoom of 0, and every screen↔world conversion
1695
+ * divides by it, so it is ruled out where views are made rather than handled
1696
+ * by each conversion. This is validity, not an interaction limit: that is
1697
+ * {@link DEFAULT_MIN_ZOOM}, which a consumer may set far below.
1698
+ */
1699
+ declare const ZOOM_FLOOR = 1e-9;
1700
+ /**
1701
+ * The one rule for a zoom magnitude: a finite number no smaller than
1702
+ * {@link ZOOM_FLOOR}. Anything else (0, negative, NaN, ±Infinity) becomes the
1703
+ * floor. Dev builds warn once when a zoom that was never valid arrives; a
1704
+ * positive zoom that merely undershoots the floor clamps silently.
1705
+ */
1706
+ declare function normalizeZoom(zoom: number): number;
1168
1707
 
1169
1708
  /** Options for {@link sceneNodeClientRect}. */
1170
1709
  interface SceneNodeClientRectOpts {
@@ -1215,258 +1754,24 @@ declare function computeFitViewport(viewportW: number, viewportH: number, conten
1215
1754
  declare function useAutoCenter(width: number, height: number, contentW: number, contentH: number, setZoom: (z: number) => void, setPan: (x: number, y: number) => void): void;
1216
1755
 
1217
1756
  /**
1218
- * Pure keyboard-binding helpers shared between the tool dispatcher
1219
- * (`useKeybindings`), the gesture dispatcher (`useGestureDispatcher`), and
1220
- * individual Tool declarations.
1221
- *
1222
- * Extracted from the deleted singular `useKeybinding` hook so the remaining
1223
- * consumers don't depend on its disappearance.
1224
- */
1225
- /**
1226
- * @internal — runtime shape consumed by `matchesKeyBinding`. Public tool authors
1227
- * should use `ToolKeybinding` from `@weasel-js/core` for declaring
1228
- * configurable activation keys.
1229
- */
1230
- interface KeyBinding {
1231
- /**
1232
- * Key or list of keys to match. Compared case-insensitively against
1233
- * `event.key`, so `'a'` matches both `'a'` and `'A'`.
1234
- */
1235
- key: string | readonly string[];
1236
- /**
1237
- * Require Cmd (mac) or Ctrl (others). When `true`, exactly one of
1238
- * `metaKey`/`ctrlKey` must be held. Default `false` (both forbidden).
1239
- */
1240
- mod?: boolean;
1241
- /** Require Alt. Default `false` (forbidden). */
1242
- alt?: boolean;
1243
- /**
1244
- * Shift policy. `undefined`/`false` forbids shift, `true` requires
1245
- * shift, `'optional'` allows either. Default `undefined`.
1246
- */
1247
- shift?: boolean | 'optional';
1248
- /** Skip when focus is in an editable element. Default `true`. */
1249
- skipInEditable?: boolean;
1250
- /** When `false`, the listener is not attached. Default `true`. */
1251
- enabled?: boolean;
1252
- /** Call `preventDefault` before the handler. Default `true`. */
1253
- preventDefault?: boolean;
1254
- }
1255
- /** Returns true when the target is an input, textarea, or contenteditable element. */
1256
- declare function isEditableTarget(target: EventTarget | null): boolean;
1257
- /**
1258
- * Pure matcher for `KeyBinding` against a `KeyboardEvent`. Only checks key +
1259
- * modifier policy — does NOT apply the editable-target skip or
1260
- * `preventDefault`. Shared by the tool dispatcher (`useKeybindings`) and the
1261
- * gesture dispatcher so the rules can't drift.
1757
+ * Project an action's keyboard bindings into the shape a shortcut chip
1758
+ * renders from (`formatShortcut` / `formatShortcutParts` in
1759
+ * `@weasel-js/ui`). Palette and menu surfaces show what an action answers
1760
+ * to; the dispatcher reads the specs themselves.
1262
1761
  */
1263
- declare function matchesKeyBinding(e: KeyboardEvent, b: KeyBinding): boolean;
1264
1762
 
1763
+ /** One keyboard shortcut, flattened for display. Structurally the
1764
+ * `ShortcutInput` weasel-ui formats — kept local so core doesn't depend on
1765
+ * the UI package. */
1766
+ interface ActionShortcut {
1767
+ key: string;
1768
+ mod: boolean;
1769
+ alt: boolean;
1770
+ shift: boolean;
1771
+ }
1265
1772
  /**
1266
- * Promote a Rule tree to a fluent Condition. The function form evaluates
1267
- * the tree against a RuleCtx; combinator methods produce new Conditions
1268
- * wrapping `all`/`any`/`not` nodes.
1269
- *
1270
- * **Chain semantics: strict left-to-right.** No boolean precedence.
1271
- * `focused.or(hovering).and(selectionIs(1))` evaluates
1272
- * `((focused || hovering) && selectionIs(1))` — NOT
1273
- * `(focused || (hovering && selectionIs(1)))` as standard precedence
1274
- * would give. For grouped disjunction, use the top-level `or` / `and` /
1275
- * `not` helpers or name intermediates.
1276
- *
1277
- * Combinators flatten same-kind nesting on construction so `a.and(b).and(c)`
1278
- * produces `{ all: [a, b, c] }` rather than `{ all: [{ all: [a, b] }, c] }`.
1279
- * Canonical form simplifies downstream introspection.
1280
- *
1281
- * Use {@link when} for the inline-lambda escape hatch.
1282
- */
1283
- declare function cond(rule: Rule): Condition;
1284
- /** Inline-lambda escape hatch. Wraps the closure as a `when` rule node. */
1285
- declare function when(fn: (ctx: RuleCtx) => boolean): Condition;
1286
- /** `(a && b && c && ...)` — useful when chain mixing makes left-to-right
1287
- * semantics ambiguous. */
1288
- declare function and(...cs: (Condition | Rule)[]): Condition;
1289
- /** `(a || b || c || ...)` — preferred over `.or` chains when mixed with
1290
- * `.and` to make grouping explicit. */
1291
- declare function or(...cs: (Condition | Rule)[]): Condition;
1292
- /** `!c` — top-level negation. Most rules use `.andNot()` / `.orNot()`
1293
- * instead; this is for the lead-with-negation case. */
1294
- declare function not(c: Condition | Rule): Condition;
1295
- /** Always true. The fallback for any chrome id without a registered rule. */
1296
- declare const always: Condition;
1297
- /** Always false. Useful for "turn this chrome off entirely":
1298
- * `chromeVisibility={{ 'snap.guides': never }}`. */
1299
- declare const never: Condition;
1300
- /** Canvas surface currently focused. */
1301
- declare const focused: Condition;
1302
- /** Any action currently in flight (read: user is gesturing). */
1303
- declare const gesturing: Condition;
1304
- /** Active action's kind matches `kind` (e.g. `actionIs('move')`). */
1305
- declare const actionIs: (kind: string) => Condition;
1306
- /** Nothing selected. */
1307
- declare const selectionEmpty: Condition;
1308
- /** Exactly `n` items selected. */
1309
- declare const selectionIs: (n: number) => Condition;
1310
- /** At least `n` items selected. `selectionAtLeast(1)` is the common
1311
- * "something is selected" check. */
1312
- declare const selectionAtLeast: (n: number) => Condition;
1313
- /** Multi-mode handle behavior active (single shared union-bounds
1314
- * handle vs per-item handles). Implemented as a `when` because
1315
- * `multiActive` is a derived single-call read on RuleCtx, not a
1316
- * selector-table key. Stable; safe to introspect. */
1317
- declare const multiActive: Condition;
1318
- /** Pointer is hovering some node. */
1319
- declare const hovering: Condition;
1320
- /** Pointer is hovering a node that is currently selected. */
1321
- declare const hoveringSelected: Condition;
1322
- /** Named modifier key currently held. */
1323
- declare const modifierHeld: (m: keyof ModifierState) => Condition;
1324
- /** View scale (uniform or geometric mean for non-uniform) is at least
1325
- * `z`. Useful for "hide hairline chrome at low zoom" rules. */
1326
- declare const zoomAtLeast: (z: number) => Condition;
1327
- /** Active mode equals `m`. */
1328
- declare const modeIs: (m: string) => Condition;
1329
- /** Active mode is one of `modes`. */
1330
- declare const modeIn: (modes: readonly string[]) => Condition;
1331
- /** Active mode is NOT `m`. */
1332
- declare const modeNot: (m: string) => Condition;
1333
- /** Active mode's `allows` includes capability `cap`. */
1334
- declare const capabilityIs: (cap: string) => Condition;
1335
- /** Active mode's `allows` includes ANY of `caps` (OR). */
1336
- declare const capabilityIn: (caps: readonly string[]) => Condition;
1337
- /** Active mode's `allows` includes ALL of `caps` (AND). */
1338
- declare const capabilityAll: (caps: readonly string[]) => Condition;
1339
- /** Active mode's `allows` does NOT include capability `cap`. */
1340
- declare const capabilityNot: (cap: string) => Condition;
1341
- /** Primary pointer is imprecise (touch, most styluses). Absent device
1342
- * profile → false, so a rule written with this atom is inert on the
1343
- * mouse-shaped default rather than silently flipping. */
1344
- declare const coarsePointer: Condition;
1345
- /** Primary pointer can hover. Absent device profile → true. Pair with
1346
- * `not(...)` to gate chrome that only makes sense with a hovering
1347
- * pointer: `not(canHover)` is "this device cannot hover". */
1348
- declare const canHover: Condition;
1349
-
1350
- /**
1351
- * Kit-shipped defaults. Merged with the consumer's `chromeVisibility` map
1352
- * at resolve time; consumer entries take precedence per id.
1353
- *
1354
- * Written as literal Rule trees rather than fluent chains so the inputs
1355
- * each rule depends on are immediately visible. The fluent atoms compile
1356
- * to the same trees; either form is valid in a VisibilityRules entry.
1357
- *
1358
- * Gating is written in terms of **capabilities, not mode ids**. A
1359
- * capability rule keeps holding when a new mode is added that permits the
1360
- * same thing; a mode rule has to be found and edited every time. There is
1361
- * no `mode:` rule left in this table — the `path-edit.*` chrome used to be
1362
- * the exception, on the theory that it's the visual signature of one mode;
1363
- * see the comment on those rules below for why that was wrong in both
1364
- * directions and what replaced it.
1365
- *
1366
- * Chrome that gates on the *absence* of a capability (the selection
1367
- * outline, suppressed while an anchor-editing overlay owns the visuals)
1368
- * uses `capability: { not: … }` for the same reason.
1369
- */
1370
- declare const defaultVisibilityRules: VisibilityRules;
1371
-
1372
- /**
1373
- * Build the per-frame visibility check. Merges consumer rules on top
1374
- * of the kit defaults, then closes over `ctx` so each chrome-id
1375
- * lookup runs its rule against the current state.
1376
- *
1377
- * `VisibilityRules` entries may be either fluent `Condition` values
1378
- * (callable) or raw `Rule` trees — we normalize at lookup time.
1379
- *
1380
- * Predicates are O(1) and run once per chrome id per frame; no
1381
- * memoization in v1 — profile before adding any.
1382
- *
1383
- * `ChromeCtx` is the legacy shape; surfaces still on it get `mode='normal'`
1384
- * and `DEFAULT_ALLOWED_CAPABILITIES` filled in here, so a caller that never
1385
- * opted into modality behaves exactly like one sitting in normal mode.
1386
- */
1387
- declare function resolveVisibility(consumer: VisibilityRules | undefined, ctx: ChromeCtx | RuleCtx): (id: ChromeId) => boolean;
1388
-
1389
- /**
1390
- * Pure assembler for {@link ChromeCtx}.
1391
- *
1392
- * Called once per frame on the rendering side from whichever surface
1393
- * needs to evaluate visibility rules — `composeAffordanceLayer`,
1394
- * `createSelectionOverlayLayer`, the dispatcher overlay layer, etc.
1395
- *
1396
- * Sources are passed as plain getters / values rather than the live
1397
- * objects they come from. This keeps `chrome-caps` from depending on
1398
- * React, the dispatcher's concrete type, or `ChromeState`'s bounds
1399
- * machinery — the same builder works from a test harness, a Storybook
1400
- * fixture, or `<SceneCanvas>`.
1401
- */
1402
-
1403
- /** The pieces of live canvas state a `ChromeCtx` is assembled from. */
1404
- interface BuildChromeCtxArgs {
1405
- focused: boolean;
1406
- selection: readonly NodeId[];
1407
- multiActive: boolean;
1408
- modifiers: ModifierState;
1409
- action: {
1410
- kind: string | null;
1411
- id: string | null;
1412
- };
1413
- hover: NodeId | null;
1414
- view: View;
1415
- }
1416
- /** Gather the current canvas state into the context that chrome-visibility
1417
- * rules are evaluated against. Rebuilt per frame. */
1418
- declare function buildChromeCtx(args: BuildChromeCtxArgs): ChromeCtx;
1419
-
1420
- /**
1421
- * useHoverTracking — last-hovered NodeId for chrome-caps rules.
1422
- *
1423
- * Attaches a `pointermove` listener to the supplied canvas; on each move it
1424
- * runs the supplied `nodeAtClientPoint` and caches the resulting id on a ref.
1425
- * Cleared on `pointerleave` (pointer left the canvas → nothing is hovered).
1426
- *
1427
- * Returns a stable getter — call once per frame from `buildChromeCtx`.
1428
- *
1429
- * No re-render: the ref updates silently, and the next render that
1430
- * reads it picks up the fresh value. Chrome-caps rules are evaluated
1431
- * during paint, so the hover state is always read fresh.
1432
- */
1433
-
1434
- /** Options for `useHoverTracking`. */
1435
- interface UseHoverTrackingArgs {
1436
- canvasRef: RefObject<HTMLElement | null>;
1437
- /** Topmost id under a client point, or null. One lookup rather than a
1438
- * client→world thunk beside a world-space picker: a screen-pixel pick
1439
- * tolerance converts against the camera the point resolved to, and two
1440
- * thunks are two chances to disagree about which view that is. */
1441
- nodeAtClientPoint: (clientX: number, clientY: number) => {
1442
- id: NodeId;
1443
- } | null;
1444
- enabled?: boolean;
1445
- }
1446
- /** Track which node the pointer is over. Returns a getter rather than state,
1447
- * so per-frame code can read the current value without the hover re-rendering
1448
- * the component on every pointer move. */
1449
- declare function useHoverTracking(args: UseHoverTrackingArgs): () => NodeId | null;
1450
-
1451
- /**
1452
- * Project an action's keyboard bindings into the shape a shortcut chip
1453
- * renders from (`formatShortcut` / `formatShortcutParts` in
1454
- * `@weasel-js/ui`). Palette and menu surfaces show what an action answers
1455
- * to; the dispatcher reads the specs themselves.
1456
- */
1457
-
1458
- /** One keyboard shortcut, flattened for display. Structurally the
1459
- * `ShortcutInput` weasel-ui formats — kept local so core doesn't depend on
1460
- * the UI package. */
1461
- interface ActionShortcut {
1462
- key: string;
1463
- mod: boolean;
1464
- alt: boolean;
1465
- shift: boolean;
1466
- }
1467
- /**
1468
- * The chip form of a single gesture spec, or `undefined` when the spec has
1469
- * none.
1773
+ * The chip form of a single gesture spec, or `undefined` when the spec has
1774
+ * none.
1470
1775
  *
1471
1776
  * Two kinds of collapsing, both because a binding list is written for a
1472
1777
  * matcher rather than for a reader:
@@ -1513,7 +1818,7 @@ declare function actionShortcuts(action: Action): readonly ActionShortcut[];
1513
1818
  *
1514
1819
  * The per-frame poses still go *somewhere* the scene can see: the ephemeral
1515
1820
  * override table, which bypasses history entirely. That is what lets a node
1516
- * deriving its geometry from a dragged one follow the drag — `scenePoseLookup`
1821
+ * deriving its geometry from a dragged one follow the drag — `sceneDepLookup`
1517
1822
  * and the pick source both read overrides, and neither can see this action's
1518
1823
  * scratch. Keeping the frame in scratch alone is why the edge used to stay
1519
1824
  * anchored to the old endpoint and jump on drop.
@@ -1527,11 +1832,8 @@ declare function actionShortcuts(action: Action): readonly ActionShortcut[];
1527
1832
  *
1528
1833
  * ## Pose generics
1529
1834
  *
1530
- * `scene` dep is typed `Scene<unknown, string, unknown>` (the erased DepSchema
1531
- * entry). Poses are read and written as `unknown`; `translatePoseGeneric`
1532
- * delegates to `RECT_POSE_DESCRIPTOR.translate` which treats any pose as
1533
- * `{x, y, ...}`. Consumers with non-rect poses should register a custom
1534
- * action with a typed translatePose.
1835
+ * Poses are `unknown`; every read and write goes through the `poseDescriptor`
1836
+ * dep (`AUTO_POSE_DESCRIPTOR` when unsourced).
1535
1837
  */
1536
1838
 
1537
1839
  /**
@@ -1559,17 +1861,14 @@ declare const moveAction: Action & {
1559
1861
  * start poses, applies per-frame bounds remapping, and commits a single
1560
1862
  * `scene.batch` entry on end.
1561
1863
  *
1562
- * ## Behaviors / point-snap / expandIds / geometry — via `resizePolicy` dep
1864
+ * ## Behaviors / point-snap / expandIds — via the `resizePolicy` dep
1563
1865
  *
1564
- * The resize-behaviors-api wired the four behavior options the
1565
- * legacy `useResize` hook exposed (`behaviors`, `pointSnapBehaviors`,
1566
- * `expandIds`, `geometry`) through the `resizePolicy` dep entry. When
1567
- * the dep is registered, this invoker:
1866
+ * The `resizePolicy` dep carries the behavior options the legacy `useResize`
1867
+ * hook exposed (`behaviors`, `pointSnapBehaviors`, `expandIds`). When the dep
1868
+ * is registered, this invoker:
1568
1869
  *
1569
1870
  * - Calls `expandIds([id])` at start. When the result expands beyond the
1570
1871
  * starting id, takes the group path (union-AABB origin, per-leaf remap).
1571
- * - Projects poses through the supplied `geometry: PoseProjection<TPose>`
1572
- * instead of the rect-shaped `RECT_POSE_DESCRIPTOR` default.
1573
1872
  * - Runs `behaviors[]` after the raw anchor-math bounds are computed.
1574
1873
  * Behaviors return `{ pose? }` and rewrite the proposed bounds before
1575
1874
  * they're projected back into pose space.
@@ -1578,12 +1877,17 @@ declare const moveAction: Action & {
1578
1877
  * frame's world point lands on the snap target.
1579
1878
  *
1580
1879
  * When the dep is absent the invoker falls back to identity defaults
1581
- * (no behaviors, no snap, `ids => ids` expansion, `RECT_POSE_DESCRIPTOR`),
1582
- * which matches the unrotated rect-pose path the invoker already
1583
- * implemented.
1880
+ * (no behaviors, no snap, `ids => ids` expansion).
1881
+ *
1882
+ * ## Pose geometry — via the `poseDescriptor` dep
1883
+ *
1884
+ * Every pose read and rewrite goes through the `poseDescriptor` dep, which
1885
+ * `<SceneCanvas>` sources from its `poseDescriptor` prop. Unsourced it is
1886
+ * `AUTO_POSE_DESCRIPTOR`, which dispatches per call to `pathPoseDescriptor`
1887
+ * for Path-shaped poses and to `RECT_POSE_DESCRIPTOR` for everything else.
1584
1888
  *
1585
1889
  * @see useResize — the React hook this descriptor mirrors.
1586
- * @see src/interactions/actions/resize/geometry.ts — `PoseProjection`.
1890
+ * @see src/interactions/actions/resize/geometry.ts — `PoseDescriptor`.
1587
1891
  */
1588
1892
 
1589
1893
  /**
@@ -1603,7 +1907,7 @@ declare const resizeAction: Action & {
1603
1907
  *
1604
1908
  * ## Status: REAL (unrotated-pivot path)
1605
1909
  *
1606
- * Implements the core rotation math from `useRotate` for rect-shaped poses:
1910
+ * Implements the core rotation math from `useRotate`:
1607
1911
  * - `start`: captures origin poses + AABB centers; computes start pointer
1608
1912
  * angle around the union center of selected nodes.
1609
1913
  * - `onMove`: derives pointer angle delta from start, applies to each node's
@@ -1618,8 +1922,9 @@ declare const resizeAction: Action & {
1618
1922
  *
1619
1923
  * ## Constraints vs `useRotate`
1620
1924
  *
1621
- * - Assumes rect-shaped poses `{ x, y, width, height, rotation? }`. Non-rect
1622
- * TPose consumers need a custom action with a typed `RotateGeometry`.
1925
+ * - Reads and writes poses through the `poseDescriptor` dep; a pose whose
1926
+ * descriptor has no `withRotation`, or reports `supportsRotation` false, is
1927
+ * left alone.
1623
1928
  * - No behavior pipeline (snap, etc.). Behaviors wait for a later phase.
1624
1929
  * - No overlay rendering — deferred to Phase 7 overlay surface.
1625
1930
  * - Shift-snap (15° quantum) is NOT wired in this phase — omitted deliberately
@@ -1633,9 +1938,7 @@ declare const resizeAction: Action & {
1633
1938
  *
1634
1939
  * Requires dep-schema entries: `selection`, `scene`.
1635
1940
  *
1636
- * Implements the unrotated-pivot rotation path from `useRotate` for rect-
1637
- * shaped poses. Non-rect or behavior-rich consumers should register a custom
1638
- * `rotateAction` with a typed `RotateGeometry` dep.
1941
+ * Implements the unrotated-pivot rotation path from `useRotate`.
1639
1942
  *
1640
1943
  * @see useRotate — the React hook this descriptor mirrors for the rect case.
1641
1944
  */
@@ -1850,9 +2153,7 @@ declare const clearSelectionAction: Action & {
1850
2153
  *
1851
2154
  * ## Pose generics
1852
2155
  *
1853
- * Poses are translated using the same `{x, y, ...}` generic spread as
1854
- * `moveAction`. Non-rect poses with custom layout (e.g. paths) should register
1855
- * a custom clone action with a typed geometry dep.
2156
+ * Poses are translated through the `poseDescriptor` dep, as `moveAction` does.
1856
2157
  */
1857
2158
 
1858
2159
  /**
@@ -2154,6 +2455,19 @@ declare const lassoSelectAction: Action & {
2154
2455
  requires: string[];
2155
2456
  };
2156
2457
 
2458
+ /**
2459
+ * @experimental
2460
+ * Static descriptor for the `slice` Action.
2461
+ *
2462
+ * Ongoing drag invoker: tracks a slice line from drag start to current
2463
+ * pointer, publishes it as a `'cut'` overlay while the gesture is in flight,
2464
+ * and on commit calls `SliceDep.commit(a, b)`. No-ops gracefully when
2465
+ * the `slice` dep is absent.
2466
+ */
2467
+ declare const sliceAction: Action & {
2468
+ requires: string[];
2469
+ };
2470
+
2157
2471
  /**
2158
2472
  * `pinchZoomAction` — ongoing Action descriptor for two-finger pinch zoom
2159
2473
  * and pan. The id and label stay `pinchZoom` / `Pinch Zoom`.
@@ -2217,6 +2531,143 @@ declare const pinchZoomAction: Action & {
2217
2531
  requires: string[];
2218
2532
  };
2219
2533
 
2534
+ /**
2535
+ * @experimental
2536
+ * Static descriptor for the `clipboard.copy` Action (Cmd/Ctrl+C).
2537
+ */
2538
+ declare const clipboardCopyAction: Action & {
2539
+ requires: string[];
2540
+ };
2541
+ /**
2542
+ * @experimental
2543
+ * Static descriptor for the `clipboard.cut` Action (Cmd/Ctrl+X) — copy, then
2544
+ * the same batched delete `deleteAction` performs, as one undo entry.
2545
+ */
2546
+ declare const clipboardCutAction: Action & {
2547
+ requires: string[];
2548
+ };
2549
+
2550
+ /**
2551
+ * `enterTextEditAction` — immediate Action descriptor for entering in-place
2552
+ * text editing on a selected text node.
2553
+ *
2554
+ * ## Status: REAL
2555
+ *
2556
+ * Fires via `useTextTool.bindings` when the user clicks on a
2557
+ * selected text node. Calls `deps.textEdit.startEdit(id)` to activate the
2558
+ * contenteditable overlay managed by `useTextEdit` / `useSceneTextEdit`.
2559
+ *
2560
+ * ## No defaultBinding / defaultBinding
2561
+ *
2562
+ * This action has no ambient key or gesture binding — it fires ONLY via
2563
+ * `useTextTool`'s `Tool.bindings` entry:
2564
+ *
2565
+ * ```ts
2566
+ * bindings: [
2567
+ * { spec: { kind: 'click', target: 'selected-body' }, actionId: 'enterTextEdit' },
2568
+ * ]
2569
+ * ```
2570
+ *
2571
+ * Keeping it binding-free avoids ambient double-fire and scopes the action to
2572
+ * the text tool context where `classifyTarget` is already wired.
2573
+ *
2574
+ * ## Self-guard: only act on text nodes
2575
+ *
2576
+ * The `'selected-body'` target yields a match for any selected node kind. To
2577
+ * avoid entering text-edit mode when the text tool happens to have a non-text
2578
+ * node selected, the action self-guards via an optional `isTextNode` predicate
2579
+ * on `TextEditDep`:
2580
+ *
2581
+ * - When `isTextNode` is absent: action fires unconditionally (the binding
2582
+ * spec is the real gate — consumers should only bind this action from the
2583
+ * text tool).
2584
+ * - When `isTextNode(id)` returns `false`: action is a no-op for that node.
2585
+ *
2586
+ * ### Pre-filtering at dispatch time
2587
+ *
2588
+ * `classifyTarget` now surfaces node kind, so a binding can pre-filter instead
2589
+ * of relying on the self-guard:
2590
+ *
2591
+ * ```ts
2592
+ * { spec: { kind: 'click', target: 'kind:text:selected' }, actionId: 'enterTextEdit' }
2593
+ * ```
2594
+ *
2595
+ * That reads the *routing trait's* kind, so it matches whatever names the
2596
+ * consumer registered in `<SceneCanvas routing>` — `'text'` under the kit's
2597
+ * inferred default. `isTextNode` stays on `TextEditDep` because it also covers
2598
+ * consumers who bind the broader `'selected-body'` target, and because it is
2599
+ * the only guard for a consumer who opted out of routing entirely.
2600
+ *
2601
+ * ## Migration plan for useTextTool
2602
+ *
2603
+ * When wiring `useTextTool` to `Tool.bindings`:
2604
+ *
2605
+ * 1. Add to `useTextTool`'s `bindings`:
2606
+ * ```ts
2607
+ * { spec: { kind: 'click', target: 'selected-body' }, actionId: 'enterTextEdit' }
2608
+ * ```
2609
+ * 2. Register a `textEdit` dep sourced from the `useTextEdit` / `useSceneTextEdit`
2610
+ * return value, plus an `isTextNode` predicate that checks `data.kind === 'text'`
2611
+ * (or however the consumer identifies text nodes).
2612
+ * 3. The existing `hitExisting` gate in `useTextTool`'s click route becomes
2613
+ * redundant — remove it in the same pass.
2614
+ */
2615
+
2616
+ /**
2617
+ * @experimental
2618
+ * Static descriptor for the `enterTextEdit` Action.
2619
+ *
2620
+ * Requires dep-schema entries: `textEdit`, `selection`.
2621
+ *
2622
+ * No `defaultBinding` / `defaultBinding` — fires only via `Tool.bindings`.
2623
+ * Self-guards via `TextEditDep.isTextNode` when provided.
2624
+ */
2625
+ declare const enterTextEditAction: Action & {
2626
+ requires: string[];
2627
+ };
2628
+
2629
+ /** Somewhere selection can live outside this hook. `Scene` satisfies it;
2630
+ * so does any store with the same three methods. */
2631
+ interface SelectionStore {
2632
+ getSelection(): readonly NodeId[];
2633
+ setSelection(ids: readonly NodeId[]): void;
2634
+ subscribe(listener: () => void): () => void;
2635
+ }
2636
+ /** Options for {@link useSelection}. */
2637
+ interface UseSelectionOptions {
2638
+ /** Default `'single'`. */
2639
+ mode?: SelectionMode;
2640
+ /** Default `'shift'`. Ignored in single-mode. */
2641
+ extend?: SelectionExtendKey;
2642
+ /** Default `[]`. */
2643
+ initial?: readonly NodeId[];
2644
+ /** Keep the selection on this store rather than in the hook, so every
2645
+ * consumer of the same scene shares one selection and undo / redo can
2646
+ * restore it. `initial` then only seeds a store that has none yet.
2647
+ * Omit it and the hook owns a selection nobody else sees. */
2648
+ scene?: SelectionStore;
2649
+ /** When `true`, every mutator (`set`/`add`/`remove`/`toggle`/`clear`/
2650
+ * `applyClick`) is a no-op — selection stays at whatever `initial`
2651
+ * pinned it to. Useful for demos that exist to showcase a single
2652
+ * pre-selected node and don't want a
2653
+ * stray click to deselect. */
2654
+ lock?: boolean;
2655
+ }
2656
+ /**
2657
+ * Default implementation of the `getSelection` / `setSelection` adapter
2658
+ * contract every action hook (delete, duplicate, nudge, group, ...) requires.
2659
+ *
2660
+ * Owns selection state, exposes a click-policy helper (single vs multi with
2661
+ * an extend key), and pre-builds the two adapter methods consumers otherwise
2662
+ * hand-roll in every demo:
2663
+ *
2664
+ * ```tsx
2665
+ * const selection = useSelection({ mode: 'multi' });
2666
+ * const adapter = { ...arrayAdapter({...}), ...selection.adapterMethods };
2667
+ * ```
2668
+ */
2669
+ declare function useSelection(opts?: UseSelectionOptions): SelectionApi;
2670
+
2220
2671
  /** @experimental */
2221
2672
  interface UseStandardActionsOptions {
2222
2673
  /** Kit selection state — ids of currently selected nodes. */
@@ -2257,25 +2708,6 @@ declare const KIT_STANDARD_ACTION_IDS: readonly string[];
2257
2708
  */
2258
2709
  declare function useStandardActions(opts: UseStandardActionsOptions): void;
2259
2710
 
2260
- /**
2261
- * Shared scene-backed commit adapter for default actions.
2262
- *
2263
- * Default actions route data/layer/pose/parent mutations through the
2264
- * consumer's `applyOps` commit hook when one is present; when it isn't, they
2265
- * fall back to applying the committed ops directly against the scene through
2266
- * this adapter. It carries the scene-backed op-apply methods (`setPose` /
2267
- * `setParent` / `setData` / `setLayer` / `removeNode` / `insertNode` /
2268
- * `setChildOrder`) plus the read-side queries (`getNode` / `getNodes` /
2269
- * `getPose` / `getParent` / `getChildren` / `getSelection`) and
2270
- * `setSelection`. Known exclusions from the op factory roster — surfaces the
2271
- * scene doesn't own: `setPath` and `setText`.
2272
- *
2273
- * Lives in `interactions/actions/` (not `canvas/sceneAdapter.ts`) so default
2274
- * actions never import from `canvas/` — that back-edge would create an
2275
- * `interactions → canvas → interactions` cycle. Mirrors `moveGestureAdapter`,
2276
- * widened to all op-apply methods.
2277
- */
2278
-
2279
2711
  /** Build the adapter the default actions commit through when the consumer
2280
2712
  * supplies no `applyOps` hook of its own — it applies ops straight to the
2281
2713
  * scene. Path and text ops are not covered; those surfaces belong to their
@@ -2301,289 +2733,26 @@ declare function defaultCommitAdapter<TPose>(scene: Scene<unknown, string, TPose
2301
2733
  /** Options for `useResizePolicy`. Each omitted field falls back to the kit
2302
2734
  * default. */
2303
2735
  interface UseResizePolicyOptions<TPose> {
2304
- constraints?: TPose extends ResizePose ? BoundsConstraint<TPose>[] : never[];
2305
- pointSnap?: TPose extends ResizePose ? PointSnapBehavior<TPose>[] : never[];
2736
+ constraints?: TPose extends Bounds ? BoundsConstraint<TPose>[] : never[];
2737
+ pointSnap?: TPose extends Bounds ? PointSnapBehavior<TPose>[] : never[];
2306
2738
  expandIds?: (ids: string[]) => string[];
2307
- projection?: PoseProjection<TPose>;
2308
2739
  }
2309
2740
  /** Publish how resizing should behave — constraints, point snapping, group
2310
- * expansion, pose projection — for the resize action to consult. */
2741
+ * expansion — for the resize action to consult. */
2311
2742
  declare function useResizePolicy<TPose>(options: UseResizePolicyOptions<TPose>): void;
2312
2743
 
2744
+ /** Publish the pose descriptor every built-in action reads. */
2745
+ declare function usePoseDescriptorDepSource(descriptor: PoseDescriptor<unknown> | undefined): void;
2746
+
2747
+ /** Publish the scene's pose-composition strategy to the built-in actions.
2748
+ * Absent is the absolute-pose model: `scenePoseFrame` falls back to identity
2749
+ * and every world/local conversion in an action is a no-op. */
2750
+ declare function usePoseCompositionDepSource(composition: PoseComposition<unknown> | undefined): void;
2751
+
2313
2752
  /** Publish how a slice (knife cut) is performed, so the `slice` action can
2314
2753
  * run against the consumer's geometry. */
2315
2754
  declare function useSliceDep(dep: SliceDep): void;
2316
2755
 
2317
- /**
2318
- * The painted cursor a surface is currently showing, shared between whoever
2319
- * decides it and the layer that draws it.
2320
- *
2321
- * Two slots rather than one, mirroring the precedence the cursor pipeline
2322
- * already has: `<Canvas>` writes the active tool's cursor to `base` from
2323
- * render, and the hover pump writes an affordance's or an action's cursor to
2324
- * `override` imperatively. The override wins while it is set, and clearing it
2325
- * restores the base without a React commit — the same reason the pump uses an
2326
- * inline style for the CSS tier.
2327
- */
2328
-
2329
- /** The painted arm of `ResolvedCursor` — what this module stores. */
2330
- type PaintedCursor = Extract<ResolvedCursor, {
2331
- kind: 'painted';
2332
- }>;
2333
- interface PaintedCursorFrame {
2334
- readonly cursor: PaintedCursor;
2335
- /** Pointer position in the layer's own space: canvas-local CSS px. */
2336
- readonly at: {
2337
- readonly x: number;
2338
- readonly y: number;
2339
- };
2340
- }
2341
- interface PaintedCursorState {
2342
- setBase(cursor: PaintedCursor | null): void;
2343
- setOverride(cursor: PaintedCursor | null): void;
2344
- /** Canvas-local CSS px. */
2345
- setPointer(x: number, y: number): void;
2346
- /** Pointer left the surface: nothing to draw until it returns. */
2347
- clearPointer(): void;
2348
- /**
2349
- * Whether a painted cursor is set at all, regardless of where the pointer is.
2350
- *
2351
- * Lets the pointer path skip measuring the canvas rect on every move in the
2352
- * overwhelmingly common case where the compositor is drawing the cursor and
2353
- * nothing here needs its position.
2354
- */
2355
- active(): boolean;
2356
- /** What the layer should draw this frame, or null for none. */
2357
- current(): PaintedCursorFrame | null;
2358
- /** Run `fn` whenever the answer to `current()` may have changed. */
2359
- subscribe(fn: () => void): () => void;
2360
- }
2361
- declare function createPaintedCursorState(): PaintedCursorState;
2362
-
2363
- /**
2364
- * Everything about handling an input event that depends on *which view* it
2365
- * landed in: the dispatcher that runs it, and the three lookups that resolve
2366
- * a client point against that view's camera.
2367
- *
2368
- * @internal One per view. The hook builds the `id: null` one from its flat
2369
- * options; `views` supplies the rest, and the hook chooses between them per
2370
- * event, so that it — and its listener set — still mounts exactly once.
2371
- */
2372
- interface DispatcherViewTarget {
2373
- /** `null` is the root view — the whole canvas. Matches `ViewTarget.id`. */
2374
- id: string | null;
2375
- dispatcher: Dispatcher;
2376
- affordanceAt: UseGestureDispatcherOptions['affordanceAt'];
2377
- classifyTarget: UseGestureDispatcherOptions['classifyTarget'];
2378
- clientToWorld: UseGestureDispatcherOptions['clientToWorld'];
2379
- /**
2380
- * The deps this view answers for itself — its camera, its selection, and
2381
- * whatever else is per-view rather than per-canvas. Read per event; every
2382
- * name it does not carry still resolves through the canvas registry.
2383
- *
2384
- * This is why a view does not get a `DepRegistryProvider` of its own. The
2385
- * registry is where a consumer registers *sources*, and one per view would
2386
- * fragment that: a consumer overriding `insert` would have to know how many
2387
- * views exist and override each. An overlay keeps one place to register and
2388
- * one authority per dep, with the view claiming only what is genuinely its.
2389
- *
2390
- * Without this a gesture inside a panel pans the whole canvas and selects
2391
- * into the canvas's selection — correct coordinates alone do not make
2392
- * routing correct.
2393
- */
2394
- deps?: () => Partial<DepSchema>;
2395
- /**
2396
- * This view's chrome-caps rule context, for the eligibility filter. The rule
2397
- * table is the surface's, but a rule keyed on selection or the in-flight
2398
- * action answers per view — so an action hidden in one panel must not
2399
- * decline a gesture in another. `undefined` means "nothing gates here", the
2400
- * same answer a surface with no mode registry gives.
2401
- */
2402
- getRuleCtx?: () => RuleCtx | undefined;
2403
- }
2404
- /**
2405
- * The part of `features/viewports`' `ViewResolver` the dispatcher needs: which
2406
- * view a client point belongs to, pinned to the view a gesture began in.
2407
- *
2408
- * @internal Structural on purpose — a `ViewResolver` satisfies it, and the
2409
- * dispatcher stays free of the viewport module.
2410
- */
2411
- interface ViewIdResolver {
2412
- begin(pointerId: number, clientX: number, clientY: number): {
2413
- id: string | null;
2414
- };
2415
- at(pointerId: number | null, clientX: number, clientY: number): {
2416
- id: string | null;
2417
- };
2418
- end(pointerId: number): void;
2419
- }
2420
- /** Options for `useGestureDispatcher`: the element to listen on, the actions
2421
- * and tools in play, and the hooks that turn raw DOM events into the world
2422
- * coordinates and hit targets bindings match against. */
2423
- interface UseGestureDispatcherOptions {
2424
- /** Ref to the canvas element. Pointer/wheel/multitouch listeners attach here. */
2425
- canvasRef: RefObject<HTMLElement | null>;
2426
- /** Action registry (ActionsRegistry from registry.tsx). */
2427
- actions: ActionsRegistry;
2428
- /** Tool definitions keyed by id. Typically passes an empty Map. */
2429
- toolsById: ReadonlyMap<string, Tool>;
2430
- /** Default true. Set false to opt out of dispatcher wiring (e.g. demos that disable it). */
2431
- enabled?: boolean;
2432
- /**
2433
- * Observer fired whenever the dispatcher synthesizes a double click, in
2434
- * world coordinates. Runs BEFORE the event is dispatched and independently
2435
- * of which binding (if any) handles it.
2436
- *
2437
- * This is deliberately not an Action. `<SceneCanvas onDoubleClick>` is a
2438
- * notification — "the user double-clicked, here's what they hit" — and a
2439
- * notification must not compete with behavior for the gesture. As a binding
2440
- * it would lose to `enterPathEdit` on any body hit and silently never fire.
2441
- * Routing it here keeps a single definition of "double click" (the point of
2442
- * consolidating the kit's three detectors) without giving it
2443
- * first-match-wins semantics it shouldn't have.
2444
- */
2445
- onDoubleClick?: (world: {
2446
- x: number;
2447
- y: number;
2448
- }) => void;
2449
- /**
2450
- * Default true. Set false to leave the window `keydown`/`keyup` listeners
2451
- * unattached so keyboard-bound actions never dispatch — pointer, wheel, and
2452
- * contextmenu channels stay live. `<SceneCanvas>` wires this to
2453
- * `enableKeybindings`, so opting out of keybindings disables the modern
2454
- * dispatcher key path as well as the legacy `useKeybindings` hook.
2455
- */
2456
- keyboard?: boolean;
2457
- /**
2458
- * Optional affordance classifier. Called on every pointerdown with the
2459
- * world-space coordinates of the pointer. Returns an `AffordanceHit` when
2460
- * the pointer lands on a known affordance (resize handle, rotate handle, etc.)
2461
- * or `null` when the pointer hit open canvas.
2462
- *
2463
- * The hit is packed into `InputEvent.pointerdown.affordance` and flows
2464
- * through into `InvocationCtx.drag.affordance`. Action invokers that require
2465
- * a specific affordance (e.g. `resizeAction` requires `handle:*`) use this
2466
- * field as a guard in their `start` body.
2467
- *
2468
- * When omitted, `affordance` is always `undefined` — meaning only consumers
2469
- * that explicitly wire a classifier get affordance-gated behavior.
2470
- * `<SceneCanvas>` wires the full chrome→dispatcher bridge.
2471
- */
2472
- affordanceAt?: (worldPoint: {
2473
- x: number;
2474
- y: number;
2475
- }) => AffordanceHit | null;
2476
- /**
2477
- * Optional body classifier. Called on every pointerdown with the world-space
2478
- * coordinates of the pointer. Its result is packed onto the event as
2479
- * `bodyTarget` + `bodyKind`, which `matchTarget` reads to resolve the
2480
- * string-form `TargetSpec` values in `Tool.bindings`.
2481
- *
2482
- * `body` is `'empty'` when nothing is under the pointer, `'selected-body'`
2483
- * when the topmost hit belongs to the current selection, or
2484
- * `'unselected-body'` when it belongs to a node that isn't selected. `kind`
2485
- * is the hit node's semantic kind, when the scene can name it.
2486
- *
2487
- * When omitted, every body-derived target form (`'empty'`,
2488
- * `'selected-body'`, `'unselected-body'`, `kind:<k>`, `kind:<k>:selected`)
2489
- * never matches — bindings using those specs are silently skipped.
2490
- * `<SceneCanvas>` wires this.
2491
- */
2492
- classifyTarget?: (worldPoint: {
2493
- x: number;
2494
- y: number;
2495
- }) => BodyClassification;
2496
- /**
2497
- * Optional pre-created `Dispatcher`. When provided, this hook pumps events
2498
- * into the supplied instance instead of creating its own. Lets a parent
2499
- * scope (e.g. `<SceneCanvas>`) share one dispatcher between the gesture
2500
- * mounter and other consumers (the preview-ghost layer).
2501
- */
2502
- dispatcher?: Dispatcher;
2503
- /**
2504
- * Converts a client-space pointer position (e.g. `e.clientX`, `e.clientY`)
2505
- * to world-space coordinates. When supplied, every pointer/wheel event's
2506
- * `x`/`y` is converted before the dispatcher builds `InvocationCtx.world`.
2507
- *
2508
- * Without this, `ctx.world` is populated with the raw client coords, which
2509
- * silently breaks any action whose overlay/output uses absolute world
2510
- * positions (marquee, lasso polyline, world-space affordances). Actions
2511
- * that only read `drag.delta` are unaffected because client→world deltas
2512
- * are equal at scale 1, but as soon as a consumer pans/zooms the view the
2513
- * deltas diverge too.
2514
- *
2515
- * `<SceneCanvas>` always wires this via its canvas rect + current view.
2516
- * Tests / harnesses without a view can omit it and continue passing raw
2517
- * coordinates as before.
2518
- */
2519
- clientToWorld?: (clientX: number, clientY: number) => {
2520
- x: number;
2521
- y: number;
2522
- };
2523
- /**
2524
- * Invoked once per pump event (`pointermove`, `pointerup`, `pointercancel`,
2525
- * `key-held` up-phase, `multitouch` move) when a dispatcher-side handle is
2526
- * in flight. Lets the host canvas schedule a redraw so dispatcher-only
2527
- * overlays (marquee, lasso, preview-ghost) repaint on each frame.
2528
- *
2529
- * Required because dispatcher actions don't go through the legacy
2530
- * `tools.dispatcher.onGestureChange` redraw bump that ambient tool drags
2531
- * relied on. Without it, the overlay layer's `draw` never runs between
2532
- * pointerdown and pointerup, and the chrome flashes once at gesture start
2533
- * and then sits frozen until the gesture ends.
2534
- *
2535
- * `<SceneCanvas>` wires this to the canvas's `requestRedraw`. Test
2536
- * harnesses can omit it; their dispatchers won't paint between events but
2537
- * that's already the test contract.
2538
- */
2539
- requestRedraw?: () => void;
2540
- /**
2541
- * The surface's painted-cursor channel, read live because the canvas handle
2542
- * it lives on arrives a render after this hook runs.
2543
- *
2544
- * Given one, a cursor the CSS tier cannot express — sized in world units, or
2545
- * past the size the browser drops the image at — is published here and drawn
2546
- * by the painted-cursor layer instead. Without one, such a cursor resolves to
2547
- * `none` and the pointer shows nothing.
2548
- */
2549
- paintedCursor?: () => PaintedCursorState | undefined;
2550
- /**
2551
- * Thunk returning the live `RuleCtx` for the current frame. When supplied,
2552
- * the dispatcher filters matched candidates by their declared
2553
- * `Action.eligible` rule (omitted => always eligible). `<SceneCanvas>`
2554
- * wires this; tests / harnesses without chrome-caps state can omit it.
2555
- */
2556
- getRuleCtx?: () => RuleCtx | undefined;
2557
- /**
2558
- * Routing for a canvas hosting more than one view: the non-root dispatch
2559
- * records to choose between, read fresh per event, and the resolver that
2560
- * chooses. Omit for a single view — then every event runs on the record the
2561
- * flat options above describe, which is what they are: view zero.
2562
- *
2563
- * A resolved id with no live record falls back to the root, so a view that
2564
- * unmounts mid-gesture degrades instead of dropping the event.
2565
- *
2566
- * Keyboard and paste have no coordinates to resolve; they run on the view
2567
- * the last coordinate-bearing event resolved to.
2568
- *
2569
- * @internal
2570
- */
2571
- views?: {
2572
- targets: () => readonly DispatcherViewTarget[];
2573
- resolver: ViewIdResolver;
2574
- };
2575
- }
2576
- /**
2577
- * Attach the input pipeline to a canvas: DOM pointer, wheel, keyboard and
2578
- * multitouch listeners in, normalized input events out, routed through the
2579
- * dispatcher to whichever action a binding names.
2580
- *
2581
- * Everything it needs beyond its options — the active tool, the dep registry —
2582
- * comes from context, so it must be mounted inside `<SceneCanvas>`'s
2583
- * providers.
2584
- */
2585
- declare function useGestureDispatcher(opts: UseGestureDispatcherOptions): void;
2586
-
2587
2756
  /**
2588
2757
  * The one place weasel decides whether a frame may run, so that "a loop does no
2589
2758
  * work nobody can see" holds by construction rather than by every loop author
@@ -2687,14 +2856,6 @@ declare function wheelPan(view: View, delta: {
2687
2856
  /** Pure reducer: the whole wheel convention in one call. */
2688
2857
  declare function computeWheelAction(view: View, input: WheelInput, clamp?: ZoomClampOpts, opts?: Pick<WheelPanOpts, 'axis'>): View;
2689
2858
 
2690
- /**
2691
- * Convert client coords to element CSS-pixel coords (relative to the element's
2692
- * top-left). Apps drawing in CSS-pixel space feed the result directly into
2693
- * world math when pan/zoom is identity. With pan/zoom, compose this with
2694
- * your inverse-viewport transform.
2695
- */
2696
- declare function clientToCanvas(canvas: HTMLElement, clientX: number, clientY: number): [number, number];
2697
-
2698
2859
  /** Records recent deltas and reports the current velocity, averaged over the
2699
2860
  * last 100ms — the throw speed a momentum decay starts from. */
2700
2861
  interface VelocityTracker {
@@ -2734,93 +2895,28 @@ declare function usePinchGesture(canvasRef: React.RefObject<HTMLElement | null>,
2734
2895
  declare function interpolateView(from: View, to: View): (t: number) => View;
2735
2896
 
2736
2897
  /**
2737
- * Build a `Tool<TScratch>` from a declarative `ToolDef<TScratch>`.
2898
+ * The routing types that carry an overlay, bound to the kit's `RenderLayer`.
2738
2899
  *
2739
- * This used to be a translator: `ToolDef` carried `initial` / `engaged` phase
2740
- * tables of hit-keyed route handlers, and `defineTool` compiled them into the
2741
- * imperative `pointer` / `drag` / `keyboard` / `wheel` handlers the
2742
- * tool-routing dispatcher called. Both ends of that are gone — tools declare
2743
- * `bindings` and the gesture dispatcher routes them — so what remains is
2744
- * identity plumbing plus the id check and the cursor resolver.
2745
- *
2746
- * It stays a function rather than becoming a spread because the id validation
2747
- * and the `initScratch` / `cursor` defaults are worth applying uniformly, and
2748
- * because `Tool.def` gives reflection a handle on the authored form.
2900
+ * `@weasel-js/routing` never reads an overlay — it collects the live ones and
2901
+ * hands them back in scope order — so it leaves the element type open. What a
2902
+ * weasel canvas draws is a `RenderLayer`, and every kit call site should see
2903
+ * that rather than `unknown`, so core binds the parameter once, here, and
2904
+ * re-exports these names under the ones they have always had.
2749
2905
  */
2750
- declare function defineTool<TScratch = void>(def: ToolDef<TScratch>): Tool<TScratch>;
2751
2906
 
2752
- /**
2753
- * Define a tool that acts on the viewport rather than the scene.
2754
- *
2755
- * This used to do real work: `ViewportPhaseDef` was a narrowed `PhaseDef`
2756
- * (no click routes, drag restricted to the function form), and the factory
2757
- * lifted it back to the permissive shape before handing it to `defineTool`.
2758
- * With phase tables gone there is no shape left to narrow — a viewport tool
2759
- * declares `bindings` like any other, pointing at `viewport.*` actions.
2760
- *
2761
- * It survives as an authoring signal. `defineViewportTool` at the top of a
2762
- * hook says "this tool moves the camera, not the drawing", which is worth
2763
- * more than the type gymnastics it replaced.
2764
- */
2907
+ /** What a canvas overlay is, at this layer. */
2908
+ type Overlay = RenderLayer<unknown>;
2909
+ type Contribution = Contribution$1<Overlay>;
2910
+ type ContributionChrome = ContributionChrome$1<Overlay>;
2911
+ type Tool<TScratch = unknown> = Tool$1<TScratch, Overlay>;
2912
+ type AnyTool = AnyToolOf<Overlay>;
2913
+ type ToolDef<TScratch = void> = ToolDef$1<TScratch, Overlay>;
2914
+ type ViewportToolDef<TScratch = void> = ViewportToolDef$1<TScratch, Overlay>;
2915
+ type ToolsApi = ToolsApi$1<Overlay>;
2916
+ type UseToolsOptions = UseToolsOptions$1<Overlay>;
2917
+ declare function defineTool<TScratch = void>(def: ToolDef<TScratch>): Tool<TScratch>;
2765
2918
  declare function defineViewportTool<TScratch = void>(def: ViewportToolDef<TScratch>): Tool<TScratch>;
2766
-
2767
- /** Options for `useTools`: which tools exist, which one starts active, and
2768
- * which run continuously regardless of the active one. */
2769
- interface UseToolsOptions {
2770
- /** Initial active-slot tool id. Must exist in `registry`. */
2771
- active: string;
2772
- /** Tools eligible for the active slot or hotkey slot. The keys are the
2773
- * tool ids; the values are the tool records. A tool with `hotkey` set
2774
- * is wired into the hotkey slot whenever the engagement state matches. */
2775
- registry: Record<string, AnyTool>;
2776
- /** Always-on tools — listen continuously regardless of active slot. */
2777
- ambient?: AnyTool[];
2778
- }
2779
- /** The tool registry's runtime surface: which tool is active, which is
2780
- * temporarily held by a hotkey, and how to change either. */
2781
- interface ToolsApi {
2782
- /** Current active-slot tool id. */
2783
- active: string;
2784
- /** Set the active-slot tool. The gesture dispatcher watches the active
2785
- * tool and cancels any in-flight handle itself. */
2786
- setActive: (id: string) => void;
2787
- /** Currently hotkey-engaged tool id (or `null`). Derived as the top of
2788
- * the hotkey stack for backwards compat with the pre-stack API. */
2789
- hotkeyEngaged: string | null;
2790
- /** Engage a hotkey-slot tool by id. */
2791
- engageHotkey: (id: string) => void;
2792
- /** Disengage the hotkey-slot tool, if any. */
2793
- disengageHotkey: () => void;
2794
- /** All always-on tools, in registration order. */
2795
- ambient: readonly AnyTool[];
2796
- /** Full registry — for userland UI (palette buttons, etc.). */
2797
- registry: Readonly<Record<string, AnyTool>>;
2798
- /** Returns true if a tool with the given id is in the registry or ambient list. */
2799
- has(id: string): boolean;
2800
- /** All overlay layers from currently-engaged tools (active slot, hotkey
2801
- * slot if engaged, all ambient slot tools) that declare `position`.
2802
- * Filters out tools with no `overlay` field. Order: active, then hotkey
2803
- * (if engaged), then ambient (registration order). */
2804
- getActiveOverlays(position?: OverlayPosition): RenderLayer<unknown>[];
2805
- }
2806
- /**
2807
- * Manages the active tool and hotkey slot.
2808
- *
2809
- * A thin shim over {@link useContributions}: the `registry` / `ambient`
2810
- * arguments are restated as declared eligibility (`focus` / `always`), and
2811
- * assembly happens in one place for tools and non-tool contributions alike.
2812
- *
2813
- * Requires `<ActiveToolContextProvider>` (or `<WeaselProvider>` /
2814
- * `<SceneCanvas>`, which mount one internally) in scope: active/hotkey state
2815
- * lives in the context so the gesture dispatcher and any sibling
2816
- * `useTools` calls all read the same source of truth.
2817
- *
2818
- * **First-mount-wins semantics**: if `opts.active` differs from the context
2819
- * default (`'select'`) on first mount, `useTools` pushes `opts.active` to
2820
- * the context. Subsequent mounts respect whatever the context currently
2821
- * holds (the first caller wins).
2822
- */
2823
- declare function useTools(opts: UseToolsOptions): ToolsApi;
2919
+ declare const useTools: (opts: UseToolsOptions) => ToolsApi;
2824
2920
 
2825
2921
  /** Options for `useKeybindings`. */
2826
2922
  interface UseKeybindingsOptions {
@@ -2876,6 +2972,9 @@ interface ToolPrefBase<K extends string, Value> {
2876
2972
  }
2877
2973
  /** How a schema-driven UI should present a number pref. */
2878
2974
  type ToolPrefNumberControl = 'input' | 'slider';
2975
+ /** How a schema-driven UI should show a number pref's value. `compact`
2976
+ * abbreviates from a thousand up, as in `2.0M`. */
2977
+ type ToolPrefNumberFormat = 'plain' | 'compact';
2879
2978
  /** How a schema-driven UI should present a boolean pref. */
2880
2979
  type ToolPrefBooleanControl = 'checkbox' | 'switch' | 'toggle';
2881
2980
  /** How a schema-driven UI should present a string pref. */
@@ -2890,7 +2989,21 @@ interface ToolPrefNumberUnit {
2890
2989
  fromDisplay: (display: number) => number;
2891
2990
  /** Shown after the input, e.g. `'°'`. */
2892
2991
  suffix?: string;
2992
+ /** Suffixes a person may type, each mapped to the factor that turns a
2993
+ * number in that unit into a display number: `{ mm: 0.1, cm: 1 }` for a
2994
+ * field showing centimeters. */
2995
+ accepts?: Readonly<Record<string, number>>;
2893
2996
  }
2997
+ /**
2998
+ * A display unit built from a {@link UnitSystem}: values are stored in the
2999
+ * system's base and shown in `display`, rounded to `precision` places when
3000
+ * given, and every unit in the system is accepted as typed text. `suffix`
3001
+ * defaults to the unit's name and is accepted too.
3002
+ */
3003
+ declare function prefUnit(system: UnitSystem, display: Unit, opts?: {
3004
+ precision?: number;
3005
+ suffix?: string;
3006
+ }): ToolPrefNumberUnit;
2894
3007
  /** A numeric pref, optionally bounded and stepped, and optionally stored in a
2895
3008
  * different unit from the one shown. */
2896
3009
  interface ToolPrefNumber extends ToolPrefBase<'number', number> {
@@ -2898,6 +3011,7 @@ interface ToolPrefNumber extends ToolPrefBase<'number', number> {
2898
3011
  max?: number;
2899
3012
  step?: number;
2900
3013
  control?: ToolPrefNumberControl;
3014
+ format?: ToolPrefNumberFormat;
2901
3015
  unit?: ToolPrefNumberUnit;
2902
3016
  }
2903
3017
  /** An on/off pref. */
@@ -3045,21 +3159,144 @@ interface ToolPrefGroup {
3045
3159
  children: Record<string, ToolPrefLeaf | ToolPrefGroup>;
3046
3160
  }
3047
3161
 
3162
+ /**
3163
+ * `DebugSink`, `HitShape` and `HandleKind` are declared in
3164
+ * `@weasel-js/routing` — `ToolCtx.debug` carries a sink, so routing has to
3165
+ * name the type. Re-exported here, beside the overlay that reads one.
3166
+ */
3167
+
3168
+ /** One bit per debug feature; absent keys are off. */
3169
+ interface DebugConfig {
3170
+ hitboxes?: boolean;
3171
+ handles?: boolean;
3172
+ bounds?: boolean;
3173
+ origins?: boolean;
3174
+ snap?: boolean;
3175
+ layers?: boolean;
3176
+ /** Render each tracked node's id as a label at the top-left of its
3177
+ * bounds. Pulls from the same `recordBounds` stream `bounds` uses, so
3178
+ * no extra sink calls are required to enable. */
3179
+ ids?: boolean;
3180
+ /** Rolling FPS counter rendered in the top-left corner of the canvas.
3181
+ * Tracks the rate at which the debug overlay's draw callback runs;
3182
+ * this matches the canvas's effective repaint rate. */
3183
+ fps?: boolean;
3184
+ /** Optional per-feature color overrides; falls back to the default theme. */
3185
+ theme?: Partial<DebugTheme>;
3186
+ /** Optional per-feature line-width / dash overrides; falls back to
3187
+ * {@link DEFAULT_DEBUG_STROKES}. */
3188
+ strokes?: Partial<DebugStrokes>;
3189
+ }
3190
+ /** The name of one debug-overlay feature — the keys of {@link DebugConfig}
3191
+ * that toggle a visualization. */
3192
+ type DebugFeature = 'hitboxes' | 'handles' | 'bounds' | 'origins' | 'snap' | 'layers' | 'ids' | 'fps';
3193
+ /** Colors the debug overlay draws with, one entry per feature. */
3194
+ interface DebugTheme {
3195
+ hitboxFill: string;
3196
+ hitboxStroke: string;
3197
+ handle: string;
3198
+ bounds: string;
3199
+ origin: string;
3200
+ snap: string;
3201
+ layerText: string;
3202
+ layerTextBg: string;
3203
+ /** Color for the per-node id label rendered when `config.ids` is on. */
3204
+ idText: string;
3205
+ /** Foreground / background for the FPS panel. */
3206
+ fpsText: string;
3207
+ fpsTextBg: string;
3208
+ }
3209
+ /** Line width and dash pattern for one stroked debug feature. An empty (or
3210
+ * omitted) `dash` is a solid line. */
3211
+ interface DebugStroke {
3212
+ width: number;
3213
+ dash?: readonly number[];
3214
+ }
3215
+ /** The stroked half of the debug overlay's appearance, split from
3216
+ * {@link DebugTheme} because only some features draw a line at all — text
3217
+ * panels and filled origin dots take color and nothing else. */
3218
+ interface DebugStrokes {
3219
+ hitbox: DebugStroke;
3220
+ bounds: DebugStroke;
3221
+ handle: DebugStroke;
3222
+ /** Rejected snap candidates only; accepted ones paint as a filled dot. */
3223
+ snap: DebugStroke;
3224
+ }
3225
+ /** A hit region tested during the current frame. */
3226
+ interface RecordedHitbox {
3227
+ id: string;
3228
+ kind: 'body' | 'handle' | 'rotation' | 'anchor';
3229
+ shape: HitShape;
3230
+ }
3231
+ /** A handle drawn during the current frame, and where. */
3232
+ interface RecordedHandle {
3233
+ id: string;
3234
+ position: {
3235
+ x: number;
3236
+ y: number;
3237
+ };
3238
+ kind: HandleKind;
3239
+ }
3240
+ /** A node's bounds as computed during the current frame. */
3241
+ interface RecordedBounds {
3242
+ id: string;
3243
+ bounds: {
3244
+ x: number;
3245
+ y: number;
3246
+ width: number;
3247
+ height: number;
3248
+ };
3249
+ }
3250
+ /** A node's transform origin as used during the current frame. */
3251
+ interface RecordedOrigin {
3252
+ id: string;
3253
+ point: {
3254
+ x: number;
3255
+ y: number;
3256
+ };
3257
+ }
3258
+ /** A snap candidate considered during the current gesture, and whether it
3259
+ * won. Unlike the other records these survive across frames, until the
3260
+ * gesture ends. */
3261
+ interface RecordedSnap {
3262
+ point: {
3263
+ x: number;
3264
+ y: number;
3265
+ };
3266
+ accepted: boolean;
3267
+ }
3268
+ /** A render layer that drew during the current frame. */
3269
+ interface RecordedLayer {
3270
+ id: string;
3271
+ label: string;
3272
+ space: 'world' | 'screen';
3273
+ index: number;
3274
+ }
3275
+ /** Everything the sink collected, ready for the overlay to draw. */
3276
+ interface DebugSnapshot {
3277
+ hitboxes: RecordedHitbox[];
3278
+ handles: RecordedHandle[];
3279
+ bounds: RecordedBounds[];
3280
+ origins: RecordedOrigin[];
3281
+ snap: RecordedSnap[];
3282
+ layers: RecordedLayer[];
3283
+ }
3284
+
3048
3285
  /** Options for `useSelectTool`: how a point resolves to nodes, how a click
3049
3286
  * chooses among them, and the appearance of the marquee. */
3050
3287
  interface UseSelectToolOptions<TPose> {
3051
3288
  /** Return ids of all objects whose painted body covers (worldX, worldY).
3052
3289
  * Order doesn't matter — the tool collapses parent/child overlap via
3053
- * `pickTopMostHit`. When omitted, defaults to a rect AABB-vs-point scan
3054
- * over `adapter.getNodes()` using `poseBounds` (identity by default,
3055
- * works for `{x,y,width,height}` poses). Override for tighter shapes
3056
- * (path / polygon hit-tests). */
3290
+ * `pickTopMostHit`. When omitted, defaults to an AABB-vs-point scan over
3291
+ * `adapter.getNodes()` using the pose descriptor. Override for tighter
3292
+ * shapes (path / polygon hit-tests). */
3057
3293
  pickEvery?: (worldX: number, worldY: number) => string[];
3058
3294
  /** Optional alt-aware selection-update hit returning the single id the
3059
3295
  * click should act on. */
3060
3296
  pickBest?: (worldX: number, worldY: number, alt: boolean, selection: readonly string[]) => string | null;
3061
- /** Project a pose to its AABB. Default: identity. */
3062
- poseBounds?: (pose: TPose) => Bounds;
3297
+ /** How to read poses for the default `pickEvery`. Default
3298
+ * `AUTO_POSE_DESCRIPTOR`. */
3299
+ poseDescriptor?: PoseDescriptor<TPose>;
3063
3300
  /**
3064
3301
  * How the default `pickEvery` decides a **leaf** node covers the pointer.
3065
3302
  * Ignored when `pickEvery` is supplied.
@@ -3090,6 +3327,13 @@ interface UseSelectToolOptions<TPose> {
3090
3327
  * Without some slop a hairline outline is an unhittable target.
3091
3328
  */
3092
3329
  pickTolerance?: number;
3330
+ /** Painted alpha per node in the view this tool picks for. A node painted
3331
+ * at alpha 0 is not under the pointer. Ignored when `pickEvery` is
3332
+ * supplied. */
3333
+ alphaOf?: (id: string) => number;
3334
+ /** Whether a node's `layer` reaches the screen in the view this tool picks
3335
+ * for. Ignored when `pickEvery` is supplied. */
3336
+ layerIsPainted?: (layer: string) => boolean;
3093
3337
  /** Move-action options. The move gesture is dispatcher-routed,
3094
3338
  * so only `behaviors` is consumed here — threaded into the move binding's
3095
3339
  * `opts.behaviors`. Other `UseMoveOptions` fields are accepted for API shape
@@ -3650,6 +3894,266 @@ interface PencilPoint {
3650
3894
  */
3651
3895
  declare function usePencilTool(): Tool<null>;
3652
3896
 
3897
+ /**
3898
+ * Live state read by chrome-visibility {@link Condition}s. Backward-compat
3899
+ * alias for the legacy ChromeCtx shape — kept for consumers that still
3900
+ * import `ChromeCtx`. Subset of `RuleCtx`: legacy ChromeCtx didn't carry
3901
+ * mode/capability info. The resolver builds a `RuleCtx` for evaluation;
3902
+ * surfaces that still operate in `ChromeCtx` shape supply defaults
3903
+ * (mode='normal', empty allowedCapabilities) at the construction site.
3904
+ */
3905
+ interface ChromeCtx {
3906
+ readonly focused: boolean;
3907
+ readonly selection: readonly NodeId[];
3908
+ readonly multiActive: boolean;
3909
+ readonly modifiers: ModifierState;
3910
+ readonly action: {
3911
+ readonly kind: string | null;
3912
+ readonly id: string | null;
3913
+ };
3914
+ readonly hover: NodeId | null;
3915
+ readonly view: View;
3916
+ }
3917
+ /**
3918
+ * Composable visibility predicate with fluent surface. Carries its underlying
3919
+ * `Rule` tree at `.rule` so the resolver can introspect / share trees with
3920
+ * the affordance pipeline and the dispatcher's eligibility filter.
3921
+ *
3922
+ * Callable form `cond(ctx)` evaluates the tree against ctx. The fluent
3923
+ * methods return new Conditions wrapping new trees.
3924
+ *
3925
+ * **Chain semantics: strict left-to-right, no precedence.**
3926
+ * `a.and(b).or(c)` is `(a && b) || c`; `a.or(b).and(c)` is
3927
+ * `(a || b) && c`. Mix `.and` and `.or` only when you mean
3928
+ * left-to-right evaluation. For grouped disjunction, name the
3929
+ * subexpression or use the top-level `or(...)`.
3930
+ */
3931
+ interface Condition {
3932
+ (ctx: RuleCtx): boolean;
3933
+ readonly rule: Rule;
3934
+ /** `this && other` */
3935
+ and(other: Condition | Rule): Condition;
3936
+ /** `this || other` */
3937
+ or(other: Condition | Rule): Condition;
3938
+ /** `this && !other` */
3939
+ andNot(other: Condition | Rule): Condition;
3940
+ /** `this || !other` */
3941
+ orNot(other: Condition | Rule): Condition;
3942
+ }
3943
+ /**
3944
+ * Stable identifier for one user-visible chrome element. The same id
3945
+ * gates both paint and hit-test — there is no separate
3946
+ * `affordance.X` / `selection.X` split — so toggling a rule cannot
3947
+ * leave a visually-present but un-hittable handle (or vice versa).
3948
+ *
3949
+ * Naming convention by lifecycle:
3950
+ *
3951
+ * - `selection.*` — chrome reflecting committed selection state
3952
+ * (persists between actions).
3953
+ * - `action.*` — chrome that only exists during an in-flight
3954
+ * action (vanishes on commit / cancel).
3955
+ * - `snap.*` — snapping system chrome (guides, target highlights).
3956
+ * - `grid`, `debug.*` — environment chrome.
3957
+ *
3958
+ * The intersection `(string & {})` keeps the union open so consumers
3959
+ * can register their own ids; the kit's built-ins are listed
3960
+ * explicitly for autocomplete.
3961
+ */
3962
+ type ChromeId = 'selection.outline' | 'selection.resize-handles' | 'selection.rotation-handle' | 'action.marquee' | 'action.lasso' | 'action.move-ghosts' | 'action.insert-preview' | 'action.polyline' | 'snap.guides' | 'snap.targets' | 'grid' | (string & {});
3963
+ /**
3964
+ * Consumer override map. Merged on top of the kit's
3965
+ * `defaultVisibilityRules`; absent keys fall through to defaults,
3966
+ * absent ids fall through to `always`. Entries may be either fluent
3967
+ * `Condition` instances OR raw `Rule` trees — the resolver normalizes.
3968
+ */
3969
+ type VisibilityRules = Partial<Record<ChromeId, Condition | Rule>>;
3970
+
3971
+ /**
3972
+ * Promote a Rule tree to a fluent Condition. The function form evaluates
3973
+ * the tree against a RuleCtx; combinator methods produce new Conditions
3974
+ * wrapping `all`/`any`/`not` nodes.
3975
+ *
3976
+ * **Chain semantics: strict left-to-right.** No boolean precedence.
3977
+ * `focused.or(hovering).and(selectionIs(1))` evaluates
3978
+ * `((focused || hovering) && selectionIs(1))` — NOT
3979
+ * `(focused || (hovering && selectionIs(1)))` as standard precedence
3980
+ * would give. For grouped disjunction, use the top-level `or` / `and` /
3981
+ * `not` helpers or name intermediates.
3982
+ *
3983
+ * Combinators flatten same-kind nesting on construction so `a.and(b).and(c)`
3984
+ * produces `{ all: [a, b, c] }` rather than `{ all: [{ all: [a, b] }, c] }`.
3985
+ * Canonical form simplifies downstream introspection.
3986
+ *
3987
+ * Use {@link when} for the inline-lambda escape hatch.
3988
+ */
3989
+ declare function cond(rule: Rule): Condition;
3990
+ /** Inline-lambda escape hatch. Wraps the closure as a `when` rule node. */
3991
+ declare function when(fn: (ctx: RuleCtx) => boolean): Condition;
3992
+ /** `(a && b && c && ...)` — useful when chain mixing makes left-to-right
3993
+ * semantics ambiguous. */
3994
+ declare function and(...cs: (Condition | Rule)[]): Condition;
3995
+ /** `(a || b || c || ...)` — preferred over `.or` chains when mixed with
3996
+ * `.and` to make grouping explicit. */
3997
+ declare function or(...cs: (Condition | Rule)[]): Condition;
3998
+ /** `!c` — top-level negation. Most rules use `.andNot()` / `.orNot()`
3999
+ * instead; this is for the lead-with-negation case. */
4000
+ declare function not(c: Condition | Rule): Condition;
4001
+ /** Always true. The fallback for any chrome id without a registered rule. */
4002
+ declare const always: Condition;
4003
+ /** Always false. Useful for "turn this chrome off entirely":
4004
+ * `chromeVisibility={{ 'snap.guides': never }}`. */
4005
+ declare const never: Condition;
4006
+ /** Canvas surface currently focused. */
4007
+ declare const focused: Condition;
4008
+ /** Any action currently in flight (read: user is gesturing). */
4009
+ declare const gesturing: Condition;
4010
+ /** Active action's kind matches `kind` (e.g. `actionIs('move')`). */
4011
+ declare const actionIs: (kind: string) => Condition;
4012
+ /** Nothing selected. */
4013
+ declare const selectionEmpty: Condition;
4014
+ /** Exactly `n` items selected. */
4015
+ declare const selectionIs: (n: number) => Condition;
4016
+ /** At least `n` items selected. `selectionAtLeast(1)` is the common
4017
+ * "something is selected" check. */
4018
+ declare const selectionAtLeast: (n: number) => Condition;
4019
+ /** Multi-mode handle behavior active (single shared union-bounds
4020
+ * handle vs per-item handles). Implemented as a `when` because
4021
+ * `multiActive` is a derived single-call read on RuleCtx, not a
4022
+ * selector-table key. Stable; safe to introspect. */
4023
+ declare const multiActive: Condition;
4024
+ /** Pointer is hovering some node. */
4025
+ declare const hovering: Condition;
4026
+ /** Pointer is hovering a node that is currently selected. */
4027
+ declare const hoveringSelected: Condition;
4028
+ /** Named modifier key currently held. */
4029
+ declare const modifierHeld: (m: keyof ModifierState) => Condition;
4030
+ /** View scale (uniform or geometric mean for non-uniform) is at least
4031
+ * `z`. Useful for "hide hairline chrome at low zoom" rules. */
4032
+ declare const zoomAtLeast: (z: number) => Condition;
4033
+ /** Active mode equals `m`. */
4034
+ declare const modeIs: (m: string) => Condition;
4035
+ /** Active mode is one of `modes`. */
4036
+ declare const modeIn: (modes: readonly string[]) => Condition;
4037
+ /** Active mode is NOT `m`. */
4038
+ declare const modeNot: (m: string) => Condition;
4039
+ /** Active mode's `allows` includes capability `cap`. */
4040
+ declare const capabilityIs: (cap: string) => Condition;
4041
+ /** Active mode's `allows` includes ANY of `caps` (OR). */
4042
+ declare const capabilityIn: (caps: readonly string[]) => Condition;
4043
+ /** Active mode's `allows` includes ALL of `caps` (AND). */
4044
+ declare const capabilityAll: (caps: readonly string[]) => Condition;
4045
+ /** Active mode's `allows` does NOT include capability `cap`. */
4046
+ declare const capabilityNot: (cap: string) => Condition;
4047
+ /** Primary pointer is imprecise (touch, most styluses). Absent device
4048
+ * profile → false, so a rule written with this atom is inert on the
4049
+ * mouse-shaped default rather than silently flipping. */
4050
+ declare const coarsePointer: Condition;
4051
+ /** Primary pointer can hover. Absent device profile → true. Pair with
4052
+ * `not(...)` to gate chrome that only makes sense with a hovering
4053
+ * pointer: `not(canHover)` is "this device cannot hover". */
4054
+ declare const canHover: Condition;
4055
+
4056
+ /**
4057
+ * Kit-shipped defaults. Merged with the consumer's `chromeVisibility` map
4058
+ * at resolve time; consumer entries take precedence per id.
4059
+ *
4060
+ * Written as literal Rule trees rather than fluent chains so the inputs
4061
+ * each rule depends on are immediately visible. The fluent atoms compile
4062
+ * to the same trees; either form is valid in a VisibilityRules entry.
4063
+ *
4064
+ * Gating is written in terms of **capabilities, not mode ids**. A
4065
+ * capability rule keeps holding when a new mode is added that permits the
4066
+ * same thing; a mode rule has to be found and edited every time. There is
4067
+ * no `mode:` rule left in this table — the `path-edit.*` chrome used to be
4068
+ * the exception, on the theory that it's the visual signature of one mode;
4069
+ * see the comment on those rules below for why that was wrong in both
4070
+ * directions and what replaced it.
4071
+ *
4072
+ * Chrome that gates on the *absence* of a capability (the selection
4073
+ * outline, suppressed while an anchor-editing overlay owns the visuals)
4074
+ * uses `capability: { not: … }` for the same reason.
4075
+ */
4076
+ declare const defaultVisibilityRules: VisibilityRules;
4077
+
4078
+ /**
4079
+ * Build the per-frame visibility check. Merges consumer rules on top
4080
+ * of the kit defaults, then closes over `ctx` so each chrome-id
4081
+ * lookup runs its rule against the current state.
4082
+ *
4083
+ * `VisibilityRules` entries may be either fluent `Condition` values
4084
+ * (callable) or raw `Rule` trees — we normalize at lookup time.
4085
+ *
4086
+ * Predicates are O(1) and run once per chrome id per frame; no
4087
+ * memoization in v1 — profile before adding any.
4088
+ *
4089
+ * `ChromeCtx` is the legacy shape; surfaces still on it get `mode='normal'`
4090
+ * and `DEFAULT_ALLOWED_CAPABILITIES` filled in here, so a caller that never
4091
+ * opted into modality behaves exactly like one sitting in normal mode.
4092
+ */
4093
+ declare function resolveVisibility(consumer: VisibilityRules | undefined, ctx: ChromeCtx | RuleCtx): (id: ChromeId) => boolean;
4094
+
4095
+ /**
4096
+ * Pure assembler for {@link ChromeCtx}.
4097
+ *
4098
+ * Called once per frame on the rendering side from whichever surface
4099
+ * needs to evaluate visibility rules — `composeAffordanceLayer`,
4100
+ * `createSelectionOverlayLayer`, the dispatcher overlay layer, etc.
4101
+ *
4102
+ * Sources are passed as plain getters / values rather than the live
4103
+ * objects they come from. This keeps `chrome-caps` from depending on
4104
+ * React, the dispatcher's concrete type, or `ChromeState`'s bounds
4105
+ * machinery — the same builder works from a test harness, a Storybook
4106
+ * fixture, or `<SceneCanvas>`.
4107
+ */
4108
+
4109
+ /** The pieces of live canvas state a `ChromeCtx` is assembled from. */
4110
+ interface BuildChromeCtxArgs {
4111
+ focused: boolean;
4112
+ selection: readonly NodeId[];
4113
+ multiActive: boolean;
4114
+ modifiers: ModifierState;
4115
+ action: {
4116
+ kind: string | null;
4117
+ id: string | null;
4118
+ };
4119
+ hover: NodeId | null;
4120
+ view: View;
4121
+ }
4122
+ /** Gather the current canvas state into the context that chrome-visibility
4123
+ * rules are evaluated against. Rebuilt per frame. */
4124
+ declare function buildChromeCtx(args: BuildChromeCtxArgs): ChromeCtx;
4125
+
4126
+ /**
4127
+ * useHoverTracking — last-hovered NodeId for chrome-caps rules.
4128
+ *
4129
+ * Attaches a `pointermove` listener to the supplied canvas; on each move it
4130
+ * runs the supplied `nodeAtClientPoint` and caches the resulting id on a ref.
4131
+ * Cleared on `pointerleave` (pointer left the canvas → nothing is hovered).
4132
+ *
4133
+ * Returns a stable getter — call once per frame from `buildChromeCtx`.
4134
+ *
4135
+ * No re-render: the ref updates silently, and the next render that
4136
+ * reads it picks up the fresh value. Chrome-caps rules are evaluated
4137
+ * during paint, so the hover state is always read fresh.
4138
+ */
4139
+
4140
+ /** Options for `useHoverTracking`. */
4141
+ interface UseHoverTrackingArgs {
4142
+ canvasRef: RefObject<HTMLElement | null>;
4143
+ /** Topmost id under a client point, or null. One lookup rather than a
4144
+ * client→world thunk beside a world-space picker: a screen-pixel pick
4145
+ * tolerance converts against the camera the point resolved to, and two
4146
+ * thunks are two chances to disagree about which view that is. */
4147
+ nodeAtClientPoint: (clientX: number, clientY: number) => {
4148
+ id: NodeId;
4149
+ } | null;
4150
+ enabled?: boolean;
4151
+ }
4152
+ /** Track which node the pointer is over. Returns a getter rather than state,
4153
+ * so per-frame code can read the current value without the hover re-rendering
4154
+ * the component on every pointer move. */
4155
+ declare function useHoverTracking(args: UseHoverTrackingArgs): () => NodeId | null;
4156
+
3653
4157
  /** Standard slot names — render in this canonical order.
3654
4158
  * `cellHighlight` is internal: emitted from the `grid` slot's nested
3655
4159
  * `highlight` config, not a top-level layer key. */
@@ -3667,6 +4171,108 @@ interface CustomLayerEntry {
3667
4171
  before?: StandardSlotName | (string & {});
3668
4172
  }
3669
4173
 
4174
+ /** A rect on the surface, in CSS pixels from the canvas top-left. */
4175
+ interface ViewRect {
4176
+ x: number;
4177
+ y: number;
4178
+ w: number;
4179
+ h: number;
4180
+ }
4181
+ /** Props for `<CanvasView>`. @experimental */
4182
+ interface CanvasViewProps {
4183
+ /** Identifies the view to the surface and to input routing. Must be unique
4184
+ * among the views on one canvas. */
4185
+ id: string;
4186
+ /** Where this view paints, recomputed every frame so the rect can track the
4187
+ * outer camera. A plain rect is accepted for a fixed panel. */
4188
+ bounds: ViewRect | ((outer: View, dims: Dims) => ViewRect);
4189
+ /** Camera. Supply this to control it; otherwise the view keeps its own,
4190
+ * seeded from `defaultView`. `onViewChange` fires either way.
4191
+ *
4192
+ * A thunk is a camera derived from the canvas's — a loupe following the
4193
+ * pointer — read fresh at every paint and every event, so the two cannot
4194
+ * disagree mid-gesture. It is controlled: a pan inside the view reaches
4195
+ * only `onViewChange`. */
4196
+ view?: View | ((outer: View, dims: Dims) => View);
4197
+ defaultView?: View;
4198
+ onViewChange?: (v: View) => void;
4199
+ /** Pan limits, applied to every camera change the same way `<Canvas>`
4200
+ * applies its own. */
4201
+ viewBounds?: Bounds;
4202
+ /** Which of the surface's layers this view paints. Defaults to all of them —
4203
+ * the same content through a second camera. */
4204
+ layers?: (surface: readonly RenderLayer<unknown>[]) => readonly RenderLayer<unknown>[];
4205
+ /**
4206
+ * Show or hide layers in this view only, by id — the map `<Canvas>` takes,
4207
+ * applied after `layers` narrows the stack. A scene layer paints as
4208
+ * `scene:<layerId>`; one hidden here neither paints nor picks in this view,
4209
+ * and a marquee or Cmd+A routed here passes over it. The surface and every
4210
+ * other view are unaffected.
4211
+ */
4212
+ layerVisibility?: Record<string, boolean>;
4213
+ /** Draw order for this view, by layer id, bottom first. A listed order is
4214
+ * the whole list, so a layer left out of it is neither painted nor picked
4215
+ * here. */
4216
+ layerOrder?: string[];
4217
+ /** Opaque ground painted before the source layers, so the surface does not
4218
+ * show through where the inner camera sees nothing. */
4219
+ background?: string;
4220
+ /** Paint and hit order. Defaults to `Infinity` — after every view the
4221
+ * surface declared as a prop. */
4222
+ order?: number;
4223
+ /** Label for debug overlays. Defaults to the id. */
4224
+ label?: string;
4225
+ /**
4226
+ * Whether input over the view resolves through its camera. Default `true`:
4227
+ * a press selects what the view shows, and a drag moves it in the view's
4228
+ * world units. `false` paints only, and input over it reaches the canvas
4229
+ * beneath as though the view were not there.
4230
+ *
4231
+ * Views do not nest. A view paints and routes the surface's own stack,
4232
+ * never another view; overlapping views are hit in paint order.
4233
+ */
4234
+ interactive?: boolean;
4235
+ /**
4236
+ * Whether the surface paints the view. Default `true`. `false` is for a
4237
+ * host that draws the view inside chrome of its own — a HUD window's
4238
+ * interior — through `SceneCanvasApi.addView`'s `draw`, so it lands in
4239
+ * that chrome's z-order rather than the surface's.
4240
+ */
4241
+ paint?: boolean;
4242
+ /** A selection of this view's own, which actions dispatched inside it read
4243
+ * and write instead of the surface's. Omit both this and
4244
+ * `selectionOptions` and the view shares the surface's selection — the
4245
+ * default, so undo restores one selection rather than N. */
4246
+ selection?: SelectionApi;
4247
+ /** Opts this view into owning a selection, configured thus. Ignored when
4248
+ * `selection` is supplied. */
4249
+ selectionOptions?: UseSelectionOptions;
4250
+ }
4251
+ /**
4252
+ * @experimental
4253
+ *
4254
+ * One view on a shared canvas. Owns a camera, contributes the viewport node
4255
+ * that paints it, and registers the dispatch record that sends gestures inside
4256
+ * its rect to that camera rather than to the canvas's.
4257
+ *
4258
+ * Renders nothing itself — it is a declaration, and the surface does the
4259
+ * drawing. Outside a surface that mounts a view registry it is inert.
4260
+ */
4261
+ declare function CanvasView(props: CanvasViewProps): null;
4262
+
4263
+ /**
4264
+ * A view added through {@link SceneCanvasApi.addView}.
4265
+ * @experimental
4266
+ */
4267
+ interface CanvasViewHandle {
4268
+ readonly id: string;
4269
+ /** Paint the view for one frame of the canvas: its layers through its own
4270
+ * camera, clipped to its rect. For a view added with `paint: false`, whose
4271
+ * host draws it; empty until the view has mounted. */
4272
+ draw(data: unknown, outer: View, dims: Dims): DrawCommand[];
4273
+ /** Stop painting and routing the view. */
4274
+ remove(): void;
4275
+ }
3670
4276
  /**
3671
4277
  * The **base imperative ref handle** shared by the canvas components. For
3672
4278
  * `<SceneCanvas>` refs use {@link SceneCanvasApi} (this type plus the
@@ -3700,8 +4306,23 @@ interface CanvasExtensionApi {
3700
4306
  *
3701
4307
  * Under `paintInto` this is the caller's shared canvas, which co-tenant
3702
4308
  * panes also paint into: its rect is the whole surface, not this pane's, so
3703
- * read geometry off {@link element} rather than off this. */
4309
+ * read geometry off {@link element} rather than off this, and find this
4310
+ * pane's pixels on it with {@link getSurfaceRect}. */
3704
4311
  readonly surface: HTMLCanvasElement | null;
4312
+ /**
4313
+ * The rect of {@link surface} this canvas paints into, in the surface's CSS
4314
+ * px — the rect the renderer is confined to. Under `paintInto` that is the
4315
+ * pane's `x`/`y` and this canvas's size; otherwise the whole canvas at the
4316
+ * origin. A point measured against {@link element} sits at
4317
+ * `(x + px, y + py)` on the surface, which is where a readback must look.
4318
+ * Read live: the value is the one the next paint uses.
4319
+ */
4320
+ getSurfaceRect(): {
4321
+ x: number;
4322
+ y: number;
4323
+ width: number;
4324
+ height: number;
4325
+ };
3705
4326
  requestRedraw(): void;
3706
4327
  /**
3707
4328
  * Run `fn` after every paint, on the frame that painted — for chrome that
@@ -3786,6 +4407,10 @@ interface CanvasExtensionApi {
3786
4407
  x: number;
3787
4408
  y: number;
3788
4409
  }): void;
4410
+ /** Add a view to the canvas from outside React. See
4411
+ * {@link SceneCanvasApi.addView}; absent on the bare-primitive handle,
4412
+ * which hosts no views. */
4413
+ addView?(props: CanvasViewProps): CanvasViewHandle;
3789
4414
  }
3790
4415
  /**
3791
4416
  * The imperative ref handle for `<SceneCanvas>` — everything on
@@ -3809,6 +4434,16 @@ interface SceneCanvasApi extends CanvasExtensionApi {
3809
4434
  /** Cancel a camera animation. The view stays where it is. */
3810
4435
  stopViewAnimation(): void;
3811
4436
  isViewAnimating(): boolean;
4437
+ /**
4438
+ * Add a view — the same declaration as a `<CanvasView>` child, for code
4439
+ * outside React: chrome that opens a lens, a panel a plugin owns. Input over
4440
+ * it resolves through its camera unless `interactive` is `false`.
4441
+ *
4442
+ * Pass thunks for `bounds` and `view` rather than re-adding to move it.
4443
+ * Adding an id already present replaces that view.
4444
+ * @experimental
4445
+ */
4446
+ addView(props: CanvasViewProps): CanvasViewHandle;
3812
4447
  }
3813
4448
 
3814
4449
  /**
@@ -4016,7 +4651,10 @@ interface CanvasHelpers<TPose> extends CanvasViewHelpers<TPose>, CanvasSurfaceHe
4016
4651
  * Built-in entries (`kit:text`, `kit:path`, `kit:rect-fallback`) are
4017
4652
  * registered at module load. Consumer entries added via
4018
4653
  * `registerNodeShape` join the chain; the first entry whose
4019
- * `matches` predicate returns true paints the node.
4654
+ * `matches` predicate returns true paints the node. Every built-in but
4655
+ * `kit:derived` additionally requires a rect-shaped pose — a scene whose
4656
+ * poses are some other shape matches none of them, and paints through a
4657
+ * consumer painter or not at all.
4020
4658
  *
4021
4659
  * Two priority tiers:
4022
4660
  * - `'high'` — checked before all `'normal'` entries. Use this to
@@ -4050,6 +4688,10 @@ interface NodePaintCtx {
4050
4688
  * the wrapper hands such a node the caller's own ctx untouched. `null`
4051
4689
  * means the node derives but has nothing to draw. */
4052
4690
  derivedPath?: Path | null;
4691
+ /** A node's animated per-anchor colors: given the colors a painter would paint
4692
+ * on `channel`, the colors to paint instead. **Absent** when nothing animates
4693
+ * the node. The kit's path painters apply it; see `withColorOverrides`. */
4694
+ vertexColors?: (channel: VertexColorChannel, base: readonly number[] | undefined) => readonly number[] | undefined;
4053
4695
  }
4054
4696
  /**
4055
4697
  * Per-node draw function — the scene-slot `drawOne` signature shared by
@@ -4069,7 +4711,9 @@ interface NodeShapeEntry<TData = unknown, TPose = unknown> {
4069
4711
  * something descriptive: `'kit:text'`, `'app:image'`, etc. */
4070
4712
  id: string;
4071
4713
  /** Returns true when this painter renders the node. The first matching
4072
- * painter (`'high'` tier first, then `'normal'`) wins. */
4714
+ * painter (`'high'` tier first, then `'normal'`) wins. The kit's own
4715
+ * painters also require a rect-shaped pose, since their geometry reads
4716
+ * `x`/`y`/`width`/`height` off it. */
4073
4717
  matches(node: Node$1<TData, string, TPose>): boolean;
4074
4718
  /** Emits the draw commands for the node's primary visual. `ctx` is an
4075
4719
  * optional per-call paint context (see `NodePaintCtx`); painters that
@@ -4227,11 +4871,9 @@ declare function getNodeShapes(): readonly NodeShapeEntry[];
4227
4871
  * `createSelectionOverlayLayer` is a thin convenience that returns a single
4228
4872
  * `RenderLayer` whose draw runs the outline pass then the handles pass.
4229
4873
  *
4230
- * **Pose shape:** TPose is generic; callers must supply `getBounds(pose)`
4231
- * to project any pose into the AABB the renderer needs. For rect-shaped
4232
- * poses (`{x, y, width, height}`) pass the identity. For `Path` poses pass
4233
- * `boundsOfPath`. Container ids reduce via `unionAABB` over the projected
4234
- * AABBs.
4874
+ * **Pose shape:** TPose is generic; callers pass `poseDescriptor` for poses
4875
+ * `AUTO_POSE_DESCRIPTOR` can't read. Container ids reduce via `unionAABB`
4876
+ * over the projected AABBs.
4235
4877
  */
4236
4878
 
4237
4879
  /** Options for `composeSelectionPose`. */
@@ -4253,19 +4895,8 @@ interface ComposeSelectionPoseOpts<TPose> {
4253
4895
  } | null;
4254
4896
  /** Fallback pose lookup (typically the stored/committed pose). */
4255
4897
  getStoredPose: (id: string) => TPose;
4256
- /**
4257
- * Project a pose into its AABB. Used when reducing a group of leaf poses
4258
- * into a single union AABB. Defaults to the identity — rect-shaped poses
4259
- * (`{x, y, width, height}`) need no override. For `Path` poses pass
4260
- * `boundsOfPath`.
4261
- */
4262
- getBounds?: (pose: TPose) => Bounds;
4263
- /**
4264
- * Wrap an AABB back into a TPose. Called only when the resolver collapses
4265
- * a container's leaves into a single union AABB. Defaults to the identity —
4266
- * for `Path` poses pass `(b) => ({ kind: 'rect', ...b })`.
4267
- */
4268
- fromBounds?: (bounds: Bounds) => TPose;
4898
+ /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */
4899
+ poseDescriptor?: PoseDescriptor<TPose>;
4269
4900
  /** Walk a container's direct children (e.g. `scene.childrenOf`). With
4270
4901
  * `isContainer`, a selected container resolves to the union AABB of its
4271
4902
  * transitive leaf poses instead of its own stored pose. */
@@ -4285,12 +4916,8 @@ declare function composeSelectionPose<TPose>(opts: ComposeSelectionPoseOpts<TPos
4285
4916
  * declared on {@link SelectionOverlayLayerOpts}, which makes both optional —
4286
4917
  * omitted, they come off the draw envelope. */
4287
4918
  interface SelectionLayerCommon<TPose> {
4288
- /**
4289
- * Project a pose into its AABB. Defaults to the identity — rect-shaped
4290
- * poses (`{x, y, width, height}`) need no override. For `Path` poses pass
4291
- * `boundsOfPath`.
4292
- */
4293
- getBounds?: (pose: TPose) => Bounds;
4919
+ /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */
4920
+ poseDescriptor?: PoseDescriptor<TPose>;
4294
4921
  /** Walk a container's direct children (e.g. `scene.childrenOf`). When
4295
4922
  * supplied with `isContainer`, any id that resolves to a container is
4296
4923
  * rendered using the union bounds of all its transitive leaves. */
@@ -4388,6 +5015,10 @@ interface HierarchicalAdapter<TNode, TPose> {
4388
5015
  getNode(id: string): TNode | undefined;
4389
5016
  getChildren(parentId: string | null): readonly string[];
4390
5017
  getPose(id: string): TPose;
5018
+ /** Folds a child's local pose into its parent's frame. Absent means the
5019
+ * scene stores absolute poses and a parent contributes no transform —
5020
+ * see `PoseComposition`. */
5021
+ composePose?(parent: TPose, child: TPose): TPose;
4391
5022
  }
4392
5023
 
4393
5024
  /**
@@ -4567,16 +5198,15 @@ interface CanvasProps<TNode extends {
4567
5198
  */
4568
5199
  selection?: SelectionApi;
4569
5200
  /**
4570
- * Pose↔bounds projection for non-rect `TPose` types. When supplied, drives
4571
- * the default `boundsOf` fallback and the selection-overlay bounds source so
4572
- * non-rect poses (e.g. `Path`) don't require per-prop overrides.
5201
+ * How to read and rewrite a pose. Drives the default `boundsOf` fallback and
5202
+ * the selection-overlay bounds.
4573
5203
  * Defaults to the rect identity (`AUTO_POSE_DESCRIPTOR`).
4574
5204
  *
4575
5205
  * This is a math helper, not a scene-shaped concern — it converts a pose
4576
5206
  * value to an AABB and extracts rotation for the selection chrome. Bare-
4577
5207
  * Canvas consumers that use a non-rect pose type should supply this.
4578
5208
  */
4579
- geometry?: PoseProjection<TPose>;
5209
+ poseDescriptor?: PoseDescriptor<TPose>;
4580
5210
  /**
4581
5211
  * Used by `PickHud` to display the list of ids under the cursor.
4582
5212
  * NOT used for tool routing — see `getNodeAtPoint` for that.
@@ -4586,7 +5216,7 @@ interface CanvasProps<TNode extends {
4586
5216
  pickEvery?: (worldX: number, worldY: number) => string | string[] | null;
4587
5217
  /**
4588
5218
  * Override for committed bounds lookup. When supplied, takes precedence over
4589
- * the `geometry`-derived fallback. Used by the selection overlay, the
5219
+ * the `poseDescriptor`-derived fallback. Used by the selection overlay, the
4590
5220
  * multi-select union AABB, and `helpersRef.getEffectiveBounds`. Optional —
4591
5221
  * bare-Canvas consumers that use a custom bounds shape should supply this;
4592
5222
  * `<SceneCanvas>` derives it from its scene adapter and passes it via the
@@ -4851,6 +5481,12 @@ interface ReorderAdapter {
4851
5481
  * touch an adapter directly. */
4852
5482
  type SceneCanvasAdapter<TData, TLayer extends string, TPose> = MoveAdapter<Node$1<TData, TLayer, TPose>, TPose> & ResizeAdapter<Node$1<TData, TLayer, TPose>, TPose> & RotateAdapter<Node$1<TData, TLayer, TPose>, TPose> & AreaSelectAdapter & LassoSelectAdapter & LayerEnumerableAdapter<TLayer> & ReorderAdapter & Partial<InsertAdapter<Node$1<TData, TLayer, TPose>>> & {
4853
5483
  getParent(id: string): string | null;
5484
+ /** The node's pose with every ancestor's frame folded in. Equal to
5485
+ * `getPose` unless a `poseComposition` is configured. */
5486
+ getWorldPose(id: string): TPose;
5487
+ /** Present only when a composing strategy is configured; the render
5488
+ * walk feature-detects it. */
5489
+ composePose?(parent: TPose, child: TPose): TPose;
4854
5490
  getSelection(): string[];
4855
5491
  setSelection(ids: string[]): void;
4856
5492
  insertNode(node: Node$1<TData, TLayer, TPose>, index?: number): void;
@@ -4890,10 +5526,8 @@ interface SceneToAdapterOptions<TData, TLayer extends string, TPose> {
4890
5526
  * fine for read-only or selection-less canvases, but the marquee gesture
4891
5527
  * won't update any external selection state. */
4892
5528
  selection?: SceneAdapterSelection;
4893
- /** Project a pose to an AABB for `hitTestArea`. Default: identity (works
4894
- * when TPose carries top-level x/y/width/height). Override for non-rect
4895
- * poses. */
4896
- poseBounds?: (pose: TPose) => Bounds;
5529
+ /** How to read and rewrite this scene's poses. Default `AUTO_POSE_DESCRIPTOR`. */
5530
+ poseDescriptor?: PoseDescriptor<TPose>;
4897
5531
  /** Layout strategies keyed by container node id. When a container is
4898
5532
  * configured here, `move` runs its layout-aware pass on drag (reflow on
4899
5533
  * enter, reflow leftovers on exit, reparent + write reflowed poses on
@@ -4901,14 +5535,16 @@ interface SceneToAdapterOptions<TData, TLayer extends string, TPose> {
4901
5535
  * either a static map, or a `getLayout(id)` function for dynamic
4902
5536
  * resolution. */
4903
5537
  layouts?: Record<string, LayoutStrategy<TPose>> | ((containerId: string) => LayoutStrategy<TPose> | null);
4904
- /** When set, `setPose(id, ...)` on a container node cascades the translation
4905
- * to every descendant. Scene v1 stores absolute poses, so dragging a
4906
- * container needs to translate its children to keep them visually attached
4907
- * to their parent. Pass `'rect'` to use the built-in `translateRectPose`
4908
- * (works for any `TPose extends { x: number; y: number }`); pass a custom
4909
- * `(pose, dx, dy) => pose` for non-rect pose shapes. Omit to leave setPose
4910
- * primitive — containers move but their descendants don't follow. */
4911
- cascadeContainerPose?: 'rect' | ((pose: TPose, dx: number, dy: number) => TPose);
5538
+ /** When true, `setPose` on a container translates every descendant by the
5539
+ * same delta, through the pose descriptor. Scene v1 stores absolute poses,
5540
+ * so without it children stay behind. */
5541
+ cascadeContainerPose?: boolean;
5542
+ /** How a child's stored pose folds into its parent's frame. Omit for the
5543
+ * absolute-pose model, where a parent contributes no transform. Supplying a
5544
+ * composing strategy makes a container's pose a **frame**: rotating the
5545
+ * container rotates its contents, and `setPose` on it must not also
5546
+ * translate them, so it cannot be combined with `cascadeContainerPose`. */
5547
+ poseComposition?: PoseComposition<TPose>;
4912
5548
  }
4913
5549
  /** Derive the adapter for a scene. Reads go straight to the scene; writes are
4914
5550
  * ops applied through its history, so anything done through the adapter is
@@ -4933,27 +5569,17 @@ declare function useSceneAdapter<TData, TLayer extends string, TPose>(scene: Sce
4933
5569
  * Consumers should import from here directly; `rotate.ts` re-exports the
4934
5570
  * same symbols for back-compat. */
4935
5571
 
4936
- /** Projects a pose to and from a rotated bounding box, so the rotate action
4937
- * can work on pose shapes that carry rotation differently. */
4938
- interface RotateGeometry<TPose> {
4939
- getRotatedBounds(pose: TPose): RotatedPose;
4940
- /** Write a new rotation back into the pose; bounds stay the same. */
4941
- withRotation(pose: TPose, rotation: number): TPose;
4942
- }
4943
5572
  /** Options for the `rotate` action. */
4944
5573
  interface UseRotateOptions<TPose> {
4945
5574
  /** Behaviors are typed against the pose shape; the kit ships none yet
4946
5575
  * (rotation snap behaviors are deferred). For non-rect TPose, behaviors
4947
- * are typed `never` until you supply a `geometry`. */
5576
+ * are typed `never` for a pose without a numeric `rotation`. */
4948
5577
  behaviors?: TPose extends RotatedPose ? RotateBehavior<TPose>[] : never;
4949
5578
  rotateLabel?: string;
4950
5579
  /** Reserved; rotate is never transient in practice. Ignored. */
4951
5580
  transient?: boolean;
4952
5581
  onGestureStart?: (id: string) => void;
4953
5582
  onGestureEnd?: (committed: boolean) => void;
4954
- /** Project pose ↔ rotated bounds. Defaults to the identity for
4955
- * `RotatedPose`. Required for non-rect TPose (e.g. a rotated path). */
4956
- geometry?: RotateGeometry<TPose>;
4957
5583
  /** Optional debug sink. When supplied, records the rotation-handle
4958
5584
  * position + circular hitbox at gesture start. Tree-shakes via
4959
5585
  * optional-chain when omitted. */
@@ -4974,60 +5600,95 @@ interface UseRotateOptions<TPose> {
4974
5600
  pivot?: 'each' | 'union';
4975
5601
  }
4976
5602
 
4977
- /** A rect on the surface, in CSS pixels from the canvas top-left. */
4978
- interface ViewRect {
4979
- x: number;
4980
- y: number;
4981
- w: number;
4982
- h: number;
4983
- }
4984
- /** Props for `<CanvasView>`. @experimental */
4985
- interface CanvasViewProps {
4986
- /** Identifies the view to the surface and to input routing. Must be unique
4987
- * among the views on one canvas. */
4988
- id: string;
4989
- /** Where this view paints, recomputed every frame so the rect can track the
4990
- * outer camera. A plain rect is accepted for a fixed panel. */
4991
- bounds: ViewRect | ((outer: View, dims: Dims) => ViewRect);
4992
- /** Camera. Supply this to control it; otherwise the view keeps its own,
4993
- * seeded from `defaultView`. `onViewChange` fires either way. */
4994
- view?: View;
4995
- defaultView?: View;
4996
- onViewChange?: (v: View) => void;
4997
- /** Pan limits, applied to every camera change the same way `<Canvas>`
4998
- * applies its own. */
4999
- viewBounds?: Bounds;
5000
- /** Which of the surface's layers this view paints. Defaults to all of them —
5001
- * the same content through a second camera. */
5002
- layers?: (surface: readonly RenderLayer<unknown>[]) => readonly RenderLayer<unknown>[];
5003
- /** Opaque ground painted before the source layers, so the surface does not
5004
- * show through where the inner camera sees nothing. */
5005
- background?: string;
5006
- /** Paint and hit order. Defaults to `Infinity` — after every view the
5007
- * surface declared as a prop. */
5008
- order?: number;
5009
- /** Label for debug overlays. Defaults to the id. */
5010
- label?: string;
5011
- /** A selection of this view's own, which actions dispatched inside it read
5012
- * and write instead of the surface's. Omit both this and
5013
- * `selectionOptions` and the view shares the surface's selection — the
5014
- * default, so undo restores one selection rather than N. */
5015
- selection?: SelectionApi;
5016
- /** Opts this view into owning a selection, configured thus. Ignored when
5017
- * `selection` is supplied. */
5018
- selectionOptions?: UseSelectionOptions;
5019
- }
5020
5603
  /**
5021
- * @experimental
5604
+ * The kit's built-in shape kinds — one table, every other spelling derived.
5022
5605
  *
5023
- * One view on a shared canvas. Owns a camera, contributes the viewport node
5024
- * that paints it, and registers the dispatch record that sends gestures inside
5025
- * its rect to that camera rather than to the canvas's.
5606
+ * Lives in `core/` rather than beside the shape tools because both layers ask
5607
+ * questions of the same set: the interactions layer decides whether
5608
+ * `insertAction` can paint a live preview for a kind, and the canvas layer
5609
+ * decides which shape tools `useBuiltinShapeTools` mounts and what
5610
+ * `BUNDLE_TOOLS` / `defaultNodeRouting` / `defaultNodeProperties` enumerate.
5026
5611
  *
5027
- * Renders nothing itself — it is a declaration, and the surface does the
5028
- * drawing. Outside a surface that mounts a view registry it is inert.
5612
+ * This module imports nothing on purpose: `useBuiltinShapeTools` imports the
5613
+ * package barrel, so anything barrel-reachable that needs these lists at
5614
+ * module-evaluation time must not route through it.
5029
5615
  */
5030
- declare function CanvasView(props: CanvasViewProps): null;
5616
+ /** What the kit knows about one built-in shape kind. */
5617
+ interface ShapeKindDescriptor {
5618
+ /** Mounted as a built-in shape tool by `useBuiltinShapeTools`, and so a
5619
+ * member of `BuiltinShapeToolId` / `KIT_SHAPE_KINDS`. `image` is false:
5620
+ * `useImageTool` needs a `src` and can't be auto-mounted. */
5621
+ readonly tool: boolean;
5622
+ /** `insertAction` emits an `insertPreview` overlay for this kind, and the
5623
+ * dispatcher overlay layer knows how to draw it. Kinds without one still
5624
+ * commit; they just have no live drag preview (`pen` and `lasso` don't
5625
+ * route through `insertAction` at all). */
5626
+ readonly insertPreview: boolean;
5627
+ }
5628
+ /**
5629
+ * Declaration order is the enumeration order of every derived list —
5630
+ * `KIT_SHAPE_KINDS`, and through it `defaultNodeRouting` /
5631
+ * `defaultNodeProperties` / `BUNDLE_TOOLS.exhaustive`.
5632
+ */
5633
+ declare const SHAPE_KINDS: {
5634
+ readonly rect: {
5635
+ readonly tool: true;
5636
+ readonly insertPreview: true;
5637
+ };
5638
+ readonly ellipse: {
5639
+ readonly tool: true;
5640
+ readonly insertPreview: true;
5641
+ };
5642
+ readonly line: {
5643
+ readonly tool: true;
5644
+ readonly insertPreview: true;
5645
+ };
5646
+ readonly polygon: {
5647
+ readonly tool: true;
5648
+ readonly insertPreview: true;
5649
+ };
5650
+ readonly star: {
5651
+ readonly tool: true;
5652
+ readonly insertPreview: true;
5653
+ };
5654
+ readonly pen: {
5655
+ readonly tool: true;
5656
+ readonly insertPreview: false;
5657
+ };
5658
+ readonly pencil: {
5659
+ readonly tool: true;
5660
+ readonly insertPreview: true;
5661
+ };
5662
+ readonly lasso: {
5663
+ readonly tool: true;
5664
+ readonly insertPreview: false;
5665
+ };
5666
+ readonly text: {
5667
+ readonly tool: true;
5668
+ readonly insertPreview: true;
5669
+ };
5670
+ readonly image: {
5671
+ readonly tool: false;
5672
+ readonly insertPreview: true;
5673
+ };
5674
+ };
5675
+ /** The keys of a shape-kind table whose descriptor sets `F` to `true`. */
5676
+ type ShapeKindsWhere<T, F extends keyof ShapeKindDescriptor> = {
5677
+ [K in keyof T]: T[K] extends Record<F, true> ? K : never;
5678
+ }[keyof T];
5679
+ /**
5680
+ * Built-in shape tool ids handled by `useBuiltinShapeTools`. Each maps to a
5681
+ * kit tool hook + a default `create` that produces a leaf node compatible
5682
+ * with `PATH_PAINTER`.
5683
+ */
5684
+ type BuiltinShapeToolId = ShapeKindsWhere<typeof SHAPE_KINDS, 'tool'>;
5685
+ /** The insert kinds the kit's dispatcher overlay layer knows how to render.
5686
+ * Consumer-defined kinds fall outside it: no live preview, commit unaffected. */
5687
+ type KitInsertShape = ShapeKindsWhere<typeof SHAPE_KINDS, 'insertPreview'>;
5688
+ /** Runtime, iterable list of the shape-tool ids in `BuiltinShapeToolId`.
5689
+ * Surfaced so consumers (e.g. the Bundle Inspector) can enumerate the
5690
+ * builtin shape kinds without re-encoding the union. */
5691
+ declare const KIT_SHAPE_KINDS: readonly BuiltinShapeToolId[];
5031
5692
 
5032
5693
  /** Per-tool option overrides for the built-in shape/lasso tools.
5033
5694
  * Each entry is a narrow subset of the underlying hook's options surface
@@ -5230,7 +5891,7 @@ interface SceneCanvasHit {
5230
5891
  /** Props for `<SceneCanvas>`. Most are optional: a scene is the only thing it
5231
5892
  * truly needs, and everything else — tools, layers, selection handling,
5232
5893
  * layouts, animation — layers onto sensible defaults. */
5233
- type SceneCanvasProps<TData, TLayer extends string, TPose> = Omit<CanvasProps<Node$1<TData, TLayer, TPose>, TPose>, 'adapter' | 'moveOptions' | 'resizeOptions' | 'rotateOptions' | 'snap' | 'pickEvery' | 'boundsOf' | 'handleHitRadius' | 'selection' | 'selectionOptions' | 'tools' | 'geometry' | 'layers' | 'onBackgroundClick' | 'getIsVisible' | 'contentVersion'> & {
5894
+ type SceneCanvasProps<TData, TLayer extends string, TPose> = Omit<CanvasProps<Node$1<TData, TLayer, TPose>, TPose>, 'adapter' | 'moveOptions' | 'resizeOptions' | 'rotateOptions' | 'snap' | 'pickEvery' | 'boundsOf' | 'handleHitRadius' | 'selection' | 'selectionOptions' | 'tools' | 'layers' | 'onBackgroundClick' | 'getIsVisible' | 'contentVersion' | 'layerVisibility' | 'layerOrder'> & {
5234
5895
  /** A `Scene` (typically from `useScene`) — or a `SerializedScene`
5235
5896
  * JSON object, which SceneCanvas bakes into a Scene internally on
5236
5897
  * first render. The serialized form is read once; subsequent
@@ -5258,6 +5919,12 @@ type SceneCanvasProps<TData, TLayer extends string, TPose> = Omit<CanvasProps<No
5258
5919
  * to `sceneToAdapter` so `useMove`'s layout pass runs on configured
5259
5920
  * containers (reflow on enter, reparent + reflow on commit). */
5260
5921
  layouts?: SceneToAdapterOptions<TData, TLayer, TPose>['layouts'];
5922
+ /** How a child's stored pose folds into its parent's frame. Omit for the
5923
+ * absolute-pose model, where a container groups its children but imposes
5924
+ * no transform. Pass `RIGID_POSE_COMPOSITION` to make a container's pose
5925
+ * a frame, so rotating it rotates its contents and moving it carries them
5926
+ * without touching their poses. */
5927
+ poseComposition?: SceneToAdapterOptions<TData, TLayer, TPose>['poseComposition'];
5261
5928
  /**
5262
5929
  * Optional consumer seam for eager geometry sync: lets pose-transform
5263
5930
  * actions (move, resize, nudge, flip — NOT rotate) also rewrite a node's
@@ -5294,6 +5961,10 @@ type SceneCanvasProps<TData, TLayer extends string, TPose> = Omit<CanvasProps<No
5294
5961
  * it with extras is what needs the memo.)
5295
5962
  */
5296
5963
  routing?: readonly NodeRoutingEntry[];
5964
+ /** How to read and rewrite this scene's poses. Every built-in action,
5965
+ * the selection chrome and picking read it. Default `AUTO_POSE_DESCRIPTOR`
5966
+ * (rect poses and `Path` poses). */
5967
+ poseDescriptor?: PoseDescriptor<TPose>;
5297
5968
  geometry?: {
5298
5969
  /** Hit-test override. Return the topmost id, the full back-to-front hit
5299
5970
  * stack (`string[]`), or `null` for empty space. The stack form lets a
@@ -5577,9 +6248,9 @@ type SceneCanvasProps<TData, TLayer extends string, TPose> = Omit<CanvasProps<No
5577
6248
  /**
5578
6249
  * Optional animator to bind for per-frame redraws. When supplied,
5579
6250
  * SceneCanvas subscribes to `animator.onTick` and requests a redraw on
5580
- * every active animation frame. This is the supported way to drive
5581
- * repaints when an animation's effect is read from a non-scene channel
5582
- * (e.g. a custom `drawOne` consults `animator.colorOverrides`) — scene
6251
+ * every active animation frame, and paints `animator.colorOverrides`
6252
+ * onto the scene's nodes: the kit's path and shape painters apply them,
6253
+ * and a custom `drawOne` receives them as `ctx.vertexColors`. Scene
5583
6254
  * mutations trigger repaints automatically, but `colorOverrides` writes
5584
6255
  * do not.
5585
6256
  *
@@ -5702,6 +6373,25 @@ type SceneCanvasProps<TData, TLayer extends string, TPose> = Omit<CanvasProps<No
5702
6373
  * Defaults to `() => 1` (no effect).
5703
6374
  */
5704
6375
  alphaFor?: (id: string) => number;
6376
+ /**
6377
+ * Show or hide render layers in this canvas's own view, by id — the map
6378
+ * `<Canvas>` takes. Each scene layer paints as its own render layer, keyed
6379
+ * `scene:<layerId>`, so `{ 'scene:guides': false }` hides one scene layer
6380
+ * here and nowhere else.
6381
+ *
6382
+ * A layer hidden this way is gone from this view: it does not paint, and a
6383
+ * click, a marquee or Cmd+A here passes over it. Another view of the same
6384
+ * scene — a `<CanvasView>`, a second canvas, a minimap — still shows it and
6385
+ * can still take it. It applies on top of the scene's own
6386
+ * `LayerRecord.visible` and cannot show a layer the scene hides.
6387
+ */
6388
+ layerVisibility?: Record<string, boolean>;
6389
+ /**
6390
+ * Draw order for this view, by render-layer id, bottom first. A listed
6391
+ * order is the whole list: a scene layer left out of it is neither painted
6392
+ * nor picked here. See `CanvasProps.layerOrder`.
6393
+ */
6394
+ layerOrder?: string[];
5705
6395
  /**
5706
6396
  * Optional per-id pointer-interactivity predicate. When supplied, ids
5707
6397
  * for which the predicate returns `false` are excluded from hit-test
@@ -6008,6 +6698,194 @@ declare const defaultNodeProperties: readonly NodePropertiesEntry[];
6008
6698
  */
6009
6699
  declare const inferredNodeProperties: readonly NodePropertiesEntry[];
6010
6700
 
6701
+ /**
6702
+ * What an in-flight gesture is proposing, resolved against the committed scene.
6703
+ *
6704
+ * An ongoing action publishes interim poses on its handle rather than writing
6705
+ * them to the scene, and `<SceneCanvas>`'s ghost layer used to be the only
6706
+ * thing that knew how to read them: which ids are in flight, which of those are
6707
+ * roots, whose preview wins when two sources name the same id, and which are
6708
+ * merely displaced rather than dragged. None of that is about drawing, and a
6709
+ * consumer with its own renderer needs all of it.
6710
+ */
6711
+
6712
+ interface PreviewNode<TData, TLayer extends string, TPose> {
6713
+ id: NodeId;
6714
+ /** The node as committed — the gesture has not touched the scene. */
6715
+ node: Node$1<TData, TLayer, TPose>;
6716
+ /** The interim pose, or the committed one when only data is in flight. */
6717
+ pose: TPose;
6718
+ /** The interim data, or the committed one when only the pose is in flight. */
6719
+ data: TData;
6720
+ /**
6721
+ * The gesture is not carrying this one under the pointer — a layout sibling
6722
+ * reflowing into its destination slot. It reads better painted settled.
6723
+ */
6724
+ opaque: boolean;
6725
+ /** Previewed descendants, so a container's ghost brings its children. */
6726
+ children: PreviewNode<TData, TLayer, TPose>[];
6727
+ }
6728
+ /**
6729
+ * The previewing subtrees, as roots. A previewed node whose parent is also
6730
+ * previewing is a child of that parent's entry rather than a root of its own,
6731
+ * which is what lets a caller draw a container and its contents as one thing.
6732
+ *
6733
+ * An id with no node is skipped: an insert previews before the node it will
6734
+ * create exists. So is an id no source has a pose or data for.
6735
+ */
6736
+ declare function resolvePreviews<TData, TLayer extends string, TPose>(sources: Iterable<GesturePreviewSource>, scene: Scene<TData, TLayer, TPose>): PreviewNode<TData, TLayer, TPose>[];
6737
+ /** Every entry in the forest, parents before their children. */
6738
+ declare function flattenPreviews<TData, TLayer extends string, TPose>(roots: readonly PreviewNode<TData, TLayer, TPose>[]): PreviewNode<TData, TLayer, TPose>[];
6739
+
6740
+ /**
6741
+ * The one answer to "how big is the thing this in-flight insert is making".
6742
+ *
6743
+ * A drag-to-insert has no scene node until commit, so three surfaces have to
6744
+ * size the nascent shape themselves: `useDispatcherOverlayLayer` (paints the
6745
+ * preview), `canvas/deps/insert` (poses the committed node) and
6746
+ * `dispatcherGestureBounds` (reports the gesture's world AABB to `<Canvas>`).
6747
+ * They all resolve it here.
6748
+ *
6749
+ * The drag AABB alone is NOT the answer. `insertAction` hands over an
6750
+ * `extras` payload that can carry richer geometry than the drag rect —
6751
+ * a polygon's center+radius, a pencil's sample trail, a line's endpoints —
6752
+ * and where it does, that geometry is the shape. A centered Alt-drag
6753
+ * produces a `d`-wide drag rect around a `d√2` circumradius; a pencil that
6754
+ * loops back to its start produces a zero-area drag rect around a trail that
6755
+ * swept the page.
6756
+ */
6757
+
6758
+ type Point$2 = {
6759
+ x: number;
6760
+ y: number;
6761
+ };
6762
+ /** The fields of an `insertPreview` overlay this needs. `canvas/deps/insert`
6763
+ * passes the equivalent from its own `(bounds, extras)` commit arguments. */
6764
+ interface InsertPreviewLike {
6765
+ shape: string;
6766
+ bounds: {
6767
+ x: number;
6768
+ y: number;
6769
+ width: number;
6770
+ height: number;
6771
+ };
6772
+ extras: unknown;
6773
+ }
6774
+ /** Resolved preview geometry, in the terms the path builders take. */
6775
+ type InsertPreviewGeometry = {
6776
+ kind: 'box';
6777
+ } | {
6778
+ kind: 'line';
6779
+ a: Point$2;
6780
+ b: Point$2;
6781
+ } | {
6782
+ kind: 'polygon';
6783
+ center: Point$2;
6784
+ radius: number;
6785
+ sides: number;
6786
+ rotation: number;
6787
+ } | {
6788
+ kind: 'star';
6789
+ center: Point$2;
6790
+ outerRadius: number;
6791
+ innerRadius: number;
6792
+ points: number;
6793
+ rotation: number;
6794
+ } | {
6795
+ kind: 'pencil';
6796
+ samples: ReadonlyArray<Point$2>;
6797
+ };
6798
+ interface InsertPreviewExtent {
6799
+ /** The insert kind, verbatim from the caller. */
6800
+ shape: string;
6801
+ /** World-space AABB of `geometry` — the extent. */
6802
+ bounds: Bounds;
6803
+ geometry: InsertPreviewGeometry;
6804
+ }
6805
+ type InsertPreviewOverlay = Extract<OngoingOverlay, {
6806
+ kind: 'insertPreview';
6807
+ }>;
6808
+ declare function insertPreviewExtent(ov: InsertPreviewLike): InsertPreviewExtent;
6809
+
6810
+ /**
6811
+ * What an in-flight gesture is proposing to paint *beside* the scene, resolved
6812
+ * to geometry.
6813
+ *
6814
+ * The sibling of `resolvePreviews`: that one answers for the ghosts of scene
6815
+ * nodes a gesture is displacing, this one for the chrome a gesture draws that
6816
+ * is no node at all — a marquee rect, a lasso trail, the outline of a shape
6817
+ * being dragged out. `<SceneCanvas>`'s `useDispatcherOverlayLayer` used to be
6818
+ * the only thing that knew how to read an `OngoingOverlay`, and it read one
6819
+ * straight into `DrawCommand`s, so a consumer with its own renderer got
6820
+ * nothing. None of the normalizing is about drawing.
6821
+ *
6822
+ * What stays out, as in `resolvePreviews`: no view, no screen projection, no
6823
+ * `DrawCommand`, no style, no React, no dispatcher. World coordinates only.
6824
+ */
6825
+
6826
+ type Point$1 = {
6827
+ x: number;
6828
+ y: number;
6829
+ };
6830
+ /**
6831
+ * The chrome-caps id a surface consults before painting each variant. The
6832
+ * gating itself is the painter's — two views of one surface may disagree about
6833
+ * whether to show an in-flight marquee — but the id is not something a caller
6834
+ * should have to guess.
6835
+ */
6836
+ type OverlayVisibilityId = 'action.marquee' | 'action.lasso' | 'action.insert-preview' | 'action.polyline';
6837
+ /**
6838
+ * One in-flight overlay, in world coordinates.
6839
+ *
6840
+ * Every degenerate overlay is already gone: a marquee of zero size, a lasso
6841
+ * under two vertices, a zero-area insert of anything but a pencil, a pencil
6842
+ * under two samples, a run of fewer than two points. Whatever is in this list
6843
+ * is worth painting.
6844
+ */
6845
+ type ResolvedOverlay = {
6846
+ kind: 'marquee';
6847
+ visibilityId: 'action.marquee';
6848
+ /** The drag normalized: `start`/`current` in either order, one AABB. */
6849
+ bounds: Bounds;
6850
+ /** Additive intent. Core's 2D layer paints the same rect either way. */
6851
+ shiftHeld: boolean;
6852
+ } | {
6853
+ kind: 'lasso';
6854
+ visibilityId: 'action.lasso';
6855
+ /** The trail so far, at least two long. The region it encloses is the
6856
+ * trail closed back to its first vertex. */
6857
+ vertices: ReadonlyArray<Point$1>;
6858
+ /** Live pointer position — the trail's last vertex until it advances. */
6859
+ current: Point$1;
6860
+ shiftHeld: boolean;
6861
+ } | {
6862
+ kind: 'insertPreview';
6863
+ visibilityId: 'action.insert-preview';
6864
+ shape: KitInsertShape;
6865
+ /** Extent of `geometry`, which for a radial or freehand shape is not the
6866
+ * drag rect. See `insertPreviewExtent`. */
6867
+ bounds: Bounds;
6868
+ geometry: InsertPreviewGeometry;
6869
+ /** The drag's anchor — a growth axis to mark. Absent for a pencil, which
6870
+ * has none. */
6871
+ anchorPoint?: Point$1;
6872
+ /** The action's per-shape payload, verbatim. Carries what geometry
6873
+ * cannot: an image insert's `src`, say. */
6874
+ extras: unknown;
6875
+ } | {
6876
+ kind: 'polyline';
6877
+ visibilityId: 'action.polyline';
6878
+ /** The run, at least two long, open — the last point does not join the
6879
+ * first. A closed sweep is a `lasso`. */
6880
+ points: ReadonlyArray<Point$1>;
6881
+ /** What the run is, for a painter choosing a style. Never defaulted
6882
+ * away: `'chrome'` when the action named none. A role the painter has
6883
+ * no style for is drawn as plain chrome, not dropped. */
6884
+ role: OverlayRole;
6885
+ };
6886
+ /** The overlays worth painting, in the order the handles published them. */
6887
+ declare function resolveOverlays(overlays: Iterable<OngoingOverlay>): ResolvedOverlay[];
6888
+
6011
6889
  /**
6012
6890
  * `renderSceneToCanvas` — substrate for detached, read-only scene views
6013
6891
  * (`<SceneViewCanvas>` / `<MinimapCanvas>`). Given a `<canvas>`, a `Scene`,
@@ -6027,6 +6905,18 @@ declare const inferredNodeProperties: readonly NodePropertiesEntry[];
6027
6905
  * in sync by hand where it matters (DPR handling, viewToMat3 wrap).
6028
6906
  */
6029
6907
 
6908
+ /**
6909
+ * Which scene layers a detached view paints, on top of each layer's own
6910
+ * `visible` flag. Keyed the way `<SceneCanvas>` keys its scene layers —
6911
+ * `scene:<layerId>` — so the map a main canvas takes serves its minimap too.
6912
+ */
6913
+ interface SceneViewLayers {
6914
+ /** `false` hides that layer in this view. It cannot show one the scene hides. */
6915
+ layerVisibility?: Record<string, boolean>;
6916
+ /** Paint order, bottom first. A listed order is the whole list: a scene
6917
+ * layer left out of it is not painted. */
6918
+ layerOrder?: readonly string[];
6919
+ }
6030
6920
  /** What to draw into an existing canvas: the scene, the view, and the same
6031
6921
  * painting hooks `<SceneCanvas>` takes. */
6032
6922
  interface RenderSceneToCanvasArgs<TData, TLayer extends string, TPose> {
@@ -6056,6 +6946,13 @@ interface RenderSceneToCanvasArgs<TData, TLayer extends string, TPose> {
6056
6946
  * `alphaFor`. Pass the same function the main canvas uses to keep a
6057
6947
  * scoping-dim treatment consistent across both. Defaults to `() => 1`. */
6058
6948
  alphaFor?: (id: string) => number;
6949
+ /** Per-view layer visibility. See {@link SceneViewLayers}. */
6950
+ layerVisibility?: SceneViewLayers['layerVisibility'];
6951
+ /** Per-view layer order. See {@link SceneViewLayers}. */
6952
+ layerOrder?: SceneViewLayers['layerOrder'];
6953
+ /** Animated vertex colors to paint, typically an animator's
6954
+ * `colorOverrides` — see `NodePaintCtx.vertexColors`. */
6955
+ colorOverrides?: ColorOverrideRegistry;
6059
6956
  /** Optional device-pixel ratio. Defaults to `window.devicePixelRatio || 1`
6060
6957
  * when available, otherwise 1. Tests typically pin this to 1 or 2. */
6061
6958
  dpr?: number;
@@ -6077,13 +6974,21 @@ interface RenderSceneToCanvasArgs<TData, TLayer extends string, TPose> {
6077
6974
  * emit unrotated geometry and let the pose drive it.
6078
6975
  *
6079
6976
  * Output shape follows `buildSceneTree`: one group per **visible** layer, in
6080
- * scene-layer order, each holding one group per node on that layer.
6977
+ * scene-layer order (or `layers.layerOrder`), each holding one group per node
6978
+ * on that layer.
6081
6979
  *
6082
6980
  * Exported for tests and for callers that want to render into something
6083
6981
  * other than a real `<canvas>` (e.g. an offscreen renderer or a
6084
6982
  * snapshot fixture).
6085
6983
  */
6086
- declare function buildSceneViewCommands<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>, view: View, drawOne: SceneViewDrawOne<TData, TLayer, TPose>, extraCommands?: ReadonlyArray<DrawCommand>, alphaFor?: (id: string) => number): DrawCommand[];
6984
+ declare function buildSceneViewCommands<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>, view: View, drawOne: SceneViewDrawOne<TData, TLayer, TPose>, extraCommands?: ReadonlyArray<DrawCommand>, alphaFor?: (id: string) => number,
6985
+ /** How a child's stored pose folds into its parent's frame. Omit for the
6986
+ * absolute-pose model. */
6987
+ poseComposition?: PoseComposition<TPose>,
6988
+ /** This view's own layer visibility and order. */
6989
+ layers?: SceneViewLayers,
6990
+ /** Animated vertex colors to paint, typically an animator's `colorOverrides`. */
6991
+ colorOverrides?: ColorOverrideRegistry): DrawCommand[];
6087
6992
  /**
6088
6993
  * Render one frame of `scene` at `view` into `canvas`. See module docstring
6089
6994
  * for the design context.
@@ -6127,6 +7032,15 @@ interface SceneViewCanvasProps<TData, TLayer extends string, TPose> {
6127
7032
  * `alphaFor`. Pass the same function the main canvas uses to keep a
6128
7033
  * scoping-dim treatment consistent across both. Defaults to `() => 1`. */
6129
7034
  alphaFor?: (id: string) => number;
7035
+ /** Hide scene layers in this view only, keyed `scene:<layerId>` as on
7036
+ * `<SceneCanvas>` — pass the main canvas's map to keep the two in step. */
7037
+ layerVisibility?: SceneViewLayers['layerVisibility'];
7038
+ /** Paint order for this view, keyed as `layerVisibility`. */
7039
+ layerOrder?: SceneViewLayers['layerOrder'];
7040
+ /** Optional animator, as on `<SceneCanvas>`: the view repaints on its ticks
7041
+ * and paints its `colorOverrides`. Pass the main canvas's animator so both
7042
+ * show the same colors. */
7043
+ animator?: Animator;
6130
7044
  /** Optional CSS class for sizing / positioning the `<canvas>`. The kit
6131
7045
  * does not emit inline styles for layout — use a class. */
6132
7046
  className?: string;
@@ -6160,7 +7074,7 @@ declare function sceneSelectionStore(scene: {
6160
7074
  * registry passed in `options`. Throws on unknown version, unknown registry
6161
7075
  * keys, or invalid scene shape (cross-layer subtrees, unknown layer ids).
6162
7076
  * Loaded scenes start with empty history — undo/redo is NOT serialized. */
6163
- declare function sceneFromJSON<TData, TLayer extends string, TPose>(json: SerializedScene<TData, TLayer, TPose>, options: {
7077
+ declare function sceneFromJSON<TData, TLayer extends string, TPose>(json: SerializedScene<TData, TLayer, TPose>, options?: {
6164
7078
  registry?: SceneRegistry<TPose>;
6165
7079
  historyLimit?: number;
6166
7080
  coalesceWindowMs?: number;
@@ -6206,18 +7120,116 @@ declare function useScene<TItem extends {
6206
7120
  declare function useScene<TData, TLayer extends string, TPose = RectPose>(options: UseSceneOptions<TData, TLayer, TPose>): Scene<TData, TLayer, TPose>;
6207
7121
 
6208
7122
  /**
6209
- * Pure math helpers for `<MinimapCanvas>`.
7123
+ * Build a {@link PoseOverrides} map.
7124
+ *
7125
+ * `getNode` resolves an id to the node object the painter memo is keyed on —
7126
+ * the only thing this module needs from the scene, and the reason it doesn't
7127
+ * import one. `onInvalidate` lets the scene invalidate derived nodes from the
7128
+ * same chokepoint.
7129
+ */
7130
+ declare function createPoseOverrides<TPose>(getNode: (id: NodeId) => {
7131
+ data?: unknown;
7132
+ } | undefined, onInvalidate?: (id: NodeId) => void): PoseOverrides<TPose>;
7133
+
7134
+ /** The subset of a node this module reads. Structural so a `Node` satisfies
7135
+ * it without importing the full generic shape. */
7136
+ interface PosedNode<TPose> {
7137
+ id: NodeId;
7138
+ kind?: 'leaf' | 'container';
7139
+ pose: TPose;
7140
+ /** Read only by the memo, which keys on its reference alongside the pose. */
7141
+ data?: unknown;
7142
+ dependsOn?: readonly NodeId[] | 'children';
7143
+ derivePose?: (node: never, deps: readonly (DerivedDep<TPose> | undefined)[]) => TPose | null;
7144
+ /** Read only when something asks a dependency for its `path`. */
7145
+ derivePath?: (node: never, deps: readonly (DerivedDep<TPose> | undefined)[]) => Path | null;
7146
+ }
7147
+ /** What resolving a pose needs: the overrides, and enough of the scene to
7148
+ * reach a node's dependencies. A `Scene` satisfies it. */
7149
+ interface PoseSource<TPose> {
7150
+ readonly overrides: Pick<PoseOverrides<TPose>, 'get'>;
7151
+ get(id: NodeId): PosedNode<TPose> | undefined;
7152
+ childrenOf(id: NodeId): readonly NodeId[];
7153
+ }
7154
+ /**
7155
+ * The pose `node` computes from its dependencies, or `null` when it derives
7156
+ * nothing — it has no `derivePose`, nothing to derive from, or its
7157
+ * `derivePose` returned `null`.
7158
+ *
7159
+ * A dependency is read through {@link effectivePose}, so a group of groups
7160
+ * resolves bottom-up and a dragged dependency's override reaches the
7161
+ * derivation the same frame it is published.
7162
+ */
7163
+ declare function derivedPose<TPose>(source: PoseSource<TPose>, node: PosedNode<TPose>): TPose | null;
7164
+ /**
7165
+ * `id` as a derivation sees it: the node, the pose it is painted at, and the
7166
+ * path it derives.
7167
+ *
7168
+ * The pose is resolved eagerly — every derivation reads it — and the path
7169
+ * lazily, because most do not and resolving a route costs a router run. Both
7170
+ * resolve *through* this function, so a dependency that is itself derived is
7171
+ * resolved before it is read.
7172
+ */
7173
+ declare function derivedDepOf<TPose>(source: PoseSource<TPose>, id: NodeId): DerivedDep<TPose> | undefined;
7174
+ /**
7175
+ * The pose the *document* says `node` is at: derived when it derives, else
7176
+ * authored. `effectivePose` minus the override step.
7177
+ *
7178
+ * For a reader that must not see an in-flight gesture — an action capturing
7179
+ * the `from` of a transform op, a placement computed against a sibling. A
7180
+ * derived pose belongs here and an override does not: derivation is what the
7181
+ * document means, an override is what one gesture is currently showing.
7182
+ */
7183
+ declare function documentPose<TPose>(source: PoseSource<TPose>, node: PosedNode<TPose>): TPose;
7184
+ /**
7185
+ * The pose to draw, pick and measure `node` at.
6210
7186
  *
6211
- * `computeFitView` derives a `View` that fits a chosen world rect into a
6212
- * minimap canvas of given pixel dims. `computeIndicatorCommand` builds the
6213
- * dashed "visible window" rect — the main canvas's screen window projected
6214
- * into the minimap's own screen coordinates.
7187
+ * The one rule. Every pose a reader acts on comes from here: the three render
7188
+ * walks, the pick walk, the adapters tools and actions commit through.
7189
+ */
7190
+ declare function effectivePose<TPose>(source: PoseSource<TPose>, node: PosedNode<TPose>): TPose;
7191
+
7192
+ /** A node and the pose a renderer should draw it at. `node.pose` beside it is
7193
+ * still the committed pose, so a host has both without a second channel. */
7194
+ interface FeedNode<TData, TLayer extends string, TPose> {
7195
+ node: Node$1<TData, TLayer, TPose>;
7196
+ pose: TPose;
7197
+ }
7198
+ interface FeedDelta<TData, TLayer extends string, TPose> {
7199
+ added: readonly FeedNode<TData, TLayer, TPose>[];
7200
+ removed: readonly NodeId[];
7201
+ changed: readonly FeedNode<TData, TLayer, TPose>[];
7202
+ /** Discard the object map and rebuild. */
7203
+ reset: boolean;
7204
+ }
7205
+ interface PoseFeed<TData, TLayer extends string, TPose> {
7206
+ subscribe(fn: () => void): () => void;
7207
+ read(): FeedDelta<TData, TLayer, TPose>;
7208
+ }
7209
+ declare function createPoseFeed<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>): PoseFeed<TData, TLayer, TPose>;
7210
+
7211
+ /** Registry key for {@link unionOfChildren}. */
7212
+ declare const UNION_OF_CHILDREN = "kit:unionOfChildren";
7213
+ /**
7214
+ * A container's pose as the envelope of what it holds — `unionAABB`, so a
7215
+ * rotated member contributes the extent of its ink rather than its unrotated
7216
+ * box. Paired with `dependsOn: 'children'`, this is what makes a group's
7217
+ * bounds track its members instead of freezing at the moment it was made.
6215
7218
  *
6216
- * Neither helper touches GL, the DOM, or the renderer; they're pure
6217
- * functions, unit-testable with `expect`.
7219
+ * Returns `null` for an emptied container, which falls back to its authored
7220
+ * pose — the group stays where the last member left it rather than collapsing
7221
+ * to a zero box at the origin.
6218
7222
  *
6219
- * See `docs/superpowers/specs/2026-05-31-detached-minimap-design.md`.
7223
+ * Reads members as rect poses, and only as rect poses: a scene whose poses are
7224
+ * shaped otherwise gets `null` here and its container keeps its authored pose,
7225
+ * because this entry is registered into every scene and the scene layer holds
7226
+ * no descriptor to read another shape with. To make such a container track its
7227
+ * members, register `unionOfChildrenVia(itsDescriptor)` under
7228
+ * {@link UNION_OF_CHILDREN} — the consumer's entry wins the collision.
6220
7229
  */
7230
+ declare function unionOfChildren<TPose>(_node: unknown, deps: readonly ({
7231
+ pose: TPose;
7232
+ } | undefined)[]): TPose | null;
6221
7233
 
6222
7234
  /**
6223
7235
  * Fallback view returned when there is nothing to fit (empty scene, etc.).
@@ -6227,7 +7239,7 @@ declare const FALLBACK_FIT_VIEW: View;
6227
7239
  /**
6228
7240
  * Fit policy for `<MinimapCanvas>` / `computeFitView`.
6229
7241
  *
6230
- * - `"scene"` — union of leaf-node pose AABBs (via `poseBounds`).
7242
+ * - `"scene"` — union of leaf-node pose AABBs (via the pose descriptor).
6231
7243
  * - `{ kind: "world", rect }` — caller-supplied world rect.
6232
7244
  * - `(scene, dims) => View` — caller derives the view directly.
6233
7245
  */
@@ -6255,7 +7267,7 @@ interface ComputeFitViewOptions {
6255
7267
  * is centered with `padding` (default 8) on each side. The smaller-axis
6256
7268
  * fit ratio wins, so the whole rect is visible.
6257
7269
  *
6258
- * - `fit === "scene"`: union AABB of leaf-node poses via `poseBounds`.
7270
+ * - `fit === "scene"`: union AABB of leaf-node poses via `descriptor`.
6259
7271
  * Empty scene → {@link FALLBACK_FIT_VIEW}.
6260
7272
  * - `fit` is `{ kind: "world", rect }`: fit `rect`. A degenerate rect
6261
7273
  * (zero or negative area) falls back to identity scale centered on the
@@ -6263,7 +7275,7 @@ interface ComputeFitViewOptions {
6263
7275
  * - `fit` is a function: called with `(scene, dims)`; its return is
6264
7276
  * passed through unchanged.
6265
7277
  */
6266
- declare function computeFitView<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>, dims: ViewportDims, fit: MinimapFit<TData, TLayer, TPose>, poseBounds: (pose: TPose) => Bounds, opts?: ComputeFitViewOptions): View;
7278
+ declare function computeFitView<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>, dims: ViewportDims, fit: MinimapFit<TData, TLayer, TPose>, descriptor: PoseDescriptor<TPose>, opts?: ComputeFitViewOptions): View;
6267
7279
  /**
6268
7280
  * Build the visible-window indicator `DrawCommand` for the minimap.
6269
7281
  *
@@ -6315,13 +7327,21 @@ interface MinimapCanvasProps<TData, TLayer extends string, TPose> {
6315
7327
  * frame if it goes there, rather than making the whole minimap rescale on
6316
7328
  * every frame of a drag or a settle. */
6317
7329
  fit?: MinimapFit<TData, TLayer, TPose>;
6318
- /** Pose → AABB. Defaults to identity (`pose as Bounds`), matching
6319
- * `sceneAdapter` / `useSelectTool`. */
6320
- poseBounds?: (pose: TPose) => Bounds;
7330
+ /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */
7331
+ poseDescriptor?: PoseDescriptor<TPose>;
6321
7332
  /** Optional per-id alpha multiplier, mirroring `<SceneCanvas>`'s scene-slot
6322
7333
  * `alphaFor`. Pass the same function the main canvas uses so a
6323
7334
  * scoping-dim treatment shows up in the minimap too. */
6324
7335
  alphaFor?: (id: string) => number;
7336
+ /** Hide scene layers in the minimap, keyed `scene:<layerId>` as on
7337
+ * `<SceneCanvas>` — pass the main canvas's map so both show the same set. */
7338
+ layerVisibility?: SceneViewLayers['layerVisibility'];
7339
+ /** Paint order for the minimap, keyed as `layerVisibility`. */
7340
+ layerOrder?: SceneViewLayers['layerOrder'];
7341
+ /** Optional animator: the minimap repaints on its ticks and paints its
7342
+ * `colorOverrides`. Pass the main canvas's animator so both show the same
7343
+ * colors. */
7344
+ animator?: Animator;
6325
7345
  /** Visual tuning of the indicator stroke. */
6326
7346
  indicatorStyle?: IndicatorStyle;
6327
7347
  /** CSS class for sizing / positioning the canvas. */
@@ -6385,6 +7405,9 @@ interface RenderSceneToPixelsArgs<TData, TLayer extends string, TPose> {
6385
7405
  * `alphaFor`. Pass the same function the on-screen canvas uses so an
6386
7406
  * export matches what the user is looking at. Defaults to `() => 1`. */
6387
7407
  alphaFor?: (id: string) => number;
7408
+ /** Animated vertex colors to paint, typically an animator's
7409
+ * `colorOverrides`, so an export shows the frame on screen. */
7410
+ colorOverrides?: ColorOverrideRegistry;
6388
7411
  /** Background fill (any CSS color accepted by the renderer). Default:
6389
7412
  * fully transparent. Passing a color is always valid. */
6390
7413
  background?: string;
@@ -6893,9 +7916,9 @@ declare function renderLabel(ctx: CanvasRenderingContext2D, text: string, x: num
6893
7916
  declare const defaultLabelTextRenderer: TextRenderer;
6894
7917
 
6895
7918
  /**
6896
- * Text RenderLayer. Emits one TextDrawCommand per text node carrying the
6897
- * node's resolved runs and bounding rect. Word wrap and multi-line layout
6898
- * happen downstream in `drawText` / `layoutRuns`, not here.
7919
+ * Text RenderLayer for text that is not in a scene: one `textCommandFromPose`
7920
+ * command per item, the same command the `kit:text` node painter emits, so an
7921
+ * item lays out — and wraps, or doesn't, per its style — as a node would.
6899
7922
  *
6900
7923
  * The GL renderer uses MSDF text. The resolved style's `fontFamily` must
6901
7924
  * be registered via `registerFont(family, variant, metricsUrl, atlasUrl)`
@@ -6930,10 +7953,10 @@ declare function createTextLayer<T>(opts: CreateTextLayerOpts<T>): RenderLayer<u
6930
7953
  *
6931
7954
  * `caretIndexAt` does the finer test: given a world-space (x, y) inside the
6932
7955
  * pose, returns the corresponding character offset so the consumer can place
6933
- * the caret on click. It reads the caret stops off the same
6934
- * `cachedLayoutRuns` result the renderer paints and `textLineBoxes` picks
6935
- * against, so the caret cannot land on a different line — or between
6936
- * different glyphs — than the one under the pointer.
7956
+ * the caret on click. It reads the caret stops off `layoutTextPose`, the
7957
+ * layout the painters draw and `textLineBoxes` picks against, so the caret
7958
+ * cannot land on a different line — or between different glyphs — than the
7959
+ * one under the pointer.
6937
7960
  */
6938
7961
 
6939
7962
  /** Options for `pointInTextPose`. */
@@ -6943,19 +7966,6 @@ interface PointInTextPoseOpts {
6943
7966
  }
6944
7967
  /** Coarse pose-rect hit-test for a text node — suitable for click-to-edit dispatch. */
6945
7968
  declare function pointInTextPose(x: number, y: number, pose: TextPose, opts?: PointInTextPoseOpts): boolean;
6946
- /** Options for `caretIndexAt`. */
6947
- interface CaretIndexAtOpts {
6948
- /**
6949
- * Wrap width. Default `pose.width`, which is what `createTextLayer` passes
6950
- * and what `TextPose` means by its box.
6951
- *
6952
- * Pass `Infinity` for a node painted by the built-in `kit:text` painter:
6953
- * that painter deliberately does not forward `maxWidth`, so its text does
6954
- * not wrap, and a caret mapped through a finite width would answer for a
6955
- * line break the paint never made. Mirrors `textLineBoxes`.
6956
- */
6957
- maxWidth?: number;
6958
- }
6959
7969
  /**
6960
7970
  * Map a world-space point inside `pose` to a character offset into the pose's
6961
7971
  * text (0..length). Clicks above the first line clamp to 0; clicks below the
@@ -6967,7 +7977,7 @@ interface CaretIndexAtOpts {
6967
7977
  * produced) and `pose.verticalAlign`. The offset is into the runs'
6968
7978
  * concatenated text, which `TextPose` requires to equal `pose.text`.
6969
7979
  */
6970
- declare function caretIndexAt(x: number, y: number, pose: TextPose, opts?: CaretIndexAtOpts): number;
7980
+ declare function caretIndexAt(x: number, y: number, pose: TextPose): number;
6971
7981
 
6972
7982
  /**
6973
7983
  * Resize a text node's pose to fit its content. Pure helper — does not own
@@ -6977,8 +7987,9 @@ declare function caretIndexAt(x: number, y: number, pose: TextPose, opts?: Caret
6977
7987
  * Two modes:
6978
7988
  *
6979
7989
  * - `axis: 'height'` (default): keep `pose.width`, recompute `height` as
6980
- * the wrapped block height plus optional vertical padding. The common
6981
- * case for column-layout text — chat bubbles, sticky notes, label cards.
7990
+ * the block height plus optional vertical padding — wrapped at the width
7991
+ * inside the horizontal padding when the style declares `wrap`. The
7992
+ * common case for column-layout text — chat bubbles, sticky notes.
6982
7993
  *
6983
7994
  * - `axis: 'both'`: ignore wrapping; recompute both `width` (longest
6984
7995
  * `\n`-split line) and `height` (line count × line height) plus padding.
@@ -7198,6 +8209,13 @@ interface TextEditScreenPose {
7198
8209
  */
7199
8210
  zoom?: number;
7200
8211
  }
8212
+ /** A box in CSS pixels relative to `useTextEdit`'s `container`. */
8213
+ interface TextEditClipRect {
8214
+ x: number;
8215
+ y: number;
8216
+ width: number;
8217
+ height: number;
8218
+ }
7201
8219
  /** Options for `useTextEdit`. */
7202
8220
  interface UseTextEditOptions {
7203
8221
  /** Element the overlay is appended to. Must be `position: relative`/absolute. */
@@ -7224,6 +8242,15 @@ interface UseTextEditOptions {
7224
8242
  setStyle?: (id: string, style: TextStyle) => void;
7225
8243
  /** Read screen-space pose for `id`. Called per frame while editing. */
7226
8244
  getScreenPose: (id: string) => TextEditScreenPose | null;
8245
+ /**
8246
+ * The box, in CSS pixels relative to `container`, the overlay is visible
8247
+ * within — where the canvas clips the glyphs the overlay stands in for.
8248
+ * Re-read every frame. Omit it, or return `null`, to clip nothing.
8249
+ *
8250
+ * The clip cannot scroll, so a caret moving past its edge leaves the page
8251
+ * where it is; a scrollable container would drag the canvas after the caret.
8252
+ */
8253
+ getClipRect?: () => TextEditClipRect | null;
7227
8254
  /** Commit text. Caller wraps in op/undo. */
7228
8255
  setText: (id: string, text: string) => void;
7229
8256
  /**
@@ -7386,9 +8413,9 @@ declare function unionAABB<TPose extends RectPose>(parts: Iterable<TPose | null
7386
8413
  * (`getText` / `getStyle` / `getRuns` / `setText` / `setRuns` / `setStyle`).
7387
8414
  *
7388
8415
  * Pose component: the helper reads `(x, y, width, height)` straight off
7389
- * the node's pose (typed `RectPose`). Pass `view` and it projects that box
7390
- * through the viewport; omit it and world units are handed through as
7391
- * screen pixels, which is correct only for an unpanned, unzoomed canvas.
8416
+ * the node's pose (typed `RectPose`) and projects that box through the view
8417
+ * of the weasel canvas mounted inside `container` — see the `view` option.
8418
+ * The overlay is clipped to that canvas's box, where its glyphs are clipped.
7392
8419
  * Consumers with non-rect poses should drop down to raw `useTextEdit` and
7393
8420
  * supply their own `getScreenPose`.
7394
8421
  */
@@ -7402,6 +8429,7 @@ interface DefaultTextData {
7402
8429
  runs?: readonly StyledRun[];
7403
8430
  fill?: FillStyle | null;
7404
8431
  stroke?: Stroke | null;
8432
+ verticalAlign?: TextVerticalAlign;
7405
8433
  }
7406
8434
  /** All-optional projections + fontSize fallback. */
7407
8435
  interface UseSceneTextEditOptions<TData> {
@@ -7413,6 +8441,8 @@ interface UseSceneTextEditOptions<TData> {
7413
8441
  getPaint?: (data: TData) => TextPaint | undefined;
7414
8442
  /** Read rich-text runs from `data`. Default: `data.runs`. */
7415
8443
  getRuns?: (data: TData) => readonly StyledRun[] | undefined;
8444
+ /** Read the box vertical alignment from `data`. Default: `data.verticalAlign`. */
8445
+ getVerticalAlign?: (data: TData) => TextVerticalAlign | undefined;
7416
8446
  /** Produce updated data with new text. Default: `{ ...data, text }`. */
7417
8447
  setText?: (data: TData, text: string) => TData;
7418
8448
  /** Produce updated data with new runs. Default: `{ ...data, runs }`. */
@@ -7428,21 +8458,24 @@ interface UseSceneTextEditOptions<TData> {
7428
8458
  /** Fallback fontSize when `style.fontSize` is unset. Default `16`. */
7429
8459
  defaultFontSize?: number;
7430
8460
  /**
7431
- * Current viewport. Supply it on a canvas that pans or zooms: the overlay
7432
- * is then positioned at the node's projected screen origin and CSS-scaled
8461
+ * The view to project through. Omit it and the view is read live from the
8462
+ * weasel canvas mounted inside `container` (the one a double-click landed
8463
+ * on, when there are several) — which is all a canvas that pans or zooms
8464
+ * needs. With no canvas there, the node's world box is passed through as
8465
+ * screen pixels.
8466
+ *
8467
+ * The overlay is positioned at the node's projected origin and CSS-scaled
7433
8468
  * by the view, so every typographic metric on it — including the
7434
8469
  * `fontSize` / `letterSpacing` a *run* carries — stays in world units and
7435
- * scales together. Omit it and the node's world box is passed through as
7436
- * screen pixels (correct at `{x: 0, y: 0, scale: 1}`).
8470
+ * scales together.
7437
8471
  *
7438
8472
  * The overlay takes a single scale factor, so a non-uniform view scale is
7439
8473
  * represented by its `scale.x`; text under `scale.x !== scale.y` will not
7440
8474
  * match the canvas.
7441
8475
  *
7442
- * A thunk is re-read on every projection, which is what an uncontrolled
7443
- * `SceneCanvas` needs — its camera lives in a ref and moves without a
7444
- * render, so pass the handle's `getView`. A plain `View` is the value from
7445
- * the render that supplied it, which is correct for a controlled consumer.
8476
+ * Pass one to project through a camera other than the canvas's own. A
8477
+ * thunk is re-read on every projection; a plain `View` is the value from
8478
+ * the render that supplied it.
7446
8479
  */
7447
8480
  view?: View | (() => View);
7448
8481
  /**
@@ -7468,8 +8501,10 @@ interface UseSceneTextEditReturn extends UseTextEditReturn {
7468
8501
  declare function useSceneTextEdit<TData extends DefaultTextData, TLayer extends string, TPose extends RectPose = RectPose>(scene: Scene<TData, TLayer, TPose>, container: HTMLElement | null, options?: UseSceneTextEditOptions<TData>): UseSceneTextEditReturn;
7469
8502
 
7470
8503
  /**
7471
- * Build a `TextDrawCommand`. `textCommand` takes a plain string and wraps it
7472
- * in one run; `textCommandFromRuns` takes the styled runs directly. Both
8504
+ * Build a `TextDrawCommand`. `textCommandFromPose` is the command for a text
8505
+ * node — what `kit:text` and `createTextLayer` both emit. `textCommand` takes
8506
+ * a plain string and wraps it in one run; `textCommandFromRuns` takes the
8507
+ * styled runs directly, for text that has no pose. All three
7473
8508
  * resolve through `resolveTextStyle` + `resolveRuns`, so every emitter of a
7474
8509
  * text command derives `align` and per-run resolution the same way — a
7475
8510
  * caller that assembles the command by hand is one field away from a
@@ -7479,11 +8514,18 @@ declare function useSceneTextEdit<TData extends DefaultTextData, TLayer extends
7479
8514
  * a HUD widget, a debug overlay — states its color on the run instead.
7480
8515
  */
7481
8516
 
7482
- declare function textCommandFromRuns(x: number, y: number, runs: readonly StyledRun[], style?: TextStyle, maxWidth?: number, height?: number, verticalAlign?: TextVerticalAlign, paint?: TextPaint): DrawCommand;
8517
+ declare function textCommandFromRuns(x: number, y: number, runs: readonly StyledRun[], style?: TextStyle, maxWidth?: number, height?: number, verticalAlign?: TextVerticalAlign, paint?: TextPaint, width?: number): DrawCommand;
7483
8518
  /** Build a draw command for a single unstyled string. Text is laid out with
7484
- * the registered font's metrics, wrapped at `maxWidth` and aligned within
7485
- * `height` when both are given. */
7486
- declare function textCommand(x: number, y: number, text: string, style?: TextStyle, maxWidth?: number, height?: number, verticalAlign?: TextVerticalAlign, paint?: TextPaint): DrawCommand;
8519
+ * the registered font's metrics, wrapped at `maxWidth`, aligned across
8520
+ * `width` (default `maxWidth`) and within `height` when `verticalAlign` is
8521
+ * given. */
8522
+ declare function textCommand(x: number, y: number, text: string, style?: TextStyle, maxWidth?: number, height?: number, verticalAlign?: TextVerticalAlign, paint?: TextPaint, width?: number): DrawCommand;
8523
+ /**
8524
+ * The draw command for a text pose. Its wrap width, alignment box and runs
8525
+ * come from `textPoseLayoutInput`, so the renderer lays it out into exactly
8526
+ * the lines `layoutTextPose` reports for the same pose.
8527
+ */
8528
+ declare function textCommandFromPose(pose: TextPose): TextDrawCommand;
7487
8529
 
7488
8530
  /**
7489
8531
  * Pure DOM ↔ `StyledRun[]` serializers for the contenteditable overlay
@@ -7975,10 +9017,8 @@ interface NestedHitOpts<TNode extends {
7975
9017
  /** Compose a child's local pose into world coords given its parent's world
7976
9018
  * pose. Same shape as `composeRectPose` (the default expectation). */
7977
9019
  composePose: (parent: TPose, child: TPose) => TPose;
7978
- /** Derive an axis-aligned bounding rect from a (world-space) pose. Default
7979
- * reads `x` / `y` / `width` / `height` straight off the pose (matches
7980
- * `RectPose`). Override for non-rect poses (e.g. paths). */
7981
- poseBounds?: (pose: TPose) => Bounds;
9020
+ /** How to read world poses. Default `AUTO_POSE_DESCRIPTOR`. */
9021
+ poseDescriptor?: PoseDescriptor<TPose>;
7982
9022
  /** Predicate for "this object is a nesting parent body". The leaf scan
7983
9023
  * skips objects for which this returns true so a click on a parent's
7984
9024
  * painted body resolves to a child leaf, not the parent itself. Default:
@@ -8007,6 +9047,22 @@ declare function nestedHitTester<TNode extends {
8007
9047
  id: string;
8008
9048
  }, TPose>(adapter: HitAdapter<TNode, TPose>, opts: NestedHitOpts<TNode, TPose>): NestedHitTester;
8009
9049
 
9050
+ type DerivePose<TPose> = (node: {
9051
+ pose: TPose;
9052
+ }, deps: readonly ({
9053
+ pose: TPose;
9054
+ } | undefined)[]) => TPose | null;
9055
+ /**
9056
+ * A container's pose as the envelope of what it holds, read through
9057
+ * `descriptor` — a rotated member contributes the extent of its ink. Register
9058
+ * the result under `UNION_OF_CHILDREN` in `createScene`'s `registry` to teach
9059
+ * a scene how to size its groups around a pose shape the kit cannot read.
9060
+ *
9061
+ * Returns `null` for an emptied container, which falls back to its authored
9062
+ * pose rather than collapsing to a zero box at the origin.
9063
+ */
9064
+ declare function unionOfChildrenVia<TPose>(descriptor: PoseDescriptor<TPose>): DerivePose<TPose>;
9065
+
8010
9066
  /**
8011
9067
  * Fluent builder for `PolygonPath`. Hides the `Uint8Array` / `Float32Array`
8012
9068
  * encoding behind move/line/curve/close calls and a final `build()`. Use
@@ -8242,6 +9298,35 @@ declare function pathIntersectsPolygon(path: Path, polygon: readonly Vec2[], opt
8242
9298
  * combine with `pathContainsPoint` at the call site. */
8243
9299
  declare function pathDistanceToPoint(path: Path, px: number, py: number): number;
8244
9300
 
9301
+ /**
9302
+ * A station along a path: where it is at a fraction of its length, and which
9303
+ * way it is heading there.
9304
+ *
9305
+ * For anything positioned *along* geometry rather than beside it — a label on a
9306
+ * routed edge, a tick on a curve, a badge near an arrowhead. Curves are
9307
+ * flattened first, so the fraction is arc length along the drawn shape rather
9308
+ * than a curve parameter, which is what makes 0.5 look like the middle.
9309
+ */
9310
+
9311
+ interface PathStation {
9312
+ point: Vec2;
9313
+ /** Unit vector along the path at `point`, pointing toward the end. */
9314
+ tangent: Vec2;
9315
+ }
9316
+ interface PointAlongPathOptions {
9317
+ /** Curve flattening tolerance, in world units. Default 0.5. */
9318
+ flattenTolerance?: number;
9319
+ }
9320
+ /**
9321
+ * Where `path` is at `t` of its total length, and its heading there.
9322
+ *
9323
+ * `t` is clamped to 0..1. Subpaths are measured in order and treated as one
9324
+ * run, the way a browser measures a whole `<path>`. Returns `null` for a path
9325
+ * with no points at all; a path of zero length answers at its single point,
9326
+ * heading along +X.
9327
+ */
9328
+ declare function pointAlongPath(path: Path, t: number, opts?: PointAlongPathOptions): PathStation | null;
9329
+
8245
9330
  /**
8246
9331
  * In-place and copy-out path transforms. Translation is the most common —
8247
9332
  * called every pointermove during a drag — so the polygon variant mutates
@@ -8249,9 +9334,7 @@ declare function pathDistanceToPoint(path: Path, px: number, py: number): number
8249
9334
  *
8250
9335
  * `scalePathToBounds` is for the resize interaction: given the path's
8251
9336
  * current AABB and the desired new AABB, scales every coordinate
8252
- * proportionally. Degenerate source bounds (zero width/height) collapse
8253
- * the corresponding axis to the new origin — preferable to dividing by
8254
- * zero or refusing to resize.
9337
+ * proportionally.
8255
9338
  */
8256
9339
 
8257
9340
  /**
@@ -8270,9 +9353,9 @@ declare function translatePolygonInPlace(path: PolygonPath, dx: number, dy: numb
8270
9353
  * Scale a path's coords so its current AABB maps to `target`. Resize
8271
9354
  * interactions use this to make a polygon follow a corner-handle drag.
8272
9355
  *
8273
- * Degenerate source axes (width or height == 0) collapse to `target.x` /
8274
- * `target.y` — every coord on that axis becomes the new origin. Avoids
8275
- * division by zero without throwing.
9356
+ * A degenerate source axis (zero width or height) has no ratio to scale by,
9357
+ * so `boxToBox` translates that axis instead — a zero scale is not
9358
+ * invertible and would discard what is left on it.
8276
9359
  */
8277
9360
  declare function scalePathToBounds(path: Path, target: RectPath): Path;
8278
9361
 
@@ -8429,48 +9512,6 @@ interface CreatePathLayerOpts<T> {
8429
9512
  /** Build a `RenderLayer` that fills/strokes `Path` instances enumerated from a node list. */
8430
9513
  declare function createPathLayer<T>(opts: CreatePathLayerOpts<T>): RenderLayer<unknown>;
8431
9514
 
8432
- /**
8433
- * Bezier flattening — subdivide cubic and quadratic segments into polyline
8434
- * approximations within a flatness tolerance. Used by hit-testing and
8435
- * (eventually) any kernel that doesn't want to special-case curves.
8436
- *
8437
- * The flatness metric is the maximum perpendicular distance from any
8438
- * control point to the chord between endpoints. When that distance falls
8439
- * below `tolerance`, the segment is "flat enough" and emitted as a single
8440
- * line segment.
8441
- *
8442
- * Tolerance is in world units. 0.5 is a sensible default for screen-rate
8443
- * rendering at 1× zoom; consumers that zoom in heavily should pass a
8444
- * tighter tolerance.
8445
- */
8446
- declare const DEFAULT_FLATTEN_TOLERANCE = 0.5;
8447
- /**
8448
- * Recursively subdivide a cubic bezier (P0..P3) and append `lineTo`-style
8449
- * vertices to `out` (interleaved x,y). The starting endpoint is *not*
8450
- * appended — callers usually emitted it as the segment's previous vertex.
8451
- */
8452
- declare function flattenCubic(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, tolerance: number, out: number[]): void;
8453
- /** Recursively subdivide a quadratic bezier (P0, P1, P2). */
8454
- declare function flattenQuadratic(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, tolerance: number, out: number[]): void;
8455
- /**
8456
- * Like `flattenCubic` but also appends, for each new flattened point, its
8457
- * arc-length fraction `t` (relative to the polyline distance accumulated so
8458
- * far inside this curve) to `arcOut`. Caller then post-processes the segment's
8459
- * `arcOut` range by dividing each by the segment's total flattened arc length
8460
- * to yield t ∈ (0, 1].
8461
- *
8462
- * The returned values are *cumulative distance from the segment start*, not
8463
- * normalized fractions. Two-pass design (accumulate, then divide) keeps the
8464
- * recursive splitter simple — it doesn't need to know the total length up
8465
- * front.
8466
- */
8467
- 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;
8468
- /** Flatten a quadratic bezier into line segments within `tolerance`, appending
8469
- * points to `out` and their cumulative arc lengths to `arcOut`. The arc
8470
- * lengths are what lets per-anchor color and dash phase be interpolated
8471
- * evenly along the curve rather than per segment. */
8472
- declare function flattenQuadraticWithArcLen(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, tolerance: number, out: number[], arcOut: number[]): number;
8473
-
8474
9515
  /**
8475
9516
  * `pathFromD` — build a weasel `Path` from an **SVG path-data string** (the
8476
9517
  * value of SVG's `d` attribute, e.g. `"M0 0 L100 0 Z"`).
@@ -8564,17 +9605,16 @@ declare function splitPathByLine(path: Path, a: Point, b: Point, opts?: SplitByL
8564
9605
  declare function unionBoundsPath(paths: Iterable<Path>): RectPath | null;
8565
9606
 
8566
9607
  /**
8567
- * `PoseProjection` for `Path` poses — wires `useResize` to operate
9608
+ * `PoseDescriptor` for `Path` poses — wires `useResize` to operate
8568
9609
  * on `Path` directly. `getBounds` defers to the same `boundsOfPath` kernel
8569
- * the rest of the kit uses; `remapBounds` does an affine scale of every
8570
- * coord against `src`/`dst`. Degenerate axes (zero src extent) collapse to
8571
- * the new origin so resize from a flat edge doesn't produce NaN.
9610
+ * the rest of the kit uses.
8572
9611
  *
8573
- * Mirrors `scalePathToBounds` but takes `src` explicitly: the resize hook
8574
- * knows the group's origin AABB and uses it for every leaf, instead of
8575
- * each leaf scaling against its own AABB (which would ignore group context).
9612
+ * `remapBounds` mirrors `scalePathToBounds` but takes `src` explicitly: the
9613
+ * resize hook knows the group's origin AABB and uses it for every leaf,
9614
+ * instead of each leaf scaling against its own AABB (which would ignore
9615
+ * group context).
8576
9616
  */
8577
- declare const pathPoseDescriptor: PoseProjection<Path>;
9617
+ declare const pathPoseDescriptor: PoseDescriptor<Path>;
8578
9618
 
8579
9619
  /**
8580
9620
  * `OriginProjection` for `Path` poses. The "origin" is the top-left of the
@@ -8710,11 +9750,6 @@ declare function pathExclude(...paths: Path[]): PolygonPath;
8710
9750
  * Fracture N paths along every intersection into the maximal set of
8711
9751
  * non-overlapping regions. Returns one `PolygonPath` per region.
8712
9752
  *
8713
- * Algorithm: for every non-empty subset S ⊆ {A1..AN}, emit the region
8714
- * `(∩ S) − (∪ complement)` — points covered by exactly the members of S
8715
- * and no others. By construction the emitted regions are pairwise disjoint
8716
- * and their union equals `pathUnion(A1..AN)`.
8717
- *
8718
9753
  * For N=2 this collapses to the three Illustrator "Divide" outputs
8719
9754
  * (A−B, B−A, A∩B). For N=3 up to 7 regions are emitted. The 2^N − 1
8720
9755
  * subset count limits this to small N in practice; passing more than ~8
@@ -8901,10 +9936,19 @@ interface PaintBindContext {
8901
9936
  * from the paint's space to the frame the geometry arrives in. Paired with
8902
9937
  * the vertex shader's `v_world` varying this is *the* paint-space
8903
9938
  * convention; it is not gradient-specific.
9939
+ *
9940
+ * `null` when that space has no inverse — a transform or view that flattens
9941
+ * an axis. Nothing the paint draws there means anything, so `bind` should
9942
+ * return `null` and draw nothing.
9943
+ */
9944
+ spaceInverse(units: GradientUnits | undefined): Mat3$1 | null;
9945
+ /**
9946
+ * Bake a stop ramp into the frame's ramp atlas, bind that atlas to a texture
9947
+ * unit, and return the `v` the ramp's own row sits at — every ramp in a
9948
+ * frame shares one texture, so a paint must sample at the returned `v` and
9949
+ * not at a constant.
8904
9950
  */
8905
- spaceInverse(units: GradientUnits | undefined): Mat3$1;
8906
- /** Upload a stop ramp and bind it to a texture unit. */
8907
- bindRamp(stops: GradStop[], unit: number): void;
9951
+ bindRamp(stops: GradStop[], unit: number): number;
8908
9952
  }
8909
9953
  /**
8910
9954
  * One paint kind.
@@ -9247,21 +10291,15 @@ interface ArrayAdapterConfig<TNode extends {
9247
10291
  * Consumers own id generation and any palette/payload fields. Returning
9248
10292
  * `null` aborts the insert. When omitted, `commitInsert` returns `null`. */
9249
10293
  createDefault?: (bounds: Bounds) => TNode | null;
9250
- /** Project a pose to an AABB for `hitTestArea`. Default: identity (works
9251
- * when TPose carries top-level x/y/width/height). */
9252
- poseBounds?: (pose: TPose) => Bounds;
9253
- /** Tight intersection test against a pose. Default: AABB-vs-AABB using
9254
- * `poseBounds`. Override for non-rect poses (e.g. polygons via
9255
- * `pathPoseDescriptor.intersectsRect`). */
9256
- intersectsRect?: (pose: TPose, rect: Bounds) => boolean;
10294
+ /** How to read and rewrite item poses. Default `RECT_POSE_DESCRIPTOR`,
10295
+ * which reads the pose as its own AABB — the canonical axis-aligned rect
10296
+ * pose. `AUTO_POSE_DESCRIPTOR` lives above `core/` and so cannot be the
10297
+ * default here; pass it for a scene whose poses may be Paths. */
10298
+ poseDescriptor?: PoseDescriptor<TPose>;
9257
10299
  /** Factory for fresh node ids in `commitPaste`. Default: `crypto.randomUUID()`
9258
10300
  * when available, otherwise a monotonic `paste-<n>` counter. Override
9259
10301
  * when consumers want stable id schemes (e.g. `clip-${n++}`). */
9260
10302
  nextId?: () => string;
9261
- /** Translate a pose by `(dx, dy)`. Default: shallow-spread `{ x, y }`,
9262
- * which matches the canonical axis-aligned rect pose. Override for
9263
- * non-rect poses whose translation isn't a top-level `x`/`y` bump. */
9264
- translatePose?: (pose: TPose, dx: number, dy: number) => TPose;
9265
10303
  }
9266
10304
  /**
9267
10305
  * Combined adapter satisfying every narrow adapter the kit ships. Methods
@@ -9433,14 +10471,6 @@ interface GuidesLayerOpts {
9433
10471
  * screen space, projected from world offsets via the active view. */
9434
10472
  declare function createGuidesLayer(opts: GuidesLayerOpts): RenderLayer<unknown>;
9435
10473
 
9436
- /** Axis-aligned bounding box. Alignment matches AABBs throughout; a rotated
9437
- * pose enters as the AABB of its ink (see `AlignBoundsProjection.boundsOf`). */
9438
- interface AlignBounds {
9439
- x: number;
9440
- y: number;
9441
- width: number;
9442
- height: number;
9443
- }
9444
10474
  /** Which feature of a box to test against candidates, per axis.
9445
10475
  * 'min' = left/top edge, 'center' = centerline, 'max' = right/bottom edge. */
9446
10476
  type AlignAnchor = 'min' | 'center' | 'max';
@@ -9453,31 +10483,18 @@ interface AlignMatchResult {
9453
10483
  activeX: Guide | null;
9454
10484
  activeY: Guide | null;
9455
10485
  }
9456
- /** Bounds analog of the gesture `OriginProjection`: reads an AABB from a pose
9457
- * and translates a pose. The rect default handles `{x,y,width,height}` poses;
9458
- * non-rect poses (Path, polygon) supply their own. */
9459
- interface AlignBoundsProjection<TPose> {
9460
- /** The pose's *visual* AABB — a rotated pose reports the extent of its ink,
9461
- * not the box it was posed in. Guides and matching both read this, so an
9462
- * implementation that returns the stored box makes a rotated shape snap to
9463
- * lines nothing is drawn at. */
9464
- boundsOf(pose: TPose): AlignBounds;
9465
- /** Move the pose, preserving every other field it carries — nothing
9466
- * downstream re-derives rotation or style from anywhere else. */
9467
- translate(pose: TPose, dx: number, dy: number): TPose;
9468
- }
9469
10486
  /** Which candidate lines to derive from a set of poses — edges, centers, or
9470
10487
  * both, and whether the page box contributes its own. */
9471
- interface DeriveAlignmentGuidesOptions<TPose = AlignBounds> {
10488
+ interface DeriveAlignmentGuidesOptions<TPose = Bounds> {
9472
10489
  /** Include the document/page box's edges + center as candidates. */
9473
- page?: AlignBounds;
10490
+ page?: Bounds;
9474
10491
  /** Emit left/right (x) and top/bottom (y) edge guides. Default true. */
9475
10492
  edges?: boolean;
9476
10493
  /** Emit centerX (x) and centerY (y) guides. Default true. */
9477
10494
  centers?: boolean;
9478
- /** Reads each target's AABB. Defaults to `RECT_ALIGN_PROJECTION`. Pass the
9479
- * same projection `alignMoveBehavior` gets, or the two sides disagree. */
9480
- projection?: AlignBoundsProjection<TPose>;
10495
+ /** How to read each target. Pass the same descriptor `alignMoveBehavior`
10496
+ * gets, or the two sides disagree. Default `AUTO_POSE_DESCRIPTOR`. */
10497
+ poseDescriptor?: PoseDescriptor<TPose>;
9481
10498
  }
9482
10499
  /** Common options shared by the three alignment behavior factories. */
9483
10500
  interface AlignmentBehaviorBase {
@@ -9497,20 +10514,15 @@ interface AlignmentBehaviorBase {
9497
10514
  /** Derive candidate alignment lines from a set of sibling poses plus an
9498
10515
  * optional page box. Each box contributes up to 3 guides per axis: the two
9499
10516
  * edges and the center. Overlapping offsets collapse to one candidate.
9500
- * Poses go through the same projection `alignMoveBehavior` matches with, so
10517
+ * Poses go through the same descriptor `alignMoveBehavior` matches with, so
9501
10518
  * a rotated sibling advertises its ink edges rather than its stored box. */
9502
- declare function deriveAlignmentGuides<TPose = AlignBounds>(targets: readonly TPose[], opts?: DeriveAlignmentGuidesOptions<TPose>): Guide[];
10519
+ declare function deriveAlignmentGuides<TPose = Bounds>(targets: readonly TPose[], opts?: DeriveAlignmentGuidesOptions<TPose>): Guide[];
9503
10520
 
9504
10521
  /** Move/insert test all three features per axis. */
9505
10522
  declare const MOVE_ANCHORS: {
9506
10523
  x: readonly AlignAnchor[];
9507
10524
  y: readonly AlignAnchor[];
9508
10525
  };
9509
- /** Default projection for rect-shaped poses (`{x,y,width,height,rotation?}`).
9510
- * A rotated pose reports the AABB of its ink, so guides derived from a
9511
- * stationary sibling and the box a dragged selection matches with are the
9512
- * same measurement. */
9513
- declare const RECT_ALIGN_PROJECTION: AlignBoundsProjection<RectPose>;
9514
10526
  /**
9515
10527
  * Match a moving box's selected edge/center features against candidate guide
9516
10528
  * lines. Returns the per-axis snap delta and the matched candidate line(s).
@@ -9522,7 +10534,7 @@ declare const RECT_ALIGN_PROJECTION: AlignBoundsProjection<RectPose>;
9522
10534
  * distance along that axis alone, so there is an exact answer rather than an
9523
10535
  * approximation. Pass the same number twice for a world-space tolerance.
9524
10536
  */
9525
- declare function matchAlignment(bounds: AlignBounds, candidates: readonly Guide[], worldTolerance: {
10537
+ declare function matchAlignment(bounds: Bounds, candidates: readonly Guide[], worldTolerance: {
9526
10538
  x: number;
9527
10539
  y: number;
9528
10540
  }, anchors: {
@@ -9530,9 +10542,9 @@ declare function matchAlignment(bounds: AlignBounds, candidates: readonly Guide[
9530
10542
  y: readonly AlignAnchor[];
9531
10543
  }): AlignMatchResult;
9532
10544
 
9533
- /** Options for move/insert — adds the bounds projection for non-rect poses. */
10545
+ /** Options for move/insert — adds the pose descriptor for non-rect poses. */
9534
10546
  interface AlignMoveArgs<TPose> extends AlignmentBehaviorBase {
9535
- projection?: AlignBoundsProjection<TPose>;
10547
+ poseDescriptor?: PoseDescriptor<TPose>;
9536
10548
  }
9537
10549
  /** Move behavior: snap the dragged selection's union box (edges + center) to
9538
10550
  * candidates, shaping the proposed translate. The gesture applies the
@@ -9545,10 +10557,10 @@ declare function alignMoveBehavior<TPose>(args: AlignMoveArgs<TPose>): MoveBehav
9545
10557
  declare function alignInsertBehavior<TPose>(args: AlignmentBehaviorBase): InsertBehavior<TPose>;
9546
10558
  /** Resize constraint: snap the moving edge(s) of the dragged rect to
9547
10559
  * candidates. The pinned (anchor) edge stays fixed. Publishes the line(s). */
9548
- declare function alignResizeBehavior<TPose extends ResizePose>(args: AlignmentBehaviorBase): BoundsConstraint<TPose>;
10560
+ declare function alignResizeBehavior<TPose extends Bounds>(args: AlignmentBehaviorBase): BoundsConstraint<TPose>;
9549
10561
 
9550
10562
  /** AABB center of an unrotated rect — the canonical rotation pivot. */
9551
- declare function aabbCenter(bounds: ResizePose): {
10563
+ declare function aabbCenter(bounds: Bounds): {
9552
10564
  x: number;
9553
10565
  y: number;
9554
10566
  };
@@ -9558,7 +10570,7 @@ declare function rotatePoint(px: number, py: number, cx: number, cy: number, ang
9558
10570
  y: number;
9559
10571
  };
9560
10572
  /** Four corners of an unrotated rect, in TL/TR/BR/BL order. */
9561
- declare function rectCorners(bounds: ResizePose): {
10573
+ declare function rectCorners(bounds: Bounds): {
9562
10574
  x: number;
9563
10575
  y: number;
9564
10576
  }[];
@@ -9843,65 +10855,6 @@ interface AnchorHit {
9843
10855
  * are within `threshold` (controls are smaller and rendered on top). */
9844
10856
  declare function hitAnchor(path: PolygonPath, worldX: number, worldY: number, threshold: number): AnchorHit | null;
9845
10857
 
9846
- /**
9847
- * Typed keys for the gesture/behavior scratch store.
9848
- *
9849
- * Gestures expose `ctx.scratch: Record<string, unknown>` as a per-gesture
9850
- * mutable bag that behaviors use to stash state across `onDown` / `onMove`
9851
- * / `onEnd` calls. The store is `unknown`-valued because behaviors are
9852
- * tool-agnostic — a single behavior may run under different tools with
9853
- * different scratch shapes. Without a typing convention every read site
9854
- * has to `(ctx.scratch as <some shape>)[KEY]`, and a writer changing the
9855
- * shape can silently break readers with no compile-time signal.
9856
- *
9857
- * `ScratchKey<T>` is a phantom-typed string that carries its payload type
9858
- * via a branded interface. `getScratch` and `setScratch` use the brand to
9859
- * narrow / constrain at the typing layer; at runtime the key is just its
9860
- * underlying string and the store remains a plain `Record`.
9861
- *
9862
- * @example
9863
- * ```ts
9864
- * // Module-level (or behavior-level) constant, shared by writer + reader:
9865
- * const LASSO_VERTICES = scratchKey<readonly { x: number; y: number }[]>('lasso.vertices');
9866
- *
9867
- * // Writer (a tool's onMove):
9868
- * setScratch(ctx.scratch, LASSO_VERTICES, vertices);
9869
- *
9870
- * // Reader (a behavior's onEnd):
9871
- * const vertices = getScratch(ctx.scratch, LASSO_VERTICES) ?? [];
9872
- * // ^? readonly { x: number; y: number }[] | undefined
9873
- * ```
9874
- */
9875
- /** Phantom-typed key for a scratch slot. The `__scratchKeyPayload` phantom
9876
- * field carries the value type without occupying any runtime memory. */
9877
- interface ScratchKey<T> {
9878
- readonly name: string;
9879
- /** Phantom — never read at runtime. Only present so TypeScript can
9880
- * recover `T` at use sites. */
9881
- readonly __scratchKeyPayload?: (_: T) => T;
9882
- }
9883
- /** Compatible scratch store shape. The kit's gesture context's `scratch`
9884
- * field already satisfies this; consumers don't need to construct one. */
9885
- type ScratchStore = Record<string, unknown>;
9886
- /**
9887
- * Make a typed scratch key. Use module-level constants so the same key
9888
- * is shared by writer and reader.
9889
- *
9890
- * Namespace the name by behavior or feature to avoid collisions
9891
- * (`'behavior.field'` is a good convention). Two keys with the same
9892
- * `name` refer to the same slot at runtime — the type parameter is a
9893
- * compile-time contract, not a uniqueness guarantee.
9894
- */
9895
- declare function scratchKey<T>(name: string): ScratchKey<T>;
9896
- /** Read a typed slot from the scratch store. Returns `undefined` if
9897
- * nothing has been written under the key. */
9898
- declare function getScratch<T>(store: ScratchStore, key: ScratchKey<T>): T | undefined;
9899
- /** Write a value to a typed slot. Overwrites whatever was there. */
9900
- declare function setScratch<T>(store: ScratchStore, key: ScratchKey<T>, value: T): void;
9901
- /** Remove a slot from the scratch store. Returns `true` if it was set,
9902
- * `false` if it wasn't. */
9903
- declare function deleteScratch<T>(store: ScratchStore, key: ScratchKey<T>): boolean;
9904
-
9905
10858
  /** Options for `selectFromLasso`. */
9906
10859
  interface SelectFromLassoOptions {
9907
10860
  /** Hit mode for `hitTestLasso`. Default 'intersect'. */
@@ -9919,7 +10872,11 @@ type AlignEdge = 'left' | 'right' | 'top' | 'bottom' | 'center-x' | 'center-y';
9919
10872
  /** Adapter for `useAlign`. */
9920
10873
  interface AlignAdapter<TPose> {
9921
10874
  getSelection(): NodeId[];
10875
+ /** The pose as stored — local to the node's parent. */
9922
10876
  getPose(id: NodeId): TPose;
10877
+ /** The parent chain, for a scene whose container poses define a frame.
10878
+ * Omit it (or leave `composition` unset) for an absolute-pose scene. */
10879
+ getParent?(id: NodeId): NodeId | null;
9923
10880
  applyOps?(ops: Op[], label?: string): void;
9924
10881
  }
9925
10882
  /** Options for `useAlign`. */
@@ -9927,38 +10884,30 @@ interface UseAlignOptions<TPose> {
9927
10884
  /** Projection between `TPose` and bounds. Defaults to `RECT_POSE_DESCRIPTOR`
9928
10885
  * for `{x,y,width,height}` poses. Pass `pathPoseDescriptor` for `Path`
9929
10886
  * poses so polygon coords translate correctly. */
9930
- geometry?: PoseProjection<TPose>;
10887
+ geometry?: PoseDescriptor<TPose>;
9931
10888
  /** Label passed to applyOps. Default 'Align'. */
9932
10889
  label?: string;
10890
+ /** How local poses fold up to world. Default IDENTITY, where the two are
10891
+ * the same value and the alignment runs entirely in stored coordinates. */
10892
+ composition?: PoseComposition<TPose>;
9933
10893
  }
9934
10894
  /** Return shape of `useAlign`. */
9935
10895
  interface UseAlignReturn {
9936
10896
  /** Imperative trigger. No-op when fewer than 2 items selected. */
9937
10897
  align(edge: AlignEdge): void;
9938
10898
  }
9939
- /**
9940
- * The pose's *visual* bounds: its descriptor bounds expanded to cover the
9941
- * rotated rectangle, so a turned shape reports the extent of its ink rather
9942
- * than the box it was posed in. Align, distribute and flip all fold these.
9943
- *
9944
- * Both ends of an align must use it — a visual union measured against
9945
- * unrotated member boxes misplaces every rotated member. The expanded box
9946
- * shares its centre with the stored one, so the delta stays a translation of
9947
- * the stored pose and no re-posing is needed.
9948
- */
9949
- declare function visualBoundsViaDescriptor<TPose>(pose: TPose, geometry: PoseProjection<TPose>): ResizePose;
9950
10899
  /** Compute the (dx, dy) translation that moves AABB `b` so that the requested
9951
10900
  * `edge`/center matches the corresponding feature of the union AABB `u`. */
9952
- declare function alignDeltaFor(b: ResizePose, u: ResizePose, edge: AlignEdge): {
10901
+ declare function alignDeltaFor(b: Bounds, u: Bounds, edge: AlignEdge): {
9953
10902
  dx: number;
9954
10903
  dy: number;
9955
10904
  };
9956
- /** Translate `pose` by `(dx, dy)` using `geometry.translate` if available,
9957
- * otherwise via `remapBounds` with a translated `dst` rect. */
9958
- declare function translatePoseViaDescriptor<TPose>(pose: TPose, dx: number, dy: number, geometry: PoseProjection<TPose>): TPose;
9959
10905
  /** Align the current multi-selection to a shared edge or center of the
9960
10906
  * selection's union AABB. No-op when fewer than 2 items selected.
9961
- * Single batch — one undo step. */
10907
+ * Single batch — one undo step.
10908
+ *
10909
+ * The edge is a world edge: bounds are measured and translated in world, and
10910
+ * each result is stored back in its own parent's frame. */
9962
10911
  declare function useAlign<TPose>(adapter: AlignAdapter<TPose>, options?: UseAlignOptions<TPose>): UseAlignReturn;
9963
10912
 
9964
10913
  /** Axis along which selection is distributed. `'x'` spreads horizontally. */
@@ -9970,18 +10919,25 @@ type DistributeMode = 'centers' | 'gaps';
9970
10919
  /** Adapter for `useDistribute`. */
9971
10920
  interface DistributeAdapter<TPose> {
9972
10921
  getSelection(): NodeId[];
10922
+ /** The pose as stored — local to the node's parent. */
9973
10923
  getPose(id: NodeId): TPose;
10924
+ /** The parent chain, for a scene whose container poses define a frame.
10925
+ * Omit it (or leave `composition` unset) for an absolute-pose scene. */
10926
+ getParent?(id: NodeId): NodeId | null;
9974
10927
  applyOps?(ops: Op[], label?: string): void;
9975
10928
  }
9976
10929
  /** Options for `useDistribute`. */
9977
10930
  interface UseDistributeOptions<TPose> {
9978
10931
  /** Projection between `TPose` and bounds. Defaults to `RECT_POSE_DESCRIPTOR`
9979
10932
  * for `{x,y,width,height}` poses. */
9980
- geometry?: PoseProjection<TPose>;
10933
+ geometry?: PoseDescriptor<TPose>;
9981
10934
  /** Default mode when `distribute(axis)` is called without one. Default 'centers'. */
9982
10935
  defaultMode?: DistributeMode;
9983
10936
  /** Label passed to applyOps. Default 'Distribute'. */
9984
10937
  label?: string;
10938
+ /** How local poses fold up to world. Default IDENTITY, where the two are
10939
+ * the same value and the spread runs entirely in stored coordinates. */
10940
+ composition?: PoseComposition<TPose>;
9985
10941
  }
9986
10942
  /** Return shape of `useDistribute`. */
9987
10943
  interface UseDistributeReturn {
@@ -9990,7 +10946,10 @@ interface UseDistributeReturn {
9990
10946
  }
9991
10947
  /** Distribute the current multi-selection along `axis`. Requires ≥3 items;
9992
10948
  * no-op otherwise. Endpoints (min and max along the axis) stay put; the
9993
- * remaining items are repositioned. Single batch — one undo step. */
10949
+ * remaining items are repositioned. Single batch — one undo step.
10950
+ *
10951
+ * The span being divided is a world span: bounds are measured and translated
10952
+ * in world, and each result is stored back in its own parent's frame. */
9994
10953
  declare function useDistribute<TPose>(adapter: DistributeAdapter<TPose>, options?: UseDistributeOptions<TPose>): UseDistributeReturn;
9995
10954
 
9996
10955
  /** The six Boolean path operations, each acting on the current selection and
@@ -10122,7 +11081,7 @@ interface TweenPoseOptions<TPose> {
10122
11081
  easing?: EasingSpec;
10123
11082
  /** Pose descriptor with a `lerp(from, to, t)` method. Defaults to
10124
11083
  * `RECT_POSE_DESCRIPTOR`, which interpolates x/y/width/height linearly. */
10125
- geometry?: PoseProjection<TPose>;
11084
+ geometry?: PoseDescriptor<TPose>;
10126
11085
  /** When true (default), emit a transform op before the tween so undo
10127
11086
  * restores the pre-animation pose. */
10128
11087
  recordOp?: boolean;
@@ -10138,7 +11097,7 @@ interface SpringPoseOptions<TPose> {
10138
11097
  stiffness?: number;
10139
11098
  damping?: number;
10140
11099
  mass?: number;
10141
- geometry?: PoseProjection<TPose>;
11100
+ geometry?: PoseDescriptor<TPose>;
10142
11101
  recordOp?: boolean;
10143
11102
  opLabel?: string;
10144
11103
  onDone?: () => void;
@@ -10173,7 +11132,7 @@ interface AnimateOnSetPoseOptions<TPose> {
10173
11132
  damping?: number;
10174
11133
  mass?: number;
10175
11134
  };
10176
- geometry?: PoseProjection<TPose>;
11135
+ geometry?: PoseDescriptor<TPose>;
10177
11136
  /** Predicate: return false to skip animation and write through immediately. */
10178
11137
  shouldAnimate?: (id: string, from: TPose, to: TPose) => boolean;
10179
11138
  /** Convenience: when true, auto-skip animation if the id is currently being
@@ -10214,7 +11173,7 @@ interface LifecycleAnimation<TPose> {
10214
11173
  exitTo?: (current: TPose) => TPose;
10215
11174
  ms?: number;
10216
11175
  easing?: EasingSpec;
10217
- geometry?: PoseProjection<TPose>;
11176
+ geometry?: PoseDescriptor<TPose>;
10218
11177
  }
10219
11178
  /** Wrap an adapter so inserts and removals animate — the scene-graph
10220
11179
  * equivalent of CSS enter/leave transitions. */
@@ -10259,6 +11218,8 @@ interface MomentumOptions {
10259
11218
  * decays the velocity). Default 'stop'.
10260
11219
  */
10261
11220
  boundary?: 'stop' | 'continue';
11221
+ /** How to translate poses. Default `AUTO_POSE_DESCRIPTOR`. */
11222
+ poseDescriptor?: PoseDescriptor<unknown>;
10262
11223
  }
10263
11224
  /**
10264
11225
  * Move behavior that keeps a dragged node coasting after the pointer is
@@ -10730,43 +11691,6 @@ declare function CropIcon(): react_jsx_runtime.JSX.Element;
10730
11691
  declare const PAINTED_CURSOR_LAYER_ID = "painted-cursor";
10731
11692
  declare function createPaintedCursorLayer(state: PaintedCursorState): RenderLayer<unknown>;
10732
11693
 
10733
- /** What the registry knows at dispatch time. */
10734
- interface EligibilityState {
10735
- focusedId: string | null;
10736
- heldTriggers: ReadonlySet<string>;
10737
- /** Ids the host reports as hotkey-engaged. A declared `offhand` registers
10738
- * the binding, but `tool.offhand`'s invoker still reports engagement by
10739
- * pushing an id — this retires only if that contract changes. */
10740
- engagedIds?: ReadonlySet<string>;
10741
- /** Whether the active mode allows these capability tags. Omitted → allow. */
10742
- allows?: (tags: readonly CapabilityTag[]) => boolean;
10743
- }
10744
- /**
10745
- * The scope tier an entry's bindings are live at, or null when none are.
10746
- * Ordered hotkey > active > ambient to match the dispatcher's own walk.
10747
- */
10748
- declare function liveScope(id: string, eligibility: Eligibility, state: EligibilityState): BindingScope | null;
10749
-
10750
- /**
10751
- * Every binding the entry set contributes right now, each tiered by the
10752
- * entry's own declared eligibility. Entries with no live tier are omitted.
10753
- *
10754
- * Order is preserved: `matchSorted` sorts by specificity within a scope and
10755
- * breaks ties by declaration order, so the caller's entry order decides which
10756
- * of two same-specificity bindings in one tier wins.
10757
- */
10758
- declare function scopeBindings(entries: Iterable<Contribution>, state: EligibilityState): ScopedBinding[];
10759
-
10760
- /**
10761
- * Concatenate contribution bundles into one registry, preserving order —
10762
- * entry order decides which of two same-specificity bindings in one scope
10763
- * tier wins, so it is part of the result, not an accident of it.
10764
- *
10765
- * Throws on a duplicate id rather than dropping one: a feature silently
10766
- * losing its bindings is the failure this registry exists to make loud.
10767
- */
10768
- declare function mergeContributions(...bundles: readonly Contribution[][]): Contribution[];
10769
-
10770
11694
  /** Appearance of the dashed box drawn during a marquee or insert drag. */
10771
11695
  interface InsertOverlayStyle {
10772
11696
  fill?: string;
@@ -10775,4 +11699,4 @@ interface InsertOverlayStyle {
10775
11699
  lineWidth?: number;
10776
11700
  }
10777
11701
 
10778
- export { ANCHOR_HIT_BASE_PX, Action, type ActionShortcut, ActionsProp, ActionsProviderIfRoot, ActionsRegistry, Affordance, AffordanceBinding, AffordanceHit, AffordanceRegion, type AffordanceRegionHit, type AlignAdapter, type AlignAnchor, type AlignBounds, type AlignBoundsProjection, type AlignEdge, type AlignMatchResult, type AlignMoveArgs, type AlignmentBehaviorBase, type AnchorHit, type AnchorScratch, type AnchorState, type AnimateOnSetPoseOptions, AnimationHandle, Animator, AnyTool, AreaSelectAdapter, type ArrayAdapter, type ArrayAdapterConfig, ArrowIcon, BUILTIN_MARKERS, BUNDLE_TOOLS, BindingScope, BooleansAdapter, Bounds, BoundsConstraint, type BuildChromeCtxArgs, BuiltinShapeToolId, type BuiltinToolId, type BuiltinToolOptions, COARSE_TARGET_SCALE, CURVE_REPS, type CanvasExtensionApi, type CanvasFocusReturn, type CanvasHelpers, type CanvasProps, type CanvasSelectionMode, type CanvasSize, type CanvasSizeSnapshot, type CanvasSurfaceHelpers, CanvasView, type CanvasViewHelpers, type CanvasViewProps, type CaretIndexAtOpts, type CellHighlightLayerOpts, ChromeCtx, ChromeId, ChromeState, type ClampBounds, ClipboardSnapshot, type CoalescedCtx, type ColorInterpolate, ColorOverrideRegistry, type ColorSpace, CommonAffordanceScratch, type ComposeSelectionPoseOpts, type ComputeFitViewOptions, Condition, ContentHandlerEntry, Contribution, type CornerResizeAffordanceOptions, type CornerResizeScratch, type CreateChildrenLayerOpts, type CreateParallaxLayerOpts, type CreatePathEditingOverlayLayerOptions, type CreatePathLayerOpts, type CreatePenPreviewLayerOptions, type CreateTextLayerOpts, type CreateViewResolverOpts, type CreateViewportLayerOpts, CropIcon, CursorCoordsHud, type CursorCoordsHudProps, type CurveRepKind, type CurveRepresentation, type CustomLayerEntry, type CycleHandle, type CycleVertexColorsOptions, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_FLATTEN_TOLERANCE, DEFAULT_GUIDE_TOLERANCE_PX, DEFAULT_HANDLE_SIZE, DEFAULT_MAX_ZOOM, DEFAULT_MIN_ZOOM, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_SHAPE_FILL, DEFAULT_STROKE_COLOR, DEFAULT_VELOCITY_DECAY, DebugConfig, DebugSink, DebugSnapshot, DebugStrokes, DebugTheme, type DefaultTextData, DepRegistryProviderIfRoot, DepSchema, type DeriveAlignmentGuidesOptions, DetectedDeviceFacts, DeviceProfile, DeviceProfileProvider, type DeviceProfileProviderProps, Dims, type Discriminator, Dispatcher, type DistributeAdapter, type DistributeAxis, type DistributeMode, DivideIcon, type DragGestureController, type DragGestureCtx, type DragGestureEndCtx, type DragGesturePhase, type DragGesturePoint, type DragHandleOptions, type DragPanParams, type DragPayload, type DragRadialController, type DragRadialCtx, type DragRadialEndCtx, type DragRadialPoint, type DragRadialState, type DragRectBounds, type DragRectController, type DragRectCtx, type DragRectEndCtx, type DragRectPoint, DrawCommand, type DropZoneOptions, EasingSpec, Eligibility, type EligibilityState, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, type FillPoseBox, type FitTextPoseOptions, type FlagKey, type FreeformOptions, GHOST_STROKE, type GateLayerOptions, GeometryProjection, type GesturePreviewSource, type GestureSource, type GridLayerOpts, type GridSlotConfig, Guide, type GuideSnapOptions, type GuidesLayerOpts, HANDLE_BASE_PX, HandIcon, InertiaConfig as HandToolInertiaConfig, type HandleDragEnd, type HandleDragPoint, type HeadlessCanvasLike, type HostAnchorAlign, type HostAnchorInput, type HostAnchorOffset, type HostAnchorStyle, HotkeyTrigger, IDENTITY_JOINT, type IconProps, ImageIcon, type ImageNodeData, type ImageStatus, type IndicatorStyle, InertiaConfig, InsertAdapter, InsertBehavior, InsertExtras, type InsertNodeFactory, type InsertOp, type InsertOverlayStyle, IntersectIcon, type Joint, type JointTransform, KIT_STANDARD_ACTION_IDS, type LabelOptions, LassoHitMode, LassoIcon, LassoSelectAdapter, LassoSelectBehavior, LayerEnumerableAdapter, LayerGroup, LayerHit, type LayerSlotValue, type LayersMap, LayoutSnap, LayoutStrategy, type LifecycleAnimation, LineIcon, type LinePoint, MIXED, MOVE_ANCHORS, type MarkerCtx, type MarkerEntry, type MarkerPaint, type MarkerSite, type MarkerSiteRequest, Mat3$1 as Mat3, MinimapCanvas, type MinimapCanvasProps, type MinimapFit, type Mixed, ModifierState, type MomentumOptions, MoveAdapter, MoveBehavior, type NestedHitOpts, type NestedHitTester, type NodeClientRect, NodeId, type NodeInk, type NodeInkCtx, type NodeOverlayFrame, type NodePaintCtx, type NodeProperties, type NodePropertiesEntry, type NodeRouting, type NodeRoutingEntry, type NodeShapeEntry, type NodeSilhouetteCtx, OngoingOverlay, type OpenFilePickerOptions, OrderedAdapter, OriginProjection, type OverlayPoint, OverlayPosition, PAINTED_CURSOR_LAYER_ID, PATH_ANCHOR_CHROME_ID, type PaintBindContext, type PaintKind, type PaintKindEditorProps, type PaintKindEntry, type PaintProgram, type PaintedCursor, type PaintedCursorFrame, type PaintedCursorState, PanBounds, type ParallaxOpts, Path, type PathAnchor, type PathAnchorAffordanceOptions, PathBuilder, PathDrawCommand, type PathEditingOverlayStyle, PathFillRule, type PathInWorldPose, type PenAnchor, PenIcon, type PenPreviewStyle, type PenScratch, type PenSubpath, PencilIcon, type PencilPoint, PickHud, type PickHudProps, type PickTopMostHitAdapter, type PinchZoomOptions, type PixelRenderPlan, type PointInPathOptions, type PointInTextPoseOpts, PointSnapBehavior, PointerProviderIfRoot, type PointerSample, type PointerSession, type PointerSessionCallbacks, type PointerSessionCancelReason, type PointerSessionOptions, type PointerStylusState, PolygonIcon, PolygonPath, type PolygonPoint, type Pose, PoseProjection, type PoseRotation, type PressureToWidthOptions, type Pt, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, type RangeStyle, type RasterImage, RectIcon, RectPath, RectPose, type RegisterNodeShapeOptions, RegisteredOp, RenderLayer, type RenderSceneToCanvasArgs, type RenderSceneToPixelsArgs, type ReorderDirection, ResizeAdapter, ResizeAnchor, ResizePose, type ResolvableView, RotateAdapter, RotateBehavior, type RotateGeometry, RotatedPose, type RotationAffordanceOptions, type RotationHandle, type RotationScratch, Rule, RuleCtx, type RunStylePatch, SampledTrack, type ScalarOrXY, Scene, SceneAdapter, type SceneAdapterSelection, SceneCanvas, type SceneCanvasAdapter, type SceneCanvasApi, type SceneCanvasHit, type SceneCanvasProps, Node$1 as SceneNode, type SceneNodeClientRectOpts, SceneRegistry, type SceneSlotConfig, type SceneToAdapterOptions, SceneViewCanvas, type SceneViewCanvasProps, type SceneViewDrawOne, ScopedBinding, type ScratchKey, type ScratchStore, type SelectAdapter, type SelectFromLassoOptions, SelectIcon, SelectionApi, SelectionContextProvider, SelectionContextProviderIfRoot, type SelectionContextValue, type SelectionHandleStyle, type SelectionHandlesLayerOpts, type SelectionOutlineLayerOpts, type SelectionOverlayLayerOpts, type SelectionOverlaySlotConfig, SerializedScene, type SetFlagResult, type SetPathFields, ShaderProgramHandle, type ShapeCoversPointOptions, type SharedAnchor, type Simulation, type SimulationForce, type SimulationNode, type Skeleton, SliceDep, type SnapPattern, type SnapPointOptions, SnapStrategy, type SplitByLineOptions, type SpringPoseOptions, SpringPresetName, type SpringVertexColorsOptions, type StaggerVertexColorsOptions, type StandardSlotConfig, type StandardSlotName, StarIcon, type StarPoint, type StartEditOptions, type StyleKey, type StylusData, SubtractIcon, SvgIngestOptions, TOOL_PREF_KINDS, type TextEditScreenPose, type TextEditSelection, TextIcon, type ThresholdDragHandle, type ThresholdDragOptions, type TileGridOptions, type TilePatternOpts, Tool, type ToolBundle, ToolDef, ToolKeybinding, type ToolPref, type ToolPrefBoolean, type ToolPrefBooleanControl, type ToolPrefColor, type ToolPrefCustom, type ToolPrefEnum, type ToolPrefEnumControl, type ToolPrefEnumEncoding, type ToolPrefGroup, type ToolPrefKind, type ToolPrefLeaf, type ToolPrefNumber, type ToolPrefNumberControl, type ToolPrefNumberUnit, type ToolPrefObject, type ToolPrefPaint, type ToolPrefString, type ToolPrefStringControl, type ToolsApi, type TweenPoseOptions, type TweenVertexColorsOptions, UnionIcon, UnitSystem, UnitValue, UnknownIcon, type UseAlignOptions, type UseAlignReturn, UseAnimatorOptions, type UseArrayAdapterOptions, type UseBooleansOptions, type UseBooleansReturn, type UseCanvasFocusOptions, type UseDistributeOptions, type UseDistributeReturn, type UseDragGestureOptions, type UseDragRadialOptions, type UseDragRectOptions, type UseEyedropperToolOptions, type UseGestureDispatcherOptions, type UseGridCellHoverOptions, type UseGridCellHoverReturn, type UseGuidesReturn, type UseHandToolOptions, type UseHandleDragOptions, type UseHandleDragReturn, type UseHostAnchorOptions, type UseHoverTrackingArgs, type UseImageToolOptions, type UseKeybindingsOptions, type UseLassoSelectOptions, type UseLassoToolOptions, UseMoveOptions, type UseNodeOverlayFrameOptions, type UsePenToolOptions, type UsePointerStylusOptions, type UsePolygonToolOptions, UseResizeOptions, type UseResizePolicyOptions, type UseRotateOptions, type UseRotateToolOptions, UseSceneOptions, type UseSceneTextEditOptions, type UseSceneTextEditReturn, type UseSceneTrivialOptions, type UseSelectToolOptions, UseSelectionOptions, type UseSimulationOptions, type UseStandardActionsOptions, type UseStarToolOptions, type UseTextEditOptions, type UseTextEditReturn, type UseToolsOptions, VERSION, type Vec2, type VelocityTracker, VertexColorChannel, View, ViewAnimationOptions, type ViewRect, type ViewResolver, type ViewTarget, ViewTransform, ViewportDims, type ViewportLayer, ViewportToolDef, type ViewportZoomAnimateOptions, type ViewportZoomOptions, VisibilityRules, type VisibleRaf, type VisibleRafOptions, type VisibleRafTarget, WHEEL_ZOOM_STEP, WeaselProvider, type WheelInput, type WheelPanOptions, type WheelPanOpts, ZoomBound, type ZoomClampOpts, ZoomFactor, _resetMarkersForTests, _resetPaintKindsForTests, aabbCenter, actionIs, actionShortcuts, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyOpsTo, applyStyleToRange, areaSelectAction, arrayAdapter, asPaint, axisAlignedBounds, bezierCubic, bezierQuadratic, blendPoses, boundsOfPath, buildChromeCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clientToCanvas, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeSelectionPose, computeFitView, computeFitViewport, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDeleteOp, createGridLayer, createGuidesLayer, createHistory, createInsertOp, createMoveToIndexOp, createNodeProperties, createNodeRouting, createPaintedCursorLayer, createPaintedCursorState, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createReparentOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetSelectionOp, createSetTextOp, createTextLayer, createTilePattern, createTransformOp, createVelocityTracker, createViewResolver, createViewportLayer, cycleVertexColors, decomposePath, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deleteScratch, deriveAlignmentGuides, deriveParallaxView, dispatchApplyBatch, dlog, domPositionToCharOffset, domToRuns, dwarn, editAnchorsAction, ellipsePath, enumerateAnchors, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitZoom, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, focused, forEachCoalesced, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getMarker, getNodeShapes, getPaintKind, getScratch, getStylusData, gradientForBounds, gradientGeometry, guideSnapStrategy, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hostAnchorCss, hostAnchorRect, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, interpolateView, isBuiltinToolPref, isDebugEnabled, isEditableTarget, isGradientFill, isPatternSpec, keySpecShortcut, lassoSelectAction, lerpColorArray, lerpOklab, lerpOklch, linePath, listMarkers, listPaintKinds, liveScope, makePinchZoomAction, makeViewportWheelPanAction, makeViewportZoomAction, markerDrawCommands, markerInset, markerKeyOf, markerSites, matchAlignment, matchesKeyBinding, meanScale, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, openPointerSession, or, paintAlpha, paintKindOf, paintWithAlpha, paintWithColor, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathPoseDescriptor, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointInPath, pointInRotatedRect, pointInTextPose, polygonFromPoints, polylineFromPoints, poseRotationOf, pressureToWidth, pxExtent, rainbowVertexColors, rebuildOp, rectCorners, rectPath, registerMarker, registerNodeShape, registerOpFactory, registerPaintKind, registeredOpNames, regularPolygonPath, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveFillPattern, resolveMarkerSize, resolvePatternSpec, resolveSkeleton, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, sampleGradientStops, sampleTrack, scaleDelta, scalePathToBounds, sceneFromJSON, sceneNodeClientRect, sceneSelectionStore, sceneToAdapter, scopeBindings, scratchKey, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, setScratch, shapeCoversPoint, snap, snapPoint, solid, solidVertexColors, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, starPath, startThresholdDrag, strokeInsets, strokeOf, strokeWith, styleAtRange, subscribeImageReady, textCommand, textCommandFromRuns, tileGrid, toHex8, transformPath, translatePath, translatePolygonInPlace, translatePoseViaDescriptor, trimPolyline, tweenPose, tweenVertexColors, unionAABB, unionBounds, unionBoundsPath, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGestureDispatcher, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHostAnchor, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useNodeOverlayFrame, usePenTool, usePencilTool, usePinchGesture, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useVisibleRaf, viewportDragPanAction, viewportWheelPanAction, viewportZoomAction, viewportsAt, visualBoundsViaDescriptor, wheelPan, wheelZoom, wheelZoomFactor, when, withAlpha01, withCoord, withGradientKind, withinPxBox, withinPxRadius, worldEditToStorage, zoomAt, zoomAtLeast };
11702
+ export { ANCHOR_HIT_BASE_PX, type ActionShortcut, ActionsProviderIfRoot, type Affordance, type AffordanceBinding, type AffordanceRegion, type AffordanceRegionHit, type AlignAdapter, type AlignAnchor, type AlignEdge, type AlignMatchResult, type AlignMoveArgs, type AlignmentBehaviorBase, type AnchorHit, type AnchorScratch, type AnchorState, type AnimateOnSetPoseOptions, AnimationHandle, Animator, type AnyTool, AreaSelectAdapter, type ArrayAdapter, type ArrayAdapterConfig, ArrowIcon, BUILTIN_MARKERS, BUNDLE_TOOLS, BooleansAdapter, BoundsConstraint, type BuildChromeCtxArgs, type BuiltinShapeToolId, type BuiltinToolId, type BuiltinToolOptions, CURVE_REPS, type CanvasExtensionApi, type CanvasFocusReturn, type CanvasHelpers, type CanvasProps, type CanvasSelectionMode, type CanvasSize, type CanvasSizeSnapshot, type CanvasSurfaceHelpers, CanvasView, type CanvasViewHandle, type CanvasViewHelpers, type CanvasViewProps, type CellHighlightLayerOpts, type ChromeCtx, type ChromeId, type ChromeState, type ClampBounds, ClipboardSnapshot, type CoalescedCtx, type ColorInterpolate, ColorOverrideRegistry, type ColorSpace, type CommonAffordanceScratch, type ComposeSelectionPoseOpts, type ComputeFitViewOptions, type Condition, ContentHandlerEntry, type Contribution, type ContributionChrome, type CornerResizeAffordanceOptions, type CornerResizeScratch, type CreateChildrenLayerOpts, type CreateParallaxLayerOpts, type CreatePathEditingOverlayLayerOptions, type CreatePathLayerOpts, type CreatePenPreviewLayerOptions, type CreateTextLayerOpts, type CreateViewResolverOpts, type CreateViewportLayerOpts, CropIcon, CursorCoordsHud, type CursorCoordsHudProps, type CurveRepKind, type CurveRepresentation, type CustomLayerEntry, type CustomPaintContext, type CycleHandle, type CycleVertexColorsOptions, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_FILL_COLOR, DEFAULT_GUIDE_TOLERANCE_PX, DEFAULT_HANDLE_SIZE, DEFAULT_MAX_ZOOM, DEFAULT_MIN_ZOOM, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_SHAPE_FILL, DEFAULT_STROKE_COLOR, DEFAULT_VELOCITY_DECAY, type DebugConfig, type DebugFeature, type DebugSnapshot, type DebugStroke, type DebugStrokes, type DebugTheme, type DefaultTextData, DepRegistryProviderIfRoot, type DeriveAlignmentGuidesOptions, DerivedDep, DeviceProfileProvider, type DeviceProfileProviderProps, type Dims, type Discriminator, type DistributeAdapter, type DistributeAxis, type DistributeMode, DivideIcon, type DragGestureController, type DragGestureCtx, type DragGestureEndCtx, type DragGesturePhase, type DragGesturePoint, type DragHandleOptions, type DragPanParams, type DragPayload, type DragRadialController, type DragRadialCtx, type DragRadialEndCtx, type DragRadialPoint, type DragRadialState, type DragRectBounds, type DragRectController, type DragRectCtx, type DragRectEndCtx, type DragRectPoint, DrawCommand, type DropZoneOptions, EasingSpec, Effect, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, type FeedDelta, type FeedNode, type FillPoseBox, type FitTextPoseOptions, type FlagKey, type FreeformOptions, GHOST_STROKE, type GateLayerOptions, GeometryProjection, type GesturePreviewSource, type GestureSource, type GridLayerOpts, type GridSlotConfig, Guide, type GuideSnapOptions, type GuidesLayerOpts, HANDLE_BASE_PX, HandIcon, InertiaConfig as HandToolInertiaConfig, type HandleDragEnd, type HandleDragPoint, type HeadlessCanvasLike, type HostAnchorAlign, type HostAnchorInput, type HostAnchorOffset, type HostAnchorStyle, IDENTITY_JOINT, type IconProps, ImageIcon, type ImageNodeData, type ImageStatus, type IndicatorStyle, InertiaConfig, InsertAdapter, InsertBehavior, InsertExtras, type InsertNodeFactory, type InsertOp, type InsertOverlayStyle, type InsertPreviewExtent, type InsertPreviewGeometry, type InsertPreviewLike, type InsertPreviewOverlay, IntersectIcon, type Joint, type JointTransform, KIT_SHAPE_KINDS, KIT_STANDARD_ACTION_IDS, type LabelOptions, LassoHitMode, LassoIcon, LassoSelectAdapter, LassoSelectBehavior, type LayerCommandCache, type LayerDrawFailure, LayerEnumerableAdapter, type LayerGroup, type LayerHit, type LayerSlotValue, type LayersMap, LayoutSnap, LayoutStrategy, type LifecycleAnimation, LineIcon, type LinePoint, MIXED, MOVE_ANCHORS, type MarkerCtx, type MarkerEntry, type MarkerPaint, type MarkerSite, type MarkerSiteRequest, Mat3$1 as Mat3, MinimapCanvas, type MinimapCanvasProps, type MinimapFit, type Mixed, type MomentumOptions, MoveAdapter, MoveBehavior, type NestedHitOpts, type NestedHitTester, type NodeClientRect, type NodeInk, type NodeInkCtx, type NodeOverlayFrame, type NodePaintCtx, type NodeProperties, type NodePropertiesEntry, type NodeRouting, type NodeRoutingEntry, type NodeShapeEntry, type NodeSilhouetteCtx, type OpenFilePickerOptions, OrderedAdapter, OriginProjection, type OverlayPoint, type OverlayVisibilityId, PAINTED_CURSOR_LAYER_ID, PATH_ANCHOR_CHROME_ID, type PaintBindContext, type PaintKind, type PaintKindEditorProps, type PaintKindEntry, type PaintProgram, PanBounds, type ParallaxOpts, Path, type PathAnchor, type PathAnchorAffordanceOptions, PathBuilder, PathDrawCommand, type PathEditingOverlayStyle, PathFillRule, type PathInWorldPose, type PathStation, type PenAnchor, PenIcon, type PenPreviewStyle, type PenScratch, type PenSubpath, PencilIcon, type PencilPoint, PickHud, type PickHudProps, type PickTopMostHitAdapter, type PinchZoomOptions, type PixelRenderPlan, type PointAlongPathOptions, type PointInPathOptions, type PointInTextPoseOpts, PointSnapBehavior, PointerProviderIfRoot, type PointerSample, type PointerStylusState, PolygonIcon, PolygonPath, type PolygonPoint, type Pose, PoseComposition, PoseDescriptor, type PoseFeed, PoseOverrides, type PoseRotation, type PoseRun, type PoseRunCtx, type PoseRunStep, type PoseSource, type PosedNode, type PressureToWidthOptions, type PreviewNode, type Pt, ROTATION_HANDLE_BASE_PX, type RangeStyle, type RasterImage, type RecordedBounds, type RecordedHandle, type RecordedHitbox, type RecordedLayer, type RecordedOrigin, type RecordedSnap, RectIcon, RectPath, RectPose, type RegisterNodeShapeOptions, RegisteredOp, type RenderLayer, type RenderSceneToCanvasArgs, type RenderSceneToPixelsArgs, type ReorderDirection, ResizeAdapter, type ResolvableView, type ResolvedOverlay, RotateAdapter, RotateBehavior, RotatedPose, type RotationAffordanceOptions, type RotationHandle, type RotationScratch, type RunStylePatch, SampledTrack, type ScalarOrXY, Scene, SceneAdapter, type SceneAdapterSelection, SceneCanvas, type SceneCanvasAdapter, type SceneCanvasApi, type SceneCanvasHit, type SceneCanvasProps, Node$1 as SceneNode, type SceneNodeClientRectOpts, SceneRegistry, type SceneSlotConfig, type SceneToAdapterOptions, SceneViewCanvas, type SceneViewCanvasProps, type SceneViewDrawOne, type SceneViewLayers, type SelectAdapter, type SelectFromLassoOptions, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, type SelectionContextValue, type SelectionHandleStyle, type SelectionHandlesLayerOpts, type SelectionOutlineLayerOpts, type SelectionOverlayLayerOpts, type SelectionOverlaySlotConfig, SerializedScene, type SetFlagResult, type SetPathFields, ShaderProgramHandle, type ShapeCoversPointOptions, type SharedAnchor, type Simulation, type SimulationCore, type SimulationForce, type SimulationNode, type SimulationOptions, type Skeleton, SliceDep, type SnapPattern, type SnapPointOptions, SnapStrategy, type SplitByLineOptions, type SpringPoseOptions, SpringPresetName, type SpringVertexColorsOptions, type StaggerVertexColorsOptions, type StandardSlotConfig, type StandardSlotName, StarIcon, type StarPoint, type StartEditOptions, type StyleKey, type StylusData, SubtractIcon, SvgIngestOptions, TOOL_PREF_KINDS, TextDrawCommand, type TextEditClipRect, type TextEditScreenPose, type TextEditSelection, TextIcon, type ThresholdDragHandle, type ThresholdDragOptions, type TileGridOptions, type TilePatternOpts, type Tool, type ToolBundle, type ToolDef, type ToolPref, type ToolPrefBoolean, type ToolPrefBooleanControl, type ToolPrefColor, type ToolPrefCustom, type ToolPrefEnum, type ToolPrefEnumControl, type ToolPrefEnumEncoding, type ToolPrefGroup, type ToolPrefKind, type ToolPrefLeaf, type ToolPrefNumber, type ToolPrefNumberControl, type ToolPrefNumberFormat, type ToolPrefNumberUnit, type ToolPrefObject, type ToolPrefPaint, type ToolPrefString, type ToolPrefStringControl, type ToolsApi, type TweenPoseOptions, type TweenVertexColorsOptions, UNION_OF_CHILDREN, UnionIcon, Unit, UnitSystem, UnitValue, UnknownIcon, type UseAlignOptions, type UseAlignReturn, UseAnimatorOptions, type UseArrayAdapterOptions, type UseBooleansOptions, type UseBooleansReturn, type UseCanvasFocusOptions, type UseDistributeOptions, type UseDistributeReturn, type UseDragGestureOptions, type UseDragRadialOptions, type UseDragRectOptions, type UseEyedropperToolOptions, type UseGridCellHoverOptions, type UseGridCellHoverReturn, type UseGuidesReturn, type UseHandToolOptions, type UseHandleDragOptions, type UseHandleDragReturn, type UseHostAnchorOptions, type UseHoverTrackingArgs, type UseImageToolOptions, type UseKeybindingsOptions, type UseLassoSelectOptions, type UseLassoToolOptions, UseMoveOptions, type UseNodeOverlayFrameOptions, type UsePenToolOptions, type UsePointerStylusOptions, type UsePolygonToolOptions, type UsePoseRunOptions, UseResizeOptions, type UseResizePolicyOptions, type UseRotateOptions, type UseRotateToolOptions, UseSceneOptions, type UseSceneTextEditOptions, type UseSceneTextEditReturn, type UseSceneTrivialOptions, type UseSelectToolOptions, type UseSelectionOptions, type UseSimulationOptions, type UseStandardActionsOptions, type UseStarToolOptions, type UseTextEditOptions, type UseTextEditReturn, type UseToolsOptions, VERSION, type Vec2, type VelocityTracker, VertexColorChannel, ViewAnimationOptions, type ViewRect, type ViewResolver, type ViewTarget, type ViewTransform, ViewportDims, type ViewportLayer, type ViewportToolDef, type ViewportZoomAnimateOptions, type ViewportZoomOptions, type VisibilityRules, type VisibleRaf, type VisibleRafOptions, type VisibleRafTarget, WHEEL_ZOOM_STEP, WeaselProvider, type WheelInput, type WheelPanOptions, type WheelPanOpts, ZOOM_FLOOR, type ZoomBound, type ZoomClampOpts, type ZoomFactor, _resetMarkersForTests, _resetPaintKindsForTests, aabbCenter, actionIs, actionShortcuts, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyOpsTo, applyStyleToRange, areaSelectAction, arrayAdapter, asPaint, axisAlignedBounds, bezierCubic, bezierQuadratic, blendPoses, boundsOfPath, buildChromeCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clipboardCopyAction, clipboardCutAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeSelectionPose, computeFitView, computeFitViewport, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDeleteOp, createGridLayer, createGuidesLayer, createHistory, createInsertOp, createMoveToIndexOp, createNodeProperties, createNodeRouting, createPaintedCursorLayer, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createPoseFeed, createPoseOverrides, createReorderOp, createReparentOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetSelectionOp, createSetTextOp, createSimulation, createTextLayer, createTilePattern, createTransformOp, createVelocityTracker, createViewResolver, createViewportLayer, cycleVertexColors, decomposePath, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deriveAlignmentGuides, deriveParallaxView, derivedDepOf, derivedPose, dispatchApplyBatch, dlog, documentPose, domPositionToCharOffset, domToRuns, drawLayers, drawOneLayer, dwarn, editAnchorsAction, effectivePose, ellipsePath, enterTextEditAction, enumerateAnchors, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitZoom, flattenPreviews, focused, forEachCoalesced, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getMarker, getNodeShapes, getPaintKind, getStylusData, gradientForBounds, gradientGeometry, guideSnapStrategy, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hostAnchorCss, hostAnchorRect, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, insertPreviewExtent, interpolateView, isBuiltinToolPref, isDebugEnabled, isGradientFill, isLayerPainted, isLayerVisible, isPatternSpec, keySpecShortcut, lassoSelectAction, lerpColorArray, lerpOklab, lerpOklch, linePath, listMarkers, listPaintKinds, makePinchZoomAction, makeViewportWheelPanAction, makeViewportZoomAction, markerDrawCommands, markerInset, markerKeyOf, markerSites, matchAlignment, meanScale, mergeAlphaFromPrev, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, normalizeView, normalizeZoom, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, or, paintAlpha, paintKindOf, paintWithAlpha, paintWithColor, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathPoseDescriptor, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointAlongPath, pointInPath, pointInRotatedRect, pointInTextPose, polygonFromPoints, polylineFromPoints, poseRotationOf, prefUnit, pressureToWidth, pxExtent, rainbowVertexColors, rebuildOp, rectCorners, rectPath, registerMarker, registerNodeShape, registerOpFactory, registerPaintKind, registeredOpNames, regularPolygonPath, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveFillPattern, resolveMarkerSize, resolveOverlays, resolvePatternSpec, resolvePreviews, resolveSkeleton, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, sampleGradientStops, sampleTrack, scaleDelta, scalePathToBounds, sceneFromJSON, sceneNodeClientRect, sceneSelectionStore, sceneToAdapter, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snap, snapPoint, solid, solidVertexColors, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, starPath, startThresholdDrag, strokeInsets, strokeOf, strokeWith, styleAtRange, subscribeImageReady, textCommand, textCommandFromPose, textCommandFromRuns, tileGrid, toHex8, transformPath, translatePath, translatePolygonInPlace, trimPolyline, tweenPose, tweenVertexColors, unionAABB, unionBounds, unionBoundsPath, unionOfChildren, unionOfChildrenVia, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHostAnchor, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useNodeOverlayFrame, usePenTool, usePencilTool, usePinchGesture, usePointerStylus, usePolygonTool, usePoseCompositionDepSource, usePoseDescriptorDepSource, usePoseRun, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useVisibleRaf, viewToTransform, viewZoom, viewportDragPanAction, viewportWheelPanAction, viewportZoomAction, viewportsAt, wheelPan, wheelZoom, wheelZoomFactor, when, withAlpha01, withCoord, withGradientKind, withinPxBox, withinPxRadius, worldEditToStorage, worldToScreen, zoomAt, zoomAtLeast };