@needle-tools/gltf-progressive 3.3.2 → 3.3.3-next.90044cd

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
@@ -4,6 +4,9 @@ All notable changes to this package will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [3.3.3] - 2025-09-08
8
+ - Update documentation and add an initial extension definition
9
+
7
10
  ## [3.3.2] - 2025-08-20
8
11
  - Update KTX2 transcoder
9
12
 
@@ -0,0 +1,106 @@
1
+ # NEEDLE Progressive Extensions Schema
2
+
3
+ This document describes the NEEDLE progressive mesh and texture extensions.
4
+
5
+ ## Base Types
6
+
7
+ ### NEEDLE_progressive_model_LOD
8
+
9
+ Represents a single Level of Detail (LOD) file reference.
10
+
11
+ | Property | Type | Required | Description |
12
+ |----------|------|----------|-------------|
13
+ | `path` | `string` | Yes | Relative path to the LOD file |
14
+ | `hash` | `string` | No | Optional hash for file verification |
15
+
16
+ ### NEEDLE_progressive_ext
17
+
18
+ Base extension format for progressive assets.
19
+
20
+ | Property | Type | Required | Description |
21
+ |----------|------|----------|-------------|
22
+ | `guid` | `string` | Yes | Unique identifier of the object (texture, mesh) the LODs belong to |
23
+ | `lods` | `Array<NEEDLE_progressive_model_LOD>` | Yes | Array of available LOD levels |
24
+
25
+ ## Extension Types
26
+
27
+ ### NEEDLE_ext_progressive_texture
28
+
29
+ Texture extension for progressive texture loading, inheriting from `NEEDLE_progressive_ext`.
30
+
31
+ | Property | Type | Required | Description |
32
+ |----------|------|----------|-------------|
33
+ | `guid` | `string` | Yes | Inherited from base type |
34
+ | `lods` | `Array<TextureLOD>` | Yes | Array of texture LOD levels with dimensions |
35
+
36
+ **TextureLOD Properties:**
37
+ | Property | Type | Required | Description |
38
+ |----------|------|----------|-------------|
39
+ | `path` | `string` | Yes | Relative path to the texture LOD file |
40
+ | `hash` | `string` | No | Optional hash for file verification |
41
+ | `width` | `number` | Yes | Texture width in pixels |
42
+ | `height` | `number` | Yes | Texture height in pixels |
43
+
44
+ ### NEEDLE_ext_progressive_mesh
45
+
46
+ Mesh extension for progressive mesh loading, inheriting from `NEEDLE_progressive_ext`.
47
+
48
+ | Property | Type | Required | Description |
49
+ |----------|------|----------|-------------|
50
+ | `guid` | `string` | Yes | Inherited from base type |
51
+ | `lods` | `Array<MeshLOD>` | Yes | Array of mesh LOD levels with geometry data |
52
+
53
+ **MeshLOD Properties:**
54
+ | Property | Type | Required | Description |
55
+ |----------|------|----------|-------------|
56
+ | `path` | `string` | Yes | Relative path to the mesh LOD file |
57
+ | `hash` | `string` | No | Optional hash for file verification |
58
+ | `densities` | `number[]` | Yes | Density values per primitive |
59
+ | `indexCount` | `number` | No | Number of indices in LOD0 |
60
+ | `vertexCount` | `number` | No | Number of vertices in LOD0 |
61
+
62
+ ## Usage Examples
63
+
64
+ ### Texture Extension Example
65
+
66
+ ```json
67
+ {
68
+ "guid": "texture-asset-123",
69
+ "lods": [
70
+ {
71
+ "path": "./textures/image_diffuse_1024.glb",
72
+ "hash": "abc123",
73
+ "width": 1024,
74
+ "height": 1024
75
+ },
76
+ {
77
+ "path": "./textures/image_diffuse_512.glb",
78
+ "width": 512,
79
+ "height": 512
80
+ }
81
+ ]
82
+ }
83
+ ```
84
+
85
+ ### Mesh Extension Example
86
+
87
+ ```json
88
+ {
89
+ "guid": "mesh-asset-456",
90
+ "lods": [
91
+ {
92
+ "path": "./meshes/mesh_0_high_detail.glb",
93
+ "hash": "def456",
94
+ "indexCount": 15000,
95
+ "vertexCount": 8000,
96
+ "densities": [100000, 50000]
97
+ },
98
+ {
99
+ "path": "./meshes/mesh_1_low_detail.glb",
100
+ "indexCount": 3000,
101
+ "vertexCount": 1500,
102
+ "densities": [100000, 50000]
103
+ }
104
+ ]
105
+ }
106
+ ```
package/README.md CHANGED
@@ -40,12 +40,12 @@ Examples are in the `/examples` directory. Live versions can be found in the lin
40
40
  - [Codesandbox](https://codesandbox.io/dashboard/sandboxes/gltf-progressive)
41
41
 
42
42
 
43
- ## Videos
43
+ <!-- ## Videos
44
44
  <a href="https://youtu.be/7EjL0BRfIp8" target="_blank">![Progressive glTF — comparison with traditional three.js optimization
45
45
  ](https://engine.needle.tools/demos/gltf-progressive/video-comparison-throttled-thumbnail-1.webp)</a>
46
46
  *Progressive glTF — comparison with traditional three.js optimization*
47
47
 
48
- <br/>
48
+ <br/> -->
49
49
 
50
50
  # Usage
51
51
 
@@ -132,6 +132,10 @@ Full model-viewer example at: `examples/modelviewer.html`
132
132
  [Needle Engine](https://needle.tools) natively supports progressive loading of these glTF files! See [docs.needle.tools](https://docs.needle.tools) for more information.
133
133
 
134
134
 
135
+ # How can I generate assets for progressive loading
136
+ Use [Needle Cloud](https://cloud.needle.tools) to generate LODs for your assets (includes hosting, global CDN, password protection, versioning, CLI support...) or use one of the [Needle integrations for Unity or Blender](https://engine.needle.tools/docs/getting-started/#choose-your-workflow).
137
+
138
+
135
139
  # Advanced
136
140
 
137
141
  ### Add a LOD Manager plugin to receive callbacks per object
@@ -158,8 +162,9 @@ Simply call `useRaycastMeshes(true)` to enable faster raycasting when using the
158
162
  Call `getRaycastMesh(<your_mesh_object>)`
159
163
 
160
164
 
161
- # How can I generate assets for progressive loading
162
- Use [Needle Cloud](https://cloud.needle.tools) to generate LODs for your assets (includes hosting, global CDN, password protection, versioning, CLI support...) or use one of the Needle integrations for Unity or Blender.
165
+ # Extension
166
+ Read more about the [NEEDLE_progressive extension](./NEEDLE_progressive/README.md)
167
+
163
168
 
164
169
  # Contact ✒️
165
170
  <b>[🌵 needle — tools for creators](https://needle.tools)</b> •
@@ -1,13 +1,13 @@
1
- import { BufferGeometry as Q, Mesh as q, Box3 as he, Vector3 as A, Sphere as De, CompressedTexture as $e, Texture as E, Matrix3 as Ge, InterleavedBuffer as Fe, InterleavedBufferAttribute as Ue, BufferAttribute as We, TextureLoader as ze, Matrix4 as _e, Clock as Ee, MeshStandardMaterial as Ne } from "three";
1
+ import { BufferGeometry as J, Mesh as q, Box3 as he, Vector3 as A, Sphere as De, CompressedTexture as $e, Texture as E, Matrix3 as Ge, InterleavedBuffer as Fe, InterleavedBufferAttribute as We, BufferAttribute as Ue, TextureLoader as ze, Matrix4 as _e, Clock as Ee, MeshStandardMaterial as Ne } from "three";
2
2
  import { GLTFLoader as ye } from "three/examples/jsm/loaders/GLTFLoader.js";
3
3
  import { MeshoptDecoder as qe } from "three/examples/jsm/libs/meshopt_decoder.module.js";
4
4
  import { DRACOLoader as Ve } from "three/examples/jsm/loaders/DRACOLoader.js";
5
5
  import { KTX2Loader as Xe } from "three/examples/jsm/loaders/KTX2Loader.js";
6
- const Ke = "";
7
- globalThis.GLTF_PROGRESSIVE_VERSION = Ke;
6
+ const je = "";
7
+ globalThis.GLTF_PROGRESSIVE_VERSION = je;
8
8
  console.debug("[gltf-progressive] version -");
9
- let k = "https://www.gstatic.com/draco/versioned/decoders/1.5.7/", V = "https://cdn.needle.tools/static/three/0.179.1/basis2/";
10
- const je = k, Ye = V, Oe = new URL(k + "draco_decoder.js");
9
+ let C = "https://www.gstatic.com/draco/versioned/decoders/1.5.7/", V = "https://cdn.needle.tools/static/three/0.179.1/basis2/";
10
+ const Ke = C, Ye = V, Oe = new URL(C + "draco_decoder.js");
11
11
  Oe.searchParams.append("range", "true");
12
12
  fetch(Oe, {
13
13
  method: "GET",
@@ -15,16 +15,16 @@ fetch(Oe, {
15
15
  Range: "bytes=0-1"
16
16
  }
17
17
  }).catch((i) => {
18
- console.debug(`Failed to fetch remote Draco decoder from ${k} (offline: ${typeof navigator < "u" ? navigator.onLine : "unknown"})`), k === je && Qe("./include/draco/"), V === Ye && Je("./include/ktx2/");
18
+ console.debug(`Failed to fetch remote Draco decoder from ${C} (offline: ${typeof navigator < "u" ? navigator.onLine : "unknown"})`), C === Ke && Qe("./include/draco/"), V === Ye && Je("./include/ktx2/");
19
19
  }).finally(() => {
20
20
  Pe();
21
21
  });
22
22
  const He = () => ({
23
- dracoDecoderPath: k,
23
+ dracoDecoderPath: C,
24
24
  ktx2TranscoderPath: V
25
25
  });
26
26
  function Qe(i) {
27
- k = i, T && T[ge] != k ? (console.debug("Updating Draco decoder path to " + i), T[ge] = k, T.setDecoderPath(k), T.preload()) : console.debug("Setting Draco decoder path to " + i);
27
+ C = i, T && T[ge] != C ? (console.debug("Updating Draco decoder path to " + i), T[ge] = C, T.setDecoderPath(C), T.preload()) : console.debug("Setting Draco decoder path to " + i);
28
28
  }
29
29
  function Je(i) {
30
30
  V = i, R && R.transcoderPath != V ? (console.debug("Updating KTX2 transcoder path to " + i), R.setTranscoderPath(V), R.init()) : console.debug("Setting KTX2 transcoder path to " + i);
@@ -38,7 +38,7 @@ function Se(i) {
38
38
  const ge = Symbol("dracoDecoderPath");
39
39
  let T, ne, R;
40
40
  function Pe() {
41
- T || (T = new Ve(), T[ge] = k, T.setDecoderPath(k), T.setDecoderConfig({ type: "js" }), T.preload()), R || (R = new Xe(), R.setTranscoderPath(V), R.init()), ne || (ne = qe);
41
+ T || (T = new Ve(), T[ge] = C, T.setDecoderPath(C), T.setDecoderConfig({ type: "js" }), T.preload()), R || (R = new Xe(), R.setTranscoderPath(V), R.init()), ne || (ne = qe);
42
42
  }
43
43
  const pe = /* @__PURE__ */ new WeakMap();
44
44
  function Te(i, t) {
@@ -64,7 +64,7 @@ function X(i) {
64
64
  return e == null || e === "0" || e === "false" ? !1 : e === "" ? !0 : e;
65
65
  }
66
66
  function tt(i, t) {
67
- if (t === void 0 || t.startsWith("./") || t.startsWith("http") || i === void 0)
67
+ if (t === void 0 || i === void 0 || t.startsWith("./") || t.startsWith("http") || t.startsWith("data:") || t.startsWith("blob:"))
68
68
  return t;
69
69
  const e = i.lastIndexOf("/");
70
70
  if (e >= 0) {
@@ -74,10 +74,10 @@ function tt(i, t) {
74
74
  }
75
75
  return t;
76
76
  }
77
- let j;
78
77
  function Ae() {
79
- return j !== void 0 || (j = /iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent), X("debugprogressive") && console.log("[glTF Progressive]: isMobileDevice", j)), j;
78
+ return K !== void 0 || (K = /iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent), X("debugprogressive") && console.log("[glTF Progressive]: isMobileDevice", K)), K;
80
79
  }
80
+ let K;
81
81
  function Le() {
82
82
  if (typeof window > "u") return !1;
83
83
  const i = new URL(window.location.href), t = i.hostname === "localhost" || /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(i.hostname);
@@ -118,11 +118,11 @@ class st {
118
118
  }
119
119
  }
120
120
  const rt = typeof window > "u" && typeof document > "u", me = Symbol("needle:raycast-mesh");
121
- function J(i) {
122
- return i?.[me] instanceof Q ? i[me] : null;
121
+ function Z(i) {
122
+ return i?.[me] instanceof J ? i[me] : null;
123
123
  }
124
124
  function nt(i, t) {
125
- if ((i.type === "Mesh" || i.type === "SkinnedMesh") && !J(i)) {
125
+ if ((i.type === "Mesh" || i.type === "SkinnedMesh") && !Z(i)) {
126
126
  const s = it(t);
127
127
  s.userData = { isRaycastMesh: !0 }, i[me] = s;
128
128
  }
@@ -132,7 +132,7 @@ function ot(i = !0) {
132
132
  if (Y) return;
133
133
  const t = Y = q.prototype.raycast;
134
134
  q.prototype.raycast = function(e, s) {
135
- const n = this, r = J(n);
135
+ const n = this, r = Z(n);
136
136
  let o;
137
137
  r && n.isMesh && (o = n.geometry, n.geometry = r), t.call(this, e, s), o && (n.geometry = o);
138
138
  };
@@ -143,29 +143,29 @@ function ot(i = !0) {
143
143
  }
144
144
  let Y = null;
145
145
  function it(i) {
146
- const t = new Q();
146
+ const t = new J();
147
147
  for (const e in i.attributes)
148
148
  t.setAttribute(e, i.getAttribute(e));
149
149
  return t.setIndex(i.getIndex()), t;
150
150
  }
151
- const W = new Array(), g = X("debugprogressive");
152
- let re, N = -1;
151
+ const U = new Array(), g = X("debugprogressive");
152
+ let Q, N = -1;
153
153
  if (g) {
154
154
  let i = function() {
155
155
  N += 1, N >= t && (N = -1), console.log(`Toggle LOD level [${N}]`);
156
156
  }, t = 6;
157
157
  window.addEventListener("keyup", (e) => {
158
- e.key === "p" && i(), e.key === "w" && (re = !re, console.log(`Toggle wireframe [${re}]`));
158
+ e.key === "p" && i(), e.key === "w" && (Q = !Q, console.log(`Toggle wireframe [${Q}]`));
159
159
  const s = parseInt(e.key);
160
160
  !isNaN(s) && s >= 0 && (N = s, console.log(`Set LOD level to [${N}]`));
161
161
  });
162
162
  }
163
163
  function Ie(i) {
164
- if (g)
164
+ if (g && Q !== void 0)
165
165
  if (Array.isArray(i))
166
166
  for (const t of i)
167
167
  Ie(t);
168
- else i && "wireframe" in i && (i.wireframe = re === !0);
168
+ else i && "wireframe" in i && (i.wireframe = Q === !0);
169
169
  }
170
170
  const H = new Array();
171
171
  let at = 0;
@@ -238,7 +238,7 @@ class we {
238
238
  }
239
239
  function dt(i) {
240
240
  for (const t of i.geometries) {
241
- const e = t.geometry, s = new Q();
241
+ const e = t.geometry, s = new J();
242
242
  if (s.name = e.name || "", e.index) {
243
243
  const n = e.index;
244
244
  s.setIndex(ae(n));
@@ -316,8 +316,8 @@ function ae(i) {
316
316
  let t = i;
317
317
  if ("isInterleavedBufferAttribute" in i && i.isInterleavedBufferAttribute) {
318
318
  const e = i.data, s = e.array, n = new Fe(s, e.stride);
319
- t = new Ue(n, i.itemSize, s.byteOffset, i.normalized), t.offset = i.offset;
320
- } else "isBufferAttribute" in i && i.isBufferAttribute && (t = new We(i.array, i.itemSize, i.normalized), t.usage = i.usage, t.gpuType = i.gpuType, t.updateRanges = i.updateRanges);
319
+ t = new We(n, i.itemSize, s.byteOffset, i.normalized), t.offset = i.offset;
320
+ } else "isBufferAttribute" in i && i.isBufferAttribute && (t = new Ue(i.array, i.itemSize, i.normalized), t.usage = i.usage, t.gpuType = i.gpuType, t.updateRanges = i.updateRanges);
321
321
  return t;
322
322
  }
323
323
  const ct = X("gltf-progressive-worker"), ft = X("gltf-progressive-reduce-mipmaps"), le = Symbol("needle-progressive-texture"), F = "NEEDLE_progressive";
@@ -326,6 +326,7 @@ class y {
326
326
  get name() {
327
327
  return F;
328
328
  }
329
+ // #region PUBLIC API
329
330
  static getMeshLODExtension(t) {
330
331
  const e = this.getAssignedLODInformation(t);
331
332
  return e?.key ? this.lodInfos.get(e.key) : null;
@@ -426,7 +427,7 @@ class y {
426
427
  const s = t.geometry, n = this.getAssignedLODInformation(s);
427
428
  if (!n)
428
429
  return Promise.resolve(null);
429
- for (const r of W)
430
+ for (const r of U)
430
431
  r.onBeforeGetLODMesh?.(t, e);
431
432
  return t["LOD:requested level"] = e, y.getOrLoadLOD(s, e).then((r) => {
432
433
  if (Array.isArray(r)) {
@@ -491,6 +492,7 @@ class y {
491
492
  }
492
493
  return Promise.resolve(null);
493
494
  }
495
+ // #region INTERNAL
494
496
  static assignTextureLODForSlot(t, e, s, n) {
495
497
  return t?.isTexture !== !0 ? Promise.resolve(null) : n === "glyphMap" ? Promise.resolve(t) : y.getOrLoadLOD(t, e).then((r) => {
496
498
  if (Array.isArray(r))
@@ -575,12 +577,12 @@ class y {
575
577
  */
576
578
  static registerTexture = (t, e, s, n, r) => {
577
579
  if (!e) {
578
- g && console.error("gltf-progressive: Called register texture without texture");
580
+ g && console.error("!! gltf-progressive: Called register texture without texture");
579
581
  return;
580
582
  }
581
583
  if (g) {
582
584
  const l = e.image?.width || e.source?.data?.width || 0, a = e.image?.height || e.source?.data?.height || 0;
583
- console.log(`> Progressive: register texture[${n}] "${e.name || e.uuid}", Current: ${l}x${a}, Max: ${r.lods[0]?.width}x${r.lods[0]?.height}, uuid: ${e.uuid}`, r, e);
585
+ console.log(`> gltf-progressive: register texture[${n}] "${e.name || e.uuid}", Current: ${l}x${a}, Max: ${r.lods[0]?.width}x${r.lods[0]?.height}, uuid: ${e.uuid}`, r, e);
584
586
  }
585
587
  e.source && (e.source[le] = r);
586
588
  const o = r.guid;
@@ -597,8 +599,8 @@ class y {
597
599
  }
598
600
  l.userData || (l.userData = {}), g && console.log("> Progressive: register mesh " + s.name, { index: r, uuid: s.uuid }, o, s), y.assignLODInformation(t, l, e, n, r), y.lodInfos.set(e, o);
599
601
  let a = y.lowresCache.get(e);
600
- a ? a.push(s.geometry) : a = [s.geometry], y.lowresCache.set(e, a), n > 0 && !J(s) && nt(s, l);
601
- for (const u of W)
602
+ a ? a.push(s.geometry) : a = [s.geometry], y.lowresCache.set(e, a), n > 0 && !Z(s) && nt(s, l);
603
+ for (const u of U)
602
604
  u.onRegisteredNewMesh?.(s, o);
603
605
  };
604
606
  /** A map of key = asset uuid and value = LOD information */
@@ -619,7 +621,9 @@ class y {
619
621
  const a = t;
620
622
  a.source && a.source[le] && (o = a.source[le]);
621
623
  }
622
- if (o || (o = y.lodInfos.get(r)), o) {
624
+ if (o || (o = y.lodInfos.get(r)), !o)
625
+ g && console.warn(`Can not load LOD ${e}: no LOD info found for "${r}" ${t.name}`, t.type, y.lodInfos);
626
+ else {
623
627
  if (e > 0) {
624
628
  let c = !1;
625
629
  const p = Array.isArray(o.lods);
@@ -638,7 +642,7 @@ class y {
638
642
  s && console.log(`LOD ${e} was already loading/loaded: ${c}`);
639
643
  let d = await _.catch((O) => (console.error(`Error loading LOD ${e} from ${u}
640
644
  `, O), null)), x = !1;
641
- if (d == null || (d instanceof E && t instanceof E ? d.image?.data || d.source?.data ? d = this.copySettings(t, d) : (x = !0, this.previouslyLoaded.delete(c)) : d instanceof Q && t instanceof Q && (d.attributes.position?.array || (x = !0, this.previouslyLoaded.delete(c)))), !x)
645
+ if (d == null || (d instanceof E && t instanceof E ? d.image?.data || d.source?.data ? d = this.copySettings(t, d) : (x = !0, this.previouslyLoaded.delete(c)) : d instanceof J && t instanceof J && (d.attributes.position?.array || (x = !0, this.previouslyLoaded.delete(c)))), !x)
642
646
  return d;
643
647
  }
644
648
  if (!p.use)
@@ -730,8 +734,7 @@ class y {
730
734
  const p = await new ze().loadAsync(u);
731
735
  return p ? (p.guid = o.guid, p.flipY = !1, p.needsUpdate = !0, p.colorSpace = t.colorSpace, s && console.log(o, p)) : g && console.warn("failed loading", u), p;
732
736
  }
733
- } else
734
- g && console.warn(`Can not load LOD ${e}: no LOD info found for "${r}" ${t.name}`, t.type);
737
+ }
735
738
  return null;
736
739
  }
737
740
  static maxConcurrent = 50;
@@ -839,7 +842,7 @@ class ue {
839
842
  });
840
843
  }
841
844
  }
842
- const C = X("debugprogressive"), gt = X("noprogressive"), de = Symbol("Needle:LODSManager"), ce = Symbol("Needle:LODState"), U = Symbol("Needle:CurrentLOD"), P = { mesh_lod: -1, texture_lod: -1 };
845
+ const k = X("debugprogressive"), gt = X("noprogressive"), de = Symbol("Needle:LODSManager"), ce = Symbol("Needle:LODState"), W = Symbol("Needle:CurrentLOD"), P = { mesh_lod: -1, texture_lod: -1 };
843
846
  class L {
844
847
  /**
845
848
  * Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
@@ -850,11 +853,11 @@ class L {
850
853
  return t[ce];
851
854
  }
852
855
  static addPlugin(t) {
853
- W.push(t);
856
+ U.push(t);
854
857
  }
855
858
  static removePlugin(t) {
856
- const e = W.indexOf(t);
857
- e >= 0 && W.splice(e, 1);
859
+ const e = U.indexOf(t);
860
+ e >= 0 && U.splice(e, 1);
858
861
  }
859
862
  /**
860
863
  * Gets the LODsManager for the given renderer. If the LODsManager does not exist yet, it will be created.
@@ -875,7 +878,7 @@ class L {
875
878
  projectionScreenMatrix = new _e();
876
879
  /** @deprecated use static `LODsManager.addPlugin()` method. This getter will be removed in later versions */
877
880
  get plugins() {
878
- return W;
881
+ return U;
879
882
  }
880
883
  /**
881
884
  * Force override the LOD level for all objects (meshes + textures) rendered in the scene
@@ -964,7 +967,7 @@ class L {
964
967
  const e = this;
965
968
  xe(this.renderer), this.renderer.render = function(s, n) {
966
969
  const r = e.renderer.getRenderTarget();
967
- (r == null || "isXRRenderTarget" in r && r.isXRRenderTarget) && (t = 0, e.#r += 1, e.#n = e.#o.getDelta(), e.#i += e.#n, e._fpsBuffer.shift(), e._fpsBuffer.push(1 / e.#n), e.#s = e._fpsBuffer.reduce((l, a) => l + a) / e._fpsBuffer.length, C && e.#r % 200 === 0 && console.log("FPS", Math.round(e.#s), "Interval:", e.#e));
970
+ (r == null || "isXRRenderTarget" in r && r.isXRRenderTarget) && (t = 0, e.#r += 1, e.#n = e.#o.getDelta(), e.#i += e.#n, e._fpsBuffer.shift(), e._fpsBuffer.push(1 / e.#n), e.#s = e._fpsBuffer.reduce((l, a) => l + a) / e._fpsBuffer.length, k && e.#r % 200 === 0 && console.log("FPS", Math.round(e.#s), "Interval:", e.#e));
968
971
  const o = t++;
969
972
  e.#t.call(this, s, n), e.onAfterRender(s, n, o);
970
973
  };
@@ -984,7 +987,7 @@ class L {
984
987
  (l.name === "EffectMaterial" || l.name === "CopyShader") && (o = !1);
985
988
  }
986
989
  if ((e.parent && e.parent.type === "CubeCamera" || s >= 1 && e.type === "OrthographicCamera") && (o = !1), o) {
987
- if (gt || (this.updateInterval === "auto" ? this.#s < 40 && this.#e < 10 ? (this.#e += 1, C && console.warn("↓ Reducing LOD updates", this.#e, this.#s.toFixed(0))) : this.#s >= 60 && this.#e > 1 && (this.#e -= 1, C && console.warn("↑ Increasing LOD updates", this.#e, this.#s.toFixed(0))) : this.#e = this.updateInterval, this.#e > 0 && this.#r % this.#e != 0))
990
+ if (gt || (this.updateInterval === "auto" ? this.#s < 40 && this.#e < 10 ? (this.#e += 1, k && console.warn("↓ Reducing LOD updates", this.#e, this.#s.toFixed(0))) : this.#s >= 60 && this.#e > 1 && (this.#e -= 1, k && console.warn("↑ Increasing LOD updates", this.#e, this.#s.toFixed(0))) : this.#e = this.updateInterval, this.#e > 0 && this.#r % this.#e != 0))
988
991
  return;
989
992
  this.internalUpdate(t, e), this._postprocessPromiseGroups();
990
993
  }
@@ -998,7 +1001,7 @@ class L {
998
1001
  const r = this.targetTriangleDensity;
999
1002
  for (const a of n) {
1000
1003
  if (a.material && (a.geometry?.type === "BoxGeometry" || a.geometry?.type === "BufferGeometry") && (a.material.name === "SphericalGaussianBlur" || a.material.name == "BackgroundCubeMaterial" || a.material.name === "CubemapFromEquirect" || a.material.name === "EquirectangularToCubeUV")) {
1001
- C && (a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] || (a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] = !0, console.warn("Ignoring skybox or BLIT object", a, a.material.name, a.material.type)));
1004
+ k && (a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] || (a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] = !0, console.warn("Ignoring skybox or BLIT object", a, a.material.name, a.material.type)));
1002
1005
  continue;
1003
1006
  }
1004
1007
  switch (a.material.type) {
@@ -1010,7 +1013,7 @@ class L {
1010
1013
  case "MeshDepthMaterial":
1011
1014
  continue;
1012
1015
  }
1013
- if (C === "color" && a.material && !a.object.progressive_debug_color) {
1016
+ if (k === "color" && a.material && !a.object.progressive_debug_color) {
1014
1017
  a.object.progressive_debug_color = !0;
1015
1018
  const c = Math.random() * 16777215, p = new Ne({ color: c });
1016
1019
  a.object.material = p;
@@ -1035,11 +1038,11 @@ class L {
1035
1038
  let r = s[ce];
1036
1039
  if (r || (r = new pt(), s[ce] = r), r.frames++ < 2)
1037
1040
  return;
1038
- for (const l of W)
1041
+ for (const l of U)
1039
1042
  l.onBeforeUpdateLOD?.(this.renderer, t, e, s);
1040
1043
  const o = this.overrideLodLevel !== void 0 ? this.overrideLodLevel : N;
1041
1044
  o >= 0 ? (P.mesh_lod = o, P.texture_lod = o) : (this.calculateLodLevel(e, s, r, n, P), P.mesh_lod = Math.round(P.mesh_lod), P.texture_lod = Math.round(P.texture_lod)), P.mesh_lod >= 0 && this.loadProgressiveMeshes(s, P.mesh_lod), s.material && P.texture_lod >= 0 && this.loadProgressiveTextures(s.material, P.texture_lod, o), g && s.material && !s.isGizmo && Ie(s.material);
1042
- for (const l of W)
1045
+ for (const l of U)
1043
1046
  l.onAfterUpdatedLOD?.(this.renderer, t, e, s, P);
1044
1047
  r.lastLodLevel_Mesh = P.mesh_lod, r.lastLodLevel_Texture = P.texture_lod;
1045
1048
  }
@@ -1056,8 +1059,8 @@ class L {
1056
1059
  return;
1057
1060
  }
1058
1061
  let n = !1;
1059
- if ((t[U] === void 0 || e < t[U]) && (n = !0), s !== void 0 && s >= 0 && (n = t[U] != s, e = s), n) {
1060
- t[U] = e;
1062
+ if ((t[W] === void 0 || e < t[W]) && (n = !0), s !== void 0 && s >= 0 && (n = t[W] != s, e = s), n) {
1063
+ t[W] = e;
1061
1064
  const r = y.assignTextureLOD(t, e).then((o) => {
1062
1065
  this._lodchangedlisteners.forEach((l) => l({ type: "texture", level: e, object: t }));
1063
1066
  });
@@ -1072,11 +1075,11 @@ class L {
1072
1075
  */
1073
1076
  loadProgressiveMeshes(t, e) {
1074
1077
  if (!t) return Promise.resolve(null);
1075
- let s = t[U] !== e;
1078
+ let s = t[W] !== e;
1076
1079
  const n = t["DEBUG:LOD"];
1077
- if (n != null && (s = t[U] != n, e = n), s) {
1078
- t[U] = e;
1079
- const r = t.geometry, o = y.assignMeshLOD(t, e).then((l) => (l && t[U] == e && r != t.geometry && this._lodchangedlisteners.forEach((a) => a({ type: "mesh", level: e, object: t })), l));
1080
+ if (n != null && (s = t[W] != n, e = n), s) {
1081
+ t[W] = e;
1082
+ const r = t.geometry, o = y.assignMeshLOD(t, e).then((l) => (l && t[W] == e && r != t.geometry && this._lodchangedlisteners.forEach((a) => a({ type: "mesh", level: e, object: t })), l));
1080
1083
  return ue.addPromise("mesh", t, o, this._newPromiseGroups), o;
1081
1084
  }
1082
1085
  return Promise.resolve(null);
@@ -1111,7 +1114,7 @@ class L {
1111
1114
  return;
1112
1115
  }
1113
1116
  let l = 10 + 1, a = !1;
1114
- if (C && e["DEBUG:LOD"] != null)
1117
+ if (k && e["DEBUG:LOD"] != null)
1115
1118
  return e["DEBUG:LOD"];
1116
1119
  const u = y.getMeshLODExtension(e.geometry)?.lods, c = y.getPrimitiveIndex(e.geometry), p = u && u.length > 0, _ = y.getMaterialMinMaxLODsCount(e.material), v = _.min_count !== 1 / 0 && _.min_count >= 0 && _.max_count >= 0;
1117
1120
  if (!p && !v) {
@@ -1132,7 +1135,7 @@ class L {
1132
1135
  }
1133
1136
  const x = d[L.$skinnedMeshBoundsOffset];
1134
1137
  if ((s.frames + x) % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
1135
- const O = J(d), B = d.geometry;
1138
+ const O = Z(d), B = d.geometry;
1136
1139
  O && (d.geometry = O), d.computeBoundingBox(), d.geometry = B;
1137
1140
  }
1138
1141
  }
@@ -1154,10 +1157,10 @@ class L {
1154
1157
  }
1155
1158
  if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && d.isPerspectiveCamera && d.fov > 70) {
1156
1159
  const f = this._tempBox.min, h = this._tempBox.max;
1157
- let M = f.x, D = f.y, $ = h.x, K = h.y;
1158
- const Z = 2, oe = 1.5, ee = (f.x + h.x) * 0.5, te = (f.y + h.y) * 0.5;
1159
- M = (M - ee) * Z + ee, D = (D - te) * Z + te, $ = ($ - ee) * Z + ee, K = (K - te) * Z + te;
1160
- const Re = M < 0 && $ > 0 ? 0 : Math.min(Math.abs(f.x), Math.abs(h.x)), Be = D < 0 && K > 0 ? 0 : Math.min(Math.abs(f.y), Math.abs(h.y)), ie = Math.max(Re, Be);
1160
+ let M = f.x, D = f.y, $ = h.x, j = h.y;
1161
+ const ee = 2, oe = 1.5, te = (f.x + h.x) * 0.5, se = (f.y + h.y) * 0.5;
1162
+ M = (M - te) * ee + te, D = (D - se) * ee + se, $ = ($ - te) * ee + te, j = (j - se) * ee + se;
1163
+ const Re = M < 0 && $ > 0 ? 0 : Math.min(Math.abs(f.x), Math.abs(h.x)), Be = D < 0 && j > 0 ? 0 : Math.min(Math.abs(f.y), Math.abs(h.y)), ie = Math.max(Re, Be);
1161
1164
  s.lastCentrality = (oe - ie) * (oe - ie) * (oe - ie);
1162
1165
  } else
1163
1166
  s.lastCentrality = 1;
@@ -1166,13 +1169,13 @@ class L {
1166
1169
  const O = t.matrixWorldInverse, B = this._tempBox2;
1167
1170
  B.copy(G), B.applyMatrix4(e.matrixWorld), B.applyMatrix4(O);
1168
1171
  const b = B.getSize(this._tempBox2Size), z = Math.max(b.x, b.y);
1169
- if (Math.max(x.x, x.y) != 0 && z != 0 && (x.z = b.z / Math.max(b.x, b.y) * Math.max(x.x, x.y)), s.lastScreenCoverage = Math.max(x.x, x.y, x.z), s.lastScreenspaceVolume.copy(x), s.lastScreenCoverage *= s.lastCentrality, C && L.debugDrawLine) {
1172
+ if (Math.max(x.x, x.y) != 0 && z != 0 && (x.z = b.z / Math.max(b.x, b.y) * Math.max(x.x, x.y)), s.lastScreenCoverage = Math.max(x.x, x.y, x.z), s.lastScreenspaceVolume.copy(x), s.lastScreenCoverage *= s.lastCentrality, k && L.debugDrawLine) {
1170
1173
  const f = this.tempMatrix.copy(this.projectionScreenMatrix);
1171
1174
  f.invert();
1172
1175
  const h = L.corner0, M = L.corner1, D = L.corner2, $ = L.corner3;
1173
1176
  h.copy(this._tempBox.min), M.copy(this._tempBox.max), M.x = h.x, D.copy(this._tempBox.max), D.y = h.y, $.copy(this._tempBox.max);
1174
- const K = (h.z + $.z) * 0.5;
1175
- h.z = M.z = D.z = $.z = K, h.applyMatrix4(f), M.applyMatrix4(f), D.applyMatrix4(f), $.applyMatrix4(f), L.debugDrawLine(h, M, 255), L.debugDrawLine(h, D, 255), L.debugDrawLine(M, $, 255), L.debugDrawLine(D, $, 255);
1177
+ const j = (h.z + $.z) * 0.5;
1178
+ h.z = M.z = D.z = $.z = j, h.applyMatrix4(f), M.applyMatrix4(f), D.applyMatrix4(f), $.applyMatrix4(f), L.debugDrawLine(h, M, 255), L.debugDrawLine(h, D, 255), L.debugDrawLine(M, $, 255), L.debugDrawLine(D, $, 255);
1176
1179
  }
1177
1180
  let w = 999;
1178
1181
  if (u && s.lastScreenCoverage > 0)
@@ -1185,16 +1188,16 @@ class L {
1185
1188
  }
1186
1189
  w < l && (l = w, a = !0);
1187
1190
  }
1188
- if (a ? r.mesh_lod = l : r.mesh_lod = s.lastLodLevel_Mesh, C && r.mesh_lod != s.lastLodLevel_Mesh) {
1191
+ if (a ? r.mesh_lod = l : r.mesh_lod = s.lastLodLevel_Mesh, k && r.mesh_lod != s.lastLodLevel_Mesh) {
1189
1192
  const x = u?.[r.mesh_lod];
1190
1193
  x && console.debug(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (density: ${x.densities?.[c].toFixed(0)}) | ${e.name}`);
1191
1194
  }
1192
1195
  if (v) {
1193
1196
  const d = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
1194
1197
  if (s.lastLodLevel_Texture < 0) {
1195
- if (r.texture_lod = _.max_count - 1, C) {
1198
+ if (r.texture_lod = _.max_count - 1, k) {
1196
1199
  const x = _.lods[_.max_count - 1];
1197
- C && console.log(`First Texture LOD ${r.texture_lod} (${x.max_height}px) - ${e.name}`);
1200
+ k && console.log(`First Texture LOD ${r.texture_lod} (${x.max_height}px) - ${e.name}`);
1198
1201
  }
1199
1202
  } else {
1200
1203
  const x = s.lastScreenspaceVolume.x + s.lastScreenspaceVolume.y + s.lastScreenspaceVolume.z;
@@ -1205,7 +1208,7 @@ class L {
1205
1208
  for (let S = _.lods.length - 1; S >= 0; S--) {
1206
1209
  const w = _.lods[S];
1207
1210
  if (!(d && w.max_height >= 2048) && !(Ae() && w.max_height > 4096) && (w.max_height > b || !z && S === 0)) {
1208
- if (z = !0, r.texture_lod = S, C && r.texture_lod < s.lastLodLevel_Texture) {
1211
+ if (z = !0, r.texture_lod = S, k && r.texture_lod < s.lastLodLevel_Texture) {
1209
1212
  const m = w.max_height;
1210
1213
  console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${m}px
1211
1214
  Screensize: ${b.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${x.toFixed(1)}
@@ -1227,16 +1230,16 @@ class pt {
1227
1230
  lastScreenspaceVolume = new A();
1228
1231
  lastCentrality = 0;
1229
1232
  }
1230
- const ve = Symbol("NEEDLE_mesh_lod"), se = Symbol("NEEDLE_texture_lod");
1233
+ const ve = Symbol("NEEDLE_mesh_lod"), re = Symbol("NEEDLE_texture_lod");
1231
1234
  let fe = null;
1232
- function Ce() {
1235
+ function ke() {
1233
1236
  const i = mt();
1234
1237
  i && (i.mapURLs(function(t) {
1235
1238
  return be(), t;
1236
1239
  }), be(), fe?.disconnect(), fe = new MutationObserver((t) => {
1237
1240
  t.forEach((e) => {
1238
1241
  e.addedNodes.forEach((s) => {
1239
- s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" && ke(s);
1242
+ s instanceof HTMLElement && s.tagName.toLowerCase() === "model-viewer" && Ce(s);
1240
1243
  });
1241
1244
  });
1242
1245
  }), fe.observe(document, { childList: !0, subtree: !0 }));
@@ -1245,18 +1248,18 @@ function mt() {
1245
1248
  if (typeof customElements > "u") return null;
1246
1249
  const i = customElements.get("model-viewer");
1247
1250
  return i || (customElements.whenDefined("model-viewer").then(() => {
1248
- console.debug("[gltf-progressive] model-viewer defined"), Ce();
1251
+ console.debug("[gltf-progressive] model-viewer defined"), ke();
1249
1252
  }), null);
1250
1253
  }
1251
1254
  function be() {
1252
1255
  if (typeof document > "u") return;
1253
1256
  document.querySelectorAll("model-viewer").forEach((t) => {
1254
- ke(t);
1257
+ Ce(t);
1255
1258
  });
1256
1259
  }
1257
1260
  const Me = /* @__PURE__ */ new WeakSet();
1258
1261
  let yt = 0;
1259
- function ke(i) {
1262
+ function Ce(i) {
1260
1263
  if (!i || Me.has(i))
1261
1264
  return null;
1262
1265
  Me.add(i), console.debug("[gltf-progressive] found new model-viewer..." + ++yt + `
@@ -1310,13 +1313,13 @@ class xt {
1310
1313
  return t.element;
1311
1314
  }
1312
1315
  tryParseTextureLOD(t, e) {
1313
- if (e[se] == !0) return;
1314
- e[se] = !0;
1316
+ if (e[re] == !0) return;
1317
+ e[re] = !0;
1315
1318
  const s = this.tryGetCurrentGLTF(t), n = this.tryGetCurrentModelViewer(t), r = this.getUrl(n);
1316
1319
  if (r && s && e.material) {
1317
1320
  let o = function(a) {
1318
- if (a[se] == !0) return;
1319
- a[se] = !0, a.userData && (a.userData.LOD = -1);
1321
+ if (a[re] == !0) return;
1322
+ a[re] = !0, a.userData && (a.userData.LOD = -1);
1320
1323
  const u = Object.keys(a);
1321
1324
  for (let c = 0; c < u.length; c++) {
1322
1325
  const p = u[c], _ = a[p];
@@ -1375,14 +1378,14 @@ function wt(...i) {
1375
1378
  const r = L.get(e);
1376
1379
  return n?.enableLODsManager !== !1 && r.enable(), r;
1377
1380
  }
1378
- Ce();
1381
+ ke();
1379
1382
  if (!rt) {
1380
1383
  const i = {
1381
1384
  gltfProgressive: {
1382
1385
  useNeedleProgressive: wt,
1383
1386
  LODsManager: L,
1384
1387
  configureLoader: Te,
1385
- getRaycastMesh: J,
1388
+ getRaycastMesh: Z,
1386
1389
  useRaycastMeshes: ot
1387
1390
  }
1388
1391
  };
@@ -1396,12 +1399,12 @@ export {
1396
1399
  F as EXTENSION_NAME,
1397
1400
  L as LODsManager,
1398
1401
  y as NEEDLE_progressive,
1399
- Ke as VERSION,
1402
+ je as VERSION,
1400
1403
  Se as addDracoAndKTX2Loaders,
1401
1404
  Te as configureLoader,
1402
1405
  xe as createLoaders,
1403
- J as getRaycastMesh,
1404
- Ce as patchModelViewer,
1406
+ Z as getRaycastMesh,
1407
+ ke as patchModelViewer,
1405
1408
  nt as registerRaycastMesh,
1406
1409
  Qe as setDracoDecoderLocation,
1407
1410
  Je as setKTX2TranscoderLocation,