Types Reference
ObjectBinding
The core data record for each interactive mesh in the viewer.
type ObjectBinding = {
id: string;
type: ObjectBindingType;
modelObjectId: string;
label?: string;
group?: string;
tags?: string[];
visible?: boolean;
selectable?: boolean;
hoverable?: boolean;
transform?: ObjectBindingTransform;
style?: ObjectBindingStyle;
actions?: ObjectBindingAction[];
metrics?: Record<string, number>;
metadata?: Record<string, unknown>;
cameraState?: ObjectBindingCameraState;
};Key Notes
- The
objectBindingsrecord is keyed by node name, not byid groupassigns a binding to one named set, whiletagscan assign it to several queryable setstransformstores persistent local-space position, rotation, and scale overrides; rotation values use radiansvisibleis live render state, not just an initial defaultselectable: falseandhoverable: falsemake the mesh inert to viewport picking; clicks resolve the front-most surface under the pointer, so a non-selectable mesh does not pass the click through to meshes behind itstyle.material.baseColoris the committed source of truth for color picksstyle.material.texture.pathis the committed source of truth for texture uploads- If no
texture.pathand nostyle.material.baseColorare set, the viewer falls back to the original GLB/GLTF material - See
ObjectBindingMaterialfor the full set of per-object material overrides metricsandmetadataare displayed in the side panel as nested key/value fields (objects expand into indented child labels)cameraStatestores a saved camera view for the object; when bothpositionandtargetare set, the viewer uses that view when the object is focused or selected instead of falling back tofitToBox
defineObjectBindings
A runtime identity helper that validates binding literals while preserving their exact inferred TypeScript types.
import {
defineObjectBindings,
type ObjectBindingActionId,
type ObjectBindingKey,
} from "@liveroom-tech/react-immersive";
const bindings = defineObjectBindings({
body: {
id: "vehicle-body",
modelObjectId: "body",
type: "body",
actions: [{ id: "repaint", label: "Repaint", type: "command" }],
},
});
type BindingKeys = ObjectBindingKey<typeof bindings>; // "body"
type BodyActions = ObjectBindingActionId<typeof bindings, "body">; // "repaint"ObjectBindingKey<T> extracts the binding-map key union. ObjectBindingActionId<T, K> extracts the declared action-id union for binding K.
ObjectBindingTransform
type ObjectBindingTransform = {
position?: [number, number, number]; // local model units
rotation?: [number, number, number]; // local Euler angles in radians
scale?: [number, number, number];
};Missing fields retain their model-authored local values. Removing the complete transform restores the model-authored position, rotation, and scale.
ModelViewer and BindingBuilder convert World/Local gizmo interactions back
into this local-space data before saving. BindingBuilder displays rotation in
degrees for authoring, but exports radians. Its transform gizmo is positioned
at the center of the object’s renderable geometry so an object can rotate around
itself even when its source node origin is offset; that temporary authoring
pivot does not modify the model file’s origin.
ObjectBindingType
A large union covering vehicles, rooms, furniture, characters, weapons, environment, and more.
type ObjectBindingType =
| "body"
| "light"
| "wheel"
| "glass"
| "interior"
| "floor"
| "wall"
| "door"
| "furniture"
| "decor"
| "electronics"
| "other";
// ... and moreObjectBindingStyle
Controls the visual appearance of a mesh. All visual overrides live under
material (an ObjectBindingMaterial); there are no style-level color /
metalness / roughness fields.
type ObjectBindingStyle = {
material?: ObjectBindingMaterial;
};ObjectBindingMaterial
Per-object overrides applied on top of the mesh’s original GLB/GLTF material as a
MeshPhysicalMaterial. Every field is optional, only the fields you set are
overridden; everything else falls back to the model-authored value. Texture slots
are { path: string } objects.
type TextureSlot = { path: string };
type ObjectBindingMaterial = {
// ── Base / PBR ──────────────────────────────────────────────
texture?: TextureSlot; // base color (albedo) map
baseColor?: string; // hex, e.g. "#ff0000"
metalness?: number; // 0–1
metalnessMap?: TextureSlot;
roughness?: number; // 0–1
roughnessMap?: TextureSlot;
reflectivity?: number; // 0–1 (specular F0)
specularIntensity?: number; // 0–1
specularIntensityMap?: TextureSlot;
specularColor?: string; // hex
specularColorMap?: TextureSlot;
// ── Emission ────────────────────────────────────────────────
emissive?: string; // hex
emissiveIntensity?: number; // 0–10
emissiveMap?: TextureSlot;
// ── Opacity / blending ──────────────────────────────────────
opacity?: number; // 0–1
alphaMap?: TextureSlot;
alphaTest?: number; // 0–1
alphaHash?: boolean;
dithering?: boolean; // banding reduction on gradients
blendingMode?: "normal" | "additive";
// ── Normal / bump ───────────────────────────────────────────
normalMap?: TextureSlot;
normalScale?: number;
flipNormalY?: boolean;
bumpMap?: TextureSlot;
bumpScale?: number;
// ── Displacement ────────────────────────────────────────────
displacementMap?: TextureSlot;
displacementScale?: number;
displacementBias?: number;
// ── Ambient occlusion ───────────────────────────────────────
aoMap?: TextureSlot;
aoMapIntensity?: number;
// ── Clearcoat ───────────────────────────────────────────────
clearcoat?: number; // 0–1
clearcoatMap?: TextureSlot;
clearcoatRoughness?: number; // 0–1
clearcoatRoughnessMap?: TextureSlot;
clearcoatNormalMap?: TextureSlot;
clearcoatNormalScale?: number;
flipClearcoatNormalY?: boolean;
// ── Sheen ───────────────────────────────────────────────────
sheen?: number; // 0–1
sheenColor?: string; // hex
sheenColorMap?: TextureSlot;
sheenRoughness?: number; // 0–1
sheenRoughnessMap?: TextureSlot;
// ── Anisotropy ──────────────────────────────────────────────
anisotropy?: number; // 0–1
anisotropyRotation?: number; // radians
anisotropyMap?: TextureSlot;
// ── Transmission / volume ───────────────────────────────────
transmission?: number; // 0–1
transmissionMap?: TextureSlot;
thickness?: number;
thicknessMap?: TextureSlot;
attenuationColor?: string; // hex (volume tint)
attenuationDistance?: number;
// ── Faces ───────────────────────────────────────────────────
side?: "front" | "back" | "double";
};Texture color space
Texture slots are decoded with the correct color space automatically, so maps render at the right brightness:
- sRGB (color) maps:
texture(base color/albedo),emissiveMap,sheenColorMap,specularColorMap - Linear (data) maps: everything else,
normalMap,roughnessMap,metalnessMap,aoMap,displacementMap,bumpMap,alphaMap,clearcoat*Map,anisotropyMap,transmissionMap,thicknessMap,sheenRoughnessMap,specularIntensityMap
The shared texture cache is keyed by URL and color space, so the same image URL can be used safely as both a color map and a data map.
ObjectBindingAction
Defines an action button shown in the side panel.
type ObjectBindingAction = {
id: string;
label: string;
type: "command";
effects?: ObjectActionEffect[];
};effects are executed in declaration order by useViewerActions. Each effect updates one concern through the corresponding library controller:
type ObjectActionEffect =
| {
target: ObjectBindingTarget;
objectBindings: ObjectBindingPatch;
}
| { sceneConfig: SceneConfigPatch }
| {
target: ObjectBindingTarget;
visibility: "show" | "hide" | "toggle";
}
| { camera: CameraAction }
| { animation: AnimationAction };
type CameraAction =
| { type: "focus-object"; objectId?: string }
| { type: "fit-scene" }
| { type: "reset" }
| { type: "set-target"; target: [number, number, number]; transition?: boolean }
| { type: "set-state"; state: ViewerCameraState; transition?: boolean };
type AnimationAction =
| { type: "play"; clip: string }
| { type: "pause" }
| { type: "stop" }
| { type: "set-speed"; speed: number }
| { type: "seek"; time: number };ObjectBindingTarget supports an object id, an array of ids, { group }, { tag }, or { type }.
Built-in action IDs:
| ID | Behavior |
|---|---|
toggle-visibility | Toggle mesh visibility |
change-color | Open color picker |
change-material | Open texture upload |
ObjectBindingCameraState
Saved camera state for zooming to an object.
type ObjectBindingCameraState = {
position?: [number, number, number];
target?: [number, number, number];
fov?: number;
zoom?: number;
};When both position and target are set on a binding’s cameraState, the viewer uses that saved view when the object is focused or selected instead of falling back to fitToBox.
ObjectActionEvent
The event shape emitted by onAction and useViewerActions.runAction.
type ObjectActionEvent = {
objectId: string;
action: ObjectBindingAction;
binding?: ObjectBinding;
screenX?: number;
screenY?: number;
};AnimationControls
Provided via onAnimationsReady.
type AnimationPlaybackState = {
currentClip: string | null;
isPlaying: boolean;
speed: number;
time: number; // live position of the current clip, in seconds
duration: number; // length of the current clip, in seconds
};
type AnimationControls = {
clips: string[];
clipDetails?: { sourceName: string; duration: number }[];
play: (clipName: string) => void;
pause: () => void;
stop: () => void;
setSpeed: (speed: number) => void;
seek?: (time: number) => void; // scrub the current clip to an absolute time (seconds)
getState?: () => AnimationPlaybackState;
subscribe?: (listener: (state: AnimationPlaybackState) => void) => () => void;
};SceneLight
type SceneLightAttachment = {
objectId: string;
offset: [number, number, number];
};
type SceneLight = {
id: string;
type: "none" | "directional" | "point" | "hemisphere";
color: string;
intensity: number;
position: [number, number, number];
distance?: number;
decay?: number;
attachedToCamera: boolean;
attachment?: SceneLightAttachment;
castShadow: boolean;
shadowBias: number;
visible: boolean;
};position is world-space unless the light is attached. An attachment resolves
binding keys, binding ids, modelObjectId values, and raw model node names. Its
offset uses the target object’s local space.
SceneModelRenderer
Selects the whole-model material renderer used by SceneConfig.model.renderer.
type SceneModelRenderer = "pbr" | "matcap" | "uv-checker";"pbr"renders the model-authored and binding-overridden physical materials."matcap"renders a lighting-independent studio material."uv-checker"renders a numbered directional UV0 test chart. Meshes without UV0 coordinates appear magenta.
CinematicConfig
Configures the cinematic auto-camera on ModelViewer.
type CinematicConfig = {
waypoints?: CinematicWaypoint[]; // camera keyframes to glide through
duration?: number; // seconds for one full pass (auto-scales when omitted)
loop?: boolean; // default true
autoPlay?: boolean; // start once the model has loaded and framed (default false)
};
type CinematicWaypoint = {
position: [number, number, number];
target: [number, number, number]; // world-space look-at point
azimuthAngle?: number; // preserves orbit rotation at vertical poles
polarAngle?: number;
};With fewer than two waypoints the camera falls back to an auto-generated orbit around the model’s bounding sphere.
SceneCinematicConfig
The persisted form of the cinematic path carried on SceneConfig.cinematic, authored visually in BindingBuilder’s Cinematic tab.
type SceneCinematicConfig = {
enabled: boolean; // turns the auto-camera on at runtime
waypoints: SceneCinematicWaypoint[];
duration?: number;
loop: boolean;
autoPlay: boolean;
};
type SceneCinematicWaypoint = {
position: [number, number, number];
target: [number, number, number];
azimuthAngle?: number;
polarAngle?: number;
};ModelViewer activates a sceneConfig-authored path when enabled is true and there are at least two waypoints. The cinematic prop overrides it field-by-field.
CustomObjectBindingDataPanelProps
Props passed to a customObjectBindingDataPanel render prop.
type CustomObjectBindingDataPanelProps = {
isOpen: boolean;
selectedObject: ObjectBinding | null;
currentAction: ObjectActionEvent | null;
onClose: () => void;
onAction: (event: ObjectActionEvent) => void;
};CustomSceneObjectsPanelProps
Props passed to a customSceneObjectsPanel render prop.
type CustomSceneObjectsPanelProps = {
objectBindings: Record<string, ObjectBinding>;
onAction?: (event: ObjectActionEvent) => void;
onFocus?: (binding: ObjectBinding) => void;
onHover?: (binding: ObjectBinding | null) => void;
};