@vctrl/hooks 0.22.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,64 @@
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
+
37
+ ## [0.23.0](https://github.com/Vectreal/vectreal-platform/compare/hooks-v0.22.0...hooks-v0.23.0) (2026-07-03)
38
+
39
+
40
+ ### Features
41
+
42
+ * **hooks:** fetch manifest scene assets in parallel as raw bytes ([c669e9d](https://github.com/Vectreal/vectreal-platform/commit/c669e9d01e644687483e6666b7fdc1feebd3a1f1))
43
+ * **hooks:** load scenes via GET manifest with legacy POST fallback ([72f8bef](https://github.com/Vectreal/vectreal-platform/commit/72f8bef1f3cbfac63175524b2665dfcbd080c53c))
44
+
45
+
46
+ ### Bug Fixes
47
+
48
+ * **hooks:** abort sibling asset fetches on failure and fix mixed-size progress ([6657673](https://github.com/Vectreal/vectreal-platform/commit/6657673c4a2873c400d10f8ebfcd48dcf4acb8ec))
49
+
50
+
51
+ ### Performance Improvements
52
+
53
+ * **viewer:** direct GLTFLoader parse path for view-only scene loading ([c3c148d](https://github.com/Vectreal/vectreal-platform/commit/c3c148dc8cb6194cb5555982688046017f595ac4))
54
+
55
+
56
+ ### Dependencies
57
+
58
+ * The following workspace dependencies were updated
59
+ * dependencies
60
+ * @vctrl/core bumped to 0.23.0
61
+
3
62
  ## [0.22.0](https://github.com/Vectreal/vectreal-platform/compare/hooks-v0.21.0...hooks-v0.22.0) (2026-07-01)
4
63
 
5
64
 
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-B9M4cF4B.cjs"),t=require("./use-export-model-8JbUalyf.cjs"),n=require("./use-optimize-model-CPGezwrM.cjs");exports.reconstructGltfFiles=e.n,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
- import { n as e, t } from "./use-load-model-BDCy9n2U.js";
2
- import { t as n } from "./use-export-model-BXg6L_W5.js";
3
- import { t as r } from "./use-optimize-model-KAGxtv_k.js";
1
+ import { r as e, t } from "./use-load-model-C88r8-HE.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.22.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,7 +62,7 @@
62
62
  "three": "^0.177.0"
63
63
  },
64
64
  "dependencies": {
65
- "@vctrl/core": "^0.22.0",
65
+ "@vctrl/core": "^0.24.1",
66
66
  "file-saver": "^2.0.5"
67
67
  }
68
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,4 +1,5 @@
1
1
  export { default as useLoadModel } from './use-load-model';
2
2
  export { type EventHandler, type EventTypes, type InputFileOrDirectory, type LoadData, type ModelFile, type SceneDataLoadOptions, type SceneLoadOptions, type SceneLoadResult, type StructuredLoadError, type UseLoadModelReturn, type ViewerLoadErrorCode, type ServerSceneData } from './types';
3
3
  export { reconstructGltfFiles } from './utils/reconstruct-files';
4
+ export { fetchManifestAssetData, type FetchManifestAssetsOptions } from './utils/fetch-manifest-assets';
4
5
  export * from './model-context';
@@ -35,6 +35,8 @@ export interface SceneLoadOptions {
35
35
  serverOptions?: ServerOptions;
36
36
  /** Whether to automatically apply scene settings (default: true) */
37
37
  applySettings?: boolean;
38
+ /** 'direct' parses glTF JSON straight with GLTFLoader (view-only fast path). */
39
+ parseMode?: 'document' | 'direct';
38
40
  }
39
41
  /**
40
42
  * Configuration options for loading an already-resolved scene payload.
@@ -46,6 +48,8 @@ export interface SceneDataLoadOptions {
46
48
  sceneData: ServerSceneData;
47
49
  /** Whether to automatically apply scene settings (default: true) */
48
50
  applySettings?: boolean;
51
+ /** 'direct' parses glTF JSON straight with GLTFLoader (view-only fast path). */
52
+ parseMode?: 'document' | 'direct';
49
53
  }
50
54
  /**
51
55
  * Result of a scene load operation based on server data.
@@ -0,0 +1,10 @@
1
+ import { SceneAssetRefMap, SerializedSceneAssetDataMap } from '../../../../core/src/index.ts';
2
+ export interface FetchManifestAssetsOptions {
3
+ headers?: HeadersInit;
4
+ onProgress?: (fraction: number) => void;
5
+ }
6
+ /**
7
+ * Fetches manifest asset refs in parallel into raw byte entries.
8
+ * Progress is byte-weighted when all sizes are known, count-weighted otherwise.
9
+ */
10
+ export declare function fetchManifestAssetData(assetRefs: SceneAssetRefMap, options?: FetchManifestAssetsOptions): Promise<SerializedSceneAssetDataMap>;
@@ -2,3 +2,4 @@ export { default as readDirectory } from './read-directory';
2
2
  export { reconstructGltfFiles } from './reconstruct-files';
3
3
  export { calculateReferencedBytesFromFiles, calculateReferencedBytesFromServerScene } from './calculate-referenced-bytes';
4
4
  export { resolveServerSceneDataContract } from './resolve-scene-payload';
5
+ export { fetchManifestAssetData, type FetchManifestAssetsOptions } from './fetch-manifest-assets';
@@ -0,0 +1 @@
1
+ let e=require("@vctrl/core"),t=require("@vctrl/core/model-loader"),n=require("react");var r=({code:e,message:t,recoverable:n,source:r,cause:i,context:a})=>({code:e,message:t,recoverable:n,source:r,cause:i,context:a}),i=e=>e instanceof Error&&e.message?e.message:typeof e==`string`&&e.trim().length>0?e:`Unknown error`,a=(e,t,n)=>{let a=i(e);return r({code:a.includes(`missing required referenced assets`)?`missing_assets`:t,message:a,recoverable:!0,source:`local-upload`,cause:e,context:n})},o=(e,t)=>{let n=i(e),a=`server_load_failed`;return n.includes(`Server responded with 404`)?a=`not_found`:(n.includes(`Server responded with 402`)||n.includes(`Server responded with 403`))&&(a=`quota_exceeded`),r({code:a,message:n,recoverable:a!==`not_found`,source:`server-load`,cause:e,context:{sceneId:t}})},s={},c={emit(e,t){let n=s[e];console.debug(`Event emitted: ${e}`,t),n&&n.forEach(e=>e(t))},on(e,t){s[e]||(s[e]=[]),s[e].push(t)},off(e,t){let n=s[e];n&&(s[e]=n.filter(e=>e!==t))}},l=t=>{try{return(0,e.normalizeAssetUri)(t)}catch{return t}},u=e=>{let t=new Set,n=e,r=Array.isArray(n.images)?n.images:[];for(let e of r)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&t.add(e.uri);let i=Array.isArray(n.buffers)?n.buffers:[];for(let e of i)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&t.add(e.uri);return t},d=async(t,n)=>{let r=JSON.parse(await t.text()),i=u(r),a={},o=new Map,s=new Map,c=new Set,d=async e=>{let t=s.get(e);if(t)return t;let n=new Uint8Array(await e.arrayBuffer());return s.set(e,n),n};for(let t of n){for(let n of(0,e.buildAssetLookupKeys)(t.name))o.set(n,t);if(t.webkitRelativePath)for(let n of(0,e.buildAssetLookupKeys)(t.webkitRelativePath))o.set(n,t)}let f=[];for(let e of i){let t=l(e),n=t.split(`/`).pop()||t,r=o.get(e)||o.get(t)||o.get(n);if(!r){f.push(e);continue}c.add(r);let i=await d(r);a[t]={data:Array.from(i),fileName:t,mimeType:r.type||`application/octet-stream`}}if(f.length>0)throw Error(`Scene payload is missing required referenced assets: ${f.slice(0,5).join(`, `)}`);for(let[e,t]of n.entries()){if(c.has(t))continue;let n=l(t.name),r=n.split(`/`).pop()||n,i=await d(t);a[`extra-${e}-${r}`]={data:Array.from(i),fileName:r,mimeType:t.type||`application/octet-stream`}}return{gltfJson:r,assetData:a}},f=async(e,n,r,i,o)=>{try{let a={model:(await r.loadToThreeJS(e)).scene,type:n,name:e.name};if(o({type:`set-file`,payload:a}),o({type:`set-file-loading`,payload:!1}),i&&n!==t.ModelFileTypes.usdz){let t=new Uint8Array(await e.arrayBuffer());await i.loadFromGlbBuffer(t)}return a}catch(t){return console.error(`Error loading binary model:`,t),o({type:`set-file-loading`,payload:!1}),c.emit(`load-error`,a(t,`binary_load_failed`,{fileName:e.name,fileType:n,fileSize:e.size})),null}},p=async(e,n,r,i,o,s)=>{try{let{sourcePackageBytes:a,textureBytes:c}=await s(e,n),l=await r.loadGLTFWithAssetsToThreeJS(e,n),u={model:l.scene,type:t.ModelFileTypes.gltf,name:e.name,sourcePackageBytes:a,sourceTextureBytes:c};if(o({type:`set-file`,payload:u}),o({type:`set-file-loading`,payload:!1}),i)try{let t=await d(e,n);await i.loadFromServerSceneData(t)}catch(t){console.warn(`Failed to initialize optimizer from source GLTF payload; trying direct asset load.`,t);try{if(`loadFromGLTFWithAssets`in i){let t=new Uint8Array(await e.arrayBuffer()),r=new Map;for(let e of n){let t=new Uint8Array(await e.arrayBuffer());r.set(e.name,t),e.webkitRelativePath&&r.set(e.webkitRelativePath,t)}await i.loadFromGLTFWithAssets(t,r)}else throw Error(`loadFromGLTFWithAssets not available`)}catch(e){console.warn(`Direct asset load also failed; falling back to Three.js scene import. Texture names may be generic.`,e),await i.load(l.scene)}}return u}catch(t){return console.error(`Error loading GLTF model:`,t),console.error(`GLTF file:`,e.name),console.error(`Asset files:`,n.map(e=>e.name)),o({type:`set-file-loading`,payload:!1}),c.emit(`load-error`,a(t,`gltf_load_failed`,{fileName:e.name,fileSize:e.size,assetCount:n.length})),null}};function m(e,r,i,a){let o=(0,n.useCallback)(async(n,o)=>{if(!e){console.warn(`Optimizer is not available`);return}try{n&&await n(o);let s=await e.getModel();if(!s){console.warn(`No optimized model available after optimization`);return}let c=s instanceof Uint8Array?s.slice():new Uint8Array(s).slice(),l=new File([c],i?.name||`optimized_model.glb`,{type:`model/gltf-binary`});r({type:`set-file`,payload:{model:(await a.loadToThreeJS(l)).scene,type:t.ModelFileTypes.glb,name:l.name}})}catch(e){console.error(`Optimization failed:`,e)}},[e,a,i,r]);if(!e)return null;let s=e.isReady,c=!!i?.model&&!s;return{...e,isReady:s,isPreparing:c,applyOptimization:o,reset:e?.reset,error:e?.error,loading:e?.loading}}var h={file:null,isFileLoading:!1,progress:0,supportedFileTypes:[t.ModelFileTypes.gltf,t.ModelFileTypes.glb,t.ModelFileTypes.usdz]};function g(e,t){switch(t.type){case`set-file`:return{...e,file:t.payload};case`set-file-loading`:return{...e,isFileLoading:t.payload};case`set-progress`:return{...e,progress:t.payload};case`reset-state`:return{...h};default:return e}}async function _(e){let t=[];async function*n(e){let t=e;for await(let[,e]of t)e.kind===`file`?yield await e.getFile():e.kind===`directory`&&(yield*n(e))}for await(let r of n(e))t.push(r);return t}function v(t){let n=[];if(t.assetData&&typeof t.assetData==`object`)for(let[,r]of Object.entries(t.assetData)){let{fileName:t,mimeType:i}=r;if(t===e.PERSISTED_BAKE_FILENAME)continue;let a=(0,e.toSerializedAssetBytes)(r),o=new Uint8Array(a.byteLength);o.set(a);let s=new Blob([o],{type:i}),c=new File([s],t,{type:i});n.push(c)}let r=JSON.stringify(t.gltfJson),i=new Blob([r],{type:`model/gltf+json`}),a=t.meta?.name,o=a?`${a}.gltf`:`scene.gltf`;return[new File([i],o,{type:`model/gltf+json`}),...n]}var y=(t,n)=>{let r=(0,e.normalizeAssetUri)(t),i=r.split(`/`).pop()||r;for(let t of n){let n=(0,e.buildAssetLookupKeys)(t.fileName);if(n.has(r)||n.has(i))return t.size}return 0},b=e=>{let t=new Set,n=new Set,r=e,i=Array.isArray(r.images)?r.images:[];for(let e of i)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&n.add(e.uri);let a=Array.isArray(r.buffers)?r.buffers:[];for(let e of a)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&t.add(e.uri);return{bufferUris:t,imageUris:n}};async function x(e,t){let n=await e.text(),r;try{r=JSON.parse(n)}catch{return{sourcePackageBytes:e.size,textureBytes:0}}let i=t.map(e=>({fileName:e.name,size:e.size})),{bufferUris:a,imageUris:o}=b(r),s=Array.from(a).reduce((e,t)=>e+y(t,i),0),c=Array.from(o).reduce((e,t)=>e+y(t,i),0);return{sourcePackageBytes:e.size+s+c,textureBytes:c}}function S(t){let n=t.gltfJson,r=Object.values(t.assetData||{}).map(t=>({fileName:t.fileName,size:(0,e.getSerializedAssetByteSize)(t.data)})),i=new TextEncoder().encode(JSON.stringify(n)).byteLength,{bufferUris:a,imageUris:o}=b(n),s=Array.from(a).reduce((e,t)=>e+y(t,r),0),c=Array.from(o).reduce((e,t)=>e+y(t,r),0);return{sourcePackageBytes:i+s+c,textureBytes:c}}function C(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function w(t){let n=C(t.settings)?t.settings:{},r=(0,e.normalizeCameraSettings)(t.camera??n.camera);return{...n,bounds:t.bounds??n.bounds,camera:r,interactions:(0,e.normalizeSceneInteractions)(n.interactions,{camera:r}),controls:t.controls??n.controls,environment:t.environment??n.environment,shadows:t.shadows??n.shadows}}function T(e){let t=new Set,n=e,r=Array.isArray(n.images)?n.images:[];for(let e of r)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&t.add(e.uri);let i=Array.isArray(n.buffers)?n.buffers:[];for(let e of i)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&t.add(e.uri);return t}function E(t){for(let[n,r]of Object.entries(t)){if(!r||typeof r!=`object`)throw Error(`Scene payload contains invalid asset entry for ${n}`);if(typeof r.fileName!=`string`||r.fileName.trim().length===0)throw Error(`Scene payload asset ${n} is missing a valid fileName`);if(typeof r.mimeType!=`string`||r.mimeType.trim().length===0)throw Error(`Scene payload asset ${n} is missing a valid mimeType`);if(typeof r.data==`string`&&r.encoding===`base64`&&!(0,e.isValidBase64)(r.data))throw Error(`Scene payload asset ${r.fileName} has invalid base64 data`)}}function D(t,n){let r=T(t);if(r.size===0)return;let i=new Set;for(let t of Object.values(n))for(let n of(0,e.buildAssetLookupKeys)(t.fileName))i.add(n);let a=[];for(let t of r){let n=(0,e.normalizeAssetUri)(t),r=n.split(`/`).pop()||n;!i.has(t)&&!i.has(n)&&!i.has(r)&&a.push(t)}if(a.length>0)throw Error(`Scene payload is missing required referenced assets: ${a.slice(0,5).join(`, `)}`)}function O(e){if(!C(e.gltfJson))throw Error(`Scene payload is missing a valid glTF document`);let t=e.assetData??{};return E(t),D(e.gltfJson,t),{meta:e.meta,gltfJson:e.gltfJson,assetData:t,...w(e)}}async function k(e,t={}){let n=Object.entries(e);if(n.length===0)return t.onProgress?.(1),{};let r=n.every(([,e])=>e.byteSize!=null),i=r?n.reduce((e,[,t])=>e+(t.byteSize??0),0):0,a=0,o=0,s={},c=new AbortController;return await Promise.all(n.map(async([e,l])=>{try{let u=await fetch(l.url,{headers:t.headers,credentials:`same-origin`,signal:c.signal});if(!u.ok)throw c.abort(),Error(`Failed to fetch scene asset ${l.fileName}: ${u.status}`);s[e]={data:new Uint8Array(await u.arrayBuffer()),fileName:l.fileName,mimeType:l.mimeType},o+=1,a+=l.byteSize??0,t.onProgress?.(r&&i>0?a/i:o/n.length)}catch(e){throw c.abort(),e}})),s}async function A(e,t){try{let n=await fetch(e,{method:`GET`,headers:{Accept:`application/json`,...t}});if(!n.ok)return null;let r=await n.json(),i=r.data??r;return!i||typeof i!=`object`||!i.gltfJson||!i.assetRefs&&!i.assetData?null:i}catch{return null}}async function j(e,t,n){let r=new FormData;r.append(`action`,`get-scene-settings`),r.append(`sceneId`,n);let i=await fetch(e,{method:`POST`,headers:t,body:r});if(!i.ok)throw Error(`Server responded with ${i.status} ${i.statusText}`);let a=await i.json();return a.data??a}function M(r){let i=(0,n.useRef)(!1),a=(0,n.useRef)(null),[s,l]=(0,n.useReducer)(g,h),u=(0,n.useMemo)(()=>{let e=new t.ModelLoader;return e.onProgress(e=>{l({type:`set-progress`,payload:e.progress}),e.progress!==100&&c.emit(`load-progress`,e.progress)}),e},[]),d=(0,n.useCallback)(e=>{l({type:`set-progress`,payload:e}),c.emit(`load-progress`,e)},[]),y=(0,n.useCallback)(()=>{l({type:`reset-state`}),c.emit(`load-reset`)},[]),b=(0,n.useCallback)((e,t)=>e.find(e=>e.name.endsWith(`.`+t)),[]),C=(0,n.useCallback)(async e=>{if(e.length===0)return;let n=b(e,t.ModelFileTypes.gltf),o=b(e,t.ModelFileTypes.glb),s=b(e,t.ModelFileTypes.usdz),d=[n,o,s].filter(Boolean);if(d.length>1){c.emit(`multiple-models`,d);return}let m=e.filter(e=>e!==n&&e!==o&&e!==s),h=()=>{i.current=!0,a.current&&(c.emit(`load-complete`,a.current),i.current=!1)};if(n){let e=await p(n,m,u,r,l,x);e&&(a.current=e),h()}else if(o){let e=await f(o,t.ModelFileTypes.glb,u,r,l);e&&(a.current=e),h()}else if(s){let e=await f(s,t.ModelFileTypes.usdz,u,r,l);e&&(a.current=e),h()}else c.emit(`not-loaded-files`,e),l({type:`set-file-loading`,payload:!1})},[b,u,r]),w=(0,n.useCallback)(async e=>{let t=[];c.emit(`load-start`),l({type:`reset-state`}),l({type:`set-file-loading`,payload:!0}),d(0),i.current=!1;for(let n of e)if(n instanceof File)t.push(n);else if(`kind`in n&&n.kind===`directory`){let e=await _(n);t.push(...e)}await C(t)},[C,d]),T=(0,n.useCallback)(async n=>{let{sceneData:i,sceneId:o}=n;if(d(40),n.parseMode===`direct`&&i.gltfJson){let n=new Map;for(let t of Object.values(i.assetData??{}))t.fileName!==e.PERSISTED_BAKE_FILENAME&&n.set(t.fileName,(0,e.toSerializedAssetBytes)(t));let{sourcePackageBytes:r,textureBytes:s}=S(i);d(60);let c={model:(await u.parseGLTFJsonToThreeJS(i.gltfJson,n)).scene,type:t.ModelFileTypes.gltf,name:i.meta?.name||`scene`,sourcePackageBytes:r,sourceTextureBytes:s};return l({type:`set-file`,payload:c}),l({type:`set-file-loading`,payload:!1}),a.current=c,d(100),{file:c,sceneId:o,...i}}let s=v(i),{sourcePackageBytes:c,textureBytes:f}=S(i);d(60);let p=s[0],m=s.slice(1),h={model:(await u.loadGLTFWithAssetsToThreeJS(p,m)).scene,type:t.ModelFileTypes.gltf,name:p.name,sourcePackageBytes:c,sourceTextureBytes:f};return l({type:`set-file`,payload:h}),l({type:`set-file-loading`,payload:!1}),a.current=h,r&&await r.loadFromServerSceneData(i),d(100),{file:h,sceneId:o,...i}},[u,r,d]),E=(0,n.useCallback)(async e=>{let{sceneId:t,serverOptions:n,parseMode:r}=e;try{c.emit(`server-load-start`,t),l({type:`reset-state`}),l({type:`set-file-loading`,payload:!0}),d(0);let e=n?.endpoint??`/api/scenes/${t}`,i=n?.apiKey?{Authorization:`Bearer ${n.apiKey}`,...n.headers}:{...n?.headers},a=await A(e,i);if(a?.assetRefs&&!a.assetData){d(10);let e=await k(a.assetRefs,{headers:i,onProgress:e=>d(10+Math.round(e*30))});a={...a,assetData:e}}a||=await j(e,i,t);let o=await T({sceneId:t,sceneData:O(a),parseMode:r});return c.emit(`server-load-complete`,o),o}catch(e){console.error(`Server scene loading failed:`,e),l({type:`set-file-loading`,payload:!1});let n=o(e,t);throw c.emit(`server-load-error`,n),n}},[T,d]),D=m(r,l,s.file,u);return{...s,on:c.on,off:c.off,load:w,loadFromData:T,loadFromServer:E,reset:y,optimizer:D}}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return M}});