@liveroom-tech/react-immersive 3.0.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +249 -39
- package/dist/bvhWorkerCode-6366A3UC.mjs +3664 -0
- package/dist/chunk-CPHWRR2L.mjs +1 -0
- package/dist/chunk-JR557W27.mjs +1 -0
- package/dist/decoders/basis/README.md +46 -0
- package/dist/decoders/basis/basis_transcoder.js +19 -0
- package/dist/decoders/basis/basis_transcoder.wasm +0 -0
- package/dist/decoders/draco/README.md +32 -0
- package/dist/decoders/draco/draco_decoder.js +33 -0
- package/dist/decoders/draco/draco_decoder.wasm +0 -0
- package/dist/decoders/draco/draco_wasm_wrapper.js +116 -0
- package/dist/index.css +1 -0
- package/dist/index.d.mts +97 -565
- package/dist/index.d.ts +97 -565
- package/dist/index.js +3664 -20232
- package/dist/index.mjs +7 -20342
- package/dist/utils-BUwXD_DX.d.mts +563 -0
- package/dist/utils-BUwXD_DX.d.ts +563 -0
- package/dist/utils.d.mts +1 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +1 -0
- package/dist/utils.mjs +1 -0
- package/package.json +25 -3
- package/dist/bvhWorkerCode-JRKQF4QH.mjs +0 -7
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# React Immersive — 3D model viewer for React
|
|
2
2
|
|
|
3
|
-
`@liveroom-tech/react-immersive` is a React-based 3D model viewer for interactive GLB
|
|
3
|
+
`@liveroom-tech/react-immersive` is a React-based 3D model viewer for interactive GLB, GLTF, OBJ, FBX, and USDZ assets. It renders a model with React Three Fiber, lets users click named meshes, shows a built-in side panel for the selected object, and supports per-object actions such as color changes, texture uploads, and visibility toggles.
|
|
4
|
+
|
|
5
|
+
[Website](https://react-immersive.liveroom.dev) · [Documentation](https://react-immersive.liveroom.dev/docs) · [Live editor](https://react-immersive.liveroom.dev/editor) · [npm](https://www.npmjs.com/package/@liveroom-tech/react-immersive) · [GitHub](https://github.com/Liveroom-Technologies/react-immersive-docs)
|
|
4
6
|
|
|
5
7
|
## What It Does
|
|
6
8
|
|
|
@@ -31,11 +33,12 @@ import {
|
|
|
31
33
|
} from "@liveroom-tech/react-immersive";
|
|
32
34
|
```
|
|
33
35
|
|
|
34
|
-
It also exports types for `ObjectBinding`, `ObjectBindingMaterial`, `ObjectBindingsController`, `ObjectActionEvent`, `SceneConfig`, `SceneConfigPatch`, `SceneConfigController`, `AnimationControls`, `CinematicConfig` / `CinematicWaypoint`, and related shapes used throughout this document.
|
|
36
|
+
It also exports types for `ObjectBinding`, `ObjectBindingMaterial`, `ObjectBindingsController`, `ObjectActionEvent`, `ObjectTransformSpace`, `SceneConfig`, `SceneConfigPatch`, `SceneConfigController`, `AnimationControls`, `CinematicConfig` / `CinematicWaypoint`, and related shapes used throughout this document.
|
|
35
37
|
|
|
36
38
|
`ModelViewer` provides:
|
|
37
39
|
|
|
38
|
-
- GLB/GLTF model rendering through `@react-three/fiber`
|
|
40
|
+
- GLB/GLTF, OBJ/MTL, FBX, and USDZ model rendering through `@react-three/fiber`
|
|
41
|
+
- camera-driven 3D Tiles streaming through `tilesetUrl`, with configurable screen-space error and bounded tile cache
|
|
39
42
|
- orbit/pan/zoom camera controls via `CameraControls`
|
|
40
43
|
- auto-fits the model on load, and re-fits when the canvas is resized (window resize, device rotation, or a panel opening/closing), toggleable through `refitOnResize` to instead preserve the user's orbit/zoom
|
|
41
44
|
- optional custom scene lighting through a `lights` prop
|
|
@@ -43,10 +46,13 @@ It also exports types for `ObjectBinding`, `ObjectBindingMaterial`, `ObjectBindi
|
|
|
43
46
|
- optional custom background color through a `backgroundColor` prop
|
|
44
47
|
- optional shadow rendering toggle through a `shadows` prop (on by default)
|
|
45
48
|
- optional on-screen movement controller through `showMouseController` and its tuning props
|
|
49
|
+
- optional canvas-focused keyboard camera navigation through `enableKeyboardNavigation`
|
|
50
|
+
- optional top-right camera orientation control through `showViewGizmo`
|
|
51
|
+
- optional per-object move and rotate gizmo through `moveModeEnabled`, with World/Local axis alignment through `objectTransformSpace`
|
|
46
52
|
- optional custom left object data panel through `customObjectBindingDataPanel`
|
|
47
53
|
- optional custom right scene objects panel through `customSceneObjectsPanel`
|
|
48
54
|
- optional hiding of either built-in panel through `showObjectBindingDataPanel` and `showSceneObjectsPanel`
|
|
49
|
-
- optional model export button through `showDownloadButton` and `downloadFilename`, plus an independent `showResetButton` toggle for the rest of that action bar
|
|
55
|
+
- optional model export button through `showDownloadButton` and `downloadFilename`, opt-in PNG capture through `preserveDrawingBuffer`, plus an independent `showResetButton` toggle for the rest of that action bar
|
|
50
56
|
- an optional UV Checker toolbar button through `showUvCheckerButton`, for inspecting UV scale, stretching, seams, orientation, and missing UV0 coordinates directly in `ModelViewer`
|
|
51
57
|
- click-to-measure distance tool and a bounding-box dimensions overlay through `showMeasureTools` and `measurementUnit`
|
|
52
58
|
- an exploded-view slider that slides each bound part outward from the model center to reveal interior/assembly structure through `showExplodeControls`
|
|
@@ -72,14 +78,15 @@ It also exports types for `ObjectBinding`, `ObjectBindingMaterial`, `ObjectBindi
|
|
|
72
78
|
- camera change callbacks through `onCameraChange`
|
|
73
79
|
- viewer-ready callbacks through `onViewerReady`
|
|
74
80
|
- action event callbacks through `onAction`
|
|
75
|
-
- animation playback for GLB/GLTF models with embedded animations through `onAnimationsReady`
|
|
81
|
+
- animation playback for GLB/GLTF, FBX, and USDZ models with supported embedded animations through `onAnimationsReady`
|
|
76
82
|
- annotation marker callbacks through `onAnnotationsChange` and controlled/uncontrolled `activeAnnotation` / `onActiveAnnotationChange`
|
|
77
83
|
|
|
78
84
|
`BindingBuilder` provides:
|
|
79
85
|
|
|
80
|
-
- a design-time UI for generating starter bindings from GLB
|
|
81
|
-
- demo model loading or custom `.glb`, `.gltf`, or
|
|
86
|
+
- a design-time UI for generating starter bindings from GLB, GLTF, OBJ, FBX, and USDZ assets, gated by `licenseKey` (see "`BindingBuilder` licensing & plan tiers" below)
|
|
87
|
+
- demo model loading or custom `.glb`, `.gltf`, `.obj`, `.fbx`, `.usdz`, or model ZIP bundle upload
|
|
82
88
|
- editable binding fields for identity, basics, style, actions, metrics, metadata, and saved camera state
|
|
89
|
+
- per-object move and rotate authoring with a geometry-centered pivot, World/Local axes, numeric fields, and restore-to-authored-transform support
|
|
83
90
|
- a one-click material preset gallery (wood, metal, chrome, glass, plastic, fabric, ceramic, concrete, etc.)
|
|
84
91
|
- undo/redo for both the Object tab's bindings and the Scene tab's config, independently, with `Cmd/Ctrl+Z` / `Cmd/Ctrl+Shift+Z` shortcuts
|
|
85
92
|
- a Scene tab for the same `sceneConfig` shape `ModelViewer` accepts (lighting, environment, background, post-processing, animations, annotations, and cinematic camera paths)
|
|
@@ -91,8 +98,8 @@ It also exports types for `ObjectBinding`, `ObjectBindingMaterial`, `ObjectBindi
|
|
|
91
98
|
|
|
92
99
|
`SimpleModelViewer` provides:
|
|
93
100
|
|
|
94
|
-
- a lightweight GLB/GLTF viewer that does not require `objectBindings` and does not require a `licenseKey`
|
|
95
|
-
- optional local `.glb`, standalone/data-URI `.gltf`, or
|
|
101
|
+
- a lightweight GLB/GLTF/OBJ/FBX/USDZ viewer that does not require `objectBindings` and does not require a `licenseKey`
|
|
102
|
+
- optional local `.glb`, standalone/data-URI `.gltf`, `.obj`, `.fbx`, `.usdz`, or model ZIP bundle upload mode for ad-hoc inspection without relying on the `modelUrl` asset
|
|
96
103
|
- built-in scene objects panel with search and visibility toggles
|
|
97
104
|
- a built-in environment/scene settings panel (background color, environment preset, auto-rotate, exposure, ambient + directional light) toggleable via `showSceneSettingsPanel`, with each control's initial value seedable via props
|
|
98
105
|
- click-to-select and fit-to-object focus behavior
|
|
@@ -112,7 +119,7 @@ domain model. It is a serializable record, keyed by mesh node name, that lets
|
|
|
112
119
|
you:
|
|
113
120
|
|
|
114
121
|
- declare which meshes are interactive
|
|
115
|
-
- carry live render state such as visibility and per-object material overrides
|
|
122
|
+
- carry live render state such as visibility, local transforms, and per-object material overrides
|
|
116
123
|
- attach actions like `change-color`, `change-material`, and `toggle-visibility`
|
|
117
124
|
- store metadata and metrics alongside the 3D scene
|
|
118
125
|
- save camera framing so object focus can use curated views
|
|
@@ -161,7 +168,16 @@ has its own meaning, state, or behavior," object bindings are a strong fit.
|
|
|
161
168
|
npm install @liveroom-tech/react-immersive
|
|
162
169
|
```
|
|
163
170
|
|
|
164
|
-
|
|
171
|
+
Import the library stylesheet once from your application root (for example,
|
|
172
|
+
Next.js `app/layout.tsx`):
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import "@liveroom-tech/react-immersive/styles.css";
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The styles ship as a static CSS file rather than a runtime-injected `<style>`
|
|
179
|
+
tag, so a strict CSP does not need `style-src 'unsafe-inline'`. Tailwind is not
|
|
180
|
+
required in the consuming app.
|
|
165
181
|
|
|
166
182
|
Peer dependencies:
|
|
167
183
|
|
|
@@ -174,7 +190,7 @@ Peer dependencies:
|
|
|
174
190
|
|
|
175
191
|
- [Developer Portal](https://react-immersive.liveroom.dev), sign in, pick a plan, and generate a `licenseKey`
|
|
176
192
|
- [Docs](https://react-immersive.liveroom.dev/docs), full reference for every component, hook, and prop
|
|
177
|
-
- [Examples & community repo](https://github.com/liveroom-technologies/react-immersive), public docs source, starter examples, and community resources
|
|
193
|
+
- [Examples & community repo](https://github.com/liveroom-technologies/react-immersive-docs/examples), public docs source, starter examples, and community resources
|
|
178
194
|
- [Report a bug / request a feature](https://github.com/liveroom-technologies/react-immersive-docs/issues), for public bug reports, docs issues, and feature requests
|
|
179
195
|
- [Discussions & Q&A](https://github.com/liveroom-technologies/react-immersive-docs/discussions), ask questions, share ideas, and compare approaches
|
|
180
196
|
- [Private support / security](mailto:developers@liveroom.xyz?subject=React%20Immersive%20Support), for license, account, confidential customer, or security-sensitive issues
|
|
@@ -185,7 +201,6 @@ Peer dependencies:
|
|
|
185
201
|
|
|
186
202
|
```tsx
|
|
187
203
|
import {
|
|
188
|
-
defineObjectBindings,
|
|
189
204
|
ModelViewer,
|
|
190
205
|
useObjectBinding,
|
|
191
206
|
useObjectBindings,
|
|
@@ -196,6 +211,7 @@ import {
|
|
|
196
211
|
useViewerModel,
|
|
197
212
|
useViewerSelection,
|
|
198
213
|
} from "@liveroom-tech/react-immersive";
|
|
214
|
+
import { defineObjectBindings } from "@liveroom-tech/react-immersive/utils";
|
|
199
215
|
|
|
200
216
|
const initialBindings = defineObjectBindings({
|
|
201
217
|
CarBody: {
|
|
@@ -412,7 +428,10 @@ updateMetadata({ group: "lights" }, { state: "on" });
|
|
|
412
428
|
|
|
413
429
|
When a parent or store owns the state, use the pure `selectBindings` and
|
|
414
430
|
`selectBindingKeys` helpers for the same queries, and `patchBindings` to update
|
|
415
|
-
all matches.
|
|
431
|
+
all matches. Import these helpers from
|
|
432
|
+
`@liveroom-tech/react-immersive/utils` when the module must remain usable from a
|
|
433
|
+
React Server Component; the main entry continues to re-export them for
|
|
434
|
+
backwards compatibility.
|
|
416
435
|
|
|
417
436
|
The hook returns:
|
|
418
437
|
|
|
@@ -624,21 +643,52 @@ export default function App() {
|
|
|
624
643
|
}
|
|
625
644
|
```
|
|
626
645
|
|
|
627
|
-
`BindingBuilder` accepts one required prop
|
|
646
|
+
`BindingBuilder` accepts one required prop and the same optional decoder
|
|
647
|
+
configuration as the viewers:
|
|
628
648
|
|
|
629
649
|
```ts
|
|
630
650
|
type BindingBuilderProps = {
|
|
631
651
|
licenseKey: string;
|
|
652
|
+
licenseValidationUrl?: string;
|
|
653
|
+
dracoDecoderPath?: string | false;
|
|
654
|
+
ktx2TranscoderPath?: string | false;
|
|
655
|
+
meshopt?: boolean;
|
|
656
|
+
project?: BindingBuilderProject | null;
|
|
657
|
+
onProjectChange?: (snapshot: BindingBuilderProjectSnapshot, origin: "local" | "remote") => void;
|
|
658
|
+
projectChangeDebounceMs?: number;
|
|
659
|
+
onModelUpload?: (file: File) => Promise<BindingBuilderProjectModel>;
|
|
660
|
+
onEditLeaseChange?: (featureId: string, editing: boolean) => void;
|
|
632
661
|
};
|
|
633
662
|
```
|
|
634
663
|
|
|
664
|
+
Pass `tilesetUrl` to `ModelViewer` for a processed 3D Tiles asset. The original
|
|
665
|
+
`modelUrl` remains the durable source/fallback URL, but is not downloaded by the
|
|
666
|
+
viewer while a tileset is present:
|
|
667
|
+
|
|
668
|
+
```tsx
|
|
669
|
+
<ModelViewer
|
|
670
|
+
modelUrl="https://assets.example.com/source/building.glb"
|
|
671
|
+
tilesetUrl="https://assets.example.com/tiles/building/tileset.json"
|
|
672
|
+
tilesErrorTarget={8}
|
|
673
|
+
tilesCacheSize={800}
|
|
674
|
+
licenseKey="your-license-key"
|
|
675
|
+
objectBindings={{}}
|
|
676
|
+
/>
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
Tiles are a dynamic level-of-detail scene, so automatic mesh binding generation
|
|
680
|
+
is intentionally disabled in streamed `BindingBuilder` projects. Scene settings
|
|
681
|
+
remain editable. Per-part editing requires the conversion pipeline to provide a
|
|
682
|
+
stable CAD/object catalog that can be mapped to tile feature metadata.
|
|
683
|
+
|
|
635
684
|
`licenseKey` is validated the same way as `ModelViewer`'s (see [`licenseKey`](#licensekey) below). While the key is being checked, `BindingBuilder` renders a "Verifying license…" placeholder; if it's invalid, it renders an error message instead of the editor.
|
|
636
685
|
|
|
637
686
|
Current behavior, Object tab:
|
|
638
687
|
|
|
639
|
-
-
|
|
688
|
+
- upload a `.glb`, standalone/data-URI `.gltf`, or `.zip` containing a `.gltf` plus its referenced `.bin` and texture files
|
|
640
689
|
- traverse renderable mesh nodes and generate starter bindings automatically
|
|
641
690
|
- edit binding identity, label, type, status, booleans, style, actions, metrics, metadata, and saved camera state
|
|
691
|
+
- move and rotate the selected object from the **Move & Rotate** panel using a geometry-centered pivot, World/Local axis alignment, or numeric position and degree fields; restore its authored transform with one click
|
|
642
692
|
- apply a one-click material preset (wood, metal, chrome, glass, plastic, fabric, ceramic, concrete, etc.) onto the selected object's material
|
|
643
693
|
- undo/redo the current bindings (toolbar buttons or `Cmd/Ctrl+Z` / `Cmd/Ctrl+Shift+Z`); rapid edits coalesce into a single undo step
|
|
644
694
|
- import a previously exported `objectBindings.json`, merged onto the current model by `modelObjectId`
|
|
@@ -654,6 +704,7 @@ Current behavior, Scene tab:
|
|
|
654
704
|
Preview:
|
|
655
705
|
|
|
656
706
|
- the selected node previews live in an embedded `ModelViewer`
|
|
707
|
+
- enable **Transform gizmo**, select a mesh, then use the arrows and plane handles to move it or the rings to rotate it; all changes are saved to `binding.transform`
|
|
657
708
|
|
|
658
709
|
### `BindingBuilder` licensing & plan tiers
|
|
659
710
|
|
|
@@ -669,7 +720,7 @@ A locked feature renders in place (not hidden) with a message naming the require
|
|
|
669
720
|
|
|
670
721
|
## `SimpleModelViewer`
|
|
671
722
|
|
|
672
|
-
`SimpleModelViewer` is an exported lightweight viewer for cases where you want to load a GLB
|
|
723
|
+
`SimpleModelViewer` is an exported lightweight viewer for cases where you want to load a GLB, GLTF, OBJ, FBX, or USDZ asset, inspect meshes, and toggle visibility without building `objectBindings`. It can either load a fixed `modelUrl` or, when `enableModelUpload` is turned on, let the user drag-and-drop or choose a local model at runtime.
|
|
673
724
|
|
|
674
725
|
Basic usage:
|
|
675
726
|
|
|
@@ -694,7 +745,7 @@ Sizing note:
|
|
|
694
745
|
|
|
695
746
|
Current behavior:
|
|
696
747
|
|
|
697
|
-
- discovers renderable meshes directly from the loaded
|
|
748
|
+
- discovers renderable meshes directly from the loaded model scene
|
|
698
749
|
- renders a right-side scene objects panel with search and visibility toggles
|
|
699
750
|
- renders a left-side environment/scene settings panel (background color, environment preset, auto-rotate, exposure, ambient + directional light) toggleable via `showSceneSettingsPanel`, with every control seedable via props
|
|
700
751
|
- optionally replaces `modelUrl` with a drag-and-drop / file-picker flow when `enableModelUpload` is enabled
|
|
@@ -831,8 +882,11 @@ const { clips, currentClip, isPlaying, play, pause, stop, setSpeed } =
|
|
|
831
882
|
The source code currently defines `ModelViewer` with these props:
|
|
832
883
|
|
|
833
884
|
```ts
|
|
885
|
+
type ObjectTransformSpace = "local" | "world";
|
|
886
|
+
|
|
834
887
|
type Props = {
|
|
835
888
|
modelUrl: string;
|
|
889
|
+
modelFormat?: "glb" | "gltf" | "obj" | "fbx" | "usdz";
|
|
836
890
|
licenseKey: string;
|
|
837
891
|
objectBindings: Record<string, ObjectBinding>;
|
|
838
892
|
selectedObject?: ObjectBinding | null;
|
|
@@ -881,10 +935,15 @@ type Props = {
|
|
|
881
935
|
sceneConfig?: SceneConfig;
|
|
882
936
|
disableZoom?: boolean;
|
|
883
937
|
zoomOnSelected?: boolean;
|
|
938
|
+
enableCameraControls?: boolean;
|
|
939
|
+
moveModeEnabled?: boolean;
|
|
940
|
+
objectTransformSpace?: ObjectTransformSpace;
|
|
941
|
+
enableKeyboardNavigation?: boolean;
|
|
884
942
|
onAutoFit?: () => Promise<boolean>;
|
|
885
943
|
refitOnResize?: boolean;
|
|
886
944
|
renderMode?: "always" | "demand";
|
|
887
945
|
maxDpr?: number;
|
|
946
|
+
preserveDrawingBuffer?: boolean;
|
|
888
947
|
performanceProfile?: "auto" | "high" | "low";
|
|
889
948
|
dracoDecoderPath?: string | false;
|
|
890
949
|
ktx2TranscoderPath?: string | false;
|
|
@@ -900,12 +959,13 @@ type Props = {
|
|
|
900
959
|
mobileHandoffUrl?: string;
|
|
901
960
|
showAnnotationNavigation?: boolean;
|
|
902
961
|
showAnnotationOnHover?: boolean;
|
|
962
|
+
showViewGizmo?: boolean;
|
|
903
963
|
};
|
|
904
964
|
```
|
|
905
965
|
|
|
906
966
|
### `modelUrl`
|
|
907
967
|
|
|
908
|
-
URL or public path to
|
|
968
|
+
URL or public path to a `.glb`, `.gltf`, `.obj`, `.fbx`, or `.usdz` model. Hosted GLTF, OBJ, and FBX assets must serve external buffers, MTL files, and textures at their declared relative paths. USDZ dependencies are contained in the USDZ package. Use `modelFormat` when a signed or extensionless URL cannot be auto-detected.
|
|
909
969
|
|
|
910
970
|
Example:
|
|
911
971
|
|
|
@@ -913,6 +973,11 @@ Example:
|
|
|
913
973
|
modelUrl = "/model.glb";
|
|
914
974
|
```
|
|
915
975
|
|
|
976
|
+
### `modelFormat`
|
|
977
|
+
|
|
978
|
+
Optional explicit format for signed or extensionless model URLs. Normal URLs
|
|
979
|
+
ending in `.glb`, `.gltf`, `.obj`, `.fbx`, or `.usdz` are detected automatically.
|
|
980
|
+
|
|
916
981
|
### `licenseKey`
|
|
917
982
|
|
|
918
983
|
License key for the library. Required.
|
|
@@ -932,7 +997,7 @@ A map keyed by the model node name. Each key should match a mesh name from the G
|
|
|
932
997
|
Example:
|
|
933
998
|
|
|
934
999
|
```ts
|
|
935
|
-
import { defineObjectBindings } from "@liveroom-tech/react-immersive";
|
|
1000
|
+
import { defineObjectBindings } from "@liveroom-tech/react-immersive/utils";
|
|
936
1001
|
|
|
937
1002
|
const objectBindings = defineObjectBindings({
|
|
938
1003
|
Object_2: {
|
|
@@ -1008,6 +1073,7 @@ This fires for:
|
|
|
1008
1073
|
- color picks (`binding.style.material.baseColor`), committed when the color picker closes
|
|
1009
1074
|
- texture uploads (`binding.style.material.texture.path`), committed immediately (via `onTextureUpload` when provided, otherwise as a blob URL)
|
|
1010
1075
|
- texture removal (`binding.style.material.texture` cleared)
|
|
1076
|
+
- object movement and rotation (`binding.transform.position` and `binding.transform.rotation`)
|
|
1011
1077
|
|
|
1012
1078
|
If you want the viewer and your app state to stay in sync, pass `objectBindings` from state and wire this callback back into that state setter.
|
|
1013
1079
|
|
|
@@ -1077,16 +1143,19 @@ type CaptureImageOptions = {
|
|
|
1077
1143
|
};
|
|
1078
1144
|
```
|
|
1079
1145
|
|
|
1080
|
-
`captureImage` forces a render and resolves with a `data:image/png` URL. Pass `width`/`height` to render at a resolution other than the canvas's current size, and `transparent` to hide the configured background so the PNG carries an alpha channel instead. It rejects if called before the viewer is ready.
|
|
1146
|
+
`captureImage` requires the opt-in `preserveDrawingBuffer` prop, forces a render, and resolves with a `data:image/png` URL. Pass `width`/`height` to render at a resolution other than the canvas's current size, and `transparent` to hide the configured background so the PNG carries an alpha channel instead. It rejects if called before the viewer is ready or when framebuffer preservation is disabled. The Download PNG menu item is also shown only when this prop is enabled.
|
|
1081
1147
|
|
|
1082
1148
|
```tsx
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1149
|
+
<ModelViewer
|
|
1150
|
+
preserveDrawingBuffer
|
|
1151
|
+
onViewerReady={(viewer) => {
|
|
1152
|
+
viewer
|
|
1153
|
+
.captureImage({ width: 1920, height: 1080, transparent: true })
|
|
1154
|
+
.then((dataUrl) => {
|
|
1155
|
+
// upload, preview, etc.
|
|
1156
|
+
});
|
|
1157
|
+
}}
|
|
1158
|
+
/>;
|
|
1090
1159
|
```
|
|
1091
1160
|
|
|
1092
1161
|
Note: requesting a custom `width`/`height` briefly resizes the live canvas to render at that resolution before restoring it, which can cause a momentary flicker on screen, fine for an occasional snapshot, not for rapid/looped calls.
|
|
@@ -1098,7 +1167,10 @@ const camera = useViewerCamera();
|
|
|
1098
1167
|
const effects = useViewerEffects();
|
|
1099
1168
|
const connection = useViewerConnection(camera, effects);
|
|
1100
1169
|
|
|
1101
|
-
<ModelViewer
|
|
1170
|
+
<ModelViewer
|
|
1171
|
+
preserveDrawingBuffer
|
|
1172
|
+
onViewerReady={connection.handleViewerReady}
|
|
1173
|
+
/>;
|
|
1102
1174
|
|
|
1103
1175
|
const dataUrl = await connection.captureImage({ width: 1920, height: 1080 });
|
|
1104
1176
|
```
|
|
@@ -1336,8 +1408,9 @@ true;
|
|
|
1336
1408
|
|
|
1337
1409
|
### `showDownloadButton`
|
|
1338
1410
|
|
|
1339
|
-
Optional boolean that enables the download split-button (export GLB, export
|
|
1340
|
-
|
|
1411
|
+
Optional boolean that enables the download split-button (export GLB, export the
|
|
1412
|
+
model's UV layout, and—when `preserveDrawingBuffer` is enabled—export a PNG
|
|
1413
|
+
screenshot).
|
|
1341
1414
|
|
|
1342
1415
|
Default:
|
|
1343
1416
|
|
|
@@ -1495,6 +1568,82 @@ Default:
|
|
|
1495
1568
|
true;
|
|
1496
1569
|
```
|
|
1497
1570
|
|
|
1571
|
+
### Moving and rotating objects
|
|
1572
|
+
|
|
1573
|
+
Set `moveModeEnabled` to show a centered Drei `PivotControls` gizmo for the
|
|
1574
|
+
selected bound object. Translation arrows, plane handles, and rotation rings
|
|
1575
|
+
are available together; scaling is not enabled. While object editing is on,
|
|
1576
|
+
the camera controls are paused so pointer drags manipulate the object instead
|
|
1577
|
+
of the camera.
|
|
1578
|
+
|
|
1579
|
+
```tsx
|
|
1580
|
+
import { useState } from "react";
|
|
1581
|
+
import {
|
|
1582
|
+
ModelViewer,
|
|
1583
|
+
type ObjectBinding,
|
|
1584
|
+
} from "@liveroom-tech/react-immersive";
|
|
1585
|
+
|
|
1586
|
+
export function EditableViewer({
|
|
1587
|
+
initialBindings,
|
|
1588
|
+
}: {
|
|
1589
|
+
initialBindings: Record<string, ObjectBinding>;
|
|
1590
|
+
}) {
|
|
1591
|
+
const [objectBindings, setObjectBindings] = useState(initialBindings);
|
|
1592
|
+
|
|
1593
|
+
return (
|
|
1594
|
+
<ModelViewer
|
|
1595
|
+
modelUrl="/model.glb"
|
|
1596
|
+
licenseKey="your-license-key"
|
|
1597
|
+
objectBindings={objectBindings}
|
|
1598
|
+
onObjectBindingsChange={setObjectBindings}
|
|
1599
|
+
moveModeEnabled
|
|
1600
|
+
objectTransformSpace="world"
|
|
1601
|
+
/>
|
|
1602
|
+
);
|
|
1603
|
+
}
|
|
1604
|
+
```
|
|
1605
|
+
|
|
1606
|
+
Click a bound mesh to select it, then drag an arrow to move on one axis, a
|
|
1607
|
+
plane handle to move on two axes, or a ring to rotate. The pivot is placed at
|
|
1608
|
+
the center of the selected object's renderable geometry, so rotation happens
|
|
1609
|
+
around the object itself even when the source model's node origin is elsewhere.
|
|
1610
|
+
|
|
1611
|
+
`objectTransformSpace` accepts:
|
|
1612
|
+
|
|
1613
|
+
- `"world"` (default): the gizmo remains aligned with the scene axes
|
|
1614
|
+
- `"local"`: the gizmo follows the selected object's current orientation
|
|
1615
|
+
|
|
1616
|
+
Axis space changes the direction of the handles; it does not change the
|
|
1617
|
+
object's position when toggled. The resulting `transform.position` and
|
|
1618
|
+
`transform.rotation` values are always persisted in the object's local space,
|
|
1619
|
+
with rotation stored in radians.
|
|
1620
|
+
|
|
1621
|
+
Passing `onObjectBindingsChange` makes binding edits controlled, so the parent
|
|
1622
|
+
must store the returned record as shown above. Without that callback,
|
|
1623
|
+
`ModelViewer` keeps edits internally for the mounted viewer. Similarly, when
|
|
1624
|
+
you pass `selectedObject`, update it from `onObjectSelect`; otherwise selection
|
|
1625
|
+
is managed internally.
|
|
1626
|
+
|
|
1627
|
+
### `enableCameraControls`
|
|
1628
|
+
|
|
1629
|
+
Optional boolean controlling orbit, pan, and zoom input. Default: `true`.
|
|
1630
|
+
Camera controls are temporarily disabled whenever `moveModeEnabled` is on.
|
|
1631
|
+
|
|
1632
|
+
### `enableKeyboardNavigation`
|
|
1633
|
+
|
|
1634
|
+
Optional boolean enabling camera shortcuts after the viewer canvas is clicked
|
|
1635
|
+
or focused. Default: `false`. Use `W`/`S` to move forward/back, `A`/`D` to
|
|
1636
|
+
truck left/right, Space/`C` to move up/down, and the arrow keys to orbit.
|
|
1637
|
+
`Shift` + Up/Down moves forward/back. Keyboard navigation is inactive while
|
|
1638
|
+
object editing or camera controls are disabled.
|
|
1639
|
+
|
|
1640
|
+
### `showViewGizmo`
|
|
1641
|
+
|
|
1642
|
+
Optional boolean showing a clickable orientation gizmo in the top-right of the
|
|
1643
|
+
viewer. Default: `false`. It indicates the camera's view of the scene axes and
|
|
1644
|
+
can snap the camera to an axis; it is separate from the selected object's
|
|
1645
|
+
transform gizmo and is hidden while `moveModeEnabled` is on.
|
|
1646
|
+
|
|
1498
1647
|
### `onAutoFit`
|
|
1499
1648
|
|
|
1500
1649
|
Optional async callback fired once the model has loaded and the scene is ready. When provided, the viewer calls it so consumers can run their own fit-to-scene behavior (e.g. an animated fit); if omitted, the viewer falls back to its internal `fitScene`, unless an explicit [`camera`](#camera) prop was given, in which case that position is treated as the chosen initial view and `fitScene` is skipped.
|
|
@@ -1562,6 +1711,18 @@ Default:
|
|
|
1562
1711
|
2;
|
|
1563
1712
|
```
|
|
1564
1713
|
|
|
1714
|
+
### `preserveDrawingBuffer`
|
|
1715
|
+
|
|
1716
|
+
Optional boolean that retains the WebGL framebuffer for PNG screenshots. It is
|
|
1717
|
+
`false` by default to avoid imposing framebuffer-retention cost on every frame.
|
|
1718
|
+
Enable it when using `captureImage` or the built-in Download PNG action.
|
|
1719
|
+
|
|
1720
|
+
Default:
|
|
1721
|
+
|
|
1722
|
+
```ts
|
|
1723
|
+
false;
|
|
1724
|
+
```
|
|
1725
|
+
|
|
1565
1726
|
### `performanceProfile`
|
|
1566
1727
|
|
|
1567
1728
|
Optional control over how aggressively the viewer trades visual fidelity for a stable WebGL context on constrained GPUs.
|
|
@@ -1590,7 +1751,43 @@ ktx2TranscoderPath?: string | false;
|
|
|
1590
1751
|
meshopt?: boolean;
|
|
1591
1752
|
```
|
|
1592
1753
|
|
|
1593
|
-
|
|
1754
|
+
Meshopt is bundled and enabled by default. DRACO and KTX2 are also enabled by
|
|
1755
|
+
default through immutable, versioned decoder builds hosted on the first-party
|
|
1756
|
+
`assets.react-immersive.liveroom.dev` domain. They are fetched lazily only when a model
|
|
1757
|
+
uses the corresponding compression format.
|
|
1758
|
+
|
|
1759
|
+
```ts
|
|
1760
|
+
dracoDecoderPath =
|
|
1761
|
+
"https://assets.react-immersive.liveroom.dev/three-r184/draco/";
|
|
1762
|
+
ktx2TranscoderPath =
|
|
1763
|
+
"https://assets.react-immersive.liveroom.dev/three-r184/basis/";
|
|
1764
|
+
```
|
|
1765
|
+
|
|
1766
|
+
Pass `false` to disable either decoder. For a fully self-hosted or offline
|
|
1767
|
+
deployment, version-matched files are included under `dist/decoders`.
|
|
1768
|
+
|
|
1769
|
+
Copy those files into your app's public/static directory during deployment:
|
|
1770
|
+
|
|
1771
|
+
```sh
|
|
1772
|
+
cp -R node_modules/@liveroom-tech/react-immersive/dist/decoders public/react-immersive-decoders
|
|
1773
|
+
```
|
|
1774
|
+
|
|
1775
|
+
Then pass the public URL directories (including the trailing slash):
|
|
1776
|
+
|
|
1777
|
+
```tsx
|
|
1778
|
+
<ModelViewer
|
|
1779
|
+
dracoDecoderPath="/react-immersive-decoders/draco/"
|
|
1780
|
+
ktx2TranscoderPath="/react-immersive-decoders/basis/"
|
|
1781
|
+
{...props}
|
|
1782
|
+
/>
|
|
1783
|
+
```
|
|
1784
|
+
|
|
1785
|
+
The same props are available on `SimpleModelViewer` and `BindingBuilder`. When
|
|
1786
|
+
using the built-in defaults with a strict CSP, allow the first-party asset
|
|
1787
|
+
origin and decoder workers; a typical baseline is
|
|
1788
|
+
`connect-src 'self' https://assets.react-immersive.liveroom.dev; worker-src 'self' blob:; script-src 'self' 'wasm-unsafe-eval'`.
|
|
1789
|
+
Self-hosted paths only require `'self'`. Older browsers may require their
|
|
1790
|
+
WebAssembly fallback policy as well.
|
|
1594
1791
|
|
|
1595
1792
|
### `showUvCheckerButton`
|
|
1596
1793
|
|
|
@@ -1795,6 +1992,10 @@ See the full variable list in the [`ModelViewer` docs](https://react-immersive.l
|
|
|
1795
1992
|
```ts
|
|
1796
1993
|
type SimpleModelViewerProps = {
|
|
1797
1994
|
modelUrl: string;
|
|
1995
|
+
modelFormat?: "glb" | "gltf" | "obj" | "fbx" | "usdz";
|
|
1996
|
+
dracoDecoderPath?: string | false;
|
|
1997
|
+
ktx2TranscoderPath?: string | false;
|
|
1998
|
+
meshopt?: boolean;
|
|
1798
1999
|
backgroundColor?: string;
|
|
1799
2000
|
showSceneObjectsPanel?: boolean;
|
|
1800
2001
|
showSceneSettingsPanel?: boolean;
|
|
@@ -1821,7 +2022,12 @@ type SimpleModelViewerProps = {
|
|
|
1821
2022
|
|
|
1822
2023
|
### `modelUrl`
|
|
1823
2024
|
|
|
1824
|
-
URL or public path to the `.glb
|
|
2025
|
+
URL or public path to the `.glb`, `.gltf`, `.obj`, `.fbx`, or `.usdz` model to inspect. Hosted assets must serve external dependencies at their declared relative paths; USDZ dependencies are packaged internally. Use `modelFormat` when a signed or extensionless URL cannot be auto-detected.
|
|
2026
|
+
|
|
2027
|
+
### `modelFormat`
|
|
2028
|
+
|
|
2029
|
+
Optional explicit format for signed or extensionless model URLs. Normal URLs
|
|
2030
|
+
ending in a supported extension are detected automatically.
|
|
1825
2031
|
|
|
1826
2032
|
### `backgroundColor`
|
|
1827
2033
|
|
|
@@ -1924,7 +2130,7 @@ true;
|
|
|
1924
2130
|
|
|
1925
2131
|
### `enableModelUpload`
|
|
1926
2132
|
|
|
1927
|
-
Optional boolean that swaps the fixed `modelUrl` workflow for a built-in upload UI.
|
|
2133
|
+
Optional boolean that swaps the fixed `modelUrl` workflow for a built-in upload UI. It accepts `.glb`, standalone/data-URI `.gltf`, `.obj`, `.fbx`, `.usdz`, or a `.zip` bundle. ZIP bundles may contain a GLTF with its buffers/textures, an OBJ with its optional MTL/textures, or an FBX with external textures. A USDZ file is already a self-contained package and is uploaded directly.
|
|
1928
2134
|
|
|
1929
2135
|
Default:
|
|
1930
2136
|
|
|
@@ -1997,7 +2203,9 @@ Notes:
|
|
|
1997
2203
|
- the `objectBindings` record is keyed by node name, not by `id`
|
|
1998
2204
|
- `group` and `tags` can be assigned in `BindingBuilder` and used as targets by binding helpers and runtime material or transform effects
|
|
1999
2205
|
- `visible` is live render state, not just an initial default
|
|
2000
|
-
- `transform` is persistent local-space render state;
|
|
2206
|
+
- `transform` is persistent local-space render state; position values use model units and rotation values use radians
|
|
2207
|
+
- the transform gizmo is displayed at the center of the object's renderable geometry for intuitive rotation, even if the authored node origin is elsewhere; this does not rewrite the GLB/GLTF origin
|
|
2208
|
+
- missing transform fields retain their model-authored values, and removing `transform` restores the authored transform
|
|
2001
2209
|
- `style.material.baseColor` is read by the renderer and is the committed source of truth for color picks
|
|
2002
2210
|
- `style.material.texture.path` is read by the renderer and is the committed source of truth for texture uploads (stored as durable URLs via `onTextureUpload` when provided, or session-scoped blob URLs otherwise)
|
|
2003
2211
|
- if no `texture.path` is provided and no `style.material.baseColor` is set, the viewer falls back to the node's original GLB/GLTF material
|
|
@@ -2062,11 +2270,13 @@ Because of that, it works best when mounted in a container with an explicit heig
|
|
|
2062
2270
|
|
|
2063
2271
|
## Usage Expectations For Models
|
|
2064
2272
|
|
|
2065
|
-
To use this library successfully, your
|
|
2273
|
+
To use this library successfully, your model asset should follow these expectations:
|
|
2066
2274
|
|
|
2067
2275
|
- the mesh node names must match the keys in `objectBindings` (or be referenced via `modelObjectId`)
|
|
2068
|
-
- target nodes should have geometry and a
|
|
2069
|
-
- the file should be accessible from the browser at `modelUrl`; hosted
|
|
2276
|
+
- target nodes should have geometry and a supported Three.js mesh material; imported materials are normalized into the editable PBR pipeline
|
|
2277
|
+
- the file should be accessible from the browser at `modelUrl`; hosted GLTF, OBJ, and FBX assets must also serve external dependencies at their declared relative paths
|
|
2278
|
+
- OBJ does not contain animations; supported FBX and USDZ animation clips are exposed through the same animation controls as glTF
|
|
2279
|
+
- OBJ has no standard unit metadata, so set an appropriate measurement label/scene scale when real-world dimensions matter
|
|
2070
2280
|
|
|
2071
2281
|
If a node name or material name does not match, that object will not render through the interactive binding flow.
|
|
2072
2282
|
|