rayzee 11.13.0 → 11.14.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.
Files changed (59) hide show
  1. package/README.md +59 -4
  2. package/dist/{ArchiveImporter-DQU55mit.js → ArchiveImporter-DBMmDG98.js} +97 -92
  3. package/dist/{BidirectionalIntegrator-CLmFjSN3.js → BidirectionalIntegrator-D6rcU7N1.js} +199 -198
  4. package/dist/{ColorManagement-3xw0xXRg.js → ColorManagement-D9eYhssc.js} +1083 -547
  5. package/dist/DepthPass-D4Zh108s.js +68 -0
  6. package/dist/{EngineIssues-CfJiBaNj.js → EngineIssues-B14FGIHX.js} +1 -0
  7. package/dist/{NeuralRetouch-CEkBhI1M.js → NeuralRetouch-Cyh0AwUT.js} +3 -3
  8. package/dist/{NeuralSuperRes-Drjws9nE.js → NeuralSuperRes-BPp05Ipu.js} +3 -3
  9. package/dist/{SolarLimb-ZYl-Pwl0.js → PackedRayBuffer-BtJJxs43.js} +3 -7
  10. package/dist/{PathTracer-7a7L3cGF.js → PathTracer-BLV2bVqi.js} +3372 -4160
  11. package/dist/{PhysicalSky-DUIbTE93.js → PhysicalSky-VonV_lAD.js} +46 -45
  12. package/dist/{RayzeeRenderer-CjjGT2e0.js → RayzeeRenderer-D1NeGoVA.js} +787 -453
  13. package/dist/{SceneMetadata-CoAHTAmo.js → SceneMetadata-BBx6k2EY.js} +1 -1
  14. package/dist/SolarLimb-DSig_M0f.js +8 -0
  15. package/dist/TextureBuckets-CcSAhgVc.js +308 -0
  16. package/dist/TextureSampling-C4Sg4Yw_.js +901 -0
  17. package/dist/{ToneMapGPU-4GPwoG_c.js → ToneMapGPU-l_79riZd.js} +21 -11
  18. package/dist/addons/archives.es.js +2 -2
  19. package/dist/addons/bidirectional.es.js +1 -1
  20. package/dist/addons/color.es.js +3 -3
  21. package/dist/addons/formats.es.js +1 -1
  22. package/dist/addons/physical-sky.es.js +1 -1
  23. package/dist/addons/storage.es.js +2 -2
  24. package/dist/encoders.es.js +942 -0
  25. package/dist/{openStorage-CdyVjmps.js → openStorage-D6DBv9_I.js} +3 -3
  26. package/dist/rayzee-core.es.js +12 -11
  27. package/dist/rayzee.es.js +179 -176
  28. package/dist/rayzee.umd.js +149 -107
  29. package/dist/{sceneCachePolicy-DavHt6Ii.js → sceneCachePolicy-DcEWCTKO.js} +179 -485
  30. package/package.json +4 -1
  31. package/src/Color/BakedViews.js +5 -1
  32. package/src/Color/BasicColor.js +7 -0
  33. package/src/Color/ColorManagement.js +64 -42
  34. package/src/Color/Displays.js +35 -0
  35. package/src/Color/LutBake.js +163 -9
  36. package/src/Color/OcioViews.js +508 -55
  37. package/src/EngineIssues.js +1 -0
  38. package/src/Processor/ImageEncoders.js +1306 -0
  39. package/src/Processor/SceneProcessor.js +1 -1
  40. package/src/Processor/TextureCreator.js +154 -48
  41. package/src/Processor/ToneMapCPU.js +35 -9
  42. package/src/Processor/ToneMapGPU.js +52 -6
  43. package/src/Processor/Workers/TexturesWorker.js +10 -13
  44. package/src/RayzeeRenderer.js +303 -36
  45. package/src/Stages/Compositor.js +112 -18
  46. package/src/Stages/PathTracer.js +22 -0
  47. package/src/Stages/PathTracerStage.js +63 -1
  48. package/src/Storage/SceneGraphCodec.js +17 -2
  49. package/src/TSL/DepthPass.js +146 -0
  50. package/src/managers/VideoRenderManager.js +6 -2
  51. /package/dist/{ActiveColor-YvuQq44O.js → ActiveColor-7CZdmrsz.js} +0 -0
  52. /package/dist/{AssetConfig-DSEntE65.js → AssetConfig-BY4jDfTH.js} +0 -0
  53. /package/dist/{BufferLayout-BROyMqO1.js → BufferLayout-SvkefbAs.js} +0 -0
  54. /package/dist/{FileFormats-sPGJeCRc.js → FileFormats-B_VqIVDq.js} +0 -0
  55. /package/dist/{ViewTransforms-CYN7bq2w.js → ViewTransforms-Crdom11t.js} +0 -0
  56. /package/dist/{WorkingMatrix-C6y233hT.js → WorkingMatrix-DWJV2JM2.js} +0 -0
  57. /package/dist/{ZipReader-gDSWr0I5.js → ZipReader-Bva4oiva.js} +0 -0
  58. /package/dist/{identity-C1cLD1C0.js → identity-CtOwEU7N.js} +0 -0
  59. /package/dist/{shared-BGBcSxBQ.js → shared-ubP8eJlr.js} +0 -0
package/README.md CHANGED
@@ -533,7 +533,7 @@ To pause rendering for image-viewing UI, set `engine.pauseRendering = true` and
533
533
 
534
534
  ### Renderer core (`rayzee/core`)
535
535
 
536
- `PathTracerApp` is built on `RayzeeRenderer`, the renderer without the viewer: a scene and camera in, path-traced samples accumulated, the image out. The denoisers, camera controls, gizmo, overlays, timeline and animation playback exist only in `PathTracerApp`; six capabilities come as add-ons — file formats beyond glTF and `.hdr`, the physical sky, scene archives, bidirectional path tracing, OpenColorIO colour and on-disk storage. Its entry point downloads about 40 % less (249 KB against 418 KB compressed). It takes the same constructor options except `container`, and renders the same pixels.
536
+ `PathTracerApp` is built on `RayzeeRenderer`, the renderer without the viewer: a scene and camera in, path-traced samples accumulated, the image out. The denoisers, camera controls, gizmo, overlays, timeline and animation playback exist only in `PathTracerApp`; six capabilities come as add-ons — file formats beyond glTF and `.hdr`, the physical sky, scene archives, bidirectional path tracing, OpenColorIO colour and on-disk storage. Its entry point downloads about 30 % less at startup (277 KB against 404 KB compressed). It takes the same constructor options except `container`, and renders the same pixels.
537
537
 
538
538
  ```js
539
539
  import { RayzeeRenderer } from 'rayzee/core';
@@ -890,8 +890,8 @@ await engine.unloadColorConfig();
890
890
  ```
891
891
 
892
892
  - **Load and unload through `engine.loadColorConfig()` / `unloadColorConfig()`** once a scene exists: they undo an adopted working space while the config that converted the environment is still loaded.
893
- - A view is baked to a log2 shaper and a 65³ table, interpolated tetrahedrally; the same table drives the canvas, the GPU and CPU readbacks and the menu (`listViewTransforms()`, `onRegistryChange()`). An OCIO view returns display-encoded colour, so the engine switches the output pass to linear while one is active.
894
- - **Baked views.** `await engine.color.saveBakedView(id)` writes a view's table to a file (157 KB gzip for 65³), and `await engine.color.loadBakedView(bytes, { expect })` registers it with no runtime and no config — show the look on the first frame, load the config later. When that config loads, a baked view whose files match the fingerprint it was baked from is kept as is: no rebake, no new id, no restart.
893
+ - A view is baked to a log2 shaper and a 65³ table, interpolated tetrahedrally — where that measures poorly, on linear Rec.709's axes and at 97³, whichever is closer (`entry.error` says what it cost); the same table drives the canvas, the GPU and CPU readbacks and the menu (`listViewTransforms()`, `onRegistryChange()`). An OCIO view returns display-encoded colour, so the engine switches the output pass to linear while one is active.
894
+ - **Baked views.** `await engine.color.saveBakedView(id)` writes a view's table to a file (157 KB gzip for 65³, 426 KB for 97³), and `await engine.color.loadBakedView(bytes, { expect })` registers it with no runtime and no config — show the look on the first frame, load the config later. When that config loads, a baked view whose files match the fingerprint it was baked from is kept as is: no rebake, no new id, no restart.
895
895
  - `renderToBuffer({ colorSpace })` takes `'srgb'` (display bytes through the active view), `'linear'` (the working-space accumulation) or a config colour space; `source: 'display'` reads what the viewport shows, denoised, instead of the raw accumulation.
896
896
  - Degradations (a view that cannot bake, a display the canvas cannot show) are recorded as warnings in the [degradation contract](#degradation-contract).
897
897
 
@@ -1083,6 +1083,7 @@ surface** — pin a version and branch on the strings; they are never renamed or
1083
1083
  | `denoiser.unavailable` | a requested denoise or upscale produced nothing — the denoiser was not built, OIDN was off while accumulating, or the pass needs a canvas in a document |
1084
1084
  | `output.source_fallback` | `renderToBuffer( { source: 'display' } )` found no denoised picture and returned the raw accumulation |
1085
1085
  | `output.tonemap_fallback` | `renderToBuffer`'s `'srgb'` bytes were tone-mapped on the CPU, not the GPU — the picture is the same within a level, only slower (a warning: strict does not throw) |
1086
+ | `output.pass_unavailable` | `exportImage` was asked for an EXR layer it cannot write, such as `albedo` or `normal` with no denoiser on (`detail.pass`); the file is written without it |
1086
1087
  | `light.placeholder_skipped` | a `RectAreaLightPlaceholder` node lacked `userData.name` or `userData.type: 'RectAreaLight'`, so no light was made for it |
1087
1088
  | `capability.missing` | a feature was asked for whose add-on is not installed on the core (procedural sky, an unregistered integrator, a colour config, storage) — names the add-on |
1088
1089
  | `color.config_load_failed` / `viewTransform.bake_failed` / `viewTransform.display_mismatch` | a colour config failed to load (the previous one stays), a view could not be rebaked, or a view targets a display the canvas cannot show (a saved buffer is still right) — warnings |
@@ -1111,7 +1112,7 @@ setting as `{ value, source, routed }`, and `routed: false` means stored but rea
1111
1112
 
1112
1113
  ### Output Methods
1113
1114
 
1114
- Canvas output, screenshots, and scene statistics — accessed as direct methods on the engine.
1115
+ Canvas output, screenshots, saved files and scene statistics — accessed as direct methods on the engine.
1115
1116
 
1116
1117
  ```js
1117
1118
  engine.getCanvas() // Get the canvas with the final rendered image
@@ -1135,6 +1136,54 @@ a.click();
1135
1136
  URL.revokeObjectURL(url);
1136
1137
  ```
1137
1138
 
1139
+ #### Saving a file
1140
+
1141
+ `exportImage()` writes the render as a file and returns `{ blob, extension, mimeType, width, height, colorSpace, … }`.
1142
+ It works on the core too, and headless.
1143
+
1144
+ | `format` | What the file holds |
1145
+ |---|---|
1146
+ | `'png'` (`bitDepth: 8` or `16`), `'jpeg'`, `'webp'` | the picture the canvas shows: exposure, view and denoising applied; at 8 bits, JPEG and WebP, the AI upscaler's picture while one shows (`upscaled: false` skips it) |
1147
+ | `'heic'`, `'avif'` | the same picture, written by the browser's video encoder |
1148
+ | `'exr'` (`precision: 'half'` or `'float'`), `'hdr'` (Radiance) | the light itself, before exposure and view, in the working space or `colorSpace`; with `asShown: true`, the light the screen gives off for the picture, so any viewer shows it as the screen does |
1149
+
1150
+ ```js
1151
+ const { blob, extension } = await engine.exportImage({ format: 'png', bitDepth: 16 });
1152
+ const exr = await engine.exportImage({ format: 'exr', passes: ['albedo', 'normal', 'depth'] });
1153
+ const photo = await engine.exportImage({ format: 'jpeg', gainMap: true }); // an HDR photo
1154
+ engine.exportInfo(); // what can be written now: { width, height, upscaled, hdr, layers: { albedo, normal, depth } }
1155
+ ```
1156
+
1157
+ - **HDR photos.** `gainMap: true` on `'jpeg'`, `'heic'` or `'avif'` adds a gain map — a second, small picture that
1158
+ says how much brighter each part of the HDR version is (ISO 21496-1; Ultra HDR in a JPEG). Photo viewers that read gain
1159
+ maps show the file in HDR, others the normal picture. It needs the screen showing HDR
1160
+ (`engine.color.setHdrOutput(true)` on an HDR display; `exportInfo().hdr`).
1161
+ - **EXR layers.** `albedo` and `normal` are the denoisers' guide images, so they exist only while a denoiser is on;
1162
+ `depth` is measured when asked for. A layer that cannot be written records `output.pass_unavailable`.
1163
+ - **Where each works.** JPEG, WebP, HEIC and AVIF need a browser (its canvas or video encoder); PNG, EXR and HDR work in
1164
+ Node too. `canEncodeStill('heic')` from `rayzee/encoders` says whether this browser can write HEIC or AVIF.
1165
+ - Render details (samples, size, view, settings, versions) go into the file, except a WebP, unless `metadata: false`.
1166
+ The file writers download on the first export, not at startup.
1167
+
1168
+ The writers are also a module of their own, `rayzee/encoders`, for pixels a host already has. It is part of the
1169
+ package, not an add-on: nothing to install, and importing it loads nothing else (9 KB compressed).
1170
+
1171
+ ```js
1172
+ import { encodePNG, encodeEXR, encodeHDR, IMAGE_FORMATS } from 'rayzee/encoders';
1173
+
1174
+ const png = await encodePNG({ data, width, height }); // RGBA, Uint8Array (8 bits) or Uint16Array (16), top row first
1175
+ const hdr = await encodeHDR({ data: floats, width, height }); // RGBA Float32Array
1176
+ const exr = await encodeEXR({ width, height, channels: [
1177
+ { name: 'R', data: floats, stride: 4, offset: 0 },
1178
+ { name: 'G', data: floats, stride: 4, offset: 1 },
1179
+ { name: 'B', data: floats, stride: 4, offset: 2 },
1180
+ ] });
1181
+ ```
1182
+
1183
+ Chrome on macOS takes about 5 seconds to start its first hardware video encoder after the browser launches, and about
1184
+ 2 ms after that. HEIC and MP4 both use it. `prepareStill('heic')` starts it ahead of time without encoding anything,
1185
+ for example when an export menu opens.
1186
+
1138
1187
  ---
1139
1188
 
1140
1189
  ### Render Resolution Reserve
@@ -1616,6 +1665,12 @@ import { acquireSharedStorage } from 'rayzee/addons/storage';
1616
1665
  // Headless rendering (see Deterministic & Headless Rendering)
1617
1666
  import { renderHeadless, openHeadless, captureHeadless } from 'rayzee';
1618
1667
 
1668
+ // File writers behind exportImage(), for pixels a host already has (see Saving a file)
1669
+ import {
1670
+ IMAGE_FORMATS, encodePNG, encodeEXR, encodeHDR, encodeWithCanvas, encodeGainMapJPEG,
1671
+ encodeStill, canEncodeStill, prepareStill,
1672
+ } from 'rayzee/encoders';
1673
+
1619
1674
  // Platform services for hosts without a browser (see Running in Node)
1620
1675
  import { configurePlatform, getPlatform } from 'rayzee';
1621
1676
  import { nodePlatform, NodeWorker } from 'rayzee/node';
@@ -1,10 +1,10 @@
1
- import { n as e } from "./BidirectionalIntegrator-CLmFjSN3.js";
2
- import { A as t, T as n, Z as r, at as i, n as a, r as o, st as s, v as c, x as l } from "./sceneCachePolicy-DavHt6Ii.js";
3
- import { n as u, r as d, t as f } from "./EngineIssues-CfJiBaNj.js";
4
- import { r as p } from "./shared-BGBcSxBQ.js";
5
- import { i as m, n as h, o as g, r as _ } from "./identity-C1cLD1C0.js";
6
- import { a as v, s as y, t as b } from "./SceneMetadata-CoAHTAmo.js";
7
- import { n as x, t as S } from "./ZipReader-gDSWr0I5.js";
1
+ import { n as e } from "./BidirectionalIntegrator-D6rcU7N1.js";
2
+ import { A as t, B as n, J as r, T as i, X as a, n as o, r as s, v as c, x as l } from "./sceneCachePolicy-DcEWCTKO.js";
3
+ import { n as u, r as d, t as f } from "./EngineIssues-B14FGIHX.js";
4
+ import { r as p } from "./shared-ubP8eJlr.js";
5
+ import { i as m, n as h, o as g, r as _ } from "./identity-CtOwEU7N.js";
6
+ import { a as v, s as y, t as b } from "./SceneMetadata-BBx6k2EY.js";
7
+ import { n as x, t as S } from "./ZipReader-Bva4oiva.js";
8
8
  import { AnimationClip as C, BooleanKeyframeTrack as w, BoxGeometry as T, BufferAttribute as E, BufferGeometry as D, CapsuleGeometry as ee, ClampToEdgeWrapping as te, Color as O, ConeGeometry as ne, CylinderGeometry as re, DataTexture as k, DirectionalLight as ie, DoubleSide as A, EquirectangularReflectionMapping as ae, Euler as oe, Float32BufferAttribute as j, FloatType as se, FrontSide as ce, Group as le, InstancedBufferAttribute as ue, InstancedMesh as de, LinearFilter as fe, LoadingManager as pe, MaterialLoader as me, Matrix4 as M, Mesh as he, MeshPhysicalMaterial as N, MirroredRepeatWrapping as ge, NoColorSpace as _e, NumberKeyframeTrack as ve, Object3D as ye, OrthographicCamera as be, PerspectiveCamera as xe, PlaneGeometry as Se, PointLight as Ce, Quaternion as we, QuaternionKeyframeTrack as Te, RGBAFormat as Ee, RectAreaLight as De, RepeatWrapping as Oe, SRGBColorSpace as P, SphereGeometry as ke, SpotLight as Ae, Texture as je, Uint32BufferAttribute as F, Vector3 as I, VectorKeyframeTrack as Me } from "three";
9
9
  import { HDRLoader as Ne } from "three/addons/loaders/HDRLoader.js";
10
10
  import { Gunzip as Pe, strFromU8 as Fe } from "three/addons/libs/fflate.module.js";
@@ -646,44 +646,49 @@ function Vt(e, t) {
646
646
  }
647
647
  async function Ht(e, t, { loadTexture: n }) {
648
648
  if (e?.v !== 2) throw Error("scene graph: unknown format");
649
- let r = await Rt(t, zt(e)), i = (e) => r.get(e.offset), a = /* @__PURE__ */ new Map(), o = {};
649
+ let r = await Rt(t, zt(e)), i = (e) => r.get(e.offset), a = /* @__PURE__ */ new Map(), o = {}, s = /* @__PURE__ */ new Map();
650
650
  for (let t of e.textures) {
651
651
  let e;
652
652
  if (t.path) {
653
- if (e = await n(t.path, t.loader), !e) throw Error(`scene graph: "${t.path}" is missing from the archive`);
653
+ let r = `${t.loader}|${t.path}`, i = s.get(r);
654
+ if (i) e = i.clone(), e.userData = {};
655
+ else {
656
+ if (e = await n(t.path, t.loader), !e) throw Error(`scene graph: "${t.path}" is missing from the archive`);
657
+ s.set(r, e);
658
+ }
654
659
  e.userData[_t] = t.path, e.userData[vt] = t.loader;
655
660
  } else e = new k(i(t.data.section), t.data.width, t.data.height);
656
661
  Vt(e, t), o[t.uuid] = e;
657
662
  }
658
- let s = new me().setTextures(o), c = {};
663
+ let c = new me().setTextures(o), l = {};
659
664
  for (let t of e.materials) {
660
- let e = s.parse(t);
665
+ let e = c.parse(t);
661
666
  for (let [n, r] of Object.entries(t.exactColors ?? {})) n === "diffuseTransmissionColor" && (e[n] = new O()), e[n]?.setRGB(r[0], r[1], r[2]);
662
667
  t.exactIor !== void 0 && (e.ior = t.exactIor), t.diffuseTransmission !== void 0 && (e.diffuseTransmission = t.diffuseTransmission), t.diffuseRoughness !== void 0 && (e.diffuseRoughness = t.diffuseRoughness);
663
668
  for (let [n, r] of Object.entries(t.engineTextures ?? {})) o[r] && (e[n] = o[r]);
664
- c[t.uuid] = e;
669
+ l[t.uuid] = e;
665
670
  }
666
- let l = {};
671
+ let u = {};
667
672
  for (let t of e.geometries) {
668
673
  let e = new D();
669
674
  e.uuid = t.uuid, e.name = t.name;
670
675
  for (let [n, i] of Object.entries(t.attributes)) e.setAttribute(n, Bt(r, i));
671
676
  t.index && e.setIndex(Bt(r, t.index));
672
677
  for (let n of t.groups) e.addGroup(n.start, n.count, n.materialIndex);
673
- e.setDrawRange(t.drawRange.start, t.drawRange.count), e.userData = t.userData, l[t.uuid] = e;
678
+ e.setDrawRange(t.drawRange.start, t.drawRange.count), e.userData = t.userData, u[t.uuid] = e;
674
679
  }
675
- let u = [];
680
+ let d = [];
676
681
  for (let t of e.nodes) {
677
- let e = Array.isArray(t.material) ? t.material.map((e) => c[e]) : c[t.material], n;
682
+ let e = Array.isArray(t.material) ? t.material.map((e) => l[e]) : l[t.material], n;
678
683
  switch (t.type) {
679
684
  case "InstancedMesh": {
680
- n = new de(l[t.geometry], e, 1);
685
+ n = new de(u[t.geometry], e, 1);
681
686
  let r = a.get(t.instanceMatrix.offset);
682
687
  r || a.set(t.instanceMatrix.offset, r = new ue(i(t.instanceMatrix), 16)), n.instanceMatrix = r, n.count = t.count, t.instanceColor && (n.instanceColor = new ue(i(t.instanceColor), 3));
683
688
  break;
684
689
  }
685
690
  case "Mesh":
686
- n = new he(l[t.geometry], e);
691
+ n = new he(u[t.geometry], e);
687
692
  break;
688
693
  case "PerspectiveCamera":
689
694
  n = new xe();
@@ -728,13 +733,13 @@ async function Ht(e, t, { loadTexture: n }) {
728
733
  n.color.fromArray(t.color);
729
734
  for (let e of wt) t[e] !== void 0 && (n[e] = t[e]);
730
735
  }
731
- u.push(n), t.parent >= 0 && u[t.parent].add(n);
736
+ d.push(n), t.parent >= 0 && d[t.parent].add(n);
732
737
  }
733
- let d = new Map(u.map((e) => [e.uuid, e]));
738
+ let f = new Map(d.map((e) => [e.uuid, e]));
734
739
  return e.nodes.forEach((e, t) => {
735
- e.target && d.has(e.target) && (u[t].target = d.get(e.target));
740
+ e.target && f.has(e.target) && (d[t].target = f.get(e.target));
736
741
  }), {
737
- root: u[0],
742
+ root: d[0],
738
743
  environment: e.environment ? o[e.environment] : null,
739
744
  animations: e.animations.map((e) => C.parse(e)),
740
745
  stats: e.stats
@@ -3501,7 +3506,7 @@ var Ri = class {
3501
3506
  return this._countedGeometries.has(e) || (this._countedGeometries.add(e), this.triangleCount += t), t;
3502
3507
  }
3503
3508
  async _buildInstances(e, t) {
3504
- let n = 0;
3509
+ let r = 0;
3505
3510
  e.skippedInstances > 0 && (this.skippedForBudget += e.skippedInstances);
3506
3511
  let i = new Float64Array(16), a = new M(), o = /* @__PURE__ */ new Map(), s = (e, s, c, l, u, d, f) => {
3507
3512
  let p = l ? Array.prototype.join.call(l, ",") : "", m = o.get(e);
@@ -3509,7 +3514,7 @@ var Ri = class {
3509
3514
  let h = m.get(p), g = Math.max(0, this.maxPlacements - this.placementCount), _ = h ? h.count : Math.min(e.count, g);
3510
3515
  if (!h && _ < e.count && (this.skippedForBudget += e.count - _), _ === 0) return;
3511
3516
  let v = new de(s, c, _);
3512
- if (v.name = `instance_${n++}`, v.frustumCulled = !1, h) v.instanceMatrix = h.attribute;
3517
+ if (v.name = `instance_${r++}`, v.frustumCulled = !1, h) v.instanceMatrix = h.attribute;
3513
3518
  else {
3514
3519
  for (let t = 0; t < _; t++) {
3515
3520
  if (l) _n(i, e.matrices, t * 16, l);
@@ -3521,7 +3526,7 @@ var Ri = class {
3521
3526
  count: _
3522
3527
  }), this.placementCount += _;
3523
3528
  }
3524
- r(v), t.add(v), this.reportedMeshes += _, this.report.length < Xr && this.report.push({
3529
+ n(v), t.add(v), this.reportedMeshes += _, this.report.length < Xr && this.report.push({
3525
3530
  mesh: `${v.name} ×${_}`,
3526
3531
  shape: u,
3527
3532
  material: d,
@@ -8190,7 +8195,7 @@ var ms = /* @__PURE__ */ e({
8190
8195
  return e instanceof Uint8Array ? e.subarray(0, t) : typeof e.slice == "function" && typeof e.arrayBuffer == "function" ? new Uint8Array(await e.slice(0, t).arrayBuffer()) : new Uint8Array((await this.loader.readFileAsArrayBuffer(e)).slice(0, t));
8191
8196
  }
8192
8197
  async inspectArchive(e) {
8193
- let t = Ue(await this._readHead(e)), n = (e) => s({
8198
+ let t = Ue(await this._readHead(e)), n = (e) => a({
8194
8199
  isLoading: !0,
8195
8200
  status: `Scanning archive… ${(e.bytes / 1e9).toFixed(1)} GB`,
8196
8201
  progress: 4
@@ -8205,11 +8210,11 @@ var ms = /* @__PURE__ */ e({
8205
8210
  path: e.name,
8206
8211
  size: e.size
8207
8212
  }));
8208
- let { root: i, elements: a } = lt(r);
8213
+ let { root: i, elements: o } = lt(r);
8209
8214
  return {
8210
8215
  kind: t ?? "zip",
8211
8216
  root: i,
8212
- elements: a,
8217
+ elements: o,
8213
8218
  entryCount: r.length,
8214
8219
  totalBytes: r.reduce((e, t) => e + t.size, 0)
8215
8220
  };
@@ -8224,7 +8229,7 @@ var ms = /* @__PURE__ */ e({
8224
8229
  filter: ct(r),
8225
8230
  part: [...r].sort().join(",")
8226
8231
  } : {},
8227
- onProgress: (e) => s({
8232
+ onProgress: (e) => a({
8228
8233
  isLoading: !0,
8229
8234
  status: `Unpacking archive… ${(e / 1e9).toFixed(1)} GB`,
8230
8235
  progress: 4
@@ -8309,16 +8314,16 @@ var ms = /* @__PURE__ */ e({
8309
8314
  return this.loader._sourceKey = this.loader._keyed(s, a), l;
8310
8315
  }
8311
8316
  async _loadStoredGraph(e, t, { imageFromBytes: n, envFromBytes: r }) {
8312
- let i = this.loader.storage?.area(p.SCENES), a = i ? await i.open(e) : null;
8313
- if (!a) return null;
8314
- let o = performance.now(), c = null;
8317
+ let i = this.loader.storage?.area(p.SCENES), o = i ? await i.open(e) : null;
8318
+ if (!o) return null;
8319
+ let s = performance.now(), c = null;
8315
8320
  try {
8316
- s({
8321
+ a({
8317
8322
  isLoading: !0,
8318
8323
  status: "Opening the stored scene...",
8319
8324
  progress: 6
8320
8325
  });
8321
- let e = await a.json("graph.json"), i = await a.file("data.bin"), c = new aa({}, t), l = await Ht(e, i, { loadTexture: async (e, t) => {
8326
+ let e = await o.json("graph.json"), i = await o.file("data.bin"), c = new aa({}, t), l = await Ht(e, i, { loadTexture: async (e, t) => {
8322
8327
  let i = await c.readPath(e);
8323
8328
  return i ? t === "environment" ? r(i, e) : n(i, e) : null;
8324
8329
  } });
@@ -8329,13 +8334,13 @@ var ms = /* @__PURE__ */ e({
8329
8334
  animations: l.animations,
8330
8335
  report: null,
8331
8336
  parseMs: 0,
8332
- buildMs: performance.now() - o,
8337
+ buildMs: performance.now() - s,
8333
8338
  fromStorage: !0
8334
8339
  };
8335
8340
  } catch (e) {
8336
8341
  return c = e, null;
8337
8342
  } finally {
8338
- a.release(), c && (console.warn(`The stored scene could not be used, parsing the archive instead: ${c.message}`), this.loader._issues?.warn(u.STORAGE_ENTRY_CORRUPT, `stored scene unusable: ${c.message}`, { key: e }), i.remove(e).catch(() => {}));
8343
+ o.release(), c && (console.warn(`The stored scene could not be used, parsing the archive instead: ${c.message}`), this.loader._issues?.warn(u.STORAGE_ENTRY_CORRUPT, `stored scene unusable: ${c.message}`, { key: e }), i.remove(e).catch(() => {}));
8339
8344
  }
8340
8345
  }
8341
8346
  _storeGraph(e, t, n) {
@@ -8365,7 +8370,7 @@ var ms = /* @__PURE__ */ e({
8365
8370
  e instanceof Et ? console.info(`Scene not stored for next time: ${e.message}`) : console.warn("Scene not stored for next time:", e);
8366
8371
  return;
8367
8372
  }
8368
- let o, s = new AbortController(), c = {
8373
+ let a, s = new AbortController(), c = {
8369
8374
  key: e,
8370
8375
  encoded: i,
8371
8376
  label: n,
@@ -8375,19 +8380,19 @@ var ms = /* @__PURE__ */ e({
8375
8380
  parseMs: (t.parseMs ?? 0) + (t.buildMs ?? 0),
8376
8381
  triangles: t.triangleCount ?? null,
8377
8382
  accepted: new Promise((e) => {
8378
- o = e;
8383
+ a = e;
8379
8384
  }),
8380
8385
  decide: (e) => {
8381
- o(e), e || s.abort();
8386
+ a(e), e || s.abort();
8382
8387
  }
8383
8388
  };
8384
- this._store = c, a(c.parseMs, i.byteLength) && this._writeGraph(r, c);
8389
+ this._store = c, o(c.parseMs, i.byteLength) && this._writeGraph(r, c);
8385
8390
  }
8386
8391
  flushPendingGraph(e) {
8387
8392
  let t = this._store;
8388
8393
  if (!t || t.writing) return;
8389
8394
  let n = this.loader.storage?.area(p.SCENES);
8390
- n && a(t.parseMs + e, t.encoded.byteLength) ? this._writeGraph(n, t) : this._store = null;
8395
+ n && o(t.parseMs + e, t.encoded.byteLength) ? this._writeGraph(n, t) : this._store = null;
8391
8396
  }
8392
8397
  commitPendingGraph(e) {
8393
8398
  let t = this._store;
@@ -8412,16 +8417,16 @@ var ms = /* @__PURE__ */ e({
8412
8417
  }
8413
8418
  })();
8414
8419
  }
8415
- async _openSeekableArchive(e, t, n, r, { index: i = null, zip: a = !1 } = {}) {
8416
- let o = Array.isArray(n) ? n.filter(Boolean) : n ? [n] : [], c = o.length ? ct(o) : null, l;
8417
- if (a) l = await S(e, { filter: c });
8420
+ async _openSeekableArchive(e, t, n, r, { index: i = null, zip: o = !1 } = {}) {
8421
+ let s = Array.isArray(n) ? n.filter(Boolean) : n ? [n] : [], c = s.length ? ct(s) : null, l;
8422
+ if (o) l = await S(e, { filter: c });
8418
8423
  else {
8419
8424
  let t = i ?? await mt(e, this.loader.storage);
8420
8425
  l = await ot(e, {
8421
8426
  index: t,
8422
8427
  headersOnly: !0,
8423
8428
  filter: c,
8424
- onProgress: (e) => s({
8429
+ onProgress: (e) => a({
8425
8430
  isLoading: !0,
8426
8431
  status: `Indexing archive… ${(e.bytes / 1e9).toFixed(1)} GB`,
8427
8432
  progress: 4
@@ -8429,7 +8434,7 @@ var ms = /* @__PURE__ */ e({
8429
8434
  }), t || ht(e, this.loader.storage, l.index).catch(() => {});
8430
8435
  }
8431
8436
  let u = l.listing.reduce((e, t) => e + t.size, 0);
8432
- return o.length === 0 && this._requireElementChoice(t, l.listing, u, r), console.info(`Archive "${t}": indexed ${l.indexed} entries, ${(u / 1e9).toFixed(1)} GB, none resident` + (o.length ? `, ${o.length} part${o.length > 1 ? "s" : ""} selected.` : ".")), l;
8437
+ return s.length === 0 && this._requireElementChoice(t, l.listing, u, r), console.info(`Archive "${t}": indexed ${l.indexed} entries, ${(u / 1e9).toFixed(1)} GB, none resident` + (s.length ? `, ${s.length} part${s.length > 1 ? "s" : ""} selected.` : ".")), l;
8433
8438
  }
8434
8439
  _requireElementChoice(e, t, n, r = Ss) {
8435
8440
  if (n < r) return;
@@ -8443,16 +8448,16 @@ var ms = /* @__PURE__ */ e({
8443
8448
  }, d.WARNING), o;
8444
8449
  }
8445
8450
  async _readStreamedArchive(e, t, n, r, i) {
8446
- let a = Array.isArray(r) ? r.filter(Boolean) : r ? [r] : [], { entries: o, listing: c, retainedBytes: l, truncated: f } = await nt(e, {
8447
- filter: a.length ? ct(a) : null,
8451
+ let o = Array.isArray(r) ? r.filter(Boolean) : r ? [r] : [], { entries: s, listing: c, retainedBytes: l, truncated: f } = await nt(e, {
8452
+ filter: o.length ? ct(o) : null,
8448
8453
  ...i === void 0 ? {} : { byteBudget: i },
8449
- onProgress: (e) => s({
8454
+ onProgress: (e) => a({
8450
8455
  isLoading: !0,
8451
8456
  status: `Reading archive… ${(e.bytes / 1e9).toFixed(1)} GB`,
8452
8457
  progress: 4
8453
8458
  })
8454
8459
  });
8455
- if (f && a.length === 0) {
8460
+ if (f && o.length === 0) {
8456
8461
  let { root: e, elements: n } = lt(c), r = c.reduce((e, t) => e + t.size, 0), i = /* @__PURE__ */ Error(`"${t}" unpacks to ${(r / 1e9).toFixed(1)} GB, past the load budget. Load one of its ${n.length} parts instead.`);
8457
8462
  throw i.code = "ARCHIVE_NEEDS_ELEMENT", i.root = e, i.elements = n, i.totalBytes = r, this.loader._issues?.record(u.ASSET_ARCHIVE_TOO_LARGE, `archive unpacks to ${(r / 1e9).toFixed(1)} GB; choose one of ${n.length} parts`, {
8458
8463
  root: e,
@@ -8461,17 +8466,17 @@ var ms = /* @__PURE__ */ e({
8461
8466
  }, d.WARNING), i;
8462
8467
  }
8463
8468
  if (f) {
8464
- let e = ct(a), t = c.filter((t) => e(t.path, t.size) && !o[t.path]).length;
8469
+ let e = ct(o), t = c.filter((t) => e(t.path, t.size) && !s[t.path]).length;
8465
8470
  this.loader._issues?.record(u.ASSET_ARCHIVE_TOO_LARGE, `${t} files of the chosen parts were left out: they did not fit the ${((i ?? 15e8) / 1e9).toFixed(1)} GB in-memory read budget`, {
8466
- elements: a,
8471
+ elements: o,
8467
8472
  missing: t,
8468
8473
  retainedBytes: l
8469
8474
  }, d.WARNING);
8470
8475
  }
8471
- return a.length && console.info(`Archive "${t}": loaded ${a.map((e) => `"${e}"`).join(", ")} — ${Object.keys(o).length} of ${c.length} files, ${(l / 1048576).toFixed(1)} MB.`), o;
8476
+ return o.length && console.info(`Archive "${t}": loaded ${o.map((e) => `"${e}"`).join(", ")} — ${Object.keys(s).length} of ${c.length} files, ${(l / 1048576).toFixed(1)} MB.`), s;
8472
8477
  }
8473
- async loadPBRTFromZip(e, t, n = null, r = {}, a = null) {
8474
- if (s({
8478
+ async loadPBRTFromZip(e, t, n = null, i = {}, o = null) {
8479
+ if (a({
8475
8480
  isLoading: !0,
8476
8481
  status: "Parsing PBRT scene...",
8477
8482
  progress: 5
@@ -8480,26 +8485,26 @@ var ms = /* @__PURE__ */ e({
8480
8485
  this.loader.loaderCache.ply = new e();
8481
8486
  }
8482
8487
  let c = (e) => this.loader.loaderCache.ply.parse(e), l = (e, t) => this._archiveImage(e, t), f = (e, t) => this._archiveEnvironment(e, t), p = performance.now(), m = {
8483
- animation: r.animation,
8484
- maxTriangles: r.maxTriangles,
8485
- maxPlacements: r.maxPlacements,
8486
- mergeShapesAbove: r.mergeShapesAbove,
8487
- curveSteps: r.curveSteps,
8488
- curveSides: r.curveSides,
8489
- curveTolerance: r.curveTolerance,
8490
- instanceIncludes: r.instanceIncludes
8491
- }, h = a?.archiveId ? this.loader._keyed(`pbrt:2.14:${o}`, `${a.archiveId}|${n ?? ""}|${[...a.elements ?? []].sort().join(",")}|${JSON.stringify(m)}`) : null, g = h ? await this._loadStoredGraph(h, a, {
8488
+ animation: i.animation,
8489
+ maxTriangles: i.maxTriangles,
8490
+ maxPlacements: i.maxPlacements,
8491
+ mergeShapesAbove: i.mergeShapesAbove,
8492
+ curveSteps: i.curveSteps,
8493
+ curveSides: i.curveSides,
8494
+ curveTolerance: i.curveTolerance,
8495
+ instanceIncludes: i.instanceIncludes
8496
+ }, h = o?.archiveId ? this.loader._keyed(`pbrt:2.14:${s}`, `${o.archiveId}|${n ?? ""}|${[...o.elements ?? []].sort().join(",")}|${JSON.stringify(m)}`) : null, g = h ? await this._loadStoredGraph(h, o, {
8492
8497
  imageFromBytes: l,
8493
8498
  envFromBytes: f
8494
8499
  }) : null, _ = g ?? await va({
8495
8500
  vfs: e,
8496
- source: a,
8501
+ source: o,
8497
8502
  entryPath: n,
8498
8503
  plyParser: c,
8499
8504
  imageFromBytes: l,
8500
8505
  envFromBytes: f,
8501
8506
  ...m,
8502
- pause: this._buildPause(i())
8507
+ pause: this._buildPause(r())
8503
8508
  });
8504
8509
  this.loader._throwDeferred();
8505
8510
  let { group: v, environment: y, animations: b, report: x, warnings: S, meshCount: C, entryPath: w, candidates: T, frames: E, parseMs: D, buildMs: ee, triangleCount: te, placementCount: O, mergedShapes: ne, skippedForBudget: re, droppedNoTemplate: k, parameters: ie } = _;
@@ -8529,7 +8534,7 @@ var ms = /* @__PURE__ */ e({
8529
8534
  intensity: 1
8530
8535
  } : { enabled: !1 },
8531
8536
  ..._.render ? { render: { ..._.render } } : {}
8532
- }, s({
8537
+ }, a({
8533
8538
  isLoading: !0,
8534
8539
  status: "Processing PBRT geometry...",
8535
8540
  progress: 10
@@ -8572,38 +8577,38 @@ var ms = /* @__PURE__ */ e({
8572
8577
  }
8573
8578
  }
8574
8579
  async loadUSDScene(e, t, n = {}) {
8575
- s({
8580
+ a({
8576
8581
  isLoading: !0,
8577
8582
  status: "Reading USD scene...",
8578
8583
  progress: 5
8579
8584
  });
8580
- let r = Object.keys(e), a = new vo(r, async (t) => e[t] ? vs(e[t]) : null, { omitted: (n.listing ?? []).filter((t) => !(t.path in e)).map((e) => e.path) }), o = ls(r);
8581
- if (o.length === 0) throw Error(`No USD layer found in ${t}`);
8582
- let c = o[0];
8583
- o.length > 1 && (console.warn(`${t} holds ${o.length} top-level USD layers; loaded "${c}". Others: ${o.slice(1).join(", ")}`), this.loader._issues?.record(u.ASSET_AMBIGUOUS_ENTRY, `${t} holds ${o.length} top-level USD layers; loaded "${c}"`, {
8585
+ let i = Object.keys(e), o = new vo(i, async (t) => e[t] ? vs(e[t]) : null, { omitted: (n.listing ?? []).filter((t) => !(t.path in e)).map((e) => e.path) }), s = ls(i);
8586
+ if (s.length === 0) throw Error(`No USD layer found in ${t}`);
8587
+ let c = s[0];
8588
+ s.length > 1 && (console.warn(`${t} holds ${s.length} top-level USD layers; loaded "${c}". Others: ${s.slice(1).join(", ")}`), this.loader._issues?.record(u.ASSET_AMBIGUOUS_ENTRY, `${t} holds ${s.length} top-level USD layers; loaded "${c}"`, {
8584
8589
  loaded: c,
8585
- alternatives: o.slice(1)
8586
- }, d.WARNING)), (Array.isArray(n.element) ? n.element : [n.element]).filter(Boolean).length === 0 && await this._requireUSDPartChoice(t, a, c, n.listing ?? r.map((t) => ({
8590
+ alternatives: s.slice(1)
8591
+ }, d.WARNING)), (Array.isArray(n.element) ? n.element : [n.element]).filter(Boolean).length === 0 && await this._requireUSDPartChoice(t, o, c, n.listing ?? i.map((t) => ({
8587
8592
  path: t,
8588
8593
  size: e[t]?.size ?? e[t]?.byteLength ?? 0
8589
8594
  })), n.promptBytes);
8590
- let l = performance.now(), f = i(), p = await ds({
8591
- files: a,
8595
+ let l = performance.now(), f = r(), p = await ds({
8596
+ files: o,
8592
8597
  entryPath: c,
8593
8598
  pauseRead: (e, t) => {
8594
8599
  let n = f();
8595
- return n && s({
8600
+ return n && a({
8596
8601
  status: `${t ? "Counting" : "Reading"} USD scene... ${e.toLocaleString()} prims`,
8597
8602
  progress: t ? 5 : 6
8598
8603
  }), n;
8599
8604
  },
8600
8605
  pauseBuild: this._buildPause(f),
8601
8606
  resolveImage: async (e) => {
8602
- let t = await a.read(e);
8607
+ let t = await o.read(e);
8603
8608
  return t ? this._archiveImage(t, e) : null;
8604
8609
  },
8605
8610
  resolveEnvironment: async (e) => {
8606
- let t = await a.read(e);
8611
+ let t = await o.read(e);
8607
8612
  return t ? this._archiveEnvironment(t, e) : null;
8608
8613
  },
8609
8614
  maxTriangles: n.maxTriangles,
@@ -8631,7 +8636,7 @@ var ms = /* @__PURE__ */ e({
8631
8636
  }, d.WARNING), g.length && (console.warn(`USD loader: ${g.length} warning(s) loading "${c}"`), g.forEach((e) => console.warn(" •", e))), h?.texture && (h.texture.generateMipmaps = !0, this.loader.applyEnvironmentToScene(h.texture)), m.name = c.split("/").pop(), this.loader.releaseTargetModel(), this.loader.targetModel = m, this.loader.animations = [], this.loader.sceneMetadata = h?.texture ? { environment: {
8632
8637
  rotation: h.rotation,
8633
8638
  intensity: h.intensity
8634
- } } : null, s({
8639
+ } } : null, a({
8635
8640
  isLoading: !0,
8636
8641
  status: "Processing USD geometry...",
8637
8642
  progress: 10
@@ -8644,7 +8649,7 @@ var ms = /* @__PURE__ */ e({
8644
8649
  _buildPause(e) {
8645
8650
  return (t, n) => {
8646
8651
  let r = e();
8647
- return r && s({
8652
+ return r && a({
8648
8653
  status: `Building scene... ${t.toLocaleString()} of ${n.toLocaleString()} shapes`,
8649
8654
  progress: 8
8650
8655
  }), r;
@@ -8755,27 +8760,27 @@ var ms = /* @__PURE__ */ e({
8755
8760
  }
8756
8761
  async loadModelFromZipEntry(e, t, n, r, i = "ZIP") {
8757
8762
  try {
8758
- s({
8763
+ a({
8759
8764
  isLoading: !0,
8760
8765
  status: `Processing ${n.toUpperCase()} from ${i}...`,
8761
8766
  progress: 5
8762
8767
  });
8763
- let a;
8768
+ let o;
8764
8769
  switch (n) {
8765
8770
  case "glb":
8766
8771
  case "gltf":
8767
- a = await this.handleGltfFromZip(n, e, t, r);
8772
+ o = await this.handleGltfFromZip(n, e, t, r);
8768
8773
  break;
8769
8774
  case "obj":
8770
- a = await this.handleObjFromZip(e, t, r);
8775
+ o = await this.handleObjFromZip(e, t, r);
8771
8776
  break;
8772
- default: a = await this.loader._loadModelFileByExtension(new File([e], t), t);
8777
+ default: o = await this.loader._loadModelFileByExtension(new File([e], t), t);
8773
8778
  }
8774
8779
  return this.loader.dispatchEvent({
8775
8780
  type: "load",
8776
8781
  model: this.loader.targetModel,
8777
8782
  filename: `${t} (from ${i})`
8778
- }), a;
8783
+ }), o;
8779
8784
  } catch (e) {
8780
8785
  throw console.error(`Error loading ${n} from ${i}:`, e), this.loader.dispatchEvent({
8781
8786
  type: "error",
@@ -8784,19 +8789,19 @@ var ms = /* @__PURE__ */ e({
8784
8789
  }), e;
8785
8790
  }
8786
8791
  }
8787
- async handleGltfFromZip(e, t, r, i) {
8792
+ async handleGltfFromZip(e, t, n, r) {
8788
8793
  if (e === "gltf") {
8789
- let e = await ys(t), a = new pe(), o = r.split("/").slice(0, -1).join("/");
8790
- a.setURLModifier((e) => this.resolveZipResource(e, o, i));
8794
+ let e = await ys(t), a = new pe(), o = n.split("/").slice(0, -1).join("/");
8795
+ a.setURLModifier((e) => this.resolveZipResource(e, o, r));
8791
8796
  let s = await this.loader.createGLTFLoader();
8792
8797
  s.manager = a;
8793
8798
  try {
8794
- let t = await n(() => new Promise((t, n) => s.parse(e, "", t, n)));
8799
+ let t = await i(() => new Promise((t, n) => s.parse(e, "", t, n)));
8795
8800
  return this.loader._throwDeferred(), this.loader.releaseTargetModel(), this.loader.targetModel = t.scene, this.loader.sceneMetadata = b(t), await this.loader.onModelLoad(this.loader.targetModel), t;
8796
8801
  } finally {
8797
8802
  this.loader._disposeGLTFLoader(s);
8798
8803
  }
8799
- } else return await this.loader.loadGLBFromArrayBuffer(await xs(t), r);
8804
+ } else return await this.loader.loadGLBFromArrayBuffer(await xs(t), n);
8800
8805
  }
8801
8806
  async handleObjFromZip(e, t, n) {
8802
8807
  let r = await ys(e), i = r.match(/mtllib\s+([^\s]+)/), a = null;