Skip to Content
HooksuseViewerActions

useViewerActions

Executes declarative object-binding, scene, visibility, camera, and animation effects from an object’s actions. Use the same handleAction callback for ModelViewer actions and runAction for controls elsewhere in your app.

Usage

import { ModelViewer, useObjectBindings, useSceneConfig, useViewerActions, useViewerAnimations, useViewerCamera, } from "@liveroom-tech/react-immersive"; const bindings = useObjectBindings(initialBindings); const scene = useSceneConfig(initialSceneConfig); const camera = useViewerCamera(); const animations = useViewerAnimations(); const { getActionsForObject, handleAction, runAction } = useViewerActions({ bindings, scene, camera, animations, onAction: (event) => console.log("completed", event.action.id), }); <ModelViewer objectBindings={bindings.objectBindings} sceneConfig={scene.sceneConfig} onObjectBindingsChange={bindings.setObjectBindings} onAction={handleAction} onViewerReady={camera.handleViewerReady} onCameraChange={camera.handleCameraChange} onAnimationsReady={animations.handleAnimationsReady} />; // Run the same exported action from your own button. await runAction("switch-a", "turn-on");

Declare effects

Effects run in the order they appear. An action can combine any of the supported effect categories.

const initialBindings = { switch_a: { id: "switch-a", modelObjectId: "switch_a", actions: [ { id: "turn-on", label: "Turn On", type: "command", effects: [ { target: { group: "circuit-a" }, objectBindings: { style: { material: { emissive: "#fde047", emissiveIntensity: 3, }, }, metadata: { state: "on" }, }, }, { sceneConfig: { lighting: { ambient: { intensity: 0.2 } }, }, }, { target: { tag: "warning" }, visibility: "show" }, { camera: { type: "focus-object" } }, { animation: { type: "play", clip: "PowerOn" } }, ], }, ], }, };

Supported effects

CategoryShapeController used
Object bindings{ target, objectBindings: patch }useObjectBindings
Scene{ sceneConfig: patch }useSceneConfig
Visibility{ target, visibility: "show" | "hide" | "toggle" }useObjectBindings
Camera{ camera: action }useViewerCamera
Animation{ animation: action }useViewerAnimations

Object and visibility targets accept an object id, an array of ids, { group }, { tag }, or { type }, just like useObjectBindings.

Camera actions are focus-object, fit-scene, reset, set-target, and set-state. Animation actions are play, pause, stop, set-speed, and seek.

Parameters

NameRequiredDescription
bindingsYesThe controller returned by useObjectBindings
sceneNoThe controller returned by useSceneConfig
cameraNoThe controller returned by useViewerCamera
animationsNoThe controller returned by useViewerAnimations
onActionNoObserver called after the declared effects have run

If an optional controller is omitted, effects for that category are skipped and the remaining effects still run.

Returns

NameDescription
getActionsForObject(id)Resolves actions by binding key, binding.id, or binding.modelObjectId
handleAction(event)Executes an action event. Pass it directly to ModelViewer.onAction
runAction(id, actionId)Finds and executes an action, then resolves to its event, or null when it cannot be found

Built-in viewer actions

ModelViewer still owns the picker UI for change-color and change-material, plus its built-in toggle-visibility behavior. Declarative effects run in addition to that behavior when handleAction is connected. Do not declare an equivalent visibility effect on a built-in toggle-visibility action, because it would toggle twice.

Calling runAction executes declarative effects only. It does not invoke viewer-owned behavior such as opening a picker or running the built-in visibility toggle. For programmatic visibility, call the bindings controller directly or declare a custom action with a visibility effect.