bimatter-viewer-react 0.6.11 → 0.7.0

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 CHANGED
@@ -114,46 +114,60 @@ You can also load mixed model lists:
114
114
  IFC spaces are loaded by default when the IFC contains room geometry, but they are hidden in the viewer by default. Disable loading them when room volumes are not needed:
115
115
 
116
116
  ```ts
117
- import { loader } from "bimatter-viewer-react";
118
-
119
- await loader.loadModel(["/models/architecture.ifc"], {
117
+ await viewerRef.current?.models.loadModels(["/models/architecture.ifc"], {
118
+ clearViewer: true,
120
119
  useIfcSpace: false,
121
120
  });
122
121
  ```
123
122
 
124
123
  ## Loader API
125
124
 
126
- You can load models yourself and pass parsed data to the viewer:
125
+ You can load models through the viewer API and keep parsed data in your app state:
127
126
 
128
127
  ```tsx
129
- import { useEffect, useState } from "react";
130
- import { loader, Viewer, type ViewerLoadedModels } from "bimatter-viewer-react";
128
+ import { useState } from "react";
129
+ import {
130
+ Viewer,
131
+ type ViewerApi,
132
+ type ViewerLoadedModels,
133
+ } from "bimatter-viewer-react";
131
134
 
132
135
  function App() {
133
- const [modelsData, setModelsData] = useState<ViewerLoadedModels>();
134
-
135
- useEffect(() => {
136
- loader
137
- .loadModel(["/models/architecture.bmt", "/models/structure.bmt"])
138
- .then(setModelsData);
139
- }, []);
140
-
141
- if (!modelsData) return null;
136
+ const [modelsData, setModelsData] = useState<ViewerLoadedModels>({});
137
+
138
+ function loadInitialModels(viewer: ViewerApi) {
139
+ void viewer.models.loadModels(
140
+ ["/models/architecture.bmt", "/models/structure.bmt"],
141
+ {
142
+ clearViewer: true,
143
+ onModelsDataChange: setModelsData,
144
+ },
145
+ );
146
+ }
142
147
 
143
- return <Viewer modelsData={modelsData} />;
148
+ return <Viewer modelsData={modelsData} onReady={loadInitialModels} />;
144
149
  }
145
150
  ```
146
151
 
147
- `loader.loadModel` accepts paths or browser `File` objects:
152
+ `viewer.models.loadModels` accepts paths or browser `File` objects:
148
153
 
149
154
  ```ts
150
- await loader.loadModel(["/models/model.bmt"]);
151
- await loader.loadModel(["/models/model.ifc"]);
152
- await loader.loadModel(["/models/model.ifc"], { useIfcSpace: false });
153
- await loader.loadModel(["/models/model.bmt"], { materialMode: "performance" });
154
- await loader.loadModel(["/models/model.bmt"], { useDoubleSideMaterial: true });
155
- await loader.loadModel(["/models/model.bmt", "/models/model.ifc"]);
156
- await loader.loadModel(files);
155
+ await viewerRef.current?.models.loadModels(["/models/model.bmt"]);
156
+ await viewerRef.current?.models.loadModels(["/models/model.ifc"]);
157
+ await viewerRef.current?.models.loadModels(["/models/model.ifc"], {
158
+ useIfcSpace: false,
159
+ });
160
+ await viewerRef.current?.models.loadModels(["/models/model.bmt"], {
161
+ materialMode: "performance",
162
+ });
163
+ await viewerRef.current?.models.loadModels(["/models/model.bmt"], {
164
+ useDoubleSideMaterial: true,
165
+ });
166
+ await viewerRef.current?.models.loadModels([
167
+ "/models/model.bmt",
168
+ "/models/model.ifc",
169
+ ]);
170
+ await viewerRef.current?.models.loadModels(files);
157
171
  ```
158
172
 
159
173
  `materialMode: "performance"` uses a cheaper unlit material. Use `"quality"` or omit it for the default lit material.
@@ -163,23 +177,28 @@ await loader.loadModel(files);
163
177
  Use `useWorker` to parse BMT and IFC models outside the main thread:
164
178
 
165
179
  ```ts
166
- const models = await loader.loadModel(["/models/model.ifc"], {
167
- chunk: 200,
168
- useWorker: true,
169
- onProgress: (event) => {
170
- console.log(event.phase, Math.round(event.progress * 100));
171
- },
172
- onChunk: (chunk) => {
173
- // Optional: add chunk.geometry to your viewer state for progressive render.
174
- console.log(chunk.modelID, chunk.geometryID);
180
+ const models = await viewerRef.current?.models.loadModels(
181
+ ["/models/model.ifc"],
182
+ {
183
+ clearViewer: true,
184
+ chunk: 200,
185
+ onModelsDataChange: setModelsData,
186
+ useWorker: true,
187
+ onModelProgress: (event) => {
188
+ if (!event) return;
189
+ console.log(event.phase, Math.round(event.progress * 100));
190
+ },
191
+ onChunk: (chunk) => {
192
+ console.log(chunk.modelID, chunk.geometryID);
193
+ },
175
194
  },
176
- });
195
+ );
177
196
  ```
178
197
 
179
198
  IFC worker loading uses the same parser wasm file. By default, `ifc-parser.wasm` is resolved relative to the app document base URL, so it works with Vite `base` paths like `/my-app/` when the file is in that app's `public` folder. Pass a custom `wasmPath` only when the file is hosted elsewhere:
180
199
 
181
200
  ```ts
182
- await loader.loadModel(["/models/model.ifc"], {
201
+ await viewerRef.current?.models.loadModels(["/models/model.ifc"], {
183
202
  useWorker: true,
184
203
  wasmPath: "/ifc-parser.wasm",
185
204
  });
@@ -187,10 +206,10 @@ await loader.loadModel(["/models/model.ifc"], {
187
206
 
188
207
  For IFC, `chunk` controls how many geometries are packed before a streamed mesh is emitted. For BMT, chunks are read as they are already stored in the file.
189
208
 
190
- When you render chunks yourself in `onChunk`, set `collectWorkerChunks: false` to avoid keeping the same streamed geometry in the loader helper until the final result:
209
+ When you render chunks yourself in `onChunk`, keep `collectWorkerChunks: false` to avoid keeping the same streamed geometry in the loader helper until the final result:
191
210
 
192
211
  ```ts
193
- await loader.loadModel(["/models/model.bmt"], {
212
+ await viewerRef.current?.models.loadModels(["/models/model.bmt"], {
194
213
  collectWorkerChunks: false,
195
214
  useWorker: true,
196
215
  onChunk: (chunk) => {
@@ -202,15 +221,23 @@ await loader.loadModel(["/models/model.bmt"], {
202
221
  ## File Upload Example
203
222
 
204
223
  ```tsx
205
- import { useState } from "react";
206
- import { Viewer, loader, type ViewerLoadedModels } from "bimatter-viewer-react";
224
+ import { useRef, useState } from "react";
225
+ import {
226
+ Viewer,
227
+ type ViewerApi,
228
+ type ViewerLoadedModels,
229
+ } from "bimatter-viewer-react";
207
230
 
208
231
  function App() {
209
- const [modelsData, setModelsData] = useState<ViewerLoadedModels>();
232
+ const viewerRef = useRef<ViewerApi>(null);
233
+ const [modelsData, setModelsData] = useState<ViewerLoadedModels>({});
210
234
 
211
235
  async function onFilesChange(files: FileList | null) {
212
236
  if (!files?.length) return;
213
- setModelsData(await loader.loadModel(Array.from(files)));
237
+ await viewerRef.current?.models.loadModels(Array.from(files), {
238
+ clearViewer: true,
239
+ onModelsDataChange: setModelsData,
240
+ });
214
241
  }
215
242
 
216
243
  return (
@@ -221,7 +248,7 @@ function App() {
221
248
  type="file"
222
249
  onChange={(event) => onFilesChange(event.target.files)}
223
250
  />
224
- {modelsData && <Viewer modelsData={modelsData} />}
251
+ <Viewer ref={viewerRef} modelsData={modelsData} />
225
252
  </>
226
253
  );
227
254
  }
@@ -1,6 +1,6 @@
1
1
  import pako from "pako";
2
2
  import type { ModelGridsData } from "../utils/ModelGrids";
3
- import type { ViewerMaterialMode } from "../types";
3
+ import type { ViewerMaterialMode, ViewerUploadMode } from "../types";
4
4
  export type BmtIndexArray = Uint16Array | Uint32Array;
5
5
  export interface BmtMaterialData {
6
6
  r: number;
@@ -54,6 +54,7 @@ export type BmtModelStructure = BmtModelStructureNode | BmtModelStructureNode[]
54
54
  export type BmtModelGeometryData = Record<number, BmtGeomData>;
55
55
  export type BmtModelRenderSettings = {
56
56
  materialMode?: ViewerMaterialMode;
57
+ uploadMode?: ViewerUploadMode;
57
58
  useDoubleSideMaterial?: boolean;
58
59
  };
59
60
  export interface BmtModelData {
@@ -0,0 +1,23 @@
1
+ import { type RefObject } from "react";
2
+ import { type DataTexture, type Group, type Matrix4 } from "three";
3
+ import type { BmtGeomData, BmtMaterialData } from "./Loaders/BmtLoader";
4
+ import type { ViewerMaterialMode, ViewerUploadMode } from "./types";
5
+ export type UploadMeshData = {
6
+ data: BmtGeomData;
7
+ isIfcSpace: boolean;
8
+ key: string;
9
+ material: BmtMaterialData;
10
+ meshMatrix: Matrix4;
11
+ modelID: number;
12
+ };
13
+ type ModelUploadQueueProps = {
14
+ colorPaletteTexture: DataTexture;
15
+ groupRef: RefObject<Group | null>;
16
+ items: UploadMeshData[];
17
+ materialMode: ViewerMaterialMode;
18
+ uploadMode: ViewerUploadMode;
19
+ useDoubleSideMaterial: boolean;
20
+ useWebGPU: boolean;
21
+ };
22
+ export declare function ModelUploadQueue({ colorPaletteTexture, groupRef, items, materialMode, uploadMode, useDoubleSideMaterial, useWebGPU, }: ModelUploadQueueProps): null;
23
+ export {};
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Matrix4, type DataTexture } from "three";
2
+ import { Matrix4, MeshBasicMaterial, MeshLambertMaterial, type ColorRepresentation, type DataTexture, type Material } from "three";
3
3
  import type { BmtGeomData, BmtMaterialData } from "./Loaders/BmtLoader";
4
4
  import type { ViewerMaterialMode } from "./types";
5
5
  export type SelectableMeshProps = {
@@ -11,4 +11,9 @@ export type SelectableMeshProps = {
11
11
  meshMatrix: Matrix4;
12
12
  useDoubleSideMaterial?: boolean;
13
13
  };
14
+ export type SelectableMaterial = MeshBasicMaterial | MeshLambertMaterial;
15
+ export declare function createSelectableMaterial({ colorPaletteTexture, material, materialMode, preselectionColor, useDoubleSideMaterial, }: Pick<SelectableMeshProps, "colorPaletteTexture" | "material" | "materialMode" | "useDoubleSideMaterial"> & {
16
+ preselectionColor: ColorRepresentation;
17
+ }): MeshBasicMaterial | MeshLambertMaterial;
18
+ export declare function updateSelectableMaterialPreselectionColor(material: Material, preselectionColor: ColorRepresentation): void;
14
19
  export declare const SelectableMesh: React.MemoExoticComponent<({ colorPaletteTexture, material, materialMode, data, isIfcSpace, meshMatrix, useDoubleSideMaterial, }: SelectableMeshProps) => import("react/jsx-runtime").JSX.Element>;
@@ -1,3 +1,19 @@
1
1
  import React from "react";
2
+ import { type ColorRepresentation, type Material } from "three";
3
+ import { MeshBasicNodeMaterial, MeshLambertNodeMaterial } from "three/webgpu";
2
4
  import type { SelectableMeshProps } from "./SelectableMesh";
5
+ type NodeSelectableMaterial = (MeshBasicNodeMaterial | MeshLambertNodeMaterial) & Material & {
6
+ colorNode?: unknown;
7
+ defaultAttributeValues?: Record<string, number[]>;
8
+ opacityNode?: unknown;
9
+ };
10
+ export declare function createWebGpuSelectableMaterial({ colorPaletteTexture, material, materialMode, preselectionColor, selectionColor, useDoubleSideMaterial, }: Pick<SelectableMeshProps, "colorPaletteTexture" | "material" | "materialMode" | "useDoubleSideMaterial"> & {
11
+ preselectionColor: ColorRepresentation;
12
+ selectionColor: ColorRepresentation;
13
+ }): NodeSelectableMaterial;
14
+ export declare function updateWebGpuSelectableMaterialColors(material: Material, { preselectionColor, selectionColor, }: {
15
+ preselectionColor: ColorRepresentation;
16
+ selectionColor: ColorRepresentation;
17
+ }): void;
3
18
  export declare const WebGpuSelectableMesh: React.MemoExoticComponent<({ colorPaletteTexture, material, materialMode, data, isIfcSpace, meshMatrix, useDoubleSideMaterial, }: SelectableMeshProps) => import("react/jsx-runtime").JSX.Element>;
19
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { type BmtModelData } from "../Loaders/BmtLoader";
2
2
  import { type BmtWorkerGeometryChunk, type IfcWorkerGeometryChunk, type WorkerProgressEvent } from "../workers";
3
- import type { ViewerMaterialMode } from "../types";
3
+ import type { ViewerMaterialMode, ViewerUploadMode } from "../types";
4
4
  export type ViewerModelSource = string | File;
5
5
  export type ViewerLoadedModels = Record<number, BmtModelData>;
6
6
  export type ViewerLoaderWorkerChunk = (BmtWorkerGeometryChunk | IfcWorkerGeometryChunk) & {
@@ -14,6 +14,7 @@ export type ViewerLoadModelOptions = {
14
14
  onChunk?: (chunk: ViewerLoaderWorkerChunk) => void;
15
15
  onProgress?: (progress: WorkerProgressEvent) => void;
16
16
  streamGeometryChunks?: boolean;
17
+ uploadMode?: ViewerUploadMode;
17
18
  useDoubleSideMaterial?: boolean;
18
19
  useIfcSpace?: boolean;
19
20
  useWorker?: boolean;
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { default as Viewer } from "./Viewer";
2
2
  export type { ViewerModelsData, ViewerProps } from "./Viewer";
3
- export type { ViewerMaterialMode } from "./types";
3
+ export type { ViewerMaterialMode, ViewerUploadMode } from "./types";
4
4
  export type { ViewerApi, ViewerCameraApi, ViewerCameraGetIntersection, ViewerClippingApi, ViewerColorsApi, ViewerBmtConverterOptions, ViewerConverterApi, ViewerDimensionsApi, ViewerGeometryUtilsApi, ViewerLoadModelsOptions, ViewerModelsApi, ViewerSelection, ViewerSelectorApi, ViewerUtilsApi, } from "./api/ViewerApi";
5
5
  export type { ViewerModelLevel, ViewerModelLevelsByModel, ViewerPropertiesApi, ViewerPropertiesExcelOptions, } from "./api/ViewerPropertiesApi";
6
6
  export { BMTLoader } from "./Loaders/BmtLoader";