@weasel-js/core 1.4.4 → 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 +937 -2202
  2. package/README.md +118 -75
  3. package/dist/{autoPoseDescriptor-DF1SnnSx.d.ts → autoPoseDescriptor-CvjflWJK.d.ts} +29 -26
  4. package/dist/{chunk-2VXGHUVL.js → chunk-BDWAA634.js} +4 -22
  5. package/dist/chunk-BDWAA634.js.map +1 -0
  6. package/dist/{chunk-R3AWPTLZ.js → chunk-MG7OXCAI.js} +2760 -4491
  7. package/dist/chunk-MG7OXCAI.js.map +1 -0
  8. package/dist/{chunk-PRGBGMH3.js → chunk-MQI4PIX3.js} +3 -3
  9. package/dist/chunk-MQI4PIX3.js.map +1 -0
  10. package/dist/{chunk-WPM42WJP.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-0Pbn5B2C.d.ts → grid-BrIa38gG.d.ts} +7 -10
  16. package/dist/index.d.ts +1996 -1229
  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-DbYLImvq.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 -12
  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-ei3UMl9R.d.ts → types-DMyo7dnM.d.ts} +12 -41
  33. package/dist/{types-DEALFt5F.d.ts → types-DtjCJA5r.d.ts} +9 -3
  34. package/package.json +13 -10
  35. package/dist/DrawCommand-CD-ug3d9.d.ts +0 -332
  36. package/dist/builtins-BXFBXegF.d.ts +0 -840
  37. package/dist/chunk-2VXGHUVL.js.map +0 -1
  38. package/dist/chunk-BL65SHCX.js +0 -573
  39. package/dist/chunk-BL65SHCX.js.map +0 -1
  40. package/dist/chunk-PRGBGMH3.js.map +0 -1
  41. package/dist/chunk-R3AWPTLZ.js.map +0 -1
  42. package/dist/chunk-WPM42WJP.js.map +0 -1
  43. package/dist/geometry-6fCNhAux.d.ts +0 -114
  44. package/dist/path-JEV2c5If.d.ts +0 -48
  45. package/dist/registry-BY-wI9gm.d.ts +0 -4003
  46. package/dist/types-BHK2dkMu.d.ts +0 -172
  47. package/dist/types-bcc7jcUy.d.ts +0 -594
  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-0Pbn5B2C.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-0Pbn5B2C.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-BY-wI9gm.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-BY-wI9gm.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 { N as NodeId, S as Scene, R as RectPose, a as Node$1, b as SerializedScene, U as UseSceneOptions, c as SceneRegistry, d as RegisteredOp, P as PoseOverrides, D as DerivedDep } from './types-bcc7jcUy.js';
12
- export { A as AddLayerSpec, e as AddNodeSpec, C as ContainerNode, L as LayerRecord, f as LeafNode, g as PoseOverride, h as SerializedNode, i as SystemLayerRecord, j as SystemLayerSpec, k as UserLayerRecord, l as asNodeId } from './types-bcc7jcUy.js';
13
- import { B as Bounds, P as PoseProjection, V as ViewportDims } from './geometry-6fCNhAux.js';
14
- export { F as FitViewToBoundsOptions, R as RECT_POSE_DESCRIPTOR, a as ROTATED_POSE_DESCRIPTOR, f as fitViewToBounds } from './geometry-6fCNhAux.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-ei3UMl9R.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-ei3UMl9R.js';
19
- import { U as UseResizeOptions } from './autoPoseDescriptor-DF1SnnSx.js';
20
- export { A as AUTO_POSE_DESCRIPTOR, C as CORNER_ANCHORS, a as CornerAnchor, e as CornerEdge, b as CornerHandle, c as cornerPoint, d as cornerResizeHandles, h as hitCornerHandle, i as isPathLike, p as pointSnapToGrid } from './autoPoseDescriptor-DF1SnnSx.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-DEALFt5F.js';
24
- export { g as ContainerBounds, D as DropTarget, h as LayoutChild, i as LayoutContainer, j as LayoutDragged, S as SnapTarget } from './types-DEALFt5F.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-BXFBXegF.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-BXFBXegF.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-DbYLImvq.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
 
@@ -670,7 +1200,8 @@ interface NodeOverlayFrame {
670
1200
  };
671
1201
  /** Node box frame → overlay pixels, rotation and view included. */
672
1202
  toScreen: (p: OverlayPoint) => OverlayPoint;
673
- /** 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. */
674
1205
  toLocal: (p: OverlayPoint) => OverlayPoint;
675
1206
  /** The container's size in CSS pixels — the overlay's own box. */
676
1207
  width: number;
@@ -890,7 +1421,8 @@ interface Scale2 {
890
1421
  x: number;
891
1422
  y: number;
892
1423
  }
893
- /** 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`). */
894
1426
  declare function pxExtent(px: number, scale: Scale2): {
895
1427
  x: number;
896
1428
  y: number;
@@ -913,59 +1445,6 @@ declare function withinPxBox(dx: number, dy: number, px: number, scale: Scale2):
913
1445
  /** Is a world-space delta inside a screen-space circle of radius `px`? */
914
1446
  declare function withinPxRadius(dx: number, dy: number, px: number, scale: Scale2): boolean;
915
1447
 
916
- /**
917
- * The DOM half of a drag: one pointer, held down, from press to release.
918
- *
919
- * Every pointerdown-to-pointerup lifecycle in the kit used to answer capture,
920
- * pointer identity, teardown and lost-pointer recovery for itself, and each
921
- * answered them differently. This is the one place those are decided; anything
922
- * above it — thresholds, coordinate spaces, what the drag *means* — belongs to
923
- * its caller.
924
- */
925
- /** Why a session ended without the pointer being released. */
926
- type PointerSessionCancelReason =
927
- /** The browser cancelled the pointer (touch interrupted, palm rejection). */
928
- 'pointercancel'
929
- /** The origin left the document mid-gesture, taking capture with it. */
930
- | 'lostcapture'
931
- /** `cancel()` — an unmount, a window blur, Escape, a consumer's own rule. */
932
- | 'aborted'
933
- /** A new press arrived on this pointer, so the tracked one had ended. */
934
- | 'superseded';
935
- interface PointerSessionCallbacks {
936
- /** Every move belonging to this pointer, while it is still held. */
937
- onMove?: (e: PointerEvent) => void;
938
- /** The pointer was released. Fires once, before teardown completes. */
939
- onEnd?: (e: PointerEvent) => void;
940
- /** The session ended without a release. Fires once. */
941
- onCancel?: (reason: PointerSessionCancelReason) => void;
942
- }
943
- interface PointerSessionOptions {
944
- /** Ask the origin element to capture the pointer. Default `true`. Capture
945
- * keeps hover and click off everything the drag passes over; the session
946
- * does not depend on it to keep receiving events. */
947
- capture?: boolean;
948
- }
949
- interface PointerSession {
950
- readonly pointerId: number;
951
- /** False once the session has ended, by any route. */
952
- readonly active: boolean;
953
- /** End the session now, reporting `'aborted'`. Idempotent. */
954
- cancel: () => void;
955
- }
956
- /**
957
- * Open a session for the pointer that `down` belongs to.
958
- *
959
- * Listens on the origin's document rather than on the element: a captured
960
- * element that is removed mid-drag stops receiving events, and every listener
961
- * hung on it goes with it. Three recovery rules close the gaps a plain
962
- * pointerup/pointercancel pair leaves — losing capture cancels only once the
963
- * origin has left the document, a move reporting no held button is read as
964
- * the release that never arrived, and a fresh press on the same pointer says
965
- * the tracked one had already ended.
966
- */
967
- declare function openPointerSession(origin: Element, down: PointerEvent | React.PointerEvent, cb: PointerSessionCallbacks, opts?: PointerSessionOptions): PointerSession;
968
-
969
1448
  /** A 2D point in the rect element's local coordinate space. */
970
1449
  interface HandleDragPoint {
971
1450
  x: number;
@@ -1119,33 +1598,6 @@ interface CanvasSizeSnapshot extends CanvasSize {
1119
1598
  * query instead. */
1120
1599
  declare function useCanvasSize(containerRef: RefObject<HTMLElement | null>): CanvasSizeSnapshot;
1121
1600
 
1122
- /**
1123
- * Handle/hit multiplier applied on a coarse pointer.
1124
- *
1125
- * 8px handle → 14px; 24px rotation distance → 42px. Counting the
1126
- * surrounding grab zone, that lands in the Apple HIG 44pt / Material 48dp
1127
- * minimum-touch-target band. One constant so it is tunable in one place.
1128
- */
1129
- declare const COARSE_TARGET_SCALE = 1.75;
1130
- /**
1131
- * Fold consumer overrides over detected facts and derive `targetScale`.
1132
- *
1133
- * `targetScale` is re-derived AFTER the merge, so an override of
1134
- * `coarsePointer` alone scales the chrome as expected. An explicit
1135
- * `targetScale` override wins over the derivation.
1136
- */
1137
- declare function resolveDeviceProfile(detected: DetectedDeviceFacts, overrides?: Partial<DeviceProfile>): DeviceProfile;
1138
- /**
1139
- * Assumed when `matchMedia` is unavailable (SSR, jsdom) and used as the
1140
- * absent-means value for `RuleCtx.device`.
1141
- *
1142
- * Derived from `resolveDeviceProfile` rather than hand-written, so it can
1143
- * never drift from what the function would compute for the same facts. A
1144
- * mouse-like device is the safe default: it is what the kit has always
1145
- * assumed, so an absent profile changes nothing for existing consumers.
1146
- */
1147
- declare const DEFAULT_DEVICE_PROFILE: DeviceProfile;
1148
-
1149
1601
  /**
1150
1602
  * Base sizes for grabbable chrome, in CSS pixels at `targetScale = 1`, and the
1151
1603
  * one accessor that resolves them for a live pointer type.
@@ -1219,7 +1671,7 @@ interface ZoomClampOpts {
1219
1671
  min?: ZoomBound;
1220
1672
  max?: ZoomBound;
1221
1673
  }
1222
- declare function zoomAt(view: View, anchor: {
1674
+ declare function zoomAt(input: View, anchor: {
1223
1675
  x: number;
1224
1676
  y: number;
1225
1677
  }, factor: ZoomFactor, opts?: ZoomClampOpts): View;
@@ -1235,6 +1687,23 @@ declare function zoomAt(view: View, anchor: {
1235
1687
  */
1236
1688
  declare const DEFAULT_MIN_ZOOM = 0.1;
1237
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;
1238
1707
 
1239
1708
  /** Options for {@link sceneNodeClientRect}. */
1240
1709
  interface SceneNodeClientRectOpts {
@@ -1285,323 +1754,86 @@ declare function computeFitViewport(viewportW: number, viewportH: number, conten
1285
1754
  declare function useAutoCenter(width: number, height: number, contentW: number, contentH: number, setZoom: (z: number) => void, setPan: (x: number, y: number) => void): void;
1286
1755
 
1287
1756
  /**
1288
- * Pure keyboard-binding helpers shared between the tool dispatcher
1289
- * (`useKeybindings`), the gesture dispatcher (`useGestureDispatcher`), and
1290
- * individual Tool declarations.
1291
- *
1292
- * Extracted from the deleted singular `useKeybinding` hook so the remaining
1293
- * consumers don't depend on its disappearance.
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.
1294
1761
  */
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
+ }
1295
1772
  /**
1296
- * @internal — runtime shape consumed by `matchesKeyBinding`. Public tool authors
1297
- * should use `ToolKeybinding` from `@weasel-js/core` for declaring
1298
- * configurable activation keys.
1773
+ * The chip form of a single gesture spec, or `undefined` when the spec has
1774
+ * none.
1775
+ *
1776
+ * Two kinds of collapsing, both because a binding list is written for a
1777
+ * matcher rather than for a reader:
1778
+ *
1779
+ * - A spec's `key` may list spellings of one keycap (`['[', '{']` — the
1780
+ * shifted bracket reports as `'{'`). The first is the shortcut's name.
1781
+ * - A modifier declared `'optional'` matches held or unheld, so it isn't
1782
+ * part of what the user has to press.
1783
+ *
1784
+ * Non-keyboard specs (drag, wheel, click) have no chip form. Neither does a
1785
+ * *required* `ctrl` or `meta` — nothing in the kit declares one, and the
1786
+ * display shape carries only `mod`.
1299
1787
  */
1300
- interface KeyBinding {
1301
- /**
1302
- * Key or list of keys to match. Compared case-insensitively against
1303
- * `event.key`, so `'a'` matches both `'a'` and `'A'`.
1304
- */
1305
- key: string | readonly string[];
1306
- /**
1307
- * Require Cmd (mac) or Ctrl (others). When `true`, exactly one of
1308
- * `metaKey`/`ctrlKey` must be held. Default `false` (both forbidden).
1309
- */
1310
- mod?: boolean;
1311
- /** Require Alt. Default `false` (forbidden). */
1312
- alt?: boolean;
1313
- /**
1314
- * Shift policy. `undefined`/`false` forbids shift, `true` requires
1315
- * shift, `'optional'` allows either. Default `undefined`.
1316
- */
1317
- shift?: boolean | 'optional';
1318
- /** Skip when focus is in an editable element. Default `true`. */
1319
- skipInEditable?: boolean;
1320
- /** When `false`, the listener is not attached. Default `true`. */
1321
- enabled?: boolean;
1322
- /** Call `preventDefault` before the handler. Default `true`. */
1323
- preventDefault?: boolean;
1324
- }
1325
- /** Returns true when the target is an input, textarea, or contenteditable element. */
1326
- declare function isEditableTarget(target: EventTarget | null): boolean;
1788
+ declare function keySpecShortcut(spec: GestureSpec): ActionShortcut | undefined;
1327
1789
  /**
1328
- * Pure matcher for `KeyBinding` against a `KeyboardEvent`. Only checks key +
1329
- * modifier policy — does NOT apply the editable-target skip or
1330
- * `preventDefault`. Shared by the tool dispatcher (`useKeybindings`) and the
1331
- * gesture dispatcher so the rules can't drift.
1790
+ * Every keyboard shortcut an action answers to, in declaration order.
1791
+ * Specs `keySpecShortcut` has no chip for are skipped, and bindings it leaves
1792
+ * identical are emitted once; an action bound only to those returns empty.
1332
1793
  */
1333
- declare function matchesKeyBinding(e: KeyboardEvent, b: KeyBinding): boolean;
1794
+ declare function actionShortcuts(action: Action): readonly ActionShortcut[];
1334
1795
 
1335
1796
  /**
1336
- * Promote a Rule tree to a fluent Condition. The function form evaluates
1337
- * the tree against a RuleCtx; combinator methods produce new Conditions
1338
- * wrapping `all`/`any`/`not` nodes.
1797
+ * `moveAction` — first `ongoing`-timing Action descriptor.
1339
1798
  *
1340
- * **Chain semantics: strict left-to-right.** No boolean precedence.
1341
- * `focused.or(hovering).and(selectionIs(1))` evaluates
1342
- * `((focused || hovering) && selectionIs(1))` — NOT
1343
- * `(focused || (hovering && selectionIs(1)))` as standard precedence
1344
- * would give. For grouped disjunction, use the top-level `or` / `and` /
1345
- * `not` helpers or name intermediates.
1799
+ * Mirrors the per-frame translate semantics of the `useMove` hook:
1800
+ * - `start`: capture origin poses for all selected nodes; record the
1801
+ * current drag delta in scratch each frame.
1802
+ * - `onMove`: update the in-scratch `currentDelta`, and publish the frame's
1803
+ * poses as ephemeral overrides. No *document* writes, so the undo stack
1804
+ * still sees one entry for the whole drag.
1805
+ * - `onEnd('commit')`: emit the final delta as transform ops and route
1806
+ * them through the consumer `applyOps` hook when present, else
1807
+ * `scene.applyBatch(ops, 'Move', adapter)` — either way a single batch
1808
+ * → exactly one undo entry for the whole drag.
1809
+ * - `onEnd('cancel')`: drop the overrides — the document was never mutated,
1810
+ * so the committed poses are the restoration.
1346
1811
  *
1347
- * Combinators flatten same-kind nesting on construction so `a.and(b).and(c)`
1348
- * produces `{ all: [a, b, c] }` rather than `{ all: [{ all: [a, b] }, c] }`.
1349
- * Canonical form simplifies downstream introspection.
1812
+ * ## Why no per-frame document writes
1350
1813
  *
1351
- * Use {@link when} for the inline-lambda escape hatch.
1352
- */
1353
- declare function cond(rule: Rule): Condition;
1354
- /** Inline-lambda escape hatch. Wraps the closure as a `when` rule node. */
1355
- declare function when(fn: (ctx: RuleCtx) => boolean): Condition;
1356
- /** `(a && b && c && ...)` — useful when chain mixing makes left-to-right
1357
- * semantics ambiguous. */
1358
- declare function and(...cs: (Condition | Rule)[]): Condition;
1359
- /** `(a || b || c || ...)` — preferred over `.or` chains when mixed with
1360
- * `.and` to make grouping explicit. */
1361
- declare function or(...cs: (Condition | Rule)[]): Condition;
1362
- /** `!c` — top-level negation. Most rules use `.andNot()` / `.orNot()`
1363
- * instead; this is for the lead-with-negation case. */
1364
- declare function not(c: Condition | Rule): Condition;
1365
- /** Always true. The fallback for any chrome id without a registered rule. */
1366
- declare const always: Condition;
1367
- /** Always false. Useful for "turn this chrome off entirely":
1368
- * `chromeVisibility={{ 'snap.guides': never }}`. */
1369
- declare const never: Condition;
1370
- /** Canvas surface currently focused. */
1371
- declare const focused: Condition;
1372
- /** Any action currently in flight (read: user is gesturing). */
1373
- declare const gesturing: Condition;
1374
- /** Active action's kind matches `kind` (e.g. `actionIs('move')`). */
1375
- declare const actionIs: (kind: string) => Condition;
1376
- /** Nothing selected. */
1377
- declare const selectionEmpty: Condition;
1378
- /** Exactly `n` items selected. */
1379
- declare const selectionIs: (n: number) => Condition;
1380
- /** At least `n` items selected. `selectionAtLeast(1)` is the common
1381
- * "something is selected" check. */
1382
- declare const selectionAtLeast: (n: number) => Condition;
1383
- /** Multi-mode handle behavior active (single shared union-bounds
1384
- * handle vs per-item handles). Implemented as a `when` because
1385
- * `multiActive` is a derived single-call read on RuleCtx, not a
1386
- * selector-table key. Stable; safe to introspect. */
1387
- declare const multiActive: Condition;
1388
- /** Pointer is hovering some node. */
1389
- declare const hovering: Condition;
1390
- /** Pointer is hovering a node that is currently selected. */
1391
- declare const hoveringSelected: Condition;
1392
- /** Named modifier key currently held. */
1393
- declare const modifierHeld: (m: keyof ModifierState) => Condition;
1394
- /** View scale (uniform or geometric mean for non-uniform) is at least
1395
- * `z`. Useful for "hide hairline chrome at low zoom" rules. */
1396
- declare const zoomAtLeast: (z: number) => Condition;
1397
- /** Active mode equals `m`. */
1398
- declare const modeIs: (m: string) => Condition;
1399
- /** Active mode is one of `modes`. */
1400
- declare const modeIn: (modes: readonly string[]) => Condition;
1401
- /** Active mode is NOT `m`. */
1402
- declare const modeNot: (m: string) => Condition;
1403
- /** Active mode's `allows` includes capability `cap`. */
1404
- declare const capabilityIs: (cap: string) => Condition;
1405
- /** Active mode's `allows` includes ANY of `caps` (OR). */
1406
- declare const capabilityIn: (caps: readonly string[]) => Condition;
1407
- /** Active mode's `allows` includes ALL of `caps` (AND). */
1408
- declare const capabilityAll: (caps: readonly string[]) => Condition;
1409
- /** Active mode's `allows` does NOT include capability `cap`. */
1410
- declare const capabilityNot: (cap: string) => Condition;
1411
- /** Primary pointer is imprecise (touch, most styluses). Absent device
1412
- * profile → false, so a rule written with this atom is inert on the
1413
- * mouse-shaped default rather than silently flipping. */
1414
- declare const coarsePointer: Condition;
1415
- /** Primary pointer can hover. Absent device profile → true. Pair with
1416
- * `not(...)` to gate chrome that only makes sense with a hovering
1417
- * pointer: `not(canHover)` is "this device cannot hover". */
1418
- declare const canHover: Condition;
1419
-
1420
- /**
1421
- * Kit-shipped defaults. Merged with the consumer's `chromeVisibility` map
1422
- * at resolve time; consumer entries take precedence per id.
1423
- *
1424
- * Written as literal Rule trees rather than fluent chains so the inputs
1425
- * each rule depends on are immediately visible. The fluent atoms compile
1426
- * to the same trees; either form is valid in a VisibilityRules entry.
1427
- *
1428
- * Gating is written in terms of **capabilities, not mode ids**. A
1429
- * capability rule keeps holding when a new mode is added that permits the
1430
- * same thing; a mode rule has to be found and edited every time. There is
1431
- * no `mode:` rule left in this table — the `path-edit.*` chrome used to be
1432
- * the exception, on the theory that it's the visual signature of one mode;
1433
- * see the comment on those rules below for why that was wrong in both
1434
- * directions and what replaced it.
1435
- *
1436
- * Chrome that gates on the *absence* of a capability (the selection
1437
- * outline, suppressed while an anchor-editing overlay owns the visuals)
1438
- * uses `capability: { not: … }` for the same reason.
1439
- */
1440
- declare const defaultVisibilityRules: VisibilityRules;
1441
-
1442
- /**
1443
- * Build the per-frame visibility check. Merges consumer rules on top
1444
- * of the kit defaults, then closes over `ctx` so each chrome-id
1445
- * lookup runs its rule against the current state.
1446
- *
1447
- * `VisibilityRules` entries may be either fluent `Condition` values
1448
- * (callable) or raw `Rule` trees — we normalize at lookup time.
1449
- *
1450
- * Predicates are O(1) and run once per chrome id per frame; no
1451
- * memoization in v1 — profile before adding any.
1452
- *
1453
- * `ChromeCtx` is the legacy shape; surfaces still on it get `mode='normal'`
1454
- * and `DEFAULT_ALLOWED_CAPABILITIES` filled in here, so a caller that never
1455
- * opted into modality behaves exactly like one sitting in normal mode.
1456
- */
1457
- declare function resolveVisibility(consumer: VisibilityRules | undefined, ctx: ChromeCtx | RuleCtx): (id: ChromeId) => boolean;
1458
-
1459
- /**
1460
- * Pure assembler for {@link ChromeCtx}.
1461
- *
1462
- * Called once per frame on the rendering side from whichever surface
1463
- * needs to evaluate visibility rules — `composeAffordanceLayer`,
1464
- * `createSelectionOverlayLayer`, the dispatcher overlay layer, etc.
1465
- *
1466
- * Sources are passed as plain getters / values rather than the live
1467
- * objects they come from. This keeps `chrome-caps` from depending on
1468
- * React, the dispatcher's concrete type, or `ChromeState`'s bounds
1469
- * machinery — the same builder works from a test harness, a Storybook
1470
- * fixture, or `<SceneCanvas>`.
1471
- */
1472
-
1473
- /** The pieces of live canvas state a `ChromeCtx` is assembled from. */
1474
- interface BuildChromeCtxArgs {
1475
- focused: boolean;
1476
- selection: readonly NodeId[];
1477
- multiActive: boolean;
1478
- modifiers: ModifierState;
1479
- action: {
1480
- kind: string | null;
1481
- id: string | null;
1482
- };
1483
- hover: NodeId | null;
1484
- view: View;
1485
- }
1486
- /** Gather the current canvas state into the context that chrome-visibility
1487
- * rules are evaluated against. Rebuilt per frame. */
1488
- declare function buildChromeCtx(args: BuildChromeCtxArgs): ChromeCtx;
1489
-
1490
- /**
1491
- * useHoverTracking — last-hovered NodeId for chrome-caps rules.
1492
- *
1493
- * Attaches a `pointermove` listener to the supplied canvas; on each move it
1494
- * runs the supplied `nodeAtClientPoint` and caches the resulting id on a ref.
1495
- * Cleared on `pointerleave` (pointer left the canvas → nothing is hovered).
1496
- *
1497
- * Returns a stable getter — call once per frame from `buildChromeCtx`.
1498
- *
1499
- * No re-render: the ref updates silently, and the next render that
1500
- * reads it picks up the fresh value. Chrome-caps rules are evaluated
1501
- * during paint, so the hover state is always read fresh.
1502
- */
1503
-
1504
- /** Options for `useHoverTracking`. */
1505
- interface UseHoverTrackingArgs {
1506
- canvasRef: RefObject<HTMLElement | null>;
1507
- /** Topmost id under a client point, or null. One lookup rather than a
1508
- * client→world thunk beside a world-space picker: a screen-pixel pick
1509
- * tolerance converts against the camera the point resolved to, and two
1510
- * thunks are two chances to disagree about which view that is. */
1511
- nodeAtClientPoint: (clientX: number, clientY: number) => {
1512
- id: NodeId;
1513
- } | null;
1514
- enabled?: boolean;
1515
- }
1516
- /** Track which node the pointer is over. Returns a getter rather than state,
1517
- * so per-frame code can read the current value without the hover re-rendering
1518
- * the component on every pointer move. */
1519
- declare function useHoverTracking(args: UseHoverTrackingArgs): () => NodeId | null;
1520
-
1521
- /**
1522
- * Project an action's keyboard bindings into the shape a shortcut chip
1523
- * renders from (`formatShortcut` / `formatShortcutParts` in
1524
- * `@weasel-js/ui`). Palette and menu surfaces show what an action answers
1525
- * to; the dispatcher reads the specs themselves.
1526
- */
1527
-
1528
- /** One keyboard shortcut, flattened for display. Structurally the
1529
- * `ShortcutInput` weasel-ui formats — kept local so core doesn't depend on
1530
- * the UI package. */
1531
- interface ActionShortcut {
1532
- key: string;
1533
- mod: boolean;
1534
- alt: boolean;
1535
- shift: boolean;
1536
- }
1537
- /**
1538
- * The chip form of a single gesture spec, or `undefined` when the spec has
1539
- * none.
1540
- *
1541
- * Two kinds of collapsing, both because a binding list is written for a
1542
- * matcher rather than for a reader:
1543
- *
1544
- * - A spec's `key` may list spellings of one keycap (`['[', '{']` — the
1545
- * shifted bracket reports as `'{'`). The first is the shortcut's name.
1546
- * - A modifier declared `'optional'` matches held or unheld, so it isn't
1547
- * part of what the user has to press.
1548
- *
1549
- * Non-keyboard specs (drag, wheel, click) have no chip form. Neither does a
1550
- * *required* `ctrl` or `meta` — nothing in the kit declares one, and the
1551
- * display shape carries only `mod`.
1552
- */
1553
- declare function keySpecShortcut(spec: GestureSpec): ActionShortcut | undefined;
1554
- /**
1555
- * Every keyboard shortcut an action answers to, in declaration order.
1556
- * Specs `keySpecShortcut` has no chip for are skipped, and bindings it leaves
1557
- * identical are emitted once; an action bound only to those returns empty.
1558
- */
1559
- declare function actionShortcuts(action: Action): readonly ActionShortcut[];
1560
-
1561
- /**
1562
- * `moveAction` — first `ongoing`-timing Action descriptor.
1563
- *
1564
- * Mirrors the per-frame translate semantics of the `useMove` hook:
1565
- * - `start`: capture origin poses for all selected nodes; record the
1566
- * current drag delta in scratch each frame.
1567
- * - `onMove`: update the in-scratch `currentDelta`, and publish the frame's
1568
- * poses as ephemeral overrides. No *document* writes, so the undo stack
1569
- * still sees one entry for the whole drag.
1570
- * - `onEnd('commit')`: emit the final delta as transform ops and route
1571
- * them through the consumer `applyOps` hook when present, else
1572
- * `scene.applyBatch(ops, 'Move', adapter)` — either way a single batch
1573
- * → exactly one undo entry for the whole drag.
1574
- * - `onEnd('cancel')`: drop the overrides — the document was never mutated,
1575
- * so the committed poses are the restoration.
1576
- *
1577
- * ## Why no per-frame document writes
1578
- *
1579
- * `Scene.setPose` calls `executeAndLog`, which immediately records an undo
1580
- * entry on the scene's history engine. Per-frame writes during drag would
1581
- * create O(frames) history entries, so the drag commits one
1582
- * `createTransformOp` batch at the end.
1583
- *
1584
- * The per-frame poses still go *somewhere* the scene can see: the ephemeral
1585
- * override table, which bypasses history entirely. That is what lets a node
1586
- * deriving its geometry from a dragged one follow the drag — `sceneDepLookup`
1587
- * and the pick source both read overrides, and neither can see this action's
1588
- * scratch. Keeping the frame in scratch alone is why the edge used to stay
1589
- * anchored to the old endpoint and jump on drop.
1590
- *
1591
- * The behavior pipeline (snap-to-grid, snap-back-or-delete, snap-to-container,
1592
- * etc.) via `opts.behaviors` from `BindingOpts` IS wired: `start` builds a
1593
- * `GestureContext` + scene-backed adapter (`moveGestureAdapter`), `onMove`
1594
- * folds each behavior's proposed-transform result, and `onEnd` runs a
1595
- * first-non-undefined-wins reducer (`Op[]` commits via `scene.applyBatch`,
1596
- * `null` aborts, all-`undefined` falls through to the default translate path).
1597
- *
1598
- * ## Pose generics
1599
- *
1600
- * `scene` dep is typed `Scene<unknown, string, unknown>` (the erased DepSchema
1601
- * entry). Poses are read and written as `unknown`; `translatePoseGeneric`
1602
- * delegates to `RECT_POSE_DESCRIPTOR.translate` which treats any pose as
1603
- * `{x, y, ...}`. Consumers with non-rect poses should register a custom
1604
- * action with a typed translatePose.
1814
+ * `Scene.setPose` calls `executeAndLog`, which immediately records an undo
1815
+ * entry on the scene's history engine. Per-frame writes during drag would
1816
+ * create O(frames) history entries, so the drag commits one
1817
+ * `createTransformOp` batch at the end.
1818
+ *
1819
+ * The per-frame poses still go *somewhere* the scene can see: the ephemeral
1820
+ * override table, which bypasses history entirely. That is what lets a node
1821
+ * deriving its geometry from a dragged one follow the drag — `sceneDepLookup`
1822
+ * and the pick source both read overrides, and neither can see this action's
1823
+ * scratch. Keeping the frame in scratch alone is why the edge used to stay
1824
+ * anchored to the old endpoint and jump on drop.
1825
+ *
1826
+ * The behavior pipeline (snap-to-grid, snap-back-or-delete, snap-to-container,
1827
+ * etc.) via `opts.behaviors` from `BindingOpts` IS wired: `start` builds a
1828
+ * `GestureContext` + scene-backed adapter (`moveGestureAdapter`), `onMove`
1829
+ * folds each behavior's proposed-transform result, and `onEnd` runs a
1830
+ * first-non-undefined-wins reducer (`Op[]` commits via `scene.applyBatch`,
1831
+ * `null` aborts, all-`undefined` falls through to the default translate path).
1832
+ *
1833
+ * ## Pose generics
1834
+ *
1835
+ * Poses are `unknown`; every read and write goes through the `poseDescriptor`
1836
+ * dep (`AUTO_POSE_DESCRIPTOR` when unsourced).
1605
1837
  */
1606
1838
 
1607
1839
  /**
@@ -1629,17 +1861,14 @@ declare const moveAction: Action & {
1629
1861
  * start poses, applies per-frame bounds remapping, and commits a single
1630
1862
  * `scene.batch` entry on end.
1631
1863
  *
1632
- * ## Behaviors / point-snap / expandIds / geometry — via `resizePolicy` dep
1864
+ * ## Behaviors / point-snap / expandIds — via the `resizePolicy` dep
1633
1865
  *
1634
- * The resize-behaviors-api wired the four behavior options the
1635
- * legacy `useResize` hook exposed (`behaviors`, `pointSnapBehaviors`,
1636
- * `expandIds`, `geometry`) through the `resizePolicy` dep entry. When
1637
- * 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:
1638
1869
  *
1639
1870
  * - Calls `expandIds([id])` at start. When the result expands beyond the
1640
1871
  * starting id, takes the group path (union-AABB origin, per-leaf remap).
1641
- * - Projects poses through the supplied `geometry: PoseProjection<TPose>`
1642
- * instead of the rect-shaped `RECT_POSE_DESCRIPTOR` default.
1643
1872
  * - Runs `behaviors[]` after the raw anchor-math bounds are computed.
1644
1873
  * Behaviors return `{ pose? }` and rewrite the proposed bounds before
1645
1874
  * they're projected back into pose space.
@@ -1648,12 +1877,17 @@ declare const moveAction: Action & {
1648
1877
  * frame's world point lands on the snap target.
1649
1878
  *
1650
1879
  * When the dep is absent the invoker falls back to identity defaults
1651
- * (no behaviors, no snap, `ids => ids` expansion, `RECT_POSE_DESCRIPTOR`),
1652
- * which matches the unrotated rect-pose path the invoker already
1653
- * 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.
1654
1888
  *
1655
1889
  * @see useResize — the React hook this descriptor mirrors.
1656
- * @see src/interactions/actions/resize/geometry.ts — `PoseProjection`.
1890
+ * @see src/interactions/actions/resize/geometry.ts — `PoseDescriptor`.
1657
1891
  */
1658
1892
 
1659
1893
  /**
@@ -1673,7 +1907,7 @@ declare const resizeAction: Action & {
1673
1907
  *
1674
1908
  * ## Status: REAL (unrotated-pivot path)
1675
1909
  *
1676
- * Implements the core rotation math from `useRotate` for rect-shaped poses:
1910
+ * Implements the core rotation math from `useRotate`:
1677
1911
  * - `start`: captures origin poses + AABB centers; computes start pointer
1678
1912
  * angle around the union center of selected nodes.
1679
1913
  * - `onMove`: derives pointer angle delta from start, applies to each node's
@@ -1688,8 +1922,9 @@ declare const resizeAction: Action & {
1688
1922
  *
1689
1923
  * ## Constraints vs `useRotate`
1690
1924
  *
1691
- * - Assumes rect-shaped poses `{ x, y, width, height, rotation? }`. Non-rect
1692
- * 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.
1693
1928
  * - No behavior pipeline (snap, etc.). Behaviors wait for a later phase.
1694
1929
  * - No overlay rendering — deferred to Phase 7 overlay surface.
1695
1930
  * - Shift-snap (15° quantum) is NOT wired in this phase — omitted deliberately
@@ -1703,9 +1938,7 @@ declare const resizeAction: Action & {
1703
1938
  *
1704
1939
  * Requires dep-schema entries: `selection`, `scene`.
1705
1940
  *
1706
- * Implements the unrotated-pivot rotation path from `useRotate` for rect-
1707
- * shaped poses. Non-rect or behavior-rich consumers should register a custom
1708
- * `rotateAction` with a typed `RotateGeometry` dep.
1941
+ * Implements the unrotated-pivot rotation path from `useRotate`.
1709
1942
  *
1710
1943
  * @see useRotate — the React hook this descriptor mirrors for the rect case.
1711
1944
  */
@@ -1920,9 +2153,7 @@ declare const clearSelectionAction: Action & {
1920
2153
  *
1921
2154
  * ## Pose generics
1922
2155
  *
1923
- * Poses are translated using the same `{x, y, ...}` generic spread as
1924
- * `moveAction`. Non-rect poses with custom layout (e.g. paths) should register
1925
- * a custom clone action with a typed geometry dep.
2156
+ * Poses are translated through the `poseDescriptor` dep, as `moveAction` does.
1926
2157
  */
1927
2158
 
1928
2159
  /**
@@ -2225,12 +2456,25 @@ declare const lassoSelectAction: Action & {
2225
2456
  };
2226
2457
 
2227
2458
  /**
2228
- * `pinchZoomAction` — ongoing Action descriptor for two-finger pinch zoom
2229
- * and pan. The id and label stay `pinchZoom` / `Pinch Zoom`.
2230
- *
2231
- * ## Status: REAL
2459
+ * @experimental
2460
+ * Static descriptor for the `slice` Action.
2232
2461
  *
2233
- * Implements pinch-zoom via the multi-touch pointer stream:
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
+
2471
+ /**
2472
+ * `pinchZoomAction` — ongoing Action descriptor for two-finger pinch zoom
2473
+ * and pan. The id and label stay `pinchZoom` / `Pinch Zoom`.
2474
+ *
2475
+ * ## Status: REAL
2476
+ *
2477
+ * Implements pinch-zoom via the multi-touch pointer stream:
2234
2478
  * - `start`: captures startSpread from `ctx.multiTouch.pinch.startSpread`
2235
2479
  * (or falls back to `ctx.multiTouch.spread`). Records the initial centroid.
2236
2480
  * - `onMove`: computes zoom factor = currentSpread / startSpread, anchors
@@ -2287,6 +2531,143 @@ declare const pinchZoomAction: Action & {
2287
2531
  requires: string[];
2288
2532
  };
2289
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
+
2290
2671
  /** @experimental */
2291
2672
  interface UseStandardActionsOptions {
2292
2673
  /** Kit selection state — ids of currently selected nodes. */
@@ -2352,289 +2733,26 @@ declare function defaultCommitAdapter<TPose>(scene: Scene<unknown, string, TPose
2352
2733
  /** Options for `useResizePolicy`. Each omitted field falls back to the kit
2353
2734
  * default. */
2354
2735
  interface UseResizePolicyOptions<TPose> {
2355
- constraints?: TPose extends ResizePose ? BoundsConstraint<TPose>[] : never[];
2356
- pointSnap?: TPose extends ResizePose ? PointSnapBehavior<TPose>[] : never[];
2736
+ constraints?: TPose extends Bounds ? BoundsConstraint<TPose>[] : never[];
2737
+ pointSnap?: TPose extends Bounds ? PointSnapBehavior<TPose>[] : never[];
2357
2738
  expandIds?: (ids: string[]) => string[];
2358
- projection?: PoseProjection<TPose>;
2359
2739
  }
2360
2740
  /** Publish how resizing should behave — constraints, point snapping, group
2361
- * expansion, pose projection — for the resize action to consult. */
2741
+ * expansion — for the resize action to consult. */
2362
2742
  declare function useResizePolicy<TPose>(options: UseResizePolicyOptions<TPose>): void;
2363
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
+
2364
2752
  /** Publish how a slice (knife cut) is performed, so the `slice` action can
2365
2753
  * run against the consumer's geometry. */
2366
2754
  declare function useSliceDep(dep: SliceDep): void;
2367
2755
 
2368
- /**
2369
- * The painted cursor a surface is currently showing, shared between whoever
2370
- * decides it and the layer that draws it.
2371
- *
2372
- * Two slots rather than one, mirroring the precedence the cursor pipeline
2373
- * already has: `<Canvas>` writes the active tool's cursor to `base` from
2374
- * render, and the hover pump writes an affordance's or an action's cursor to
2375
- * `override` imperatively. The override wins while it is set, and clearing it
2376
- * restores the base without a React commit — the same reason the pump uses an
2377
- * inline style for the CSS tier.
2378
- */
2379
-
2380
- /** The painted arm of `ResolvedCursor` — what this module stores. */
2381
- type PaintedCursor = Extract<ResolvedCursor, {
2382
- kind: 'painted';
2383
- }>;
2384
- interface PaintedCursorFrame {
2385
- readonly cursor: PaintedCursor;
2386
- /** Pointer position in the layer's own space: canvas-local CSS px. */
2387
- readonly at: {
2388
- readonly x: number;
2389
- readonly y: number;
2390
- };
2391
- }
2392
- interface PaintedCursorState {
2393
- setBase(cursor: PaintedCursor | null): void;
2394
- setOverride(cursor: PaintedCursor | null): void;
2395
- /** Canvas-local CSS px. */
2396
- setPointer(x: number, y: number): void;
2397
- /** Pointer left the surface: nothing to draw until it returns. */
2398
- clearPointer(): void;
2399
- /**
2400
- * Whether a painted cursor is set at all, regardless of where the pointer is.
2401
- *
2402
- * Lets the pointer path skip measuring the canvas rect on every move in the
2403
- * overwhelmingly common case where the compositor is drawing the cursor and
2404
- * nothing here needs its position.
2405
- */
2406
- active(): boolean;
2407
- /** What the layer should draw this frame, or null for none. */
2408
- current(): PaintedCursorFrame | null;
2409
- /** Run `fn` whenever the answer to `current()` may have changed. */
2410
- subscribe(fn: () => void): () => void;
2411
- }
2412
- declare function createPaintedCursorState(): PaintedCursorState;
2413
-
2414
- /**
2415
- * Everything about handling an input event that depends on *which view* it
2416
- * landed in: the dispatcher that runs it, and the three lookups that resolve
2417
- * a client point against that view's camera.
2418
- *
2419
- * @internal One per view. The hook builds the `id: null` one from its flat
2420
- * options; `views` supplies the rest, and the hook chooses between them per
2421
- * event, so that it — and its listener set — still mounts exactly once.
2422
- */
2423
- interface DispatcherViewTarget {
2424
- /** `null` is the root view — the whole canvas. Matches `ViewTarget.id`. */
2425
- id: string | null;
2426
- dispatcher: Dispatcher;
2427
- affordanceAt: UseGestureDispatcherOptions['affordanceAt'];
2428
- classifyTarget: UseGestureDispatcherOptions['classifyTarget'];
2429
- clientToWorld: UseGestureDispatcherOptions['clientToWorld'];
2430
- /**
2431
- * The deps this view answers for itself — its camera, its selection, and
2432
- * whatever else is per-view rather than per-canvas. Read per event; every
2433
- * name it does not carry still resolves through the canvas registry.
2434
- *
2435
- * This is why a view does not get a `DepRegistryProvider` of its own. The
2436
- * registry is where a consumer registers *sources*, and one per view would
2437
- * fragment that: a consumer overriding `insert` would have to know how many
2438
- * views exist and override each. An overlay keeps one place to register and
2439
- * one authority per dep, with the view claiming only what is genuinely its.
2440
- *
2441
- * Without this a gesture inside a panel pans the whole canvas and selects
2442
- * into the canvas's selection — correct coordinates alone do not make
2443
- * routing correct.
2444
- */
2445
- deps?: () => Partial<DepSchema>;
2446
- /**
2447
- * This view's chrome-caps rule context, for the eligibility filter. The rule
2448
- * table is the surface's, but a rule keyed on selection or the in-flight
2449
- * action answers per view — so an action hidden in one panel must not
2450
- * decline a gesture in another. `undefined` means "nothing gates here", the
2451
- * same answer a surface with no mode registry gives.
2452
- */
2453
- getRuleCtx?: () => RuleCtx | undefined;
2454
- }
2455
- /**
2456
- * The part of `features/viewports`' `ViewResolver` the dispatcher needs: which
2457
- * view a client point belongs to, pinned to the view a gesture began in.
2458
- *
2459
- * @internal Structural on purpose — a `ViewResolver` satisfies it, and the
2460
- * dispatcher stays free of the viewport module.
2461
- */
2462
- interface ViewIdResolver {
2463
- begin(pointerId: number, clientX: number, clientY: number): {
2464
- id: string | null;
2465
- };
2466
- at(pointerId: number | null, clientX: number, clientY: number): {
2467
- id: string | null;
2468
- };
2469
- end(pointerId: number): void;
2470
- }
2471
- /** Options for `useGestureDispatcher`: the element to listen on, the actions
2472
- * and tools in play, and the hooks that turn raw DOM events into the world
2473
- * coordinates and hit targets bindings match against. */
2474
- interface UseGestureDispatcherOptions {
2475
- /** Ref to the canvas element. Pointer/wheel/multitouch listeners attach here. */
2476
- canvasRef: RefObject<HTMLElement | null>;
2477
- /** Action registry (ActionsRegistry from registry.tsx). */
2478
- actions: ActionsRegistry;
2479
- /** Tool definitions keyed by id. Typically passes an empty Map. */
2480
- toolsById: ReadonlyMap<string, Tool>;
2481
- /** Default true. Set false to opt out of dispatcher wiring (e.g. demos that disable it). */
2482
- enabled?: boolean;
2483
- /**
2484
- * Observer fired whenever the dispatcher synthesizes a double click, in
2485
- * world coordinates. Runs BEFORE the event is dispatched and independently
2486
- * of which binding (if any) handles it.
2487
- *
2488
- * This is deliberately not an Action. `<SceneCanvas onDoubleClick>` is a
2489
- * notification — "the user double-clicked, here's what they hit" — and a
2490
- * notification must not compete with behavior for the gesture. As a binding
2491
- * it would lose to `enterPathEdit` on any body hit and silently never fire.
2492
- * Routing it here keeps a single definition of "double click" (the point of
2493
- * consolidating the kit's three detectors) without giving it
2494
- * first-match-wins semantics it shouldn't have.
2495
- */
2496
- onDoubleClick?: (world: {
2497
- x: number;
2498
- y: number;
2499
- }) => void;
2500
- /**
2501
- * Default true. Set false to leave the window `keydown`/`keyup` listeners
2502
- * unattached so keyboard-bound actions never dispatch — pointer, wheel, and
2503
- * contextmenu channels stay live. `<SceneCanvas>` wires this to
2504
- * `enableKeybindings`, so opting out of keybindings disables the modern
2505
- * dispatcher key path as well as the legacy `useKeybindings` hook.
2506
- */
2507
- keyboard?: boolean;
2508
- /**
2509
- * Optional affordance classifier. Called on every pointerdown with the
2510
- * world-space coordinates of the pointer. Returns an `AffordanceHit` when
2511
- * the pointer lands on a known affordance (resize handle, rotate handle, etc.)
2512
- * or `null` when the pointer hit open canvas.
2513
- *
2514
- * The hit is packed into `InputEvent.pointerdown.affordance` and flows
2515
- * through into `InvocationCtx.drag.affordance`. Action invokers that require
2516
- * a specific affordance (e.g. `resizeAction` requires `handle:*`) use this
2517
- * field as a guard in their `start` body.
2518
- *
2519
- * When omitted, `affordance` is always `undefined` — meaning only consumers
2520
- * that explicitly wire a classifier get affordance-gated behavior.
2521
- * `<SceneCanvas>` wires the full chrome→dispatcher bridge.
2522
- */
2523
- affordanceAt?: (worldPoint: {
2524
- x: number;
2525
- y: number;
2526
- }) => AffordanceHit | null;
2527
- /**
2528
- * Optional body classifier. Called on every pointerdown with the world-space
2529
- * coordinates of the pointer. Its result is packed onto the event as
2530
- * `bodyTarget` + `bodyKind`, which `matchTarget` reads to resolve the
2531
- * string-form `TargetSpec` values in `Tool.bindings`.
2532
- *
2533
- * `body` is `'empty'` when nothing is under the pointer, `'selected-body'`
2534
- * when the topmost hit belongs to the current selection, or
2535
- * `'unselected-body'` when it belongs to a node that isn't selected. `kind`
2536
- * is the hit node's semantic kind, when the scene can name it.
2537
- *
2538
- * When omitted, every body-derived target form (`'empty'`,
2539
- * `'selected-body'`, `'unselected-body'`, `kind:<k>`, `kind:<k>:selected`)
2540
- * never matches — bindings using those specs are silently skipped.
2541
- * `<SceneCanvas>` wires this.
2542
- */
2543
- classifyTarget?: (worldPoint: {
2544
- x: number;
2545
- y: number;
2546
- }) => BodyClassification;
2547
- /**
2548
- * Optional pre-created `Dispatcher`. When provided, this hook pumps events
2549
- * into the supplied instance instead of creating its own. Lets a parent
2550
- * scope (e.g. `<SceneCanvas>`) share one dispatcher between the gesture
2551
- * mounter and other consumers (the preview-ghost layer).
2552
- */
2553
- dispatcher?: Dispatcher;
2554
- /**
2555
- * Converts a client-space pointer position (e.g. `e.clientX`, `e.clientY`)
2556
- * to world-space coordinates. When supplied, every pointer/wheel event's
2557
- * `x`/`y` is converted before the dispatcher builds `InvocationCtx.world`.
2558
- *
2559
- * Without this, `ctx.world` is populated with the raw client coords, which
2560
- * silently breaks any action whose overlay/output uses absolute world
2561
- * positions (marquee, lasso polyline, world-space affordances). Actions
2562
- * that only read `drag.delta` are unaffected because client→world deltas
2563
- * are equal at scale 1, but as soon as a consumer pans/zooms the view the
2564
- * deltas diverge too.
2565
- *
2566
- * `<SceneCanvas>` always wires this via its canvas rect + current view.
2567
- * Tests / harnesses without a view can omit it and continue passing raw
2568
- * coordinates as before.
2569
- */
2570
- clientToWorld?: (clientX: number, clientY: number) => {
2571
- x: number;
2572
- y: number;
2573
- };
2574
- /**
2575
- * Invoked once per pump event (`pointermove`, `pointerup`, `pointercancel`,
2576
- * `key-held` up-phase, `multitouch` move) when a dispatcher-side handle is
2577
- * in flight. Lets the host canvas schedule a redraw so dispatcher-only
2578
- * overlays (marquee, lasso, preview-ghost) repaint on each frame.
2579
- *
2580
- * Required because dispatcher actions don't go through the legacy
2581
- * `tools.dispatcher.onGestureChange` redraw bump that ambient tool drags
2582
- * relied on. Without it, the overlay layer's `draw` never runs between
2583
- * pointerdown and pointerup, and the chrome flashes once at gesture start
2584
- * and then sits frozen until the gesture ends.
2585
- *
2586
- * `<SceneCanvas>` wires this to the canvas's `requestRedraw`. Test
2587
- * harnesses can omit it; their dispatchers won't paint between events but
2588
- * that's already the test contract.
2589
- */
2590
- requestRedraw?: () => void;
2591
- /**
2592
- * The surface's painted-cursor channel, read live because the canvas handle
2593
- * it lives on arrives a render after this hook runs.
2594
- *
2595
- * Given one, a cursor the CSS tier cannot express — sized in world units, or
2596
- * past the size the browser drops the image at — is published here and drawn
2597
- * by the painted-cursor layer instead. Without one, such a cursor resolves to
2598
- * `none` and the pointer shows nothing.
2599
- */
2600
- paintedCursor?: () => PaintedCursorState | undefined;
2601
- /**
2602
- * Thunk returning the live `RuleCtx` for the current frame. When supplied,
2603
- * the dispatcher filters matched candidates by their declared
2604
- * `Action.eligible` rule (omitted => always eligible). `<SceneCanvas>`
2605
- * wires this; tests / harnesses without chrome-caps state can omit it.
2606
- */
2607
- getRuleCtx?: () => RuleCtx | undefined;
2608
- /**
2609
- * Routing for a canvas hosting more than one view: the non-root dispatch
2610
- * records to choose between, read fresh per event, and the resolver that
2611
- * chooses. Omit for a single view — then every event runs on the record the
2612
- * flat options above describe, which is what they are: view zero.
2613
- *
2614
- * A resolved id with no live record falls back to the root, so a view that
2615
- * unmounts mid-gesture degrades instead of dropping the event.
2616
- *
2617
- * Keyboard and paste have no coordinates to resolve; they run on the view
2618
- * the last coordinate-bearing event resolved to.
2619
- *
2620
- * @internal
2621
- */
2622
- views?: {
2623
- targets: () => readonly DispatcherViewTarget[];
2624
- resolver: ViewIdResolver;
2625
- };
2626
- }
2627
- /**
2628
- * Attach the input pipeline to a canvas: DOM pointer, wheel, keyboard and
2629
- * multitouch listeners in, normalized input events out, routed through the
2630
- * dispatcher to whichever action a binding names.
2631
- *
2632
- * Everything it needs beyond its options — the active tool, the dep registry —
2633
- * comes from context, so it must be mounted inside `<SceneCanvas>`'s
2634
- * providers.
2635
- */
2636
- declare function useGestureDispatcher(opts: UseGestureDispatcherOptions): void;
2637
-
2638
2756
  /**
2639
2757
  * The one place weasel decides whether a frame may run, so that "a loop does no
2640
2758
  * work nobody can see" holds by construction rather than by every loop author
@@ -2738,14 +2856,6 @@ declare function wheelPan(view: View, delta: {
2738
2856
  /** Pure reducer: the whole wheel convention in one call. */
2739
2857
  declare function computeWheelAction(view: View, input: WheelInput, clamp?: ZoomClampOpts, opts?: Pick<WheelPanOpts, 'axis'>): View;
2740
2858
 
2741
- /**
2742
- * Convert client coords to element CSS-pixel coords (relative to the element's
2743
- * top-left). Apps drawing in CSS-pixel space feed the result directly into
2744
- * world math when pan/zoom is identity. With pan/zoom, compose this with
2745
- * your inverse-viewport transform.
2746
- */
2747
- declare function clientToCanvas(canvas: HTMLElement, clientX: number, clientY: number): [number, number];
2748
-
2749
2859
  /** Records recent deltas and reports the current velocity, averaged over the
2750
2860
  * last 100ms — the throw speed a momentum decay starts from. */
2751
2861
  interface VelocityTracker {
@@ -2785,93 +2895,28 @@ declare function usePinchGesture(canvasRef: React.RefObject<HTMLElement | null>,
2785
2895
  declare function interpolateView(from: View, to: View): (t: number) => View;
2786
2896
 
2787
2897
  /**
2788
- * Build a `Tool<TScratch>` from a declarative `ToolDef<TScratch>`.
2789
- *
2790
- * This used to be a translator: `ToolDef` carried `initial` / `engaged` phase
2791
- * tables of hit-keyed route handlers, and `defineTool` compiled them into the
2792
- * imperative `pointer` / `drag` / `keyboard` / `wheel` handlers the
2793
- * tool-routing dispatcher called. Both ends of that are gone — tools declare
2794
- * `bindings` and the gesture dispatcher routes them — so what remains is
2795
- * identity plumbing plus the id check and the cursor resolver.
2898
+ * The routing types that carry an overlay, bound to the kit's `RenderLayer`.
2796
2899
  *
2797
- * It stays a function rather than becoming a spread because the id validation
2798
- * and the `initScratch` / `cursor` defaults are worth applying uniformly, and
2799
- * 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.
2800
2905
  */
2801
- declare function defineTool<TScratch = void>(def: ToolDef<TScratch>): Tool<TScratch>;
2802
2906
 
2803
- /**
2804
- * Define a tool that acts on the viewport rather than the scene.
2805
- *
2806
- * This used to do real work: `ViewportPhaseDef` was a narrowed `PhaseDef`
2807
- * (no click routes, drag restricted to the function form), and the factory
2808
- * lifted it back to the permissive shape before handing it to `defineTool`.
2809
- * With phase tables gone there is no shape left to narrow — a viewport tool
2810
- * declares `bindings` like any other, pointing at `viewport.*` actions.
2811
- *
2812
- * It survives as an authoring signal. `defineViewportTool` at the top of a
2813
- * hook says "this tool moves the camera, not the drawing", which is worth
2814
- * more than the type gymnastics it replaced.
2815
- */
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>;
2816
2918
  declare function defineViewportTool<TScratch = void>(def: ViewportToolDef<TScratch>): Tool<TScratch>;
2817
-
2818
- /** Options for `useTools`: which tools exist, which one starts active, and
2819
- * which run continuously regardless of the active one. */
2820
- interface UseToolsOptions {
2821
- /** Initial active-slot tool id. Must exist in `registry`. */
2822
- active: string;
2823
- /** Tools eligible for the active slot or hotkey slot. The keys are the
2824
- * tool ids; the values are the tool records. A tool with `hotkey` set
2825
- * is wired into the hotkey slot whenever the engagement state matches. */
2826
- registry: Record<string, AnyTool>;
2827
- /** Always-on tools — listen continuously regardless of active slot. */
2828
- ambient?: AnyTool[];
2829
- }
2830
- /** The tool registry's runtime surface: which tool is active, which is
2831
- * temporarily held by a hotkey, and how to change either. */
2832
- interface ToolsApi {
2833
- /** Current active-slot tool id. */
2834
- active: string;
2835
- /** Set the active-slot tool. The gesture dispatcher watches the active
2836
- * tool and cancels any in-flight handle itself. */
2837
- setActive: (id: string) => void;
2838
- /** Currently hotkey-engaged tool id (or `null`). Derived as the top of
2839
- * the hotkey stack for backwards compat with the pre-stack API. */
2840
- hotkeyEngaged: string | null;
2841
- /** Engage a hotkey-slot tool by id. */
2842
- engageHotkey: (id: string) => void;
2843
- /** Disengage the hotkey-slot tool, if any. */
2844
- disengageHotkey: () => void;
2845
- /** All always-on tools, in registration order. */
2846
- ambient: readonly AnyTool[];
2847
- /** Full registry — for userland UI (palette buttons, etc.). */
2848
- registry: Readonly<Record<string, AnyTool>>;
2849
- /** Returns true if a tool with the given id is in the registry or ambient list. */
2850
- has(id: string): boolean;
2851
- /** All overlay layers from currently-engaged tools (active slot, hotkey
2852
- * slot if engaged, all ambient slot tools) that declare `position`.
2853
- * Filters out tools with no `overlay` field. Order: active, then hotkey
2854
- * (if engaged), then ambient (registration order). */
2855
- getActiveOverlays(position?: OverlayPosition): RenderLayer<unknown>[];
2856
- }
2857
- /**
2858
- * Manages the active tool and hotkey slot.
2859
- *
2860
- * A thin shim over {@link useContributions}: the `registry` / `ambient`
2861
- * arguments are restated as declared eligibility (`focus` / `always`), and
2862
- * assembly happens in one place for tools and non-tool contributions alike.
2863
- *
2864
- * Requires `<ActiveToolContextProvider>` (or `<WeaselProvider>` /
2865
- * `<SceneCanvas>`, which mount one internally) in scope: active/hotkey state
2866
- * lives in the context so the gesture dispatcher and any sibling
2867
- * `useTools` calls all read the same source of truth.
2868
- *
2869
- * **First-mount-wins semantics**: if `opts.active` differs from the context
2870
- * default (`'select'`) on first mount, `useTools` pushes `opts.active` to
2871
- * the context. Subsequent mounts respect whatever the context currently
2872
- * holds (the first caller wins).
2873
- */
2874
- declare function useTools(opts: UseToolsOptions): ToolsApi;
2919
+ declare const useTools: (opts: UseToolsOptions) => ToolsApi;
2875
2920
 
2876
2921
  /** Options for `useKeybindings`. */
2877
2922
  interface UseKeybindingsOptions {
@@ -2927,6 +2972,9 @@ interface ToolPrefBase<K extends string, Value> {
2927
2972
  }
2928
2973
  /** How a schema-driven UI should present a number pref. */
2929
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';
2930
2978
  /** How a schema-driven UI should present a boolean pref. */
2931
2979
  type ToolPrefBooleanControl = 'checkbox' | 'switch' | 'toggle';
2932
2980
  /** How a schema-driven UI should present a string pref. */
@@ -2941,7 +2989,21 @@ interface ToolPrefNumberUnit {
2941
2989
  fromDisplay: (display: number) => number;
2942
2990
  /** Shown after the input, e.g. `'°'`. */
2943
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>>;
2944
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;
2945
3007
  /** A numeric pref, optionally bounded and stepped, and optionally stored in a
2946
3008
  * different unit from the one shown. */
2947
3009
  interface ToolPrefNumber extends ToolPrefBase<'number', number> {
@@ -2949,6 +3011,7 @@ interface ToolPrefNumber extends ToolPrefBase<'number', number> {
2949
3011
  max?: number;
2950
3012
  step?: number;
2951
3013
  control?: ToolPrefNumberControl;
3014
+ format?: ToolPrefNumberFormat;
2952
3015
  unit?: ToolPrefNumberUnit;
2953
3016
  }
2954
3017
  /** An on/off pref. */
@@ -3096,21 +3159,144 @@ interface ToolPrefGroup {
3096
3159
  children: Record<string, ToolPrefLeaf | ToolPrefGroup>;
3097
3160
  }
3098
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
+
3099
3285
  /** Options for `useSelectTool`: how a point resolves to nodes, how a click
3100
3286
  * chooses among them, and the appearance of the marquee. */
3101
3287
  interface UseSelectToolOptions<TPose> {
3102
3288
  /** Return ids of all objects whose painted body covers (worldX, worldY).
3103
3289
  * Order doesn't matter — the tool collapses parent/child overlap via
3104
- * `pickTopMostHit`. When omitted, defaults to a rect AABB-vs-point scan
3105
- * over `adapter.getNodes()` using `poseBounds` (identity by default,
3106
- * works for `{x,y,width,height}` poses). Override for tighter shapes
3107
- * (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). */
3108
3293
  pickEvery?: (worldX: number, worldY: number) => string[];
3109
3294
  /** Optional alt-aware selection-update hit returning the single id the
3110
3295
  * click should act on. */
3111
3296
  pickBest?: (worldX: number, worldY: number, alt: boolean, selection: readonly string[]) => string | null;
3112
- /** Project a pose to its AABB. Default: identity. */
3113
- poseBounds?: (pose: TPose) => Bounds;
3297
+ /** How to read poses for the default `pickEvery`. Default
3298
+ * `AUTO_POSE_DESCRIPTOR`. */
3299
+ poseDescriptor?: PoseDescriptor<TPose>;
3114
3300
  /**
3115
3301
  * How the default `pickEvery` decides a **leaf** node covers the pointer.
3116
3302
  * Ignored when `pickEvery` is supplied.
@@ -3141,6 +3327,13 @@ interface UseSelectToolOptions<TPose> {
3141
3327
  * Without some slop a hairline outline is an unhittable target.
3142
3328
  */
3143
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;
3144
3337
  /** Move-action options. The move gesture is dispatcher-routed,
3145
3338
  * so only `behaviors` is consumed here — threaded into the move binding's
3146
3339
  * `opts.behaviors`. Other `UseMoveOptions` fields are accepted for API shape
@@ -3699,25 +3892,387 @@ interface PencilPoint {
3699
3892
  * `{ kind: 'pencil', samples }`. The kit's default `insert` dep runs
3700
3893
  * `schneiderFit` over the samples to produce a cubic-Bezier path.
3701
3894
  */
3702
- declare function usePencilTool(): Tool<null>;
3895
+ declare function usePencilTool(): Tool<null>;
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
+
4157
+ /** Standard slot names — render in this canonical order.
4158
+ * `cellHighlight` is internal: emitted from the `grid` slot's nested
4159
+ * `highlight` config, not a top-level layer key. */
4160
+ /** @internal */
4161
+ declare const STANDARD_SLOTS: readonly ["grid", "cellHighlight", "scene", "selectionOverlay"];
4162
+ /** Names of the slots `<Canvas>` supports out of the box (excluding the implicit cell-highlight overlay). */
4163
+ type StandardSlotName = Exclude<(typeof STANDARD_SLOTS)[number], 'cellHighlight'>;
4164
+ /** Custom layer entry — any key not in `STANDARD_SLOTS`. The presence of
4165
+ * `.layer` discriminates this from a slot config. */
4166
+ interface CustomLayerEntry {
4167
+ layer: RenderLayer<unknown>;
4168
+ /** Insert immediately after the named standard slot or another custom-layer key. */
4169
+ after?: StandardSlotName | (string & {});
4170
+ /** Insert immediately before the named standard slot or another custom-layer key. */
4171
+ before?: StandardSlotName | (string & {});
4172
+ }
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;
3703
4262
 
3704
- /** Standard slot names — render in this canonical order.
3705
- * `cellHighlight` is internal: emitted from the `grid` slot's nested
3706
- * `highlight` config, not a top-level layer key. */
3707
- /** @internal */
3708
- declare const STANDARD_SLOTS: readonly ["grid", "cellHighlight", "scene", "selectionOverlay"];
3709
- /** Names of the slots `<Canvas>` supports out of the box (excluding the implicit cell-highlight overlay). */
3710
- type StandardSlotName = Exclude<(typeof STANDARD_SLOTS)[number], 'cellHighlight'>;
3711
- /** Custom layer entry — any key not in `STANDARD_SLOTS`. The presence of
3712
- * `.layer` discriminates this from a slot config. */
3713
- interface CustomLayerEntry {
3714
- layer: RenderLayer<unknown>;
3715
- /** Insert immediately after the named standard slot or another custom-layer key. */
3716
- after?: StandardSlotName | (string & {});
3717
- /** Insert immediately before the named standard slot or another custom-layer key. */
3718
- before?: StandardSlotName | (string & {});
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;
3719
4275
  }
3720
-
3721
4276
  /**
3722
4277
  * The **base imperative ref handle** shared by the canvas components. For
3723
4278
  * `<SceneCanvas>` refs use {@link SceneCanvasApi} (this type plus the
@@ -3751,8 +4306,23 @@ interface CanvasExtensionApi {
3751
4306
  *
3752
4307
  * Under `paintInto` this is the caller's shared canvas, which co-tenant
3753
4308
  * panes also paint into: its rect is the whole surface, not this pane's, so
3754
- * 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}. */
3755
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
+ };
3756
4326
  requestRedraw(): void;
3757
4327
  /**
3758
4328
  * Run `fn` after every paint, on the frame that painted — for chrome that
@@ -3837,6 +4407,10 @@ interface CanvasExtensionApi {
3837
4407
  x: number;
3838
4408
  y: number;
3839
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;
3840
4414
  }
3841
4415
  /**
3842
4416
  * The imperative ref handle for `<SceneCanvas>` — everything on
@@ -3860,6 +4434,16 @@ interface SceneCanvasApi extends CanvasExtensionApi {
3860
4434
  /** Cancel a camera animation. The view stays where it is. */
3861
4435
  stopViewAnimation(): void;
3862
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;
3863
4447
  }
3864
4448
 
3865
4449
  /**
@@ -4067,7 +4651,10 @@ interface CanvasHelpers<TPose> extends CanvasViewHelpers<TPose>, CanvasSurfaceHe
4067
4651
  * Built-in entries (`kit:text`, `kit:path`, `kit:rect-fallback`) are
4068
4652
  * registered at module load. Consumer entries added via
4069
4653
  * `registerNodeShape` join the chain; the first entry whose
4070
- * `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.
4071
4658
  *
4072
4659
  * Two priority tiers:
4073
4660
  * - `'high'` — checked before all `'normal'` entries. Use this to
@@ -4101,6 +4688,10 @@ interface NodePaintCtx {
4101
4688
  * the wrapper hands such a node the caller's own ctx untouched. `null`
4102
4689
  * means the node derives but has nothing to draw. */
4103
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;
4104
4695
  }
4105
4696
  /**
4106
4697
  * Per-node draw function — the scene-slot `drawOne` signature shared by
@@ -4120,7 +4711,9 @@ interface NodeShapeEntry<TData = unknown, TPose = unknown> {
4120
4711
  * something descriptive: `'kit:text'`, `'app:image'`, etc. */
4121
4712
  id: string;
4122
4713
  /** Returns true when this painter renders the node. The first matching
4123
- * 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. */
4124
4717
  matches(node: Node$1<TData, string, TPose>): boolean;
4125
4718
  /** Emits the draw commands for the node's primary visual. `ctx` is an
4126
4719
  * optional per-call paint context (see `NodePaintCtx`); painters that
@@ -4278,11 +4871,9 @@ declare function getNodeShapes(): readonly NodeShapeEntry[];
4278
4871
  * `createSelectionOverlayLayer` is a thin convenience that returns a single
4279
4872
  * `RenderLayer` whose draw runs the outline pass then the handles pass.
4280
4873
  *
4281
- * **Pose shape:** TPose is generic; callers must supply `getBounds(pose)`
4282
- * to project any pose into the AABB the renderer needs. For rect-shaped
4283
- * poses (`{x, y, width, height}`) pass the identity. For `Path` poses pass
4284
- * `boundsOfPath`. Container ids reduce via `unionAABB` over the projected
4285
- * 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.
4286
4877
  */
4287
4878
 
4288
4879
  /** Options for `composeSelectionPose`. */
@@ -4304,19 +4895,8 @@ interface ComposeSelectionPoseOpts<TPose> {
4304
4895
  } | null;
4305
4896
  /** Fallback pose lookup (typically the stored/committed pose). */
4306
4897
  getStoredPose: (id: string) => TPose;
4307
- /**
4308
- * Project a pose into its AABB. Used when reducing a group of leaf poses
4309
- * into a single union AABB. Defaults to the identity — rect-shaped poses
4310
- * (`{x, y, width, height}`) need no override. For `Path` poses pass
4311
- * `boundsOfPath`.
4312
- */
4313
- getBounds?: (pose: TPose) => Bounds;
4314
- /**
4315
- * Wrap an AABB back into a TPose. Called only when the resolver collapses
4316
- * a container's leaves into a single union AABB. Defaults to the identity —
4317
- * for `Path` poses pass `(b) => ({ kind: 'rect', ...b })`.
4318
- */
4319
- fromBounds?: (bounds: Bounds) => TPose;
4898
+ /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */
4899
+ poseDescriptor?: PoseDescriptor<TPose>;
4320
4900
  /** Walk a container's direct children (e.g. `scene.childrenOf`). With
4321
4901
  * `isContainer`, a selected container resolves to the union AABB of its
4322
4902
  * transitive leaf poses instead of its own stored pose. */
@@ -4336,12 +4916,8 @@ declare function composeSelectionPose<TPose>(opts: ComposeSelectionPoseOpts<TPos
4336
4916
  * declared on {@link SelectionOverlayLayerOpts}, which makes both optional —
4337
4917
  * omitted, they come off the draw envelope. */
4338
4918
  interface SelectionLayerCommon<TPose> {
4339
- /**
4340
- * Project a pose into its AABB. Defaults to the identity — rect-shaped
4341
- * poses (`{x, y, width, height}`) need no override. For `Path` poses pass
4342
- * `boundsOfPath`.
4343
- */
4344
- getBounds?: (pose: TPose) => Bounds;
4919
+ /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */
4920
+ poseDescriptor?: PoseDescriptor<TPose>;
4345
4921
  /** Walk a container's direct children (e.g. `scene.childrenOf`). When
4346
4922
  * supplied with `isContainer`, any id that resolves to a container is
4347
4923
  * rendered using the union bounds of all its transitive leaves. */
@@ -4439,6 +5015,10 @@ interface HierarchicalAdapter<TNode, TPose> {
4439
5015
  getNode(id: string): TNode | undefined;
4440
5016
  getChildren(parentId: string | null): readonly string[];
4441
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;
4442
5022
  }
4443
5023
 
4444
5024
  /**
@@ -4618,16 +5198,15 @@ interface CanvasProps<TNode extends {
4618
5198
  */
4619
5199
  selection?: SelectionApi;
4620
5200
  /**
4621
- * Pose↔bounds projection for non-rect `TPose` types. When supplied, drives
4622
- * the default `boundsOf` fallback and the selection-overlay bounds source so
4623
- * 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.
4624
5203
  * Defaults to the rect identity (`AUTO_POSE_DESCRIPTOR`).
4625
5204
  *
4626
5205
  * This is a math helper, not a scene-shaped concern — it converts a pose
4627
5206
  * value to an AABB and extracts rotation for the selection chrome. Bare-
4628
5207
  * Canvas consumers that use a non-rect pose type should supply this.
4629
5208
  */
4630
- geometry?: PoseProjection<TPose>;
5209
+ poseDescriptor?: PoseDescriptor<TPose>;
4631
5210
  /**
4632
5211
  * Used by `PickHud` to display the list of ids under the cursor.
4633
5212
  * NOT used for tool routing — see `getNodeAtPoint` for that.
@@ -4637,7 +5216,7 @@ interface CanvasProps<TNode extends {
4637
5216
  pickEvery?: (worldX: number, worldY: number) => string | string[] | null;
4638
5217
  /**
4639
5218
  * Override for committed bounds lookup. When supplied, takes precedence over
4640
- * the `geometry`-derived fallback. Used by the selection overlay, the
5219
+ * the `poseDescriptor`-derived fallback. Used by the selection overlay, the
4641
5220
  * multi-select union AABB, and `helpersRef.getEffectiveBounds`. Optional —
4642
5221
  * bare-Canvas consumers that use a custom bounds shape should supply this;
4643
5222
  * `<SceneCanvas>` derives it from its scene adapter and passes it via the
@@ -4902,6 +5481,12 @@ interface ReorderAdapter {
4902
5481
  * touch an adapter directly. */
4903
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>>> & {
4904
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;
4905
5490
  getSelection(): string[];
4906
5491
  setSelection(ids: string[]): void;
4907
5492
  insertNode(node: Node$1<TData, TLayer, TPose>, index?: number): void;
@@ -4941,10 +5526,8 @@ interface SceneToAdapterOptions<TData, TLayer extends string, TPose> {
4941
5526
  * fine for read-only or selection-less canvases, but the marquee gesture
4942
5527
  * won't update any external selection state. */
4943
5528
  selection?: SceneAdapterSelection;
4944
- /** Project a pose to an AABB for `hitTestArea`. Default: identity (works
4945
- * when TPose carries top-level x/y/width/height). Override for non-rect
4946
- * poses. */
4947
- poseBounds?: (pose: TPose) => Bounds;
5529
+ /** How to read and rewrite this scene's poses. Default `AUTO_POSE_DESCRIPTOR`. */
5530
+ poseDescriptor?: PoseDescriptor<TPose>;
4948
5531
  /** Layout strategies keyed by container node id. When a container is
4949
5532
  * configured here, `move` runs its layout-aware pass on drag (reflow on
4950
5533
  * enter, reflow leftovers on exit, reparent + write reflowed poses on
@@ -4952,14 +5535,16 @@ interface SceneToAdapterOptions<TData, TLayer extends string, TPose> {
4952
5535
  * either a static map, or a `getLayout(id)` function for dynamic
4953
5536
  * resolution. */
4954
5537
  layouts?: Record<string, LayoutStrategy<TPose>> | ((containerId: string) => LayoutStrategy<TPose> | null);
4955
- /** When set, `setPose(id, ...)` on a container node cascades the translation
4956
- * to every descendant. Scene v1 stores absolute poses, so dragging a
4957
- * container needs to translate its children to keep them visually attached
4958
- * to their parent. Pass `'rect'` to use the built-in `translateRectPose`
4959
- * (works for any `TPose extends { x: number; y: number }`); pass a custom
4960
- * `(pose, dx, dy) => pose` for non-rect pose shapes. Omit to leave setPose
4961
- * primitive — containers move but their descendants don't follow. */
4962
- 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>;
4963
5548
  }
4964
5549
  /** Derive the adapter for a scene. Reads go straight to the scene; writes are
4965
5550
  * ops applied through its history, so anything done through the adapter is
@@ -4984,27 +5569,17 @@ declare function useSceneAdapter<TData, TLayer extends string, TPose>(scene: Sce
4984
5569
  * Consumers should import from here directly; `rotate.ts` re-exports the
4985
5570
  * same symbols for back-compat. */
4986
5571
 
4987
- /** Projects a pose to and from a rotated bounding box, so the rotate action
4988
- * can work on pose shapes that carry rotation differently. */
4989
- interface RotateGeometry<TPose> {
4990
- getRotatedBounds(pose: TPose): RotatedPose;
4991
- /** Write a new rotation back into the pose; bounds stay the same. */
4992
- withRotation(pose: TPose, rotation: number): TPose;
4993
- }
4994
5572
  /** Options for the `rotate` action. */
4995
5573
  interface UseRotateOptions<TPose> {
4996
5574
  /** Behaviors are typed against the pose shape; the kit ships none yet
4997
5575
  * (rotation snap behaviors are deferred). For non-rect TPose, behaviors
4998
- * are typed `never` until you supply a `geometry`. */
5576
+ * are typed `never` for a pose without a numeric `rotation`. */
4999
5577
  behaviors?: TPose extends RotatedPose ? RotateBehavior<TPose>[] : never;
5000
5578
  rotateLabel?: string;
5001
5579
  /** Reserved; rotate is never transient in practice. Ignored. */
5002
5580
  transient?: boolean;
5003
5581
  onGestureStart?: (id: string) => void;
5004
5582
  onGestureEnd?: (committed: boolean) => void;
5005
- /** Project pose ↔ rotated bounds. Defaults to the identity for
5006
- * `RotatedPose`. Required for non-rect TPose (e.g. a rotated path). */
5007
- geometry?: RotateGeometry<TPose>;
5008
5583
  /** Optional debug sink. When supplied, records the rotation-handle
5009
5584
  * position + circular hitbox at gesture start. Tree-shakes via
5010
5585
  * optional-chain when omitted. */
@@ -5025,60 +5600,95 @@ interface UseRotateOptions<TPose> {
5025
5600
  pivot?: 'each' | 'union';
5026
5601
  }
5027
5602
 
5028
- /** A rect on the surface, in CSS pixels from the canvas top-left. */
5029
- interface ViewRect {
5030
- x: number;
5031
- y: number;
5032
- w: number;
5033
- h: number;
5034
- }
5035
- /** Props for `<CanvasView>`. @experimental */
5036
- interface CanvasViewProps {
5037
- /** Identifies the view to the surface and to input routing. Must be unique
5038
- * among the views on one canvas. */
5039
- id: string;
5040
- /** Where this view paints, recomputed every frame so the rect can track the
5041
- * outer camera. A plain rect is accepted for a fixed panel. */
5042
- bounds: ViewRect | ((outer: View, dims: Dims) => ViewRect);
5043
- /** Camera. Supply this to control it; otherwise the view keeps its own,
5044
- * seeded from `defaultView`. `onViewChange` fires either way. */
5045
- view?: View;
5046
- defaultView?: View;
5047
- onViewChange?: (v: View) => void;
5048
- /** Pan limits, applied to every camera change the same way `<Canvas>`
5049
- * applies its own. */
5050
- viewBounds?: Bounds;
5051
- /** Which of the surface's layers this view paints. Defaults to all of them —
5052
- * the same content through a second camera. */
5053
- layers?: (surface: readonly RenderLayer<unknown>[]) => readonly RenderLayer<unknown>[];
5054
- /** Opaque ground painted before the source layers, so the surface does not
5055
- * show through where the inner camera sees nothing. */
5056
- background?: string;
5057
- /** Paint and hit order. Defaults to `Infinity` — after every view the
5058
- * surface declared as a prop. */
5059
- order?: number;
5060
- /** Label for debug overlays. Defaults to the id. */
5061
- label?: string;
5062
- /** A selection of this view's own, which actions dispatched inside it read
5063
- * and write instead of the surface's. Omit both this and
5064
- * `selectionOptions` and the view shares the surface's selection — the
5065
- * default, so undo restores one selection rather than N. */
5066
- selection?: SelectionApi;
5067
- /** Opts this view into owning a selection, configured thus. Ignored when
5068
- * `selection` is supplied. */
5069
- selectionOptions?: UseSelectionOptions;
5070
- }
5071
5603
  /**
5072
- * @experimental
5604
+ * The kit's built-in shape kinds — one table, every other spelling derived.
5073
5605
  *
5074
- * One view on a shared canvas. Owns a camera, contributes the viewport node
5075
- * that paints it, and registers the dispatch record that sends gestures inside
5076
- * 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.
5077
5611
  *
5078
- * Renders nothing itself — it is a declaration, and the surface does the
5079
- * 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.
5080
5615
  */
5081
- 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[];
5082
5692
 
5083
5693
  /** Per-tool option overrides for the built-in shape/lasso tools.
5084
5694
  * Each entry is a narrow subset of the underlying hook's options surface
@@ -5281,7 +5891,7 @@ interface SceneCanvasHit {
5281
5891
  /** Props for `<SceneCanvas>`. Most are optional: a scene is the only thing it
5282
5892
  * truly needs, and everything else — tools, layers, selection handling,
5283
5893
  * layouts, animation — layers onto sensible defaults. */
5284
- 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'> & {
5285
5895
  /** A `Scene` (typically from `useScene`) — or a `SerializedScene`
5286
5896
  * JSON object, which SceneCanvas bakes into a Scene internally on
5287
5897
  * first render. The serialized form is read once; subsequent
@@ -5309,6 +5919,12 @@ type SceneCanvasProps<TData, TLayer extends string, TPose> = Omit<CanvasProps<No
5309
5919
  * to `sceneToAdapter` so `useMove`'s layout pass runs on configured
5310
5920
  * containers (reflow on enter, reparent + reflow on commit). */
5311
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'];
5312
5928
  /**
5313
5929
  * Optional consumer seam for eager geometry sync: lets pose-transform
5314
5930
  * actions (move, resize, nudge, flip — NOT rotate) also rewrite a node's
@@ -5345,6 +5961,10 @@ type SceneCanvasProps<TData, TLayer extends string, TPose> = Omit<CanvasProps<No
5345
5961
  * it with extras is what needs the memo.)
5346
5962
  */
5347
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>;
5348
5968
  geometry?: {
5349
5969
  /** Hit-test override. Return the topmost id, the full back-to-front hit
5350
5970
  * stack (`string[]`), or `null` for empty space. The stack form lets a
@@ -5628,9 +6248,9 @@ type SceneCanvasProps<TData, TLayer extends string, TPose> = Omit<CanvasProps<No
5628
6248
  /**
5629
6249
  * Optional animator to bind for per-frame redraws. When supplied,
5630
6250
  * SceneCanvas subscribes to `animator.onTick` and requests a redraw on
5631
- * every active animation frame. This is the supported way to drive
5632
- * repaints when an animation's effect is read from a non-scene channel
5633
- * (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
5634
6254
  * mutations trigger repaints automatically, but `colorOverrides` writes
5635
6255
  * do not.
5636
6256
  *
@@ -5753,6 +6373,25 @@ type SceneCanvasProps<TData, TLayer extends string, TPose> = Omit<CanvasProps<No
5753
6373
  * Defaults to `() => 1` (no effect).
5754
6374
  */
5755
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[];
5756
6395
  /**
5757
6396
  * Optional per-id pointer-interactivity predicate. When supplied, ids
5758
6397
  * for which the predicate returns `false` are excluded from hit-test
@@ -6059,6 +6698,194 @@ declare const defaultNodeProperties: readonly NodePropertiesEntry[];
6059
6698
  */
6060
6699
  declare const inferredNodeProperties: readonly NodePropertiesEntry[];
6061
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
+
6062
6889
  /**
6063
6890
  * `renderSceneToCanvas` — substrate for detached, read-only scene views
6064
6891
  * (`<SceneViewCanvas>` / `<MinimapCanvas>`). Given a `<canvas>`, a `Scene`,
@@ -6078,6 +6905,18 @@ declare const inferredNodeProperties: readonly NodePropertiesEntry[];
6078
6905
  * in sync by hand where it matters (DPR handling, viewToMat3 wrap).
6079
6906
  */
6080
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
+ }
6081
6920
  /** What to draw into an existing canvas: the scene, the view, and the same
6082
6921
  * painting hooks `<SceneCanvas>` takes. */
6083
6922
  interface RenderSceneToCanvasArgs<TData, TLayer extends string, TPose> {
@@ -6107,6 +6946,13 @@ interface RenderSceneToCanvasArgs<TData, TLayer extends string, TPose> {
6107
6946
  * `alphaFor`. Pass the same function the main canvas uses to keep a
6108
6947
  * scoping-dim treatment consistent across both. Defaults to `() => 1`. */
6109
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;
6110
6956
  /** Optional device-pixel ratio. Defaults to `window.devicePixelRatio || 1`
6111
6957
  * when available, otherwise 1. Tests typically pin this to 1 or 2. */
6112
6958
  dpr?: number;
@@ -6128,13 +6974,21 @@ interface RenderSceneToCanvasArgs<TData, TLayer extends string, TPose> {
6128
6974
  * emit unrotated geometry and let the pose drive it.
6129
6975
  *
6130
6976
  * Output shape follows `buildSceneTree`: one group per **visible** layer, in
6131
- * 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.
6132
6979
  *
6133
6980
  * Exported for tests and for callers that want to render into something
6134
6981
  * other than a real `<canvas>` (e.g. an offscreen renderer or a
6135
6982
  * snapshot fixture).
6136
6983
  */
6137
- 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[];
6138
6992
  /**
6139
6993
  * Render one frame of `scene` at `view` into `canvas`. See module docstring
6140
6994
  * for the design context.
@@ -6178,6 +7032,15 @@ interface SceneViewCanvasProps<TData, TLayer extends string, TPose> {
6178
7032
  * `alphaFor`. Pass the same function the main canvas uses to keep a
6179
7033
  * scoping-dim treatment consistent across both. Defaults to `() => 1`. */
6180
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;
6181
7044
  /** Optional CSS class for sizing / positioning the `<canvas>`. The kit
6182
7045
  * does not emit inline styles for layout — use a class. */
6183
7046
  className?: string;
@@ -6211,7 +7074,7 @@ declare function sceneSelectionStore(scene: {
6211
7074
  * registry passed in `options`. Throws on unknown version, unknown registry
6212
7075
  * keys, or invalid scene shape (cross-layer subtrees, unknown layer ids).
6213
7076
  * Loaded scenes start with empty history — undo/redo is NOT serialized. */
6214
- 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?: {
6215
7078
  registry?: SceneRegistry<TPose>;
6216
7079
  historyLimit?: number;
6217
7080
  coalesceWindowMs?: number;
@@ -6326,6 +7189,25 @@ declare function documentPose<TPose>(source: PoseSource<TPose>, node: PosedNode<
6326
7189
  */
6327
7190
  declare function effectivePose<TPose>(source: PoseSource<TPose>, node: PosedNode<TPose>): TPose;
6328
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
+
6329
7211
  /** Registry key for {@link unionOfChildren}. */
6330
7212
  declare const UNION_OF_CHILDREN = "kit:unionOfChildren";
6331
7213
  /**
@@ -6337,6 +7219,13 @@ declare const UNION_OF_CHILDREN = "kit:unionOfChildren";
6337
7219
  * Returns `null` for an emptied container, which falls back to its authored
6338
7220
  * pose — the group stays where the last member left it rather than collapsing
6339
7221
  * to a zero box at the origin.
7222
+ *
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.
6340
7229
  */
6341
7230
  declare function unionOfChildren<TPose>(_node: unknown, deps: readonly ({
6342
7231
  pose: TPose;
@@ -6350,7 +7239,7 @@ declare const FALLBACK_FIT_VIEW: View;
6350
7239
  /**
6351
7240
  * Fit policy for `<MinimapCanvas>` / `computeFitView`.
6352
7241
  *
6353
- * - `"scene"` — union of leaf-node pose AABBs (via `poseBounds`).
7242
+ * - `"scene"` — union of leaf-node pose AABBs (via the pose descriptor).
6354
7243
  * - `{ kind: "world", rect }` — caller-supplied world rect.
6355
7244
  * - `(scene, dims) => View` — caller derives the view directly.
6356
7245
  */
@@ -6378,7 +7267,7 @@ interface ComputeFitViewOptions {
6378
7267
  * is centered with `padding` (default 8) on each side. The smaller-axis
6379
7268
  * fit ratio wins, so the whole rect is visible.
6380
7269
  *
6381
- * - `fit === "scene"`: union AABB of leaf-node poses via `poseBounds`.
7270
+ * - `fit === "scene"`: union AABB of leaf-node poses via `descriptor`.
6382
7271
  * Empty scene → {@link FALLBACK_FIT_VIEW}.
6383
7272
  * - `fit` is `{ kind: "world", rect }`: fit `rect`. A degenerate rect
6384
7273
  * (zero or negative area) falls back to identity scale centered on the
@@ -6386,7 +7275,7 @@ interface ComputeFitViewOptions {
6386
7275
  * - `fit` is a function: called with `(scene, dims)`; its return is
6387
7276
  * passed through unchanged.
6388
7277
  */
6389
- 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;
6390
7279
  /**
6391
7280
  * Build the visible-window indicator `DrawCommand` for the minimap.
6392
7281
  *
@@ -6438,13 +7327,21 @@ interface MinimapCanvasProps<TData, TLayer extends string, TPose> {
6438
7327
  * frame if it goes there, rather than making the whole minimap rescale on
6439
7328
  * every frame of a drag or a settle. */
6440
7329
  fit?: MinimapFit<TData, TLayer, TPose>;
6441
- /** Pose → AABB. Defaults to identity (`pose as Bounds`), matching
6442
- * `sceneAdapter` / `useSelectTool`. */
6443
- poseBounds?: (pose: TPose) => Bounds;
7330
+ /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */
7331
+ poseDescriptor?: PoseDescriptor<TPose>;
6444
7332
  /** Optional per-id alpha multiplier, mirroring `<SceneCanvas>`'s scene-slot
6445
7333
  * `alphaFor`. Pass the same function the main canvas uses so a
6446
7334
  * scoping-dim treatment shows up in the minimap too. */
6447
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;
6448
7345
  /** Visual tuning of the indicator stroke. */
6449
7346
  indicatorStyle?: IndicatorStyle;
6450
7347
  /** CSS class for sizing / positioning the canvas. */
@@ -6508,6 +7405,9 @@ interface RenderSceneToPixelsArgs<TData, TLayer extends string, TPose> {
6508
7405
  * `alphaFor`. Pass the same function the on-screen canvas uses so an
6509
7406
  * export matches what the user is looking at. Defaults to `() => 1`. */
6510
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;
6511
7411
  /** Background fill (any CSS color accepted by the renderer). Default:
6512
7412
  * fully transparent. Passing a color is always valid. */
6513
7413
  background?: string;
@@ -7016,9 +7916,9 @@ declare function renderLabel(ctx: CanvasRenderingContext2D, text: string, x: num
7016
7916
  declare const defaultLabelTextRenderer: TextRenderer;
7017
7917
 
7018
7918
  /**
7019
- * Text RenderLayer. Emits one TextDrawCommand per text node carrying the
7020
- * node's resolved runs and bounding rect. Word wrap and multi-line layout
7021
- * 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.
7022
7922
  *
7023
7923
  * The GL renderer uses MSDF text. The resolved style's `fontFamily` must
7024
7924
  * be registered via `registerFont(family, variant, metricsUrl, atlasUrl)`
@@ -7053,10 +7953,10 @@ declare function createTextLayer<T>(opts: CreateTextLayerOpts<T>): RenderLayer<u
7053
7953
  *
7054
7954
  * `caretIndexAt` does the finer test: given a world-space (x, y) inside the
7055
7955
  * pose, returns the corresponding character offset so the consumer can place
7056
- * the caret on click. It reads the caret stops off the same
7057
- * `cachedLayoutRuns` result the renderer paints and `textLineBoxes` picks
7058
- * against, so the caret cannot land on a different line — or between
7059
- * 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.
7060
7960
  */
7061
7961
 
7062
7962
  /** Options for `pointInTextPose`. */
@@ -7066,19 +7966,6 @@ interface PointInTextPoseOpts {
7066
7966
  }
7067
7967
  /** Coarse pose-rect hit-test for a text node — suitable for click-to-edit dispatch. */
7068
7968
  declare function pointInTextPose(x: number, y: number, pose: TextPose, opts?: PointInTextPoseOpts): boolean;
7069
- /** Options for `caretIndexAt`. */
7070
- interface CaretIndexAtOpts {
7071
- /**
7072
- * Wrap width. Default `pose.width`, which is what `createTextLayer` passes
7073
- * and what `TextPose` means by its box.
7074
- *
7075
- * Pass `Infinity` for a node painted by the built-in `kit:text` painter:
7076
- * that painter deliberately does not forward `maxWidth`, so its text does
7077
- * not wrap, and a caret mapped through a finite width would answer for a
7078
- * line break the paint never made. Mirrors `textLineBoxes`.
7079
- */
7080
- maxWidth?: number;
7081
- }
7082
7969
  /**
7083
7970
  * Map a world-space point inside `pose` to a character offset into the pose's
7084
7971
  * text (0..length). Clicks above the first line clamp to 0; clicks below the
@@ -7090,7 +7977,7 @@ interface CaretIndexAtOpts {
7090
7977
  * produced) and `pose.verticalAlign`. The offset is into the runs'
7091
7978
  * concatenated text, which `TextPose` requires to equal `pose.text`.
7092
7979
  */
7093
- declare function caretIndexAt(x: number, y: number, pose: TextPose, opts?: CaretIndexAtOpts): number;
7980
+ declare function caretIndexAt(x: number, y: number, pose: TextPose): number;
7094
7981
 
7095
7982
  /**
7096
7983
  * Resize a text node's pose to fit its content. Pure helper — does not own
@@ -7100,8 +7987,9 @@ declare function caretIndexAt(x: number, y: number, pose: TextPose, opts?: Caret
7100
7987
  * Two modes:
7101
7988
  *
7102
7989
  * - `axis: 'height'` (default): keep `pose.width`, recompute `height` as
7103
- * the wrapped block height plus optional vertical padding. The common
7104
- * 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.
7105
7993
  *
7106
7994
  * - `axis: 'both'`: ignore wrapping; recompute both `width` (longest
7107
7995
  * `\n`-split line) and `height` (line count × line height) plus padding.
@@ -7321,6 +8209,13 @@ interface TextEditScreenPose {
7321
8209
  */
7322
8210
  zoom?: number;
7323
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
+ }
7324
8219
  /** Options for `useTextEdit`. */
7325
8220
  interface UseTextEditOptions {
7326
8221
  /** Element the overlay is appended to. Must be `position: relative`/absolute. */
@@ -7347,6 +8242,15 @@ interface UseTextEditOptions {
7347
8242
  setStyle?: (id: string, style: TextStyle) => void;
7348
8243
  /** Read screen-space pose for `id`. Called per frame while editing. */
7349
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;
7350
8254
  /** Commit text. Caller wraps in op/undo. */
7351
8255
  setText: (id: string, text: string) => void;
7352
8256
  /**
@@ -7509,9 +8413,9 @@ declare function unionAABB<TPose extends RectPose>(parts: Iterable<TPose | null
7509
8413
  * (`getText` / `getStyle` / `getRuns` / `setText` / `setRuns` / `setStyle`).
7510
8414
  *
7511
8415
  * Pose component: the helper reads `(x, y, width, height)` straight off
7512
- * the node's pose (typed `RectPose`). Pass `view` and it projects that box
7513
- * through the viewport; omit it and world units are handed through as
7514
- * 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.
7515
8419
  * Consumers with non-rect poses should drop down to raw `useTextEdit` and
7516
8420
  * supply their own `getScreenPose`.
7517
8421
  */
@@ -7525,6 +8429,7 @@ interface DefaultTextData {
7525
8429
  runs?: readonly StyledRun[];
7526
8430
  fill?: FillStyle | null;
7527
8431
  stroke?: Stroke | null;
8432
+ verticalAlign?: TextVerticalAlign;
7528
8433
  }
7529
8434
  /** All-optional projections + fontSize fallback. */
7530
8435
  interface UseSceneTextEditOptions<TData> {
@@ -7536,6 +8441,8 @@ interface UseSceneTextEditOptions<TData> {
7536
8441
  getPaint?: (data: TData) => TextPaint | undefined;
7537
8442
  /** Read rich-text runs from `data`. Default: `data.runs`. */
7538
8443
  getRuns?: (data: TData) => readonly StyledRun[] | undefined;
8444
+ /** Read the box vertical alignment from `data`. Default: `data.verticalAlign`. */
8445
+ getVerticalAlign?: (data: TData) => TextVerticalAlign | undefined;
7539
8446
  /** Produce updated data with new text. Default: `{ ...data, text }`. */
7540
8447
  setText?: (data: TData, text: string) => TData;
7541
8448
  /** Produce updated data with new runs. Default: `{ ...data, runs }`. */
@@ -7551,21 +8458,24 @@ interface UseSceneTextEditOptions<TData> {
7551
8458
  /** Fallback fontSize when `style.fontSize` is unset. Default `16`. */
7552
8459
  defaultFontSize?: number;
7553
8460
  /**
7554
- * Current viewport. Supply it on a canvas that pans or zooms: the overlay
7555
- * 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
7556
8468
  * by the view, so every typographic metric on it — including the
7557
8469
  * `fontSize` / `letterSpacing` a *run* carries — stays in world units and
7558
- * scales together. Omit it and the node's world box is passed through as
7559
- * screen pixels (correct at `{x: 0, y: 0, scale: 1}`).
8470
+ * scales together.
7560
8471
  *
7561
8472
  * The overlay takes a single scale factor, so a non-uniform view scale is
7562
8473
  * represented by its `scale.x`; text under `scale.x !== scale.y` will not
7563
8474
  * match the canvas.
7564
8475
  *
7565
- * A thunk is re-read on every projection, which is what an uncontrolled
7566
- * `SceneCanvas` needs — its camera lives in a ref and moves without a
7567
- * render, so pass the handle's `getView`. A plain `View` is the value from
7568
- * 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.
7569
8479
  */
7570
8480
  view?: View | (() => View);
7571
8481
  /**
@@ -7591,8 +8501,10 @@ interface UseSceneTextEditReturn extends UseTextEditReturn {
7591
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;
7592
8502
 
7593
8503
  /**
7594
- * Build a `TextDrawCommand`. `textCommand` takes a plain string and wraps it
7595
- * 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
7596
8508
  * resolve through `resolveTextStyle` + `resolveRuns`, so every emitter of a
7597
8509
  * text command derives `align` and per-run resolution the same way — a
7598
8510
  * caller that assembles the command by hand is one field away from a
@@ -7602,11 +8514,18 @@ declare function useSceneTextEdit<TData extends DefaultTextData, TLayer extends
7602
8514
  * a HUD widget, a debug overlay — states its color on the run instead.
7603
8515
  */
7604
8516
 
7605
- 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;
7606
8518
  /** Build a draw command for a single unstyled string. Text is laid out with
7607
- * the registered font's metrics, wrapped at `maxWidth` and aligned within
7608
- * `height` when both are given. */
7609
- 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;
7610
8529
 
7611
8530
  /**
7612
8531
  * Pure DOM ↔ `StyledRun[]` serializers for the contenteditable overlay
@@ -8098,10 +9017,8 @@ interface NestedHitOpts<TNode extends {
8098
9017
  /** Compose a child's local pose into world coords given its parent's world
8099
9018
  * pose. Same shape as `composeRectPose` (the default expectation). */
8100
9019
  composePose: (parent: TPose, child: TPose) => TPose;
8101
- /** Derive an axis-aligned bounding rect from a (world-space) pose. Default
8102
- * reads `x` / `y` / `width` / `height` straight off the pose (matches
8103
- * `RectPose`). Override for non-rect poses (e.g. paths). */
8104
- poseBounds?: (pose: TPose) => Bounds;
9020
+ /** How to read world poses. Default `AUTO_POSE_DESCRIPTOR`. */
9021
+ poseDescriptor?: PoseDescriptor<TPose>;
8105
9022
  /** Predicate for "this object is a nesting parent body". The leaf scan
8106
9023
  * skips objects for which this returns true so a click on a parent's
8107
9024
  * painted body resolves to a child leaf, not the parent itself. Default:
@@ -8130,6 +9047,22 @@ declare function nestedHitTester<TNode extends {
8130
9047
  id: string;
8131
9048
  }, TPose>(adapter: HitAdapter<TNode, TPose>, opts: NestedHitOpts<TNode, TPose>): NestedHitTester;
8132
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
+
8133
9066
  /**
8134
9067
  * Fluent builder for `PolygonPath`. Hides the `Uint8Array` / `Float32Array`
8135
9068
  * encoding behind move/line/curve/close calls and a final `build()`. Use
@@ -8401,9 +9334,7 @@ declare function pointAlongPath(path: Path, t: number, opts?: PointAlongPathOpti
8401
9334
  *
8402
9335
  * `scalePathToBounds` is for the resize interaction: given the path's
8403
9336
  * current AABB and the desired new AABB, scales every coordinate
8404
- * proportionally. Degenerate source bounds (zero width/height) collapse
8405
- * the corresponding axis to the new origin — preferable to dividing by
8406
- * zero or refusing to resize.
9337
+ * proportionally.
8407
9338
  */
8408
9339
 
8409
9340
  /**
@@ -8422,9 +9353,9 @@ declare function translatePolygonInPlace(path: PolygonPath, dx: number, dy: numb
8422
9353
  * Scale a path's coords so its current AABB maps to `target`. Resize
8423
9354
  * interactions use this to make a polygon follow a corner-handle drag.
8424
9355
  *
8425
- * Degenerate source axes (width or height == 0) collapse to `target.x` /
8426
- * `target.y` — every coord on that axis becomes the new origin. Avoids
8427
- * 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.
8428
9359
  */
8429
9360
  declare function scalePathToBounds(path: Path, target: RectPath): Path;
8430
9361
 
@@ -8581,48 +9512,6 @@ interface CreatePathLayerOpts<T> {
8581
9512
  /** Build a `RenderLayer` that fills/strokes `Path` instances enumerated from a node list. */
8582
9513
  declare function createPathLayer<T>(opts: CreatePathLayerOpts<T>): RenderLayer<unknown>;
8583
9514
 
8584
- /**
8585
- * Bezier flattening — subdivide cubic and quadratic segments into polyline
8586
- * approximations within a flatness tolerance. Used by hit-testing and
8587
- * (eventually) any kernel that doesn't want to special-case curves.
8588
- *
8589
- * The flatness metric is the maximum perpendicular distance from any
8590
- * control point to the chord between endpoints. When that distance falls
8591
- * below `tolerance`, the segment is "flat enough" and emitted as a single
8592
- * line segment.
8593
- *
8594
- * Tolerance is in world units. 0.5 is a sensible default for screen-rate
8595
- * rendering at 1× zoom; consumers that zoom in heavily should pass a
8596
- * tighter tolerance.
8597
- */
8598
- declare const DEFAULT_FLATTEN_TOLERANCE = 0.5;
8599
- /**
8600
- * Recursively subdivide a cubic bezier (P0..P3) and append `lineTo`-style
8601
- * vertices to `out` (interleaved x,y). The starting endpoint is *not*
8602
- * appended — callers usually emitted it as the segment's previous vertex.
8603
- */
8604
- declare function flattenCubic(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, tolerance: number, out: number[]): void;
8605
- /** Recursively subdivide a quadratic bezier (P0, P1, P2). */
8606
- declare function flattenQuadratic(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, tolerance: number, out: number[]): void;
8607
- /**
8608
- * Like `flattenCubic` but also appends, for each new flattened point, its
8609
- * arc-length fraction `t` (relative to the polyline distance accumulated so
8610
- * far inside this curve) to `arcOut`. Caller then post-processes the segment's
8611
- * `arcOut` range by dividing each by the segment's total flattened arc length
8612
- * to yield t ∈ (0, 1].
8613
- *
8614
- * The returned values are *cumulative distance from the segment start*, not
8615
- * normalized fractions. Two-pass design (accumulate, then divide) keeps the
8616
- * recursive splitter simple — it doesn't need to know the total length up
8617
- * front.
8618
- */
8619
- 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;
8620
- /** Flatten a quadratic bezier into line segments within `tolerance`, appending
8621
- * points to `out` and their cumulative arc lengths to `arcOut`. The arc
8622
- * lengths are what lets per-anchor color and dash phase be interpolated
8623
- * evenly along the curve rather than per segment. */
8624
- declare function flattenQuadraticWithArcLen(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, tolerance: number, out: number[], arcOut: number[]): number;
8625
-
8626
9515
  /**
8627
9516
  * `pathFromD` — build a weasel `Path` from an **SVG path-data string** (the
8628
9517
  * value of SVG's `d` attribute, e.g. `"M0 0 L100 0 Z"`).
@@ -8716,17 +9605,16 @@ declare function splitPathByLine(path: Path, a: Point, b: Point, opts?: SplitByL
8716
9605
  declare function unionBoundsPath(paths: Iterable<Path>): RectPath | null;
8717
9606
 
8718
9607
  /**
8719
- * `PoseProjection` for `Path` poses — wires `useResize` to operate
9608
+ * `PoseDescriptor` for `Path` poses — wires `useResize` to operate
8720
9609
  * on `Path` directly. `getBounds` defers to the same `boundsOfPath` kernel
8721
- * the rest of the kit uses; `remapBounds` does an affine scale of every
8722
- * coord against `src`/`dst`. Degenerate axes (zero src extent) collapse to
8723
- * the new origin so resize from a flat edge doesn't produce NaN.
9610
+ * the rest of the kit uses.
8724
9611
  *
8725
- * Mirrors `scalePathToBounds` but takes `src` explicitly: the resize hook
8726
- * knows the group's origin AABB and uses it for every leaf, instead of
8727
- * 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).
8728
9616
  */
8729
- declare const pathPoseDescriptor: PoseProjection<Path>;
9617
+ declare const pathPoseDescriptor: PoseDescriptor<Path>;
8730
9618
 
8731
9619
  /**
8732
9620
  * `OriginProjection` for `Path` poses. The "origin" is the top-left of the
@@ -8862,11 +9750,6 @@ declare function pathExclude(...paths: Path[]): PolygonPath;
8862
9750
  * Fracture N paths along every intersection into the maximal set of
8863
9751
  * non-overlapping regions. Returns one `PolygonPath` per region.
8864
9752
  *
8865
- * Algorithm: for every non-empty subset S ⊆ {A1..AN}, emit the region
8866
- * `(∩ S) − (∪ complement)` — points covered by exactly the members of S
8867
- * and no others. By construction the emitted regions are pairwise disjoint
8868
- * and their union equals `pathUnion(A1..AN)`.
8869
- *
8870
9753
  * For N=2 this collapses to the three Illustrator "Divide" outputs
8871
9754
  * (A−B, B−A, A∩B). For N=3 up to 7 regions are emitted. The 2^N − 1
8872
9755
  * subset count limits this to small N in practice; passing more than ~8
@@ -9053,8 +9936,12 @@ interface PaintBindContext {
9053
9936
  * from the paint's space to the frame the geometry arrives in. Paired with
9054
9937
  * the vertex shader's `v_world` varying this is *the* paint-space
9055
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.
9056
9943
  */
9057
- spaceInverse(units: GradientUnits | undefined): Mat3$1;
9944
+ spaceInverse(units: GradientUnits | undefined): Mat3$1 | null;
9058
9945
  /**
9059
9946
  * Bake a stop ramp into the frame's ramp atlas, bind that atlas to a texture
9060
9947
  * unit, and return the `v` the ramp's own row sits at — every ramp in a
@@ -9404,21 +10291,15 @@ interface ArrayAdapterConfig<TNode extends {
9404
10291
  * Consumers own id generation and any palette/payload fields. Returning
9405
10292
  * `null` aborts the insert. When omitted, `commitInsert` returns `null`. */
9406
10293
  createDefault?: (bounds: Bounds) => TNode | null;
9407
- /** Project a pose to an AABB for `hitTestArea`. Default: identity (works
9408
- * when TPose carries top-level x/y/width/height). */
9409
- poseBounds?: (pose: TPose) => Bounds;
9410
- /** Tight intersection test against a pose. Default: AABB-vs-AABB using
9411
- * `poseBounds`. Override for non-rect poses (e.g. polygons via
9412
- * `pathPoseDescriptor.intersectsRect`). */
9413
- 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>;
9414
10299
  /** Factory for fresh node ids in `commitPaste`. Default: `crypto.randomUUID()`
9415
10300
  * when available, otherwise a monotonic `paste-<n>` counter. Override
9416
10301
  * when consumers want stable id schemes (e.g. `clip-${n++}`). */
9417
10302
  nextId?: () => string;
9418
- /** Translate a pose by `(dx, dy)`. Default: shallow-spread `{ x, y }`,
9419
- * which matches the canonical axis-aligned rect pose. Override for
9420
- * non-rect poses whose translation isn't a top-level `x`/`y` bump. */
9421
- translatePose?: (pose: TPose, dx: number, dy: number) => TPose;
9422
10303
  }
9423
10304
  /**
9424
10305
  * Combined adapter satisfying every narrow adapter the kit ships. Methods
@@ -9590,14 +10471,6 @@ interface GuidesLayerOpts {
9590
10471
  * screen space, projected from world offsets via the active view. */
9591
10472
  declare function createGuidesLayer(opts: GuidesLayerOpts): RenderLayer<unknown>;
9592
10473
 
9593
- /** Axis-aligned bounding box. Alignment matches AABBs throughout; a rotated
9594
- * pose enters as the AABB of its ink (see `AlignBoundsProjection.boundsOf`). */
9595
- interface AlignBounds {
9596
- x: number;
9597
- y: number;
9598
- width: number;
9599
- height: number;
9600
- }
9601
10474
  /** Which feature of a box to test against candidates, per axis.
9602
10475
  * 'min' = left/top edge, 'center' = centerline, 'max' = right/bottom edge. */
9603
10476
  type AlignAnchor = 'min' | 'center' | 'max';
@@ -9610,31 +10483,18 @@ interface AlignMatchResult {
9610
10483
  activeX: Guide | null;
9611
10484
  activeY: Guide | null;
9612
10485
  }
9613
- /** Bounds analog of the gesture `OriginProjection`: reads an AABB from a pose
9614
- * and translates a pose. The rect default handles `{x,y,width,height}` poses;
9615
- * non-rect poses (Path, polygon) supply their own. */
9616
- interface AlignBoundsProjection<TPose> {
9617
- /** The pose's *visual* AABB — a rotated pose reports the extent of its ink,
9618
- * not the box it was posed in. Guides and matching both read this, so an
9619
- * implementation that returns the stored box makes a rotated shape snap to
9620
- * lines nothing is drawn at. */
9621
- boundsOf(pose: TPose): AlignBounds;
9622
- /** Move the pose, preserving every other field it carries — nothing
9623
- * downstream re-derives rotation or style from anywhere else. */
9624
- translate(pose: TPose, dx: number, dy: number): TPose;
9625
- }
9626
10486
  /** Which candidate lines to derive from a set of poses — edges, centers, or
9627
10487
  * both, and whether the page box contributes its own. */
9628
- interface DeriveAlignmentGuidesOptions<TPose = AlignBounds> {
10488
+ interface DeriveAlignmentGuidesOptions<TPose = Bounds> {
9629
10489
  /** Include the document/page box's edges + center as candidates. */
9630
- page?: AlignBounds;
10490
+ page?: Bounds;
9631
10491
  /** Emit left/right (x) and top/bottom (y) edge guides. Default true. */
9632
10492
  edges?: boolean;
9633
10493
  /** Emit centerX (x) and centerY (y) guides. Default true. */
9634
10494
  centers?: boolean;
9635
- /** Reads each target's AABB. Defaults to `RECT_ALIGN_PROJECTION`. Pass the
9636
- * same projection `alignMoveBehavior` gets, or the two sides disagree. */
9637
- 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>;
9638
10498
  }
9639
10499
  /** Common options shared by the three alignment behavior factories. */
9640
10500
  interface AlignmentBehaviorBase {
@@ -9654,20 +10514,15 @@ interface AlignmentBehaviorBase {
9654
10514
  /** Derive candidate alignment lines from a set of sibling poses plus an
9655
10515
  * optional page box. Each box contributes up to 3 guides per axis: the two
9656
10516
  * edges and the center. Overlapping offsets collapse to one candidate.
9657
- * Poses go through the same projection `alignMoveBehavior` matches with, so
10517
+ * Poses go through the same descriptor `alignMoveBehavior` matches with, so
9658
10518
  * a rotated sibling advertises its ink edges rather than its stored box. */
9659
- 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[];
9660
10520
 
9661
10521
  /** Move/insert test all three features per axis. */
9662
10522
  declare const MOVE_ANCHORS: {
9663
10523
  x: readonly AlignAnchor[];
9664
10524
  y: readonly AlignAnchor[];
9665
10525
  };
9666
- /** Default projection for rect-shaped poses (`{x,y,width,height,rotation?}`).
9667
- * A rotated pose reports the AABB of its ink, so guides derived from a
9668
- * stationary sibling and the box a dragged selection matches with are the
9669
- * same measurement. */
9670
- declare const RECT_ALIGN_PROJECTION: AlignBoundsProjection<RectPose>;
9671
10526
  /**
9672
10527
  * Match a moving box's selected edge/center features against candidate guide
9673
10528
  * lines. Returns the per-axis snap delta and the matched candidate line(s).
@@ -9679,7 +10534,7 @@ declare const RECT_ALIGN_PROJECTION: AlignBoundsProjection<RectPose>;
9679
10534
  * distance along that axis alone, so there is an exact answer rather than an
9680
10535
  * approximation. Pass the same number twice for a world-space tolerance.
9681
10536
  */
9682
- declare function matchAlignment(bounds: AlignBounds, candidates: readonly Guide[], worldTolerance: {
10537
+ declare function matchAlignment(bounds: Bounds, candidates: readonly Guide[], worldTolerance: {
9683
10538
  x: number;
9684
10539
  y: number;
9685
10540
  }, anchors: {
@@ -9687,9 +10542,9 @@ declare function matchAlignment(bounds: AlignBounds, candidates: readonly Guide[
9687
10542
  y: readonly AlignAnchor[];
9688
10543
  }): AlignMatchResult;
9689
10544
 
9690
- /** 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. */
9691
10546
  interface AlignMoveArgs<TPose> extends AlignmentBehaviorBase {
9692
- projection?: AlignBoundsProjection<TPose>;
10547
+ poseDescriptor?: PoseDescriptor<TPose>;
9693
10548
  }
9694
10549
  /** Move behavior: snap the dragged selection's union box (edges + center) to
9695
10550
  * candidates, shaping the proposed translate. The gesture applies the
@@ -9702,10 +10557,10 @@ declare function alignMoveBehavior<TPose>(args: AlignMoveArgs<TPose>): MoveBehav
9702
10557
  declare function alignInsertBehavior<TPose>(args: AlignmentBehaviorBase): InsertBehavior<TPose>;
9703
10558
  /** Resize constraint: snap the moving edge(s) of the dragged rect to
9704
10559
  * candidates. The pinned (anchor) edge stays fixed. Publishes the line(s). */
9705
- declare function alignResizeBehavior<TPose extends ResizePose>(args: AlignmentBehaviorBase): BoundsConstraint<TPose>;
10560
+ declare function alignResizeBehavior<TPose extends Bounds>(args: AlignmentBehaviorBase): BoundsConstraint<TPose>;
9706
10561
 
9707
10562
  /** AABB center of an unrotated rect — the canonical rotation pivot. */
9708
- declare function aabbCenter(bounds: ResizePose): {
10563
+ declare function aabbCenter(bounds: Bounds): {
9709
10564
  x: number;
9710
10565
  y: number;
9711
10566
  };
@@ -9715,7 +10570,7 @@ declare function rotatePoint(px: number, py: number, cx: number, cy: number, ang
9715
10570
  y: number;
9716
10571
  };
9717
10572
  /** Four corners of an unrotated rect, in TL/TR/BR/BL order. */
9718
- declare function rectCorners(bounds: ResizePose): {
10573
+ declare function rectCorners(bounds: Bounds): {
9719
10574
  x: number;
9720
10575
  y: number;
9721
10576
  }[];
@@ -10000,65 +10855,6 @@ interface AnchorHit {
10000
10855
  * are within `threshold` (controls are smaller and rendered on top). */
10001
10856
  declare function hitAnchor(path: PolygonPath, worldX: number, worldY: number, threshold: number): AnchorHit | null;
10002
10857
 
10003
- /**
10004
- * Typed keys for the gesture/behavior scratch store.
10005
- *
10006
- * Gestures expose `ctx.scratch: Record<string, unknown>` as a per-gesture
10007
- * mutable bag that behaviors use to stash state across `onDown` / `onMove`
10008
- * / `onEnd` calls. The store is `unknown`-valued because behaviors are
10009
- * tool-agnostic — a single behavior may run under different tools with
10010
- * different scratch shapes. Without a typing convention every read site
10011
- * has to `(ctx.scratch as <some shape>)[KEY]`, and a writer changing the
10012
- * shape can silently break readers with no compile-time signal.
10013
- *
10014
- * `ScratchKey<T>` is a phantom-typed string that carries its payload type
10015
- * via a branded interface. `getScratch` and `setScratch` use the brand to
10016
- * narrow / constrain at the typing layer; at runtime the key is just its
10017
- * underlying string and the store remains a plain `Record`.
10018
- *
10019
- * @example
10020
- * ```ts
10021
- * // Module-level (or behavior-level) constant, shared by writer + reader:
10022
- * const LASSO_VERTICES = scratchKey<readonly { x: number; y: number }[]>('lasso.vertices');
10023
- *
10024
- * // Writer (a tool's onMove):
10025
- * setScratch(ctx.scratch, LASSO_VERTICES, vertices);
10026
- *
10027
- * // Reader (a behavior's onEnd):
10028
- * const vertices = getScratch(ctx.scratch, LASSO_VERTICES) ?? [];
10029
- * // ^? readonly { x: number; y: number }[] | undefined
10030
- * ```
10031
- */
10032
- /** Phantom-typed key for a scratch slot. The `__scratchKeyPayload` phantom
10033
- * field carries the value type without occupying any runtime memory. */
10034
- interface ScratchKey<T> {
10035
- readonly name: string;
10036
- /** Phantom — never read at runtime. Only present so TypeScript can
10037
- * recover `T` at use sites. */
10038
- readonly __scratchKeyPayload?: (_: T) => T;
10039
- }
10040
- /** Compatible scratch store shape. The kit's gesture context's `scratch`
10041
- * field already satisfies this; consumers don't need to construct one. */
10042
- type ScratchStore = Record<string, unknown>;
10043
- /**
10044
- * Make a typed scratch key. Use module-level constants so the same key
10045
- * is shared by writer and reader.
10046
- *
10047
- * Namespace the name by behavior or feature to avoid collisions
10048
- * (`'behavior.field'` is a good convention). Two keys with the same
10049
- * `name` refer to the same slot at runtime — the type parameter is a
10050
- * compile-time contract, not a uniqueness guarantee.
10051
- */
10052
- declare function scratchKey<T>(name: string): ScratchKey<T>;
10053
- /** Read a typed slot from the scratch store. Returns `undefined` if
10054
- * nothing has been written under the key. */
10055
- declare function getScratch<T>(store: ScratchStore, key: ScratchKey<T>): T | undefined;
10056
- /** Write a value to a typed slot. Overwrites whatever was there. */
10057
- declare function setScratch<T>(store: ScratchStore, key: ScratchKey<T>, value: T): void;
10058
- /** Remove a slot from the scratch store. Returns `true` if it was set,
10059
- * `false` if it wasn't. */
10060
- declare function deleteScratch<T>(store: ScratchStore, key: ScratchKey<T>): boolean;
10061
-
10062
10858
  /** Options for `selectFromLasso`. */
10063
10859
  interface SelectFromLassoOptions {
10064
10860
  /** Hit mode for `hitTestLasso`. Default 'intersect'. */
@@ -10076,7 +10872,11 @@ type AlignEdge = 'left' | 'right' | 'top' | 'bottom' | 'center-x' | 'center-y';
10076
10872
  /** Adapter for `useAlign`. */
10077
10873
  interface AlignAdapter<TPose> {
10078
10874
  getSelection(): NodeId[];
10875
+ /** The pose as stored — local to the node's parent. */
10079
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;
10080
10880
  applyOps?(ops: Op[], label?: string): void;
10081
10881
  }
10082
10882
  /** Options for `useAlign`. */
@@ -10084,38 +10884,30 @@ interface UseAlignOptions<TPose> {
10084
10884
  /** Projection between `TPose` and bounds. Defaults to `RECT_POSE_DESCRIPTOR`
10085
10885
  * for `{x,y,width,height}` poses. Pass `pathPoseDescriptor` for `Path`
10086
10886
  * poses so polygon coords translate correctly. */
10087
- geometry?: PoseProjection<TPose>;
10887
+ geometry?: PoseDescriptor<TPose>;
10088
10888
  /** Label passed to applyOps. Default 'Align'. */
10089
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>;
10090
10893
  }
10091
10894
  /** Return shape of `useAlign`. */
10092
10895
  interface UseAlignReturn {
10093
10896
  /** Imperative trigger. No-op when fewer than 2 items selected. */
10094
10897
  align(edge: AlignEdge): void;
10095
10898
  }
10096
- /**
10097
- * The pose's *visual* bounds: its descriptor bounds expanded to cover the
10098
- * rotated rectangle, so a turned shape reports the extent of its ink rather
10099
- * than the box it was posed in. Align, distribute and flip all fold these.
10100
- *
10101
- * Both ends of an align must use it — a visual union measured against
10102
- * unrotated member boxes misplaces every rotated member. The expanded box
10103
- * shares its centre with the stored one, so the delta stays a translation of
10104
- * the stored pose and no re-posing is needed.
10105
- */
10106
- declare function visualBoundsViaDescriptor<TPose>(pose: TPose, geometry: PoseProjection<TPose>): ResizePose;
10107
10899
  /** Compute the (dx, dy) translation that moves AABB `b` so that the requested
10108
10900
  * `edge`/center matches the corresponding feature of the union AABB `u`. */
10109
- declare function alignDeltaFor(b: ResizePose, u: ResizePose, edge: AlignEdge): {
10901
+ declare function alignDeltaFor(b: Bounds, u: Bounds, edge: AlignEdge): {
10110
10902
  dx: number;
10111
10903
  dy: number;
10112
10904
  };
10113
- /** Translate `pose` by `(dx, dy)` using `geometry.translate` if available,
10114
- * otherwise via `remapBounds` with a translated `dst` rect. */
10115
- declare function translatePoseViaDescriptor<TPose>(pose: TPose, dx: number, dy: number, geometry: PoseProjection<TPose>): TPose;
10116
10905
  /** Align the current multi-selection to a shared edge or center of the
10117
10906
  * selection's union AABB. No-op when fewer than 2 items selected.
10118
- * 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. */
10119
10911
  declare function useAlign<TPose>(adapter: AlignAdapter<TPose>, options?: UseAlignOptions<TPose>): UseAlignReturn;
10120
10912
 
10121
10913
  /** Axis along which selection is distributed. `'x'` spreads horizontally. */
@@ -10127,18 +10919,25 @@ type DistributeMode = 'centers' | 'gaps';
10127
10919
  /** Adapter for `useDistribute`. */
10128
10920
  interface DistributeAdapter<TPose> {
10129
10921
  getSelection(): NodeId[];
10922
+ /** The pose as stored — local to the node's parent. */
10130
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;
10131
10927
  applyOps?(ops: Op[], label?: string): void;
10132
10928
  }
10133
10929
  /** Options for `useDistribute`. */
10134
10930
  interface UseDistributeOptions<TPose> {
10135
10931
  /** Projection between `TPose` and bounds. Defaults to `RECT_POSE_DESCRIPTOR`
10136
10932
  * for `{x,y,width,height}` poses. */
10137
- geometry?: PoseProjection<TPose>;
10933
+ geometry?: PoseDescriptor<TPose>;
10138
10934
  /** Default mode when `distribute(axis)` is called without one. Default 'centers'. */
10139
10935
  defaultMode?: DistributeMode;
10140
10936
  /** Label passed to applyOps. Default 'Distribute'. */
10141
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>;
10142
10941
  }
10143
10942
  /** Return shape of `useDistribute`. */
10144
10943
  interface UseDistributeReturn {
@@ -10147,7 +10946,10 @@ interface UseDistributeReturn {
10147
10946
  }
10148
10947
  /** Distribute the current multi-selection along `axis`. Requires ≥3 items;
10149
10948
  * no-op otherwise. Endpoints (min and max along the axis) stay put; the
10150
- * 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. */
10151
10953
  declare function useDistribute<TPose>(adapter: DistributeAdapter<TPose>, options?: UseDistributeOptions<TPose>): UseDistributeReturn;
10152
10954
 
10153
10955
  /** The six Boolean path operations, each acting on the current selection and
@@ -10279,7 +11081,7 @@ interface TweenPoseOptions<TPose> {
10279
11081
  easing?: EasingSpec;
10280
11082
  /** Pose descriptor with a `lerp(from, to, t)` method. Defaults to
10281
11083
  * `RECT_POSE_DESCRIPTOR`, which interpolates x/y/width/height linearly. */
10282
- geometry?: PoseProjection<TPose>;
11084
+ geometry?: PoseDescriptor<TPose>;
10283
11085
  /** When true (default), emit a transform op before the tween so undo
10284
11086
  * restores the pre-animation pose. */
10285
11087
  recordOp?: boolean;
@@ -10295,7 +11097,7 @@ interface SpringPoseOptions<TPose> {
10295
11097
  stiffness?: number;
10296
11098
  damping?: number;
10297
11099
  mass?: number;
10298
- geometry?: PoseProjection<TPose>;
11100
+ geometry?: PoseDescriptor<TPose>;
10299
11101
  recordOp?: boolean;
10300
11102
  opLabel?: string;
10301
11103
  onDone?: () => void;
@@ -10330,7 +11132,7 @@ interface AnimateOnSetPoseOptions<TPose> {
10330
11132
  damping?: number;
10331
11133
  mass?: number;
10332
11134
  };
10333
- geometry?: PoseProjection<TPose>;
11135
+ geometry?: PoseDescriptor<TPose>;
10334
11136
  /** Predicate: return false to skip animation and write through immediately. */
10335
11137
  shouldAnimate?: (id: string, from: TPose, to: TPose) => boolean;
10336
11138
  /** Convenience: when true, auto-skip animation if the id is currently being
@@ -10371,7 +11173,7 @@ interface LifecycleAnimation<TPose> {
10371
11173
  exitTo?: (current: TPose) => TPose;
10372
11174
  ms?: number;
10373
11175
  easing?: EasingSpec;
10374
- geometry?: PoseProjection<TPose>;
11176
+ geometry?: PoseDescriptor<TPose>;
10375
11177
  }
10376
11178
  /** Wrap an adapter so inserts and removals animate — the scene-graph
10377
11179
  * equivalent of CSS enter/leave transitions. */
@@ -10416,6 +11218,8 @@ interface MomentumOptions {
10416
11218
  * decays the velocity). Default 'stop'.
10417
11219
  */
10418
11220
  boundary?: 'stop' | 'continue';
11221
+ /** How to translate poses. Default `AUTO_POSE_DESCRIPTOR`. */
11222
+ poseDescriptor?: PoseDescriptor<unknown>;
10419
11223
  }
10420
11224
  /**
10421
11225
  * Move behavior that keeps a dragged node coasting after the pointer is
@@ -10887,43 +11691,6 @@ declare function CropIcon(): react_jsx_runtime.JSX.Element;
10887
11691
  declare const PAINTED_CURSOR_LAYER_ID = "painted-cursor";
10888
11692
  declare function createPaintedCursorLayer(state: PaintedCursorState): RenderLayer<unknown>;
10889
11693
 
10890
- /** What the registry knows at dispatch time. */
10891
- interface EligibilityState {
10892
- focusedId: string | null;
10893
- heldTriggers: ReadonlySet<string>;
10894
- /** Ids the host reports as hotkey-engaged. A declared `offhand` registers
10895
- * the binding, but `tool.offhand`'s invoker still reports engagement by
10896
- * pushing an id — this retires only if that contract changes. */
10897
- engagedIds?: ReadonlySet<string>;
10898
- /** Whether the active mode allows these capability tags. Omitted → allow. */
10899
- allows?: (tags: readonly CapabilityTag[]) => boolean;
10900
- }
10901
- /**
10902
- * The scope tier an entry's bindings are live at, or null when none are.
10903
- * Ordered hotkey > active > ambient to match the dispatcher's own walk.
10904
- */
10905
- declare function liveScope(id: string, eligibility: Eligibility, state: EligibilityState): BindingScope | null;
10906
-
10907
- /**
10908
- * Every binding the entry set contributes right now, each tiered by the
10909
- * entry's own declared eligibility. Entries with no live tier are omitted.
10910
- *
10911
- * Order is preserved: `matchSorted` sorts by specificity within a scope and
10912
- * breaks ties by declaration order, so the caller's entry order decides which
10913
- * of two same-specificity bindings in one tier wins.
10914
- */
10915
- declare function scopeBindings(entries: Iterable<Contribution>, state: EligibilityState): ScopedBinding[];
10916
-
10917
- /**
10918
- * Concatenate contribution bundles into one registry, preserving order —
10919
- * entry order decides which of two same-specificity bindings in one scope
10920
- * tier wins, so it is part of the result, not an accident of it.
10921
- *
10922
- * Throws on a duplicate id rather than dropping one: a feature silently
10923
- * losing its bindings is the failure this registry exists to make loud.
10924
- */
10925
- declare function mergeContributions(...bundles: readonly Contribution[][]): Contribution[];
10926
-
10927
11694
  /** Appearance of the dashed box drawn during a marquee or insert drag. */
10928
11695
  interface InsertOverlayStyle {
10929
11696
  fill?: string;
@@ -10932,4 +11699,4 @@ interface InsertOverlayStyle {
10932
11699
  lineWidth?: number;
10933
11700
  }
10934
11701
 
10935
- 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, DerivedDep, 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 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 PointerSession, type PointerSessionCallbacks, type PointerSessionCancelReason, type PointerSessionOptions, type PointerStylusState, PolygonIcon, PolygonPath, type PolygonPoint, type Pose, PoseOverrides, PoseProjection, type PoseRotation, type PoseRun, type PoseRunCtx, type PoseRunStep, type PoseSource, type PosedNode, 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 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, 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, UNION_OF_CHILDREN, 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, type UsePoseRunOptions, 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, 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, deleteScratch, deriveAlignmentGuides, deriveParallaxView, derivedDepOf, derivedPose, dispatchApplyBatch, dlog, documentPose, domPositionToCharOffset, domToRuns, dwarn, editAnchorsAction, effectivePose, 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, pointAlongPath, 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, unionOfChildren, 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, usePoseRun, 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 };