@vctrl/hooks 0.23.0 → 0.24.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/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.24.1](https://github.com/Vectreal/vectreal-platform/compare/hooks-v0.24.0...hooks-v0.24.1) (2026-08-02)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **ci:** resolve workspace protocol at publish time and publish via OIDC ([07e4b62](https://github.com/Vectreal/vectreal-platform/commit/07e4b628be16b61f3ddea9c91cc36c052d60bc8f))
9
+ * **ci:** resolve workspace protocol at publish time and publish via OIDC ([03b9305](https://github.com/Vectreal/vectreal-platform/commit/03b9305719b1cf67548f62730493ca6e3a84c823))
10
+
11
+
12
+ ### Dependencies
13
+
14
+ * The following workspace dependencies were updated
15
+ * dependencies
16
+ * @vctrl/core bumped to 0.24.1
17
+
18
+ ## [0.24.0](https://github.com/Vectreal/vectreal-platform/compare/hooks-v0.23.0...hooks-v0.24.0) (2026-08-01)
19
+
20
+
21
+ ### Features
22
+
23
+ * **publisher:** draco-first optimization pipeline and panel rework ([#652](https://github.com/Vectreal/vectreal-platform/issues/652)) ([1161236](https://github.com/Vectreal/vectreal-platform/commit/1161236d0f4b2461b6b4af1ea4069fdf9da6d9c2))
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * **publisher:** scene size inflation and stale model reloads ([#653](https://github.com/Vectreal/vectreal-platform/issues/653)) ([9c5da02](https://github.com/Vectreal/vectreal-platform/commit/9c5da02f3f524337b5d715ff5454ac4687fc73e3))
29
+
30
+
31
+ ### Dependencies
32
+
33
+ * The following workspace dependencies were updated
34
+ * dependencies
35
+ * @vctrl/core bumped to 0.24.0
36
+
3
37
  ## [0.23.0](https://github.com/Vectreal/vectreal-platform/compare/hooks-v0.22.0...hooks-v0.23.0) (2026-07-03)
4
38
 
5
39
 
package/README.md CHANGED
@@ -152,7 +152,6 @@ function Optimizer() {
152
152
  | ------------------------------------ | ------------------------------------------------------------------ | ---------------------------------------------------------------------- |
153
153
  | `load(model)` | `(model: Object3D) => Promise<void>` | Load a Three.js scene into the optimizer |
154
154
  | `loadFromServerSceneData(sceneData)` | `Promise<void>` | Initialize optimizer from a server scene payload |
155
- | `applyOptimization(fn, opts?)` | `<T>(fn?: (opts?: T) => Promise<void>, opts?: T) => Promise<void>` | Apply optimization and sync the optimized model back into loader state |
156
155
  | `simplifyOptimization(options?)` | `Promise<void>` | Simplify mesh geometry |
157
156
  | `dedupOptimization(options?)` | `Promise<void>` | Deduplicate model data |
158
157
  | `quantizeOptimization(options?)` | `Promise<void>` | Quantize vertex attributes |
@@ -162,6 +161,8 @@ function Optimizer() {
162
161
  | `report` / `info` | Objects | Optimization metrics and derived stats |
163
162
  | `loading` / `error` | State | Optimization status |
164
163
 
164
+ > `applyOptimization(fn, opts?)` is **not** returned by `useOptimizeModel` directly. It becomes available on the `optimizer` object returned by `useLoadModel(optimizer)` when you pass an optimizer instance in; it runs an optimization step and syncs the result back into loader state (see the example above).
165
+
165
166
  ### Optimization option types
166
167
 
167
168
  `useOptimizeModel` methods map directly to `@vctrl/core/model-optimizer` option types:
@@ -218,11 +219,10 @@ function ExportButton({ file }: { file: ModelFile | null }) {
218
219
 
219
220
  ## Peer dependencies
220
221
 
221
- | Package | Version |
222
- | -------------------- | -------------- |
223
- | `react` | `^18 \|\| ^19` |
224
- | `three` | `^0.170` |
225
- | `@react-three/fiber` | `^9` |
222
+ | Package | Version |
223
+ | ------- | -------------- |
224
+ | `react` | `^18 \|\| ^19` |
225
+ | `three` | `^0.177` |
226
226
 
227
227
  ---
228
228
 
package/index.cjs.js CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./use-load-model-B8oqou4I.cjs"),t=require("./use-export-model-8JbUalyf.cjs"),n=require("./use-optimize-model-Jie2FUHc.cjs");exports.reconstructGltfFiles=e.r,exports.useExportModel=t.t,exports.useLoadModel=e.t,exports.useOptimizeModel=n.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./use-load-model-B8oqou4I.cjs"),t=require("./use-export-model-yQWV3O3H.cjs"),n=require("./use-optimize-model-CD5zqTLK.cjs");exports.reconstructGltfFiles=e.r,exports.useExportModel=t.t,exports.useLoadModel=e.t,exports.useOptimizeModel=n.t;
package/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { r as e, t } from "./use-load-model-C88r8-HE.js";
2
- import { t as n } from "./use-export-model-BXg6L_W5.js";
3
- import { t as r } from "./use-optimize-model-CweunXiv.js";
2
+ import { t as n } from "./use-export-model-efFsSWe-.js";
3
+ import { t as r } from "./use-optimize-model-D16-4Zwm.js";
4
4
  export { e as reconstructGltfFiles, n as useExportModel, t as useLoadModel, r as useOptimizeModel };
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
- "version": "0.23.0",
2
+ "version": "0.24.1",
3
3
  "name": "@vctrl/hooks",
4
4
  "description": "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.",
5
5
  "bugs": {
6
- "url": "https://github.com/vectreal/vectreal-platform/issues"
6
+ "url": "https://github.com/Vectreal/vectreal-platform/issues"
7
7
  },
8
8
  "homepage": "https://vectreal.com",
9
9
  "keywords": [
@@ -25,7 +25,7 @@
25
25
  ],
26
26
  "repository": {
27
27
  "type": "git",
28
- "url": "git+https://github.com/vectreal/vectreal-platform.git"
28
+ "url": "git+https://github.com/Vectreal/vectreal-platform.git"
29
29
  },
30
30
  "license": "AGPL-3.0-only",
31
31
  "types": "./index.d.ts",
@@ -62,13 +62,7 @@
62
62
  "three": "^0.177.0"
63
63
  },
64
64
  "dependencies": {
65
- "@vctrl/core": "^0.23.0",
65
+ "@vctrl/core": "^0.24.1",
66
66
  "file-saver": "^2.0.5"
67
- },
68
- "devDependencies": {
69
- "@nx/vite": "22.5.0",
70
- "@vitejs/plugin-react": "^6.0.0",
71
- "vite": "^7.3.1",
72
- "vite-plugin-dts": "4.5.3"
73
67
  }
74
68
  }
@@ -10,5 +10,7 @@ import { ModelFile } from '../use-load-model';
10
10
  declare const useExportModel: (onSaved?: () => void, onError?: (error: Error) => void) => {
11
11
  handleThreeGltfExport: (file: ModelFile | null, binary: boolean) => Promise<void>;
12
12
  handleDocumentGltfExport: (jsonDocument: Document, file: ModelFile | null, binary?: boolean, download?: boolean) => Promise<import('../../../core/src/model-exporter/index.ts').GLTFExportResult | undefined>;
13
+ handleThreeUsdzExport: (file: ModelFile | null) => Promise<void>;
14
+ handleDocumentGlbDracoExport: (jsonDocument: Document, file: ModelFile | null) => Promise<void>;
13
15
  };
14
16
  export default useExportModel;
@@ -0,0 +1,70 @@
1
+ import { useCallback as e, useRef as t } from "react";
2
+ import { ModelExporter as n } from "@vctrl/core/model-exporter";
3
+ import r from "file-saver";
4
+ //#region packages/hooks/src/use-export-model/use-export-model.ts
5
+ var i = (i, a) => {
6
+ let o = t(new n()), s = e(async (e, t) => {
7
+ let n = e?.model;
8
+ if (!n) {
9
+ console.error("Scene not initialized");
10
+ return;
11
+ }
12
+ try {
13
+ let a = o.current, s = e.name.replace(/\.[^/.]+$/, "");
14
+ if (t) {
15
+ let e = await a.exportThreeJSGLB(n, {});
16
+ if (!(e.data instanceof Uint8Array)) throw Error("Expected GLB export to return Uint8Array");
17
+ r.saveAs(new Blob([new Uint8Array(e.data)]), `${s}.glb`);
18
+ } else {
19
+ let e = await a.exportThreeJSGLTF(n), t = await a.createZIPArchive(e, s);
20
+ r.saveAs(new Blob([new Uint8Array(t)]), `${s}.zip`);
21
+ }
22
+ i && i();
23
+ } catch (e) {
24
+ console.error("Export failed:", e), a && a(e);
25
+ }
26
+ }, [i, a]), c = e(async (e) => {
27
+ let t = e?.model;
28
+ if (!t) {
29
+ console.error("Scene not initialized");
30
+ return;
31
+ }
32
+ try {
33
+ let n = o.current, a = e.name.replace(/\.[^/.]+$/, ""), s = await n.exportThreeJSUSDZ(t);
34
+ r.saveAs(new Blob([new Uint8Array(s.data)]), `${a}.usdz`), i && i();
35
+ } catch (e) {
36
+ console.error("USDZ export failed:", e), a && a(e);
37
+ }
38
+ }, [i, a]), l = e(async (e, t) => {
39
+ try {
40
+ let n = o.current, a = t?.name.replace(/\.[^/.]+$/, "") || "model", s = await n.exportDocumentGLBDraco(e);
41
+ r.saveAs(new Blob([new Uint8Array(s.data)]), `${a}.glb`), i && i();
42
+ } catch (e) {
43
+ console.error("Draco GLB export failed:", e), a && a(e);
44
+ }
45
+ }, [i, a]);
46
+ return {
47
+ handleThreeGltfExport: s,
48
+ handleDocumentGltfExport: e(async function(e, t, n = !1, s = !0) {
49
+ try {
50
+ let a = o.current, c = t?.name.replace(/\.[^/.]+$/, "") || "model";
51
+ if (n) {
52
+ let t = await a.exportDocumentGLB(e);
53
+ r.saveAs(new Blob([new Uint8Array(t.data)]), `${c}.glb`);
54
+ } else {
55
+ let t = await a.exportDocumentGLTF(e);
56
+ if (!s) return t;
57
+ let n = await a.createZIPArchive(t, c);
58
+ r.saveAs(new Blob([new Uint8Array(n)]), `${c}.zip`);
59
+ }
60
+ i && i();
61
+ } catch (e) {
62
+ console.error("Export failed:", e), a && a(e);
63
+ }
64
+ }, [a, i]),
65
+ handleThreeUsdzExport: c,
66
+ handleDocumentGlbDracoExport: l
67
+ };
68
+ };
69
+ //#endregion
70
+ export { i as t };
@@ -0,0 +1 @@
1
+ const e=require("./chunk-CMqjfN_6.cjs");let t=require("react"),n=require("@vctrl/core/model-exporter"),r=require("file-saver");r=e.t(r,1);var i=(e,i)=>{let a=(0,t.useRef)(new n.ModelExporter),o=(0,t.useCallback)(async(t,n)=>{let o=t?.model;if(!o){console.error(`Scene not initialized`);return}try{let i=a.current,s=t.name.replace(/\.[^/.]+$/,``);if(n){let e=await i.exportThreeJSGLB(o,{});if(!(e.data instanceof Uint8Array))throw Error(`Expected GLB export to return Uint8Array`);r.default.saveAs(new Blob([new Uint8Array(e.data)]),`${s}.glb`)}else{let e=await i.exportThreeJSGLTF(o),t=await i.createZIPArchive(e,s);r.default.saveAs(new Blob([new Uint8Array(t)]),`${s}.zip`)}e&&e()}catch(e){console.error(`Export failed:`,e),i&&i(e)}},[e,i]),s=(0,t.useCallback)(async t=>{let n=t?.model;if(!n){console.error(`Scene not initialized`);return}try{let i=a.current,o=t.name.replace(/\.[^/.]+$/,``),s=await i.exportThreeJSUSDZ(n);r.default.saveAs(new Blob([new Uint8Array(s.data)]),`${o}.usdz`),e&&e()}catch(e){console.error(`USDZ export failed:`,e),i&&i(e)}},[e,i]),c=(0,t.useCallback)(async(t,n)=>{try{let i=a.current,o=n?.name.replace(/\.[^/.]+$/,``)||`model`,s=await i.exportDocumentGLBDraco(t);r.default.saveAs(new Blob([new Uint8Array(s.data)]),`${o}.glb`),e&&e()}catch(e){console.error(`Draco GLB export failed:`,e),i&&i(e)}},[e,i]);return{handleThreeGltfExport:o,handleDocumentGltfExport:(0,t.useCallback)(async function(t,n,o=!1,s=!0){try{let i=a.current,c=n?.name.replace(/\.[^/.]+$/,``)||`model`;if(o){let e=await i.exportDocumentGLB(t);r.default.saveAs(new Blob([new Uint8Array(e.data)]),`${c}.glb`)}else{let e=await i.exportDocumentGLTF(t);if(!s)return e;let n=await i.createZIPArchive(e,c);r.default.saveAs(new Blob([new Uint8Array(n)]),`${c}.zip`)}e&&e()}catch(e){console.error(`Export failed:`,e),i&&i(e)}},[i,e]),handleThreeUsdzExport:s,handleDocumentGlbDracoExport:c}};Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return i}});
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./use-export-model-8JbUalyf.cjs");exports.useExportModel=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./use-export-model-yQWV3O3H.cjs");exports.useExportModel=e.t;
@@ -1,2 +1,2 @@
1
- import { t as e } from "./use-export-model-BXg6L_W5.js";
1
+ import { t as e } from "./use-export-model-efFsSWe-.js";
2
2
  export { e as useExportModel };
@@ -1,6 +1,11 @@
1
1
  import { DedupOptions, NormalsOptions, QuantizeOptions, SimplifyOptions, TextureCompressOptions } from '../../../core/src/model-optimizer/index.ts';
2
2
  import { Object3D } from 'three';
3
- import { ServerSceneData } from '../../../core/src/index.ts';
3
+ import { DracoCompressionReport, ServerSceneData } from '../../../core/src/index.ts';
4
+ /** Optimizer state produced inside the geometry Web Worker. */
5
+ export interface WorkerResultMeta {
6
+ appliedOptimizations: string[];
7
+ dracoReport?: DracoCompressionReport;
8
+ }
4
9
  /**
5
10
  * Custom React hook for optimizing 3D models using the ModelOptimizer from @vctrl/core.
6
11
  *
@@ -42,7 +47,7 @@ declare const useOptimizeModel: () => {
42
47
  */
43
48
  load: (model: Object3D) => Promise<void>;
44
49
  loadFromServerSceneData: (sceneData: ServerSceneData) => Promise<void>;
45
- loadFromGlbBuffer: (buffer: Uint8Array) => Promise<void>;
50
+ loadFromGlbBuffer: (buffer: Uint8Array, meta?: WorkerResultMeta) => Promise<void>;
46
51
  loadFromGLTFWithAssets: (gltfBytes: Uint8Array, assets: Map<string, Uint8Array>) => Promise<void>;
47
52
  /**
48
53
  * Retrieves the current model as a binary Uint8Array in glTF (.glb) format.
@@ -1 +1 @@
1
- let e=require("@vctrl/core"),t=require("react"),n=require("@vctrl/core/model-optimizer");var r={info:null,error:null,loading:!1,report:null},i=(e,t)=>{switch(t.type){case`LOAD_START`:return{...e,loading:!0,error:null};case`LOAD_SUCCESS`:return{...e,loading:!1,report:t.payload.report};case`LOAD_ERROR`:return{...e,loading:!1,error:t.payload};case`RESET`:return{...r};default:return e}};function a(e){return e?{verticesCount:e.stats.vertices.after??0,primitivesCount:e.stats.triangles.after??0,meshesCount:e.stats.meshes.after??0,textureAssetCount:e.stats.texturesCount.after??0,materialsCount:e.stats.materials.after??0,sceneBytes:e.optimizedSize??0}:{verticesCount:0,primitivesCount:0,meshesCount:0,textureAssetCount:0,materialsCount:0,sceneBytes:0}}var o=e=>{let[n,r]=(0,t.useState)(null),i=e.report;return(0,t.useEffect)(()=>{!n&&i&&r(i)},[n,i]),{info:(0,t.useMemo)(()=>{let e=a(n),t=a(i);return{initial:{verticesCount:e.verticesCount,primitivesCount:e.primitivesCount,meshesCount:e.meshesCount,texturesCount:e.textureAssetCount,sceneBytes:e.sceneBytes},optimized:{verticesCount:t.verticesCount,primitivesCount:t.primitivesCount,meshesCount:t.meshesCount,texturesCount:t.textureAssetCount,sceneBytes:t.sceneBytes},improvement:{verticesCount:e.verticesCount-t.verticesCount,primitivesCount:e.primitivesCount-t.primitivesCount,meshesCount:e.meshesCount-t.meshesCount,texturesCount:e.textureAssetCount-t.textureAssetCount,sceneBytes:e.sceneBytes-t.sceneBytes}}},[i,n]),reset:(0,t.useCallback)(()=>{r(null)},[])}};async function s(e,t){let n=new Blob([e]),r=await createImageBitmap(n),{width:i,height:a}=r;if(t.maxWidth||t.maxHeight){let e=t.maxWidth?t.maxWidth/i:1/0,n=t.maxHeight?t.maxHeight/a:1/0,r=Math.min(e,n,1);r<1&&(i=Math.round(i*r),a=Math.round(a*r))}let o=new OffscreenCanvas(i,a),s=o.getContext(`2d`);if(!s)throw r.close(),Error(`OffscreenCanvas 2D context unavailable`);s.drawImage(r,0,0,i,a),r.close();let c=t.format===`webp`?`image/webp`:t.format===`jpeg`?`image/jpeg`:`image/png`,l=await o.convertToBlob({type:c,quality:t.quality/100});return new Uint8Array(await l.arrayBuffer())}function c(){return function(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),n=`webp`,r=80,i,a,o={resize(e,t,n){return i=e,a=t,o},webp(e){return n=`webp`,typeof e?.quality==`number`&&(r=e.quality),o},jpeg(e){return n=`jpeg`,typeof e?.quality==`number`&&(r=e.quality),o},png(e){return n=`png`,o},toFormat(e,t){return(e===`webp`||e===`jpeg`||e===`png`)&&(n=e),typeof t?.quality==`number`&&(r=t.quality),o},async toBuffer(){return s(t,{format:n,quality:r,maxWidth:i,maxHeight:a})},async metadata(){let e=new Blob([t]),n=await createImageBitmap(e),r={width:n.width,height:n.height,format:`unknown`};return n.close(),r}};return o}}var l=async(e,t)=>{e.hasModel()&&await e.compressTextures({...t,encoder:c()})},u=()=>{let[a,s]=(0,t.useReducer)(i,r),{report:c,error:u,loading:d}=a,{info:f,reset:p}=o(a),m=(0,t.useRef)(new n.ModelOptimizer);(0,t.useEffect)(()=>{let e=m.current;return()=>{e.reset()}},[]);let h=(0,t.useCallback)(async e=>{s({type:`LOAD_START`});try{let t=m.current;await t.loadFromThreeJS(e),s({type:`LOAD_SUCCESS`,payload:{report:await t.getReport()}})}catch(e){s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading model:`,e)}},[]),g=(0,t.useCallback)(async t=>{s({type:`LOAD_START`});try{let n=m.current,r=new Map;for(let n of Object.values(t.assetData??{}))for(let t of(0,e.buildAssetLookupKeys)(n.fileName))r.set(t,n);let i={},a=t.gltfJson,o=[...(a.images??[]).map(e=>e.uri).filter(e=>!!e&&!e.startsWith(`data:`)),...(a.buffers??[]).map(e=>e.uri).filter(e=>!!e&&!e.startsWith(`data:`))];for(let t of o){let n=(0,e.normalizeAssetUri)(t),a=n.split(`/`).pop()||n,o=r.get(t)??r.get(n)??r.get(a);o&&(i[t]=(0,e.toSerializedAssetBytes)(o))}let c={json:t.gltfJson,resources:i};await n.loadFromJSON(c),s({type:`LOAD_SUCCESS`,payload:{report:await n.getReport()}})}catch(e){throw s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading server scene into optimizer:`,e),e}},[]),_=(0,t.useCallback)(async e=>{s({type:`LOAD_START`});try{await m.current.loadFromBuffer(e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){throw s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading GLB buffer into optimizer:`,e),e}},[]),v=(0,t.useCallback)(async(e,t)=>{s({type:`LOAD_START`});try{await m.current.loadFromGLTFWithAssets(e,t),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){throw s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading GLTF with assets into optimizer:`,e),e}},[]),y=(0,t.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.simplify(e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){console.error(`Simplification failed:`,e)}},[]),b=(0,t.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.deduplicate(e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){console.error(`Deduplication failed:`,e)}},[]),x=(0,t.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.quantize(e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){console.error(`Quantization failed:`,e)}},[]),S=(0,t.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.optimizeNormals(e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){console.error(`Normals optimization failed:`,e)}},[]),C=(0,t.useCallback)(async e=>{try{await l(m.current,e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){throw console.error(`Texture optimization failed:`,e),e}},[]),w=(0,t.useCallback)(async()=>{if(!m.current.hasModel())return null;try{return await m.current.export()}catch(e){return console.error(`Error getting model binary:`,e),null}},[]),T=(0,t.useCallback)(()=>m.current.hasModel()?m.current.document:null,[]);return{load:h,loadFromServerSceneData:g,loadFromGlbBuffer:_,loadFromGLTFWithAssets:v,getModel:w,isReady:!!T()&&!d,_getDocument:T,reset:(0,t.useCallback)(()=>{m.current.reset(),s({type:`RESET`}),p()},[p]),error:u,loading:d,report:c,info:f,simplifyOptimization:y,dedupOptimization:b,quantizeOptimization:x,normalsOptimization:S,texturesOptimization:C}};Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return u}});
1
+ let e=require("@vctrl/core"),t=require("react"),n=require("@vctrl/core/model-optimizer");var r={info:null,error:null,loading:!1,report:null},i=(e,t)=>{switch(t.type){case`LOAD_START`:return{...e,loading:!0,error:null};case`LOAD_SUCCESS`:return{...e,loading:!1,report:t.payload.report};case`LOAD_ERROR`:return{...e,loading:!1,error:t.payload};case`RESET`:return{...r};default:return e}};function a(e){return e?{verticesCount:e.stats.vertices.after??0,primitivesCount:e.stats.triangles.after??0,meshesCount:e.stats.meshes.after??0,textureAssetCount:e.stats.texturesCount.after??0,materialsCount:e.stats.materials.after??0,sceneBytes:e.optimizedSize??0}:{verticesCount:0,primitivesCount:0,meshesCount:0,textureAssetCount:0,materialsCount:0,sceneBytes:0}}var o=e=>{let[n,r]=(0,t.useState)(null),i=e.report;return(0,t.useEffect)(()=>{!n&&i&&r(i)},[n,i]),{info:(0,t.useMemo)(()=>{let e=a(n),t=a(i);return{initial:{verticesCount:e.verticesCount,primitivesCount:e.primitivesCount,meshesCount:e.meshesCount,texturesCount:e.textureAssetCount,sceneBytes:e.sceneBytes},optimized:{verticesCount:t.verticesCount,primitivesCount:t.primitivesCount,meshesCount:t.meshesCount,texturesCount:t.textureAssetCount,sceneBytes:t.sceneBytes},improvement:{verticesCount:e.verticesCount-t.verticesCount,primitivesCount:e.primitivesCount-t.primitivesCount,meshesCount:e.meshesCount-t.meshesCount,texturesCount:e.textureAssetCount-t.textureAssetCount,sceneBytes:e.sceneBytes-t.sceneBytes}}},[i,n]),reset:(0,t.useCallback)(()=>{r(null)},[])}};async function s(e,t){let n=new Blob([e]),r=await createImageBitmap(n),{width:i,height:a}=r;if(t.maxWidth||t.maxHeight){let e=t.maxWidth?t.maxWidth/i:1/0,n=t.maxHeight?t.maxHeight/a:1/0,r=Math.min(e,n,1);r<1&&(i=Math.round(i*r),a=Math.round(a*r))}let o=new OffscreenCanvas(i,a),s=o.getContext(`2d`);if(!s)throw r.close(),Error(`OffscreenCanvas 2D context unavailable`);s.drawImage(r,0,0,i,a),r.close();let c=t.format===`webp`?`image/webp`:t.format===`jpeg`?`image/jpeg`:`image/png`,l=await o.convertToBlob({type:c,quality:t.quality/100});return new Uint8Array(await l.arrayBuffer())}function c(){return function(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),n=`webp`,r=80,i,a,o={resize(e,t,n){return i=e,a=t,o},webp(e){return n=`webp`,typeof e?.quality==`number`&&(r=e.quality),o},jpeg(e){return n=`jpeg`,typeof e?.quality==`number`&&(r=e.quality),o},png(e){return n=`png`,o},toFormat(e,t){return(e===`webp`||e===`jpeg`||e===`png`)&&(n=e),typeof t?.quality==`number`&&(r=t.quality),o},async toBuffer(){return s(t,{format:n,quality:r,maxWidth:i,maxHeight:a})},async metadata(){let e=new Blob([t]),n=await createImageBitmap(e),r={width:n.width,height:n.height,format:`unknown`};return n.close(),r}};return o}}var l=async(e,t)=>{e.hasModel()&&await e.compressTextures({...t,encoder:c()})},u=()=>{let[a,s]=(0,t.useReducer)(i,r),{report:c,error:u,loading:d}=a,{info:f,reset:p}=o(a),m=(0,t.useRef)(new n.ModelOptimizer);(0,t.useEffect)(()=>{let e=m.current;return()=>{e.reset()}},[]);let h=(0,t.useCallback)(async e=>{s({type:`LOAD_START`});try{let t=m.current;await t.loadFromThreeJS(e),s({type:`LOAD_SUCCESS`,payload:{report:await t.getReport()}})}catch(e){s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading model:`,e)}},[]),g=(0,t.useCallback)(async t=>{s({type:`LOAD_START`});try{let n=m.current,r=new Map;for(let n of Object.values(t.assetData??{}))for(let t of(0,e.buildAssetLookupKeys)(n.fileName))r.set(t,n);let i={},a=t.gltfJson,o=[...(a.images??[]).map(e=>e.uri).filter(e=>!!e&&!e.startsWith(`data:`)),...(a.buffers??[]).map(e=>e.uri).filter(e=>!!e&&!e.startsWith(`data:`))];for(let t of o){let n=(0,e.normalizeAssetUri)(t),a=n.split(`/`).pop()||n,o=r.get(t)??r.get(n)??r.get(a);o&&(i[t]=(0,e.toSerializedAssetBytes)(o))}let c={json:t.gltfJson,resources:i};await n.loadFromJSON(c),s({type:`LOAD_SUCCESS`,payload:{report:await n.getReport()}})}catch(e){throw s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading server scene into optimizer:`,e),e}},[]),_=(0,t.useCallback)(async(e,t)=>{s({type:`LOAD_START`});try{await m.current.loadFromBuffer(e),m.current.setAppliedOptimizations(t?.appliedOptimizations??[]),m.current.setDracoReport(t?.dracoReport??null),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){throw s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading GLB buffer into optimizer:`,e),e}},[]),v=(0,t.useCallback)(async(e,t)=>{s({type:`LOAD_START`});try{await m.current.loadFromGLTFWithAssets(e,t),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){throw s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading GLTF with assets into optimizer:`,e),e}},[]),y=(0,t.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.simplify(e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){console.error(`Simplification failed:`,e)}},[]),b=(0,t.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.deduplicate(e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){console.error(`Deduplication failed:`,e)}},[]),x=(0,t.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.quantize(e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){console.error(`Quantization failed:`,e)}},[]),S=(0,t.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.optimizeNormals(e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){console.error(`Normals optimization failed:`,e)}},[]),C=(0,t.useCallback)(async e=>{try{await l(m.current,e),s({type:`LOAD_SUCCESS`,payload:{report:await m.current.getReport()}})}catch(e){throw console.error(`Texture optimization failed:`,e),e}},[]),w=(0,t.useCallback)(async()=>{if(!m.current.hasModel())return null;try{return await m.current.export()}catch(e){return console.error(`Error getting model binary:`,e),null}},[]),T=(0,t.useCallback)(()=>m.current.hasModel()?m.current.document:null,[]);return{load:h,loadFromServerSceneData:g,loadFromGlbBuffer:_,loadFromGLTFWithAssets:v,getModel:w,isReady:!!T()&&!d,_getDocument:T,reset:(0,t.useCallback)(()=>{m.current.reset(),s({type:`RESET`}),p()},[p]),error:u,loading:d,report:c,info:f,simplifyOptimization:y,dedupOptimization:b,quantizeOptimization:x,normalsOptimization:S,texturesOptimization:C}};Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return u}});
@@ -191,10 +191,10 @@ var g = async (e, t) => {
191
191
  payload: e
192
192
  }), console.error("Error loading server scene into optimizer:", e), e;
193
193
  }
194
- }, []), S = r(async (e) => {
194
+ }, []), S = r(async (e, t) => {
195
195
  c({ type: "LOAD_START" });
196
196
  try {
197
- await y.current.loadFromBuffer(e), c({
197
+ await y.current.loadFromBuffer(e), y.current.setAppliedOptimizations(t?.appliedOptimizations ?? []), y.current.setDracoReport(t?.dracoReport ?? null), c({
198
198
  type: "LOAD_SUCCESS",
199
199
  payload: { report: await y.current.getReport() }
200
200
  });
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./use-optimize-model-Jie2FUHc.cjs");exports.useOptimizeModel=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./use-optimize-model-CD5zqTLK.cjs");exports.useOptimizeModel=e.t;
@@ -1,2 +1,2 @@
1
- import { t as e } from "./use-optimize-model-CweunXiv.js";
1
+ import { t as e } from "./use-optimize-model-D16-4Zwm.js";
2
2
  export { e as useOptimizeModel };
@@ -1 +0,0 @@
1
- const e=require("./chunk-CMqjfN_6.cjs");let t=require("react"),n=require("@vctrl/core/model-exporter"),r=require("file-saver");r=e.t(r,1);var i=(e,i)=>{let a=(0,t.useRef)(new n.ModelExporter);return{handleThreeGltfExport:(0,t.useCallback)(async(t,n)=>{let o=t?.model;if(!o){console.error(`Scene not initialized`);return}try{let i=a.current,s=t.name.replace(/\.[^/.]+$/,``);if(n){let e=await i.exportThreeJSGLB(o,{});if(!(e.data instanceof Uint8Array))throw Error(`Expected GLB export to return Uint8Array`);r.default.saveAs(new Blob([new Uint8Array(e.data)]),`${s}.glb`)}else{let e=await i.exportThreeJSGLTF(o),t=await i.createZIPArchive(e,s);r.default.saveAs(new Blob([new Uint8Array(t)]),`${s}.zip`)}e&&e()}catch(e){console.error(`Export failed:`,e),i&&i(e)}},[e,i]),handleDocumentGltfExport:(0,t.useCallback)(async function(t,n,o=!1,s=!0){try{let i=a.current,c=n?.name.replace(/\.[^/.]+$/,``)||`model`;if(o){let e=await i.exportDocumentGLB(t);r.default.saveAs(new Blob([new Uint8Array(e.data)]),`${c}.glb`)}else{let e=await i.exportDocumentGLTF(t);if(!s)return e;let n=await i.createZIPArchive(e,c);r.default.saveAs(new Blob([new Uint8Array(n)]),`${c}.zip`)}e&&e()}catch(e){console.error(`Export failed:`,e),i&&i(e)}},[i,e])}};Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return i}});
@@ -1,49 +0,0 @@
1
- import { useCallback as e, useRef as t } from "react";
2
- import { ModelExporter as n } from "@vctrl/core/model-exporter";
3
- import r from "file-saver";
4
- //#region packages/hooks/src/use-export-model/use-export-model.ts
5
- var i = (i, a) => {
6
- let o = t(new n());
7
- return {
8
- handleThreeGltfExport: e(async (e, t) => {
9
- let n = e?.model;
10
- if (!n) {
11
- console.error("Scene not initialized");
12
- return;
13
- }
14
- try {
15
- let a = o.current, s = e.name.replace(/\.[^/.]+$/, "");
16
- if (t) {
17
- let e = await a.exportThreeJSGLB(n, {});
18
- if (!(e.data instanceof Uint8Array)) throw Error("Expected GLB export to return Uint8Array");
19
- r.saveAs(new Blob([new Uint8Array(e.data)]), `${s}.glb`);
20
- } else {
21
- let e = await a.exportThreeJSGLTF(n), t = await a.createZIPArchive(e, s);
22
- r.saveAs(new Blob([new Uint8Array(t)]), `${s}.zip`);
23
- }
24
- i && i();
25
- } catch (e) {
26
- console.error("Export failed:", e), a && a(e);
27
- }
28
- }, [i, a]),
29
- handleDocumentGltfExport: e(async function(e, t, n = !1, s = !0) {
30
- try {
31
- let a = o.current, c = t?.name.replace(/\.[^/.]+$/, "") || "model";
32
- if (n) {
33
- let t = await a.exportDocumentGLB(e);
34
- r.saveAs(new Blob([new Uint8Array(t.data)]), `${c}.glb`);
35
- } else {
36
- let t = await a.exportDocumentGLTF(e);
37
- if (!s) return t;
38
- let n = await a.createZIPArchive(t, c);
39
- r.saveAs(new Blob([new Uint8Array(n)]), `${c}.zip`);
40
- }
41
- i && i();
42
- } catch (e) {
43
- console.error("Export failed:", e), a && a(e);
44
- }
45
- }, [a, i])
46
- };
47
- };
48
- //#endregion
49
- export { i as t };