Skip to Content
API ReferenceSimpleModelViewer

SimpleModelViewer

A lightweight viewer for cases where you want to load a GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY asset, inspect meshes, and toggle visibility without building objectBindings. It can either load a fixed modelUrl or, when enableModelUpload is enabled, let the user drag-and-drop or choose a local model at runtime.

Usage

import "@liveroom-tech/react-immersive/simple-model-viewer.css"; import { SimpleModelViewer } from "@liveroom-tech/react-immersive/simple-model-viewer"; export default function App() { return ( <div style={{ height: "100vh" }}> <SimpleModelViewer modelUrl="/model.glb" /> </div> ); }

Behavior

  • Discovers renderable meshes directly from the loaded model scene
  • Renders a right-side scene objects panel with search and visibility toggles
  • Renders a left-side environment/scene settings panel (background color, environment preset, auto-rotate, exposure, ambient + directional light color/intensity), each seedable via props
  • Can swap modelUrl for a built-in drag-and-drop / file-picker upload flow
  • Lets users click a mesh or panel row to select and focus it. Panel rows are buttons, so the keyboard can select from the panel too
  • Fits the full scene on initial load, and re-fits when the canvas is resized (window resize, device rotation, or a panel opening/closing), set refitOnResize={false} to instead preserve the user’s orbit/zoom
  • Uses built-in ambient, directional, and environment lighting
  • Renders on demand: frames are only drawn when something changes (camera movement, hover, auto-rotate, panel edits), so an idle viewer costs no GPU time or battery
  • Degrades gracefully on very large models (above roughly 12 million triangles): viewport click/hover picking is disabled for performance, a dismissible banner explains this to the user, and selection stays available through the scene objects panel

Use SimpleModelViewer when you want a quick inspection viewer. Use ModelViewer when you need binding-driven styling, actions, metadata, custom panels, exports, or animation integrations.

Props

type SimpleModelViewerProps = { modelUrl: string; poster?: string; loading?: "lazy" | "eager"; // default "lazy" reveal?: "auto" | "interaction"; // default "auto" labels?: ModelViewerLabels; modelFormat?: "glb" | "gltf" | "obj" | "fbx" | "usdz" | "stl" | "ply"; dracoDecoderPath?: string | false; ktx2TranscoderPath?: string | false; meshopt?: boolean; backgroundColor?: string; showSceneObjectsPanel?: boolean; showSceneSettingsPanel?: boolean; enableModelUpload?: boolean; zoomOnSelected?: boolean; highlightOnHover?: boolean; showLoadingOverlay?: boolean; refitOnResize?: boolean; reducedMotion?: "user" | "always" | "never"; // Initial values for the scene settings (environment) panel backgroundEnabled?: boolean; autoRotate?: boolean; envPreset?: PresetsType; // @react-three/drei environment preset exposure?: number; ambientIntensity?: number; ambientColor?: string; directionalIntensity?: number; directionalColor?: string; onModelLoaded?: (model: ViewerModelInfo) => void; onLoadError?: (error: unknown) => void; };

SimpleModelViewer does not take a licenseKey, licensing is enforced by ModelViewer and BindingBuilder.


labels

Optional plain-text overrides for built-in viewer text, including button titles, accessible labels, loading messages, tool hints, and AR placement controls. Missing keys retain their English defaults.

ModelViewer and SimpleModelViewer share the same dictionary. Each viewer has its own labels, and changing the prop updates text without reloading its model. See the full label catalog for every key, default, and named placeholder.

labels does not translate annotation content, object metadata, custom panels, or raw server/loader diagnostics. Supply translations for those in your application.

<SimpleModelViewer modelUrl="/car.glb" labels={{ guidedTour: "Visite guidée", tapToPlace: "Touchez pour placer", sceneSettings: "Réglages", objectCount: "Objets : {count}", }} />

modelUrl

Required. URL or public path to a .glb, .gltf, .obj, .fbx, .usdz, .stl, or .ply model. Hosted assets must serve external dependencies at their declared relative paths; USDZ dependencies are packaged internally.


modelFormat

Optional explicit format for extensionless or signed URLs. Supported extensions are detected automatically in normal URLs.


poster / loading / reveal

Work as on ModelViewer, sharing the same page-wide count of live 3D views. When a SimpleModelViewer is put away, only its canvas goes: the panels and their settings stay, and the canvas comes back with its camera, hidden objects and selection. onModelLoaded runs again when it does.


dracoDecoderPath / ktx2TranscoderPath / meshopt

Compressed-asset decoder configuration. Meshopt is bundled; DRACO and KTX2 default to immutable, versioned files on the first-party React Immersive domain. Override with self-hosted directories or pass false to disable either format. See the ModelViewer decoder setup.


backgroundColor

Optional canvas background color.

Default:

"#1a1a1a";

showSceneObjectsPanel

Optional boolean that controls whether the right-side scene objects panel is rendered.

Default:

true;

showSceneSettingsPanel

Optional boolean that controls whether the left-side environment/scene settings panel is rendered. It exposes background color/visibility, the @react-three/drei environment preset, auto-rotate, exposure, and ambient/directional light color and intensity.

Default:

true;

Scene settings defaults

The following optional props seed the initial values of the scene settings (environment) panel. Each maps to one control; the panel stays interactive, so the user can still adjust them at runtime. Changing one of these props after mount does not override a value the user has since changed in the panel (they are initial values, not controlled props), the exception is backgroundColor, which is kept in sync live.

PropTypePanel controlDefault
backgroundEnabledbooleanBackground on/offfalse
autoRotatebooleanAuto Rotatefalse
envPresetPresetsTypeEnvironment preset"city"
exposurenumberExposure1
ambientIntensitynumberAmbient Light Intensity0.6
ambientColorstringAmbient Light Color"#ffffff"
directionalIntensitynumberDirect Light Intensity1.2
directionalColorstringDirect Light Color"#ffffff"

envPreset accepts any @react-three/drei PresetsType (for example "city", "sunset", "dawn", "night", "warehouse", "forest", "apartment", "studio", "park", "lobby").

<SimpleModelViewer modelUrl="/model.glb" backgroundEnabled envPreset="sunset" exposure={1.2} ambientIntensity={0.4} directionalColor="#fff4e0" autoRotate />

zoomOnSelected

Optional boolean. When true, selecting a mesh (via click or the objects panel) zooms/frames the camera on it.

Default:

false;

highlightOnHover

Optional boolean. When true, hovering a mesh (in the viewport or the objects panel) highlights it.

On very large models (above roughly 12 million triangles) viewport hover is disabled for performance regardless of this prop, panel-row hover highlighting still works.

Default:

false;

showLoadingOverlay

Optional boolean controlling whether the built-in loading overlay is shown while the model is loading, uploaded files are being prepared, and the initial camera fit is settling.

Default:

true;

refitOnResize

Optional boolean controlling whether the camera re-frames the model to fit whenever the canvas is resized, a browser window resize, a device rotation, or a side panel (scene settings / scene objects) opening or closing. Set to false to preserve the user’s current orbit/zoom across resizes; the camera aspect stays correct either way, so the model never distorts, it just isn’t re-centered.

Default:

true;

reducedMotion

Cuts motion the viewer starts on its own. "user" follows the visitor’s device setting (prefers-reduced-motion); "always" and "never" override it. When motion is reduced, the autoRotate prop doesn’t start auto-rotate (the visitor can still turn it on in the scene settings panel), camera moves jump instead of gliding, and panels appear in place. See ModelViewer’s reducedMotion.

Default:

"user";

enableModelUpload

Optional boolean that swaps the fixed modelUrl workflow for a built-in upload UI. It accepts .glb, standalone/data-URI .gltf, .obj, .fbx, .usdz, .stl, .ply, or .zip. A ZIP may bundle GLTF dependencies, OBJ + MTL/textures, or FBX external textures; USDZ is already self-contained.

ZIP uploads are limited to 128 MiB compressed, 1,024 entries, 128 MiB per expanded entry, 256 MiB expanded in total, and a 200:1 per-entry compression ratio. Zipped GLTF assets may use data: URIs or paths included in the archive; external asset URLs are rejected.

Default:

false;

onModelLoaded

Optional callback fired after the model scene has loaded.

onModelLoaded?: (model: ViewerModelInfo) => void // { bounds, objectCount, materialVariants, materialVariantGroups }

onLoadError

Optional callback fired if the model fails to load or render.

onLoadError?: (error: unknown) => void