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

    Interface CanvasProps<TNode, TPose>

    Props for <Canvas> — the low-level WebGL surface + viewport + pointer routing primitive.

    Canvas is scene-agnostic. It owns the GL surface, view state, pointer/ keyboard dispatch, and slot composition. It does NOT own selection state, picking logic, kind registries, or scene-aware overlays — those belong in <SceneCanvas>.

    interface CanvasProps<
        TNode extends { id: string } = { id: string },
        TPose = unknown,
    > {
        adapter?: CanvasAdapter<TNode, TPose>;
        autoFocusOnPointerDown?: boolean;
        backgroundFill?: FillStyle;
        boundsOf?: (id: string) => Bounds | null;
        className?: string;
        clientToWorld?: (
            canvas: HTMLCanvasElement,
            cx: number,
            cy: number,
        ) => [number, number];
        cursorCoordsHud?: boolean;
        debug?: false | DebugConfig;
        debugSinkRef?: MutableRefObject<
            DebugSink & { snapshot(): DebugSnapshot }
            | null,
        >;
        decorationLayer?: RenderLayer<unknown>;
        defaultView?: View;
        dpr?: number;
        geometry?: PoseProjection<TPose>;
        gestureSource?: GestureSource;
        getIsVisible?: () => (id: string) => boolean;
        height: number;
        helpersRef?: MutableRefObject<CanvasHelpers<TPose> | null>;
        layers: LayersMap<TNode, TPose>;
        modalityHud?: boolean | { modeId?: string };
        onViewChange?: (next: View) => void;
        pickBest?: (worldX: number, worldY: number) => string | null;
        pickEvery?: (worldX: number, worldY: number) => string | string[] | null;
        pickHud?: boolean;
        previewBoundsExtra?: (id: string) => Bounds | null;
        previewIdsExtra?: () => Iterable<string, any, any> | null;
        previewPoseExtra?: (id: string) => unknown;
        selection?: SelectionApi;
        shaders?: ShaderProgramHandle[];
        style?: CSSProperties;
        tabIndex?: number;
        tools?: ToolsApi;
        view?: View;
        viewBounds?: { height: number; width: number; x: number; y: number };
        viewport?: ViewportConfig;
        width: number;
    }

    Type Parameters

    • TNode extends { id: string } = { id: string }
    • TPose = unknown
    Index

    Properties

    adapter?: CanvasAdapter<TNode, TPose>

    Combined adapter for scene-slot rendering, bounds computation, and move/resize/rotate gesture math. Optional — bare-Canvas consumers that don't need a scene slot may omit it.

    Canvas threads this adapter into layer factories and gesture hooks. The type is the move/resize/rotate intersection plus the optional scene-tree methods (getLayers/getNode/getChildren) — present on a hierarchical SceneCanvasAdapter, absent on flat adapters. The buildSceneLayer path feature-detects them at draw time.

    <SceneCanvas> synthesizes this from a Scene; bare-<Canvas> consumers must supply it explicitly when using the scene or selection-overlay slots.

    autoFocusOnPointerDown?: boolean

    When true (default), the canvas element receives focus on pointerdown so keyboard events (tool hotkeys, undo/redo) are captured without a separate click-to-focus step. Set to false for canvases embedded inside a larger focus-managed layout where auto-focus would steal focus from sibling inputs.

    backgroundFill?: FillStyle

    FillStyle applied to the full canvas surface behind the scene. Accepts the kit's FillStyle union (solid / pattern / linear-gradient / radial-gradient / conic-gradient) so consumers don't have to author a background node just to colorize the canvas.

    Rendered as a screen-space layer slotted before 'scene' — independent of pan / zoom. Canvas owns this layer; <SceneCanvas> forwards its own backgroundFill prop verbatim so consumer apps see no breaking change.

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

    Override for committed bounds lookup. When supplied, takes precedence over the geometry-derived fallback. Used by the selection overlay, the multi-select union AABB, and helpersRef.getEffectiveBounds. Optional — bare-Canvas consumers that use a custom bounds shape should supply this; <SceneCanvas> derives it from its scene adapter and passes it via the scene-slot layer config rather than this prop.

    className?: string
    clientToWorld?: (
        canvas: HTMLCanvasElement,
        cx: number,
        cy: number,
    ) => [number, number]

    Custom pointer-to-world coordinate transform. When supplied, overrides the default (clientX - canvasRect.left) / scale + pan calculation. Useful for consumers that apply an additional CSS transform to the canvas element.

    cursorCoordsHud?: boolean

    Dev HUD: when true, mounts a fixed-position widget showing live cursor coords in both viewport (client) and canvas (world) frames. Useful for diagnosing pointer-coord drift / pan-zoom misalignment without instrumenting events.

    debug?: false | DebugConfig

    Debug overlay configuration.

    • undefined (default): read ?debug=… from the URL.
    • false: force off, ignore URL.
    • DebugConfig object: force on with that config, ignore URL.

    When enabled, the Canvas appends a screen-space debug-overlay layer at the top of the layer stack and threads a DebugSink into every interaction hook so they record hit math + handle positions.

    debugSinkRef?: MutableRefObject<
        DebugSink & { snapshot(): DebugSnapshot }
        | null,
    >

    Test-only escape hatch: writes the live debug sink to this ref so tests can call snapshot() after a render. No effect when debug is off.

    decorationLayer?: RenderLayer<unknown>

    Optional mode-owned decoration layer. When supplied, Canvas inserts it between the scene-render slot and the tool-overlay slot so decoration draw commands (e.g. path-edit anchor dots) paint above scene content but below tool overlays (drag rects, etc.).

    Slot ordering: scene → (scoping mask) → decoration → tool overlay → chrome.

    Wired by the modality machine after it activates a mode whose ModeDefinition supplies a paint() factory. Omitting this prop is a no-op — existing consumers are unaffected.

    defaultView?: View

    Initial viewport for the uncontrolled path. Default {x:0, y:0}.

    dpr?: number

    Drawing-buffer density (device pixels per CSS pixel). When omitted the canvas reads window.devicePixelRatio per paint — the long-standing screen behavior. Supplying it makes density an explicit parameter, the same contract the headless renderSceneToPixels path follows (that path never reads ambient density at all).

    geometry?: PoseProjection<TPose>

    Pose↔bounds projection for non-rect TPose types. When supplied, drives the default boundsOf fallback and the selection-overlay bounds source so non-rect poses (e.g. Path) don't require per-prop overrides. Defaults to the rect identity (AUTO_POSE_DESCRIPTOR).

    This is a math helper, not a scene-shaped concern — it converts a pose value to an AABB and extracts rotation for the selection chrome. Bare- Canvas consumers that use a non-rect pose type should supply this.

    gestureSource?: GestureSource

    In-flight gesture state <Canvas> can't see for itself. Backs the getGestureBounds / subscribeGestures / getGestureVersion trio on helpersRef; wired by <SceneCanvas> from the gesture dispatcher (createGestureSource). Leaving it unwired is fine — those three then report "no gesture in flight" and never fire.

    getIsVisible?: () => (id: string) => boolean

    Chrome-caps visibility resolver. When supplied, Canvas:

    • exposes the predicate on helpersForLayers.getIsVisible so custom layers (notably composeAffordanceLayer) can gate paint by chrome id;
    • threads it into the affordance-pipeline HitTestContext.isVisible so the same gate applies to hit-testing.

    Called fresh per draw / per hitTest, so the consumer can return a predicate that closes over per-frame ChromeCtx. Omit to leave every chrome element visible (pre-chrome-caps behavior).

    height: number

    CSS-pixel height.

    helpersRef?: MutableRefObject<CanvasHelpers<TPose> | null>

    Mutable ref Canvas writes overlay-aware pose/bounds lookups to on every render. Custom layers can read it from inside their draw closure to reflect in-flight gestures (move/resize/rotate) instead of the committed scene. Both lookups apply when an id is in the active overlay; otherwise they fall back to the adapter.

    Useful for custom layers that render scene content outside of the standard slot system and need to stay in sync with gesture previews.

    Layer map. See module docstring for slot semantics.

    modalityHud?: boolean | { modeId?: string }

    Dev HUD: mounts a fixed-position widget below the pick HUD reporting the active modality mode, the active-slot tool, and the hotkey stack. Pass true to enable with no mode (renders for the mode line — useful until the modality machine is wired). Pass an object to supply the current mode id.

    onViewChange?: (next: View) => void

    Fires whenever the viewport changes — in both controlled and uncontrolled modes.

    pickBest?: (worldX: number, worldY: number) => string | null

    Optional single-best hit resolver for the pickHud — the id this point would select on a bare click. When omitted the HUD skips the bold-best highlight. <SceneCanvas> forwards its internalPickBest here so the HUD shows the same best-candidate SceneCanvas would pick.

    pickEvery?: (worldX: number, worldY: number) => string | string[] | null

    Used by PickHud to display the list of ids under the cursor. NOT used for tool routing — see getNodeAtPoint for that. <SceneCanvas> passes its internal pick function here so the HUD stays in sync with the scene's actual hit-test order.

    pickHud?: boolean

    Dev HUD: when true, mounts a fixed-position widget just below the cursor-coords HUD listing the ids returned by pickEvery(world) under the cursor. Useful for diagnosing hit-test order and container/leaf overlap during select-tool work.

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

    Extra preview-bounds lookup checked after previewBoundsExtra's previewPose fallback. Same shape as previewPoseExtra but returns AABB directly, preferred when the in-flight handle can produce bounds without going through geometry.getBounds(pose).

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

    Extra source of ids whose committed paint should be suppressed during the current frame (in addition to those reported by the tools' previewIds()).

    Wired by <SceneCanvas> to expose the new gesture-dispatcher's in-flight handles: as legacy hooks are removed from tools, the source-hide for move/clone/etc. needs to follow the preview-ghost layer onto the dispatcher's OngoingHandle.previewIds(). Optional — bare <Canvas> consumers don't need to wire it.

    previewPoseExtra?: (id: string) => unknown

    Extra preview-pose lookup checked after the active tool's previewPose misses. Wired by <SceneCanvas> to expose the gesture-dispatcher's in-flight OngoingHandle.previewPose(id) so selection chrome (resize/ rotation handles, AABB outline) tracks the ghost during dispatcher-driven drags. Returns null / undefined when no preview is in flight.

    selection?: SelectionApi

    Current selection state. Canvas is a pure pass-through — it owns no selection state of its own. When absent, Canvas behaves as if nothing is selected: no selection chrome, no select-on-click, no clear-on-background.

    <SceneCanvas> always supplies this from its internal useSelection. Bare-<Canvas> consumers may omit it for non-selection use cases (e.g. force-graph renderers or read-only viewers).

    Custom shader programs to compile on the renderer. Each handle must come from a module-level registerProgram() call. Compiled once per handle id on first render (or on context restore). Pass a stable reference (e.g. defined at module scope) — the array is read at renderer init time.

    style?: CSSProperties
    tabIndex?: number
    tools?: ToolsApi

    Tool primitive substrate. Pointer/keyboard/wheel events are routed through tools.dispatcher.

    view?: View

    Controlled viewport. When supplied, Canvas does not own the value — the consumer must supply onViewChange and re-render with the new view. See View JSDoc for the camera-position convention.

    viewBounds?: { height: number; width: number; x: number; y: number }

    Optional world-space rect that constrains pan. When supplied, every setView call passes through clampView(next, viewBounds, {width, height}) before commit, keeping the visible rect inside viewBounds. If the visible rect is larger than the bounds along an axis (zoomed out past extent), that axis is centered. Has no effect on scale — wire useZoom bounds for that.

    A viewport concern, not scene-shaped. Consumers that want the pan to stay inside a document page boundary should wire this with the page dimensions.

    viewport?: ViewportConfig

    Pinch-zoom DOM listener attachment for the canvas surface. When supplied, <Canvas> calls usePinchZoomTool with canvasRef so two-finger pinch events are handled directly on the canvas element.

    Hand tool registration, wheel pan/zoom action descriptors, and keyboard zoom shortcuts are SceneCanvas-level concerns and are NOT owned by Canvas. Those belong with the tool registry and gesture dispatcher that live in SceneCanvas.

    When omitted, no pinch-zoom listener is attached.

    width: number

    CSS-pixel width.