Skip to Content
Getting Started

Getting Started

Installation

npm install @liveroom-tech/react-immersive three @react-three/fiber

three and @react-three/fiber are peer dependencies, along with React 19, so your app has exactly one copy of each. Everything else installs with the package.

Import Styles

Import the stylesheet for each component you use, once, from your application root. In a Next.js App Router project, put these in app/layout.tsx:

import "@liveroom-tech/react-immersive/styles.css"; // ModelViewer import "@liveroom-tech/react-immersive/simple-model-viewer.css"; // SimpleModelViewer import "@liveroom-tech/react-immersive/binding-builder.css"; // BindingBuilder

SimpleModelViewer and BindingBuilder are imported from their own entry points, @liveroom-tech/react-immersive/simple-model-viewer and @liveroom-tech/react-immersive/binding-builder, so an app downloads only the components it uses.

If a component’s stylesheet is missing, it renders unstyled, and in development it logs a console warning naming the import to add.

Get a License Key

ModelViewer and BindingBuilder require a licenseKey. (SimpleModelViewer does not, it’s unlicensed.) To get one:

  1. Sign in (or sign up) at the React Immersive Console 
  2. Choose a plan
  3. Generate a license key from your dashboard

Keep your license key out of public repositories. Load it from an environment variable in your app.

Quick Start

To see your model working before you write any bindings, let the viewer generate them:

import { ModelViewer } from "@liveroom-tech/react-immersive"; export default function App() { return ( <div style={{ height: "100vh", overflow: "hidden" }}> <ModelViewer modelUrl="/model.glb" licenseKey={process.env.NEXT_PUBLIC_LICENSE_KEY!} /> </div> ); }

Every mesh can then be hovered and selected, with Change Color, Change Material, and Toggle Visibility in the side panel (or light controls for meshes whose names contain “light”). See generating bindings automatically to keep and refine them. The steps below write the bindings yourself, which gives you control over labels, actions, metadata, and camera views.

Define your object bindings

Each key in objectBindings must match a model node identifier. Unique nodes use their authored name; duplicate names receive identifiers such as Cube [1] and Cube [2]. BindingBuilder generates the correct identifiers automatically. You can write the bindings by hand, or generate starter bindings in BindingBuilder and export them as objectBindings.json or a TypeScript file to import into your app. For a configured scene, export sceneConfig.ts from BindingBuilder’s Scene tab and pass its named sceneConfig export to ModelViewer as well. The BindingBuilder export and import guide explains where each toolbar action lives and when to choose JSON versus TypeScript. If you want a ready-to-run starter, download the sample red_room.glb model and objectBindings.ts bindings file from these docs. Put red_room.glb in your app’s public/ folder, and place objectBindings.ts in your source tree so you can import it into your viewer page.

Sample model credit: “Red Room”  by LaisLH, licensed under Creative Commons Attribution 4.0 .

import { defineObjectBindings } from "@liveroom-tech/react-immersive/utils"; const objectBindings = defineObjectBindings({ BrickWall: { id: "brick-wall", modelObjectId: "BrickWall", type: "wall", label: "Room Walls", selectable: true, hoverable: true, visible: true, style: {}, metrics: {}, metadata: {}, cameraState: { position: [-0.91, 0.87, 0.42], target: [0.09, 0.98, 0.036], fov: 45, }, actions: [ { id: "change-color", label: "Change Color", type: "command" }, { id: "change-material", label: "Change Material", type: "command" }, { id: "toggle-visibility", label: "Toggle Visibility", type: "command" }, ], }, });

Mount the viewer

Wrap ModelViewer in a full-height container. The component owns its own layout.

import { useState } from "react"; import { ModelViewer } from "@liveroom-tech/react-immersive"; import { objectBindings as initialBindings } from "./objectBindings.ts"; export default function App() { const [objectBindings, setObjectBindings] = useState(initialBindings); return ( <div style={{ height: "100vh", overflow: "hidden" }}> <ModelViewer modelUrl="/red_room.glb" licenseKey="your-license-key" objectBindings={objectBindings} onObjectBindingsChange={setObjectBindings} /> </div> ); }

Control the viewer from your app

useViewer connects every viewer hook to ModelViewer at once. Spread its props onto the viewer, then drive bindings, camera, selection, animations, and scene settings from your own UI.

import { ModelViewer, useViewer } from "@liveroom-tech/react-immersive"; import { objectBindings } from "./objectBindings"; export default function Example() { const viewer = useViewer({ bindings: objectBindings, onAction: (event) => console.log(event), }); const { toggleObjectVisibility } = viewer.bindings; const { resetView, focusObject } = viewer.camera; const { clips, play } = viewer.animations; return ( <div style={{ height: "100vh", overflow: "hidden" }}> <ModelViewer modelUrl="/red_room.glb" licenseKey="your-license-key" {...viewer.props} /> <button onClick={() => toggleObjectVisibility("some-object-id")}> Toggle Visibility </button> <button onClick={() => resetView()}>Reset Camera</button> <button onClick={() => focusObject("some-object-id")}> Focus Object </button> {clips.map((name) => ( <button key={name} onClick={() => play(name)}> {name} </button> ))} </div> ); }

Leave out bindings and useViewer generates them from the model, like objectBindings="auto". See useViewer for everything it returns, and the other hooks for wiring individual pieces yourself.