OptionalaffordanceOptional affordance classifier. Called on every pointerdown with the
world-space coordinates of the pointer. Returns an AffordanceHit when
the pointer lands on a known affordance (resize handle, rotate handle, etc.)
or null when the pointer hit open canvas.
The hit is packed into InputEvent.pointerdown.affordance and flows
through into InvocationCtx.drag.affordance. Action invokers that require
a specific affordance (e.g. resizeAction requires handle:*) use this
field as a guard in their start body.
When omitted, affordance is always undefined — meaning only consumers
that explicitly wire a classifier get affordance-gated behavior.
<SceneCanvas> wires the full chrome→dispatcher bridge.
OptionalambientIds (within toolsById) of always-on tools, whose bindings assemble at
ambient scope. See DispatcherContext.ambientToolIds.
Ref to the canvas element. Pointer/wheel/multitouch listeners attach here.
OptionalclassifyOptional body classifier. Called on every pointerdown with the world-space
coordinates of the pointer. Its result is packed onto the event as
bodyTarget + bodyKind, which matchTarget reads to resolve the
string-form TargetSpec values in Tool.bindings.
body is 'empty' when nothing is under the pointer, 'selected-body'
when the topmost hit belongs to the current selection, or
'unselected-body' when it belongs to a node that isn't selected. kind
is the hit node's semantic kind, when the scene can name it.
When omitted, every body-derived target form ('empty',
'selected-body', 'unselected-body', kind:<k>, kind:<k>:selected)
never matches — bindings using those specs are silently skipped.
<SceneCanvas> wires this.
OptionalclientConverts a client-space pointer position (e.g. e.clientX, e.clientY)
to world-space coordinates. When supplied, every pointer/wheel event's
x/y is converted before the dispatcher builds InvocationCtx.world.
Without this, ctx.world is populated with the raw client coords, which
silently breaks any action whose overlay/output uses absolute world
positions (marquee, lasso polyline, world-space affordances). Actions
that only read drag.delta are unaffected because client→world deltas
are equal at scale 1, but as soon as a consumer pans/zooms the view the
deltas diverge too.
<SceneCanvas> always wires this via its canvas rect + current view.
Tests / harnesses without a view can omit it and continue passing raw
coordinates as before.
OptionaldispatcherOptional pre-created Dispatcher. When provided, this hook pumps events
into the supplied instance instead of creating its own. Lets a parent
scope (e.g. <SceneCanvas>) share one dispatcher between the gesture
mounter and other consumers (the preview-ghost layer).
OptionalenabledDefault true. Set false to opt out of dispatcher wiring (e.g. demos that disable it).
OptionalgetThunk returning the live RuleCtx for the current frame. When supplied,
the dispatcher filters matched candidates by their declared
Action.eligible rule (omitted => always eligible). <SceneCanvas>
wires this; tests / harnesses without chrome-caps state can omit it.
OptionalkeyboardDefault true. Set false to leave the window keydown/keyup listeners
unattached so keyboard-bound actions never dispatch — pointer, wheel, and
contextmenu channels stay live. <SceneCanvas> wires this to
enableKeybindings, so opting out of keybindings disables the modern
dispatcher key path as well as the legacy useKeybindings hook.
OptionalonObserver fired whenever the dispatcher synthesizes a double click, in world coordinates. Runs BEFORE the event is dispatched and independently of which binding (if any) handles it.
This is deliberately not an Action. <SceneCanvas onDoubleClick> is a
notification — "the user double-clicked, here's what they hit" — and a
notification must not compete with behavior for the gesture. As a binding
it would lose to enterPathEdit on any body hit and silently never fire.
Routing it here keeps a single definition of "double click" (the point of
consolidating the kit's three detectors) without giving it
first-match-wins semantics it shouldn't have.
OptionalrequestInvoked once per pump event (pointermove, pointerup, pointercancel,
key-held up-phase, multitouch move) when a dispatcher-side handle is
in flight. Lets the host canvas schedule a redraw so dispatcher-only
overlays (marquee, lasso, preview-ghost) repaint on each frame.
Required because dispatcher actions don't go through the legacy
tools.dispatcher.onGestureChange redraw bump that ambient tool drags
relied on. Without it, the overlay layer's draw never runs between
pointerdown and pointerup, and the chrome flashes once at gesture start
and then sits frozen until the gesture ends.
<SceneCanvas> wires this to the canvas's requestRedraw. Test
harnesses can omit it; their dispatchers won't paint between events but
that's already the test contract.
Tool definitions keyed by id. Typically passes an empty Map.
Action registry (ActionsRegistry from registry.tsx).