@vctrl/hooks 0.2.1 → 0.3.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 CHANGED
@@ -4,47 +4,54 @@
4
4
  ](https://github.com/Vectreal/vectreal-core/actions/workflows/version-release.yaml)
5
5
  [![@vctrl/hooks | NPM Downloads](https://img.shields.io/npm/dm/%40vctrl%2Fhooks?logo=npm&logoColor=%23fc6c18&label=%40vctrl%2Fhooks%20%7C%20NPM%20Downloads&color=%23fc6c18)](https://www.npmjs.com/package/@vctrl/hooks)
6
6
 
7
- > This library is still undergoing heavy development until the first major version is released. This may lead to breaking changes in upcoming updates.
7
+ > **Note**: This library is still undergoing heavy development until the first major version is released. This may lead to breaking changes in upcoming updates.
8
8
 
9
9
  ## Overview
10
10
 
11
- vctrl/hooks is a React hooks package designed to simplify 3D model loading and management within React applications. It's part of the vectreal-core ecosystem and is primarily used in the vctrl/viewer React component and the official website application.
11
+ `@vctrl/hooks` is a React hooks package designed to simplify 3D model loading, optimization, and exporting within React applications. It's part of the vectreal-core ecosystem and is primarily used in the `@vctrl/viewer` React component and the official website application.
12
12
 
13
- The package provides a powerful hook for loading various 3D model file formats, along with a React context for easy state management and an event system for handling different stages of the model loading process.
13
+ The package provides powerful hooks for:
14
14
 
15
- ## Table of contents
15
+ - **Loading various 3D model file formats** (`useLoadModel`)
16
+ - **Optimizing 3D models** (`useOptimizeModel`)
17
+ - **Exporting 3D models from Three.js scenes** (`useExportModel`)
18
+
19
+ It also includes a React context (`ModelContext`) for easy state management and an event system for handling different stages of the model loading process.
20
+
21
+ ### Table of Contents
16
22
 
17
23
  - [vctrl/hooks](#vctrlhooks)
18
24
  - [Overview](#overview)
19
- - [Table of contents](#table-of-contents)
20
- - [Features](#features)
25
+ - [Table of Contents](#table-of-contents)
21
26
  - [Installation](#installation)
22
- - [Usage](#usage)
23
- - [API Reference](#api-reference)
27
+ - [Hooks](#hooks)
24
28
  - [useLoadModel](#useloadmodel)
25
- - [Returns](#returns)
29
+ - [Overview](#overview-1)
30
+ - [Features](#features)
31
+ - [Usage](#usage)
32
+ - [API Reference](#api-reference)
33
+ - [Optimization Integration](#optimization-integration)
26
34
  - [useOptimizeModel](#useoptimizemodel)
27
- - [Returns](#returns-1)
35
+ - [Overview](#overview-2)
36
+ - [Features](#features-1)
37
+ - [Usage](#usage-1)
38
+ - [API Reference](#api-reference-1)
39
+ - [useExportModel](#useexportmodel)
40
+ - [Overview](#overview-3)
41
+ - [Features](#features-2)
42
+ - [Usage](#usage-2)
43
+ - [API Reference](#api-reference-2)
28
44
  - [ModelContext](#modelcontext)
29
- - [Event System](#event-system)
30
- - [Events](#events)
31
- - [Supported File Types](#supported-file-types)
32
- - [File Loading Process](#file-loading-process)
33
- - [State Management](#state-management)
34
- - [Integration with Three.js](#integration-with-threejs)
45
+ - [Common Concepts](#common-concepts)
46
+ - [Supported File Types](#supported-file-types)
47
+ - [File Loading Process](#file-loading-process)
48
+ - [State Management](#state-management)
49
+ - [Integration with Three.js](#integration-with-threejs)
35
50
  - [Development](#development)
36
51
  - [License](#license)
37
52
  - [Contributing](#contributing)
38
53
  - [Support](#support)
39
54
 
40
- ## Features
41
-
42
- - Direct 3D model file loading (supports GLTF, GLB, and USDZ formats)
43
- - React context for state management (ModelContext)
44
- - Event system for handling loading progress and completion
45
- - Three.js integration
46
- - TypeScript support
47
-
48
55
  ## Installation
49
56
 
50
57
  To install the package, use npm or yarn:
@@ -55,9 +62,27 @@ npm install @vctrl/hooks
55
62
  yarn add @vctrl/hooks
56
63
  ```
57
64
 
58
- ## Usage
65
+ ## Hooks
66
+
67
+ ### useLoadModel
68
+
69
+ #### Overview
70
+
71
+ `useLoadModel` is a React hook for loading and managing 3D model files in your application. It supports various file formats and integrates with Three.js for rendering.
59
72
 
60
- The main hook exported by this package is `useLoadModel`. Here's a basic example of how to use it:
73
+ #### Features
74
+
75
+ - Supports direct 3D model file loading (GLTF, GLB, USDZ)
76
+ - Provides loading progress updates
77
+ - Emits events during the loading process
78
+ - Integrates with Three.js
79
+ - Supports multiple file uploads (e.g., `.gltf` with associated `.bin` and texture files)
80
+ - Integrates with `useOptimizeModel` for model optimization
81
+ - TypeScript support
82
+
83
+ #### Usage
84
+
85
+ Here's a basic example of how to use `useLoadModel`:
61
86
 
62
87
  ```jsx
63
88
  import React from 'react';
@@ -73,7 +98,7 @@ function ModelLoader() {
73
98
 
74
99
  return (
75
100
  <div>
76
- <input type="file" onChange={onFileChange} />
101
+ <input type="file" onChange={onFileChange} multiple />
77
102
  {isLoading && <p>Loading: {progress}%</p>}
78
103
  {file && <p>Model loaded: {file.name}</p>}
79
104
  </div>
@@ -81,11 +106,101 @@ function ModelLoader() {
81
106
  }
82
107
  ```
83
108
 
84
- > Multiple files can be handled, e.g. when uploading a `.gltf` model, its `.bin` file and the relavant image texture files as `.jpeg`/`.png` (Other texture file formats have not been tested).
109
+ > **Note**: Multiple files can be handled, e.g., when uploading a `.gltf` model along with its `.bin` file and relevant texture files (e.g., `.jpeg`, `.png`).
110
+
111
+ You can also use the `ModelProvider` and `useModelContext` to access the model state across your application:
112
+
113
+ ```jsx
114
+ // App.jsx
115
+ import React from 'react';
116
+ import { ModelProvider } from '@vctrl/hooks/use-load-model';
117
+ import ModelConsumer from './ModelConsumer';
118
+
119
+ function App() {
120
+ return (
121
+ <ModelProvider>
122
+ <ModelConsumer />
123
+ </ModelProvider>
124
+ );
125
+ }
126
+
127
+ // ModelConsumer.jsx
128
+ import React from 'react';
129
+ import { useModelContext } from '@vctrl/hooks/use-load-model';
130
+
131
+ function ModelConsumer() {
132
+ const { file, isLoading, progress, load } = useModelContext();
133
+
134
+ // Use the context values
135
+ return (
136
+ // ... your component logic
137
+ );
138
+ }
139
+ ```
140
+
141
+ > **Note**: When using the React context, load models using the `useModelContext` hook.
142
+
143
+ #### API Reference
144
+
145
+ The `useLoadModel` hook returns the following:
146
+
147
+ - `file`: The loaded file object (`ModelFile | null`).
148
+ - `isLoading`: A boolean indicating whether a file is currently being loaded.
149
+ - `progress`: A number between 0 and 100 representing the loading progress.
150
+ - `load(files)`: A function to handle file uploads. It accepts an array of `File` objects or a mixed array of `File` objects and directory entries.
151
+ - `reset()`: A function to reset the internal state back to its initial values.
152
+ - `on(event, handler)`: A function to subscribe to events.
153
+ - `off(event, handler)`: A function to unsubscribe from events.
154
+ - `optimize`: An object populated by the `useOptimizeModel` hook integration, providing optimization functions (see below).
155
+
156
+ #### Optimization Integration
157
+
158
+ If you pass an instance of `useOptimizeModel` to `useLoadModel`, it will integrate optimization functions into the `optimize` object:
159
+
160
+ ```jsx
161
+ import React from 'react';
162
+ import { useLoadModel } from '@vctrl/hooks/use-load-model';
163
+ import { useOptimizeModel } from '@vctrl/hooks/use-optimize-model';
164
+
165
+ function ModelLoader() {
166
+ const optimizer = useOptimizeModel();
167
+ const { load, file, optimize } = useLoadModel(optimizer);
168
+
169
+ const handleSimplify = async () => {
170
+ await optimize.simplifyOptimization();
171
+ // The optimized model is now in file.model
172
+ };
173
+
174
+ return (
175
+ // ... your component logic
176
+ );
177
+ }
178
+ ```
179
+
180
+ The `optimize` object includes:
181
+
182
+ - `simplifyOptimization()`: Simplifies the model using mesh simplification.
183
+ - `dedupOptimization()`: Removes duplicate vertices and meshes.
184
+ - `quantizeOptimization()`: Reduces the precision of vertex attributes.
185
+
186
+ ### useOptimizeModel
187
+
188
+ #### Overview
85
189
 
86
- The `useLoadModel` and `useOptimizeModel` hooks may be used together or standalone to optimize gltf based scenes.
190
+ `useOptimizeModel` is a React hook used to optimize 3D models, particularly GLTF-based scenes. It can be used in conjunction with `useLoadModel` or independently.
87
191
 
88
- 1. Either use the optimizer directly with the `useLoadModel` hook
192
+ #### Features
193
+
194
+ - Simplifies 3D models using mesh optimization algorithms
195
+ - Provides deduplication and quantization optimizations
196
+ - Integrates with `useLoadModel` and `ModelContext`
197
+ - TypeScript support
198
+
199
+ #### Usage
200
+
201
+ There are two ways to use the `useOptimizeModel` hook:
202
+
203
+ 1. **Directly with `useLoadModel`**
89
204
 
90
205
  ```jsx
91
206
  import React from 'react';
@@ -94,77 +209,150 @@ The `useLoadModel` and `useOptimizeModel` hooks may be used together or standalo
94
209
 
95
210
  function ModelLoader() {
96
211
  const optimizer = useOptimizeModel();
97
- const { load: loadFile, file, optimize } = useLoadModel(optimizer);
98
- const { load: loadModel, getModel, simplifyOptimization } = optimize;
99
-
100
- async function handleClick() {
101
- await simplifyOptimization();
102
- }
212
+ const { load, file, optimize } = useLoadModel(optimizer);
213
+
214
+ const handleSimplify = async () => {
215
+ await optimize.simplifyOptimization();
216
+ // The optimized model is now in file.model
217
+ };
218
+
219
+ const handleDedup = async () => {
220
+ await optimize.dedupOptimization();
221
+ };
222
+
223
+ const handleQuantize = async () => {
224
+ await optimize.quantizeOptimization();
225
+ };
226
+
227
+ return (
228
+ <div>
229
+ <input
230
+ type="file"
231
+ onChange={(e) => load(Array.from(e.target.files))}
232
+ multiple
233
+ />
234
+ <button onClick={handleSimplify}>Simplify Model</button>
235
+ <button onClick={handleDedup}>Deduplicate Model</button>
236
+ <button onClick={handleQuantize}>Quantize Model</button>
237
+ </div>
238
+ );
103
239
  }
104
240
  ```
105
241
 
106
- > Changes are applied to the `file.model` field from `useLoadModel` automatically when using optimizations
242
+ > **Note**: Changes are applied to the `file.model` field from `useLoadModel` automatically when using optimizations.
107
243
 
108
- 2. Or use the optimizer together with the `ModelProvider`
244
+ 2. **With `ModelProvider` and `useModelContext`**
109
245
 
110
246
  ```jsx
111
- // App.tsx
247
+ // App.jsx
248
+ import React from 'react';
112
249
  import { ModelProvider } from '@vctrl/hooks/use-load-model';
113
250
  import { useOptimizeModel } from '@vctrl/hooks/use-optimize-model';
251
+ import Scene from './Scene';
114
252
 
115
253
  function App() {
116
- const optimizer = useOptimizeModel();
254
+ const optimizer = useOptimizeModel();
117
255
 
118
- return (
119
- <ModelProvider optimizer={optimizer}>
120
- <Scene>
121
- </ModelProvider>
122
- )
256
+ return (
257
+ <ModelProvider optimizer={optimizer}>
258
+ <Scene />
259
+ </ModelProvider>
260
+ );
123
261
  }
124
- ```
125
262
 
126
- ```jsx
127
- // Scene.tsx
263
+ // Scene.jsx
264
+ import React from 'react';
128
265
  import { useModelContext } from '@vctrl/hooks/use-load-model';
129
266
 
130
267
  function Scene() {
131
268
  const { optimize } = useModelContext();
132
- const { load, getModel, simplifyOptimization } = optimize;
133
269
 
134
- //...
270
+ const handleSimplify = async () => {
271
+ await optimize.simplifyOptimization();
272
+ };
273
+
274
+ const handleDedup = async () => {
275
+ await optimize.dedupOptimization();
276
+ };
277
+
278
+ const handleQuantize = async () => {
279
+ await optimize.quantizeOptimization();
280
+ };
281
+
282
+ return (
283
+ <div>
284
+ <button onClick={handleSimplify}>Simplify Model</button>
285
+ <button onClick={handleDedup}>Deduplicate Model</button>
286
+ <button onClick={handleQuantize}>Quantize Model</button>
287
+ </div>
288
+ );
135
289
  }
136
290
  ```
137
291
 
138
- ## API Reference
292
+ #### API Reference
139
293
 
140
- ### useLoadModel
294
+ The `useOptimizeModel` hook returns the following:
141
295
 
142
- The main hook for loading and managing 3D model files.
296
+ - `load(model)`: Loads a Three.js `Object3D` model into the optimizer.
297
+ - `getModel()`: Retrieves the optimized model as a binary array buffer.
298
+ - `simplifyOptimization()`: Simplifies the current model using the `MeshoptSimplifier`.
299
+ - `dedupOptimization()`: Removes duplicate vertices and meshes.
300
+ - `quantizeOptimization()`: Reduces the precision of vertex attributes.
143
301
 
144
- #### Returns
302
+ ### useExportModel
145
303
 
146
- - `file`: The loaded file object of type `ModelFile | null`.
147
- - `isLoading`: A boolean indicating whether a file is currently being loaded.
148
- - `progress`: A number between 0 and 100 representing the loading progress.
149
- - `load`: A function to handle file upload. It accepts an array of `File` objects or a mixed array of `File` objects and directory entries.
150
- - `reset`: A function to reset the internal state back to it's initial values.
151
- - `on`: A function to subscribe to events.
152
- - `off`: A function to unsubscribe from events.
153
- - `optimize`: An object optionally populated by the `useOptimizeModel` hook
304
+ #### Overview
154
305
 
155
- ### useOptimizeModel
306
+ `useExportModel` is a React hook for exporting 3D models from a Three.js scene.
307
+
308
+ #### Features
156
309
 
157
- An addon that may be used in conjunction with the `useLoadModel` hook. It populates the `optimize` property returned by the `useLoadModel` and `useModelContext` hooks.
310
+ - Exports models in GLTF or GLB format
311
+ - Handles embedded resources and textures
312
+ - Integrates with Three.js scenes
313
+ - TypeScript support
158
314
 
159
- #### Returns
315
+ #### Usage
160
316
 
161
- - `load`: Loads a Three.js Object3D model into the optimizer.
162
- - `getModel`: Simplifies the current model document using the MeshoptSimplifier.
163
- - `simplifyOptimization`: Returns the current model document as a binary array buffer.
317
+ ```jsx
318
+ import React from 'react';
319
+ import { useExportModel } from '@vctrl/hooks/use-export-model';
320
+
321
+ function ExportButton({ file }) {
322
+ const { handleGltfExport } = useExportModel(
323
+ () => console.log('Export complete'),
324
+ (error) => console.error('Export error:', error),
325
+ );
326
+
327
+ const exportAsGlb = () => {
328
+ handleGltfExport(file, true); // Export as GLB (binary)
329
+ };
330
+
331
+ const exportAsGltf = () => {
332
+ handleGltfExport(file, false); // Export as GLTF
333
+ };
334
+
335
+ return (
336
+ <div>
337
+ <button onClick={exportAsGlb}>Export as GLB</button>
338
+ <button onClick={exportAsGltf}>Export as GLTF</button>
339
+ </div>
340
+ );
341
+ }
342
+ ```
343
+
344
+ #### API Reference
345
+
346
+ The `useExportModel` hook returns the following:
347
+
348
+ - `handleGltfExport(file, binary)`: Function to handle exporting the model.
349
+ - `file`: The `ModelFile` object to export.
350
+ - `binary`: A boolean indicating whether to export in binary format (`true` for GLB, `false` for GLTF).
351
+ - The function exports the model and triggers file download.
164
352
 
165
353
  ### ModelContext
166
354
 
167
- A React context that provides the state and functions from `useLoadModel` to child components. It's implemented in `model-context.tsx`.
355
+ `ModelContext` is a React context that provides the state and functions from `useLoadModel` (and optionally `useOptimizeModel`) to child components.
168
356
 
169
357
  ```jsx
170
358
  import { ModelProvider, useModelContext } from '@vctrl/hooks/use-load-model';
@@ -178,95 +366,65 @@ function App() {
178
366
  }
179
367
 
180
368
  function ModelConsumer() {
181
- const { file, isLoading, progress, load } = useModelContext();
369
+ const { file, isLoading, progress, load, optimize } = useModelContext();
182
370
  // Use the context values
183
371
  }
184
372
  ```
185
373
 
186
- > When using the React Context, only load models with the `useModelContext` hook.
187
-
188
- ### Event System
189
-
190
- The package includes a custom event system for handling various stages of the model loading process. The event system is implemented in `event-system.ts` and provides three main methods:
191
-
192
- - `emit<T extends EventTypes>(event: T, data: EventData[T]): void`
193
- - `on<T extends EventTypes>(event: T, handler: EventHandler<T>): void`
194
- - `off<T extends EventTypes>(event: T, handler: EventHandler<T>): void`
195
-
196
- #### Events
197
-
198
- You can subscribe to these events using the `on` method:
199
-
200
- - `'UPLOAD_PROGRESS'`: Emitted with the current progress (0-100) during file upload.
201
- - `'UPLOAD_COMPLETE'`: Emitted with the loaded file object when the upload is complete.
202
- - `'MULTIPLE_3D_MODELS'`: Emitted if multiple supported 3D model files are detected in the upload.
203
- - `'UNSUPPORTED_FILE_TYPE'`: Emitted if an unsupported file type is uploaded.
374
+ > **Note**: When using the React context, load models using the `useModelContext` hook.
204
375
 
205
- Example usage:
206
-
207
- ```javascript
208
- const { on, off } = useLoadModel();
209
-
210
- useEffect(() => {
211
- const handleProgress = (progress) => {
212
- console.log(`Upload progress: ${progress}%`);
213
- };
214
-
215
- on('UPLOAD_PROGRESS', handleProgress);
216
-
217
- return () => off('UPLOAD_PROGRESS', handleProgress);
218
- }, [on, off]);
219
- ```
376
+ ## Common Concepts
220
377
 
221
- ## Supported File Types
378
+ ### Supported File Types
222
379
 
223
380
  The package currently supports the following 3D model file formats:
224
381
 
225
- - GLTF (.gltf)
226
- - GLB (.glb)
227
- - USDZ (.usdz)
382
+ - GLTF (`.gltf`)
383
+ - GLB (`.glb`)
384
+ - USDZ (`.usdz`)
228
385
 
229
386
  These are defined in the `ModelFileTypes` enum in `types.ts`.
230
387
 
231
- ## File Loading Process
388
+ ### File Loading Process
232
389
 
233
- The file loading process, particularly for GLTF files, is handled by the `useLoadGltf` hook in `use-load-gltf.ts`. This hook performs the following steps:
390
+ The file loading process, particularly for GLTF files, is handled internally by the hooks. The process includes:
234
391
 
235
- 1. Parses the GLTF file content.
236
- 2. Embeds external resources (buffers and images) into the GLTF content.
237
- 3. Uses Three.js GLTFLoader to parse the modified GLTF content.
238
- 4. Dispatches actions to update the state with the loaded model.
392
+ 1. Parsing the GLTF file content.
393
+ 2. Embedding external resources (buffers and images) into the GLTF content.
394
+ 3. Using Three.js `GLTFLoader` to parse the modified GLTF content.
395
+ 4. Updating the state with the loaded model.
396
+ 5. Integrating with the optimizer if provided.
239
397
 
240
398
  The loading process includes progress updates, which are communicated through the event system.
241
399
 
242
- ## State Management
400
+ ### State Management
243
401
 
244
- The package uses a reducer pattern for state management, implemented in `state.ts`. The state includes:
402
+ The package uses a reducer pattern for state management. The state includes:
245
403
 
246
404
  - `file`: The currently loaded model file.
247
- - `isFileLoading`: A boolean indicating if a file is being loaded.
405
+ - `isLoading`: A boolean indicating if a file is being loaded.
248
406
  - `progress`: The current loading progress.
249
407
  - `supportedFileTypes`: An array of supported file types.
250
408
 
251
409
  Actions for updating the state are defined in the `Action` type in `types.ts`.
252
410
 
253
- ## Integration with Three.js
411
+ ### Integration with Three.js
254
412
 
255
- The package integrates with Three.js for handling 3D model rendering. The loaded models are compatible with Three.js scene rendering, with the model stored as a Three.js `Object3D` in the `ModelFile` interface.
413
+ The package integrates with Three.js for handling 3D model rendering and manipulation. The loaded models are compatible with Three.js scenes, with the model stored as a Three.js `Object3D` in the `ModelFile` interface.
256
414
 
257
415
  ## Development
258
416
 
259
417
  This package is part of a monorepo workspace managed with Nx. To contribute or modify the package:
260
418
 
261
- 1. Clone the monorepo
262
- 2. Install dependencies: `npm install` or `yarn install`
263
- 3. Make your changes
264
- 4. Build the package: `nx build vctrl/hooks`
265
- 5. Test your changes: `nx test vctrl/hooks`
419
+ 1. Clone the monorepo from [vectreal-core](https://github.com/vectreal/vectreal-core).
420
+ 2. Install dependencies: `npm install` or `yarn install`.
421
+ 3. Make your changes.
422
+ 4. Build the package: `nx build vctrl/hooks`.
423
+ 5. Test your changes: `nx test vctrl/hooks`.
266
424
 
267
425
  ## License
268
426
 
269
- Please refer to the LICENSE file in the package root for licensing information.
427
+ This project is licensed under the **GNU Affero General Public License v3.0**. Please refer to the [LICENSE](https://github.com/vectreal/vectreal-core/blob/main/LICENSE) file in the package root for licensing information.
270
428
 
271
429
  ## Contributing
272
430
 
@@ -274,4 +432,4 @@ Contributions are welcome! Please read the contributing guidelines in the [vectr
274
432
 
275
433
  ## Support
276
434
 
277
- For issues, feature requests, or questions, please file an issue in the GitHub repository.
435
+ For issues, feature requests, or questions, please file an issue in the [GitHub repository](https://github.com/vectreal/vectreal-core/issues).