weasel API - v0.8.0
    Preparing search index...

    Interface Tool<TScratch>

    Full Tool record.

    interface Tool<TScratch = unknown> {
        actions?: Action[];
        bindings?: GestureBinding[];
        capabilities?: CapabilityTag[];
        cursor?: string | ((ctx: ToolCtx<TScratch>) => string);
        def?: unknown;
        id: string;
        initScratch?: () => TScratch;
        keybinding?: ToolKeybinding;
        onActivate?: (ctx: ToolCtx<TScratch>) => void;
        onDeactivate?: (ctx: ToolCtx<TScratch>) => void;
        overlay?: RenderLayer<unknown>;
        presentation?: ToolPresentation<TScratch>;
        previewBounds?: (id: string) => Bounds | null;
        previewIds?: () => Iterable<string, any, any> | null;
        previewPose?: (id: string) => unknown;
    }

    Type Parameters

    • TScratch = unknown
    Index

    Properties

    actions?: Action[]

    Actions this tool owns and needs registered while it is in the tools registry — e.g. polygon's polygon.adjustSides, which its own bindings reference by id.

    Declared here rather than registered by the hook with useAction, because tool hooks run wherever the consumer calls them — for <SceneCanvas> that is ABOVE <ActionsProviderIfRoot>, where useActionsRegistry() returns null and useAction silently no-ops. The result was a binding pointing at an action id nothing had registered, so the gesture fell through to whatever matched next (polygon's wheel/arrow-key side adjustment did nothing and nudge.* moved the selection instead). <ToolActionsMounter> registers these from inside the provider.

    bindings?: GestureBinding[]

    Declarative gesture bindings — the tool's entire input surface. The gesture dispatcher consults these at active scope while this tool is active, and at hotkey scope while it is held. See docs/superpowers/specs/2026-05-16-registry-unification-design.md.

    capabilities?: CapabilityTag[]

    App-level capability tags for modality. The weasel-modes package's eligibleForMode(mode, capabilities) predicate consumes these to decide whether the tool is usable in the active mode. Tags are extensible strings — apps can define their own. Untagged tools are treated as ineligible by all modes except those whose allows list includes every implicit-or-declared tag (i.e. normal in the default preset).

    cursor?: string | ((ctx: ToolCtx<TScratch>) => string)
    def?: unknown

    Reflection escape hatch: when this Tool was produced by defineTool, the source ToolDef is attached here so introspection consumers (buildRouteRegistry, findConflicts, the toolkit-builder UI, the reflection demo) can read the authored form — hookName in particular, which the runtime Tool doesn't carry. Tools constructed without defineTool may leave this undefined. Typed as unknown to keep this file from importing the routing types — consumers cast at the use site.

    id: string
    initScratch?: () => TScratch
    keybinding?: ToolKeybinding

    Optional caller-supplied key. Most built-in tools have their activation key declared in BUILTIN_SELECT_KEYS in useKeybindings.ts; this field is for tools that want their activation key to be configurable by the host (currently Lasso and Eyedropper). The dynamic loop in useKeybindings.ts picks this up and appends a binding entry to the consolidated tool.activate action (with opts.params.toolId set so the invoker knows which tool to switch to).

    onActivate?: (ctx: ToolCtx<TScratch>) => void
    onDeactivate?: (ctx: ToolCtx<TScratch>) => void
    overlay?: RenderLayer<unknown>

    Optional overlay layer rendered on top of the scene/chrome whenever this tool is in any active slot (active, hotkey, or ambient). The layer's draw function reads from this tool's scratch via React closure (re-evaluated each render). Return early from draw to render nothing — typically gated on a scratch field like if (!scratch.overlay) return.

    presentation?: ToolPresentation<TScratch>

    Presentation metadata for tool palettes. See ToolPresentation.

    previewBounds?: (id: string) => Bounds | null

    Returns the in-flight preview bounds for id if this tool is mid-gesture on it; otherwise null. Optional companion to previewPose for tools that can compute bounds without round-tripping through a geometry adapter.

    previewIds?: () => Iterable<string, any, any> | null

    Returns ids whose committed scene-render should be suppressed while this tool is mid-gesture (e.g. cascade move's dragged + descendant ids whose preview ghosts replace the committed pose). The standard scene slot consults this alongside previewPose to avoid double-rendering. Returns null when no gesture is in flight.

    previewPose?: (id: string) => unknown

    Returns the in-flight preview pose for id if this tool is mid-gesture on it; otherwise null. Lets Canvas.helpersRef.getEffectivePose reflect live gesture state without reaching into hook internals. The return type is unknown here because the Tool interface is pose-agnostic; callers that know the pose shape (e.g. Canvas typed by TPose) cast at the use site.