@needle-tools/gltf-progressive 3.6.0-canary.5401de9 → 3.6.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ 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.6.0] - 2026-07-07
8
+ - version bump
9
+
10
+ ## [3.6.0-beta.1] - 2026-06-09
11
+ - Fix: texture LOD selection regressed for meshes that only have texture LODs (no mesh LODs); screen coverage is now computed unconditionally so texture LODs update with camera distance again.
12
+
7
13
  ## [3.6.0-alpha.3] - 2026-05-27
8
14
  - Fix: stale progressive mesh and texture LOD requests no longer overwrite newer explicit targets, while still allowing useful intermediate LODs to apply during rapid target changes.
9
15
  - Fix: progressive worker/debug imports no longer assume `window` exists, and texture LOD selection now uses the renderer pixel ratio so main-thread and worker/offscreen renderers can make matching LOD decisions.
package/README.md CHANGED
@@ -26,19 +26,19 @@ useNeedleProgressive(gltf_loader, webgl_renderer)
26
26
 
27
27
  Examples are in the `/examples` directory. Live versions can be found in the links below.
28
28
 
29
- To view them locally, run `npx serve examples` and open the printed URL.
29
+ To view the examples locally with the current checkout's runtime, run `npm run examples:serve` and open the printed examples index URL.
30
30
 
31
31
  - [Loading comparisons](https://stackblitz.com/edit/gltf-progressive-comparison?file=package.json,index.html)
32
32
  - [Vanilla three.js](https://engine.needle.tools/demos/gltf-progressive/threejs/) - multiple models and animations
33
- - `examples/webgpu` - WebGPU renderer
34
- - `examples/offscreen` - main-thread OffscreenCanvas rendering
35
- - `examples/worker-rendering` - OffscreenCanvas rendering in a Worker
36
33
  - [React Three Fiber](https://engine.needle.tools/demos/gltf-progressive/r3f/)
37
34
  - \<model-viewer\>
38
35
  - [single \<model-viewer> element](https://engine.needle.tools/demos/gltf-progressive/modelviewer)
39
36
  - [multiple \<model-viewer> elements](https://engine.needle.tools/demos/gltf-progressive/modelviewer-multiple)
40
37
  - [Needle Engine](https://stackblitz.com/edit/needle-engine-gltf-progressive?file=src%2Fmain.ts)
41
38
  - [Needle Cloud](https://cloud.needle.tools/view?file=Z23hmXBZN45qJ-ZN45qJ-world)
39
+ - `examples/webgpu` - WebGPU renderer
40
+ - `examples/offscreen` - main-thread OffscreenCanvas rendering
41
+ - `examples/worker-rendering` - OffscreenCanvas rendering in a Worker
42
42
 
43
43
  **Interactive Examples**:
44
44
  - [Stackblitz](https://stackblitz.com/@marwie/collections/gltf-progressive)
@@ -79,10 +79,10 @@ gltfLoader.load(url, gltf => {
79
79
  <script type="importmap">
80
80
  {
81
81
  "imports": {
82
- "three": "https://cdn.jsdelivr.net/npm/three@latest/build/three.module.js",
83
- "three/addons/": "https://cdn.jsdelivr.net/npm/three@latest/examples/jsm/",
84
- "three/examples/": "https://cdn.jsdelivr.net/npm/three@latest/examples/",
85
- "@needle-tools/gltf-progressive": "https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive/gltf-progressive.min.js"
82
+ "three": "https://cdn.jsdelivr.net/npm/three@0.184.0/build/three.module.js",
83
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.184.0/examples/jsm/",
84
+ "three/examples/": "https://cdn.jsdelivr.net/npm/three@0.184.0/examples/",
85
+ "@needle-tools/gltf-progressive": "https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive@3.6.0-canary.5401de9/gltf-progressive.min.js"
86
86
  }
87
87
  }
88
88
  </script>
@@ -90,7 +90,7 @@ gltfLoader.load(url, gltf => {
90
90
  ```
91
91
 
92
92
 
93
- ## react three fiber
93
+ ## React Three Fiber
94
94
 
95
95
  Full react-three-fiber example at: `examples/react-three-fiber`
96
96
 
@@ -105,7 +105,7 @@ function MyModel() {
105
105
  }
106
106
  ```
107
107
 
108
- ## google \<model-viewer\>
108
+ ## Google \<model-viewer\>
109
109
 
110
110
  Full model-viewer example at: `examples/modelviewer.html`
111
111
 
@@ -115,13 +115,13 @@ Full model-viewer example at: `examples/modelviewer.html`
115
115
  <script type="importmap">
116
116
  {
117
117
  "imports": {
118
- "three": "https://unpkg.com/three/build/three.module.js",
119
- "three/": "https://unpkg.com/three/"
118
+ "three": "https://unpkg.com/three@0.184.0/build/three.module.js",
119
+ "three/": "https://unpkg.com/three@0.184.0/"
120
120
  }
121
121
  }
122
122
  </script>
123
123
  <!-- Include gltf-progressive -->
124
- <script type="module" src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive/gltf-progressive.min.js"></script>
124
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive@3.6.0-canary.5401de9/gltf-progressive.min.js"></script>
125
125
  <!-- Include model-viewer -->
126
126
  <script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
127
127
  </head>
@@ -134,7 +134,7 @@ Full model-viewer example at: `examples/modelviewer.html`
134
134
 
135
135
  ## Needle Engine
136
136
 
137
- [Needle Engine](https://needle.tools) natively supports progressive loading of these glTF files! See [docs.needle.tools](https://docs.needle.tools) for more information.
137
+ [Needle Engine](https://needle.tools) natively supports progressive loading of these glTF files! See [docs.needle.tools/gltf-progressive](https://engine.needle.tools/docs/gltf-progressive/) for more information.
138
138
 
139
139
 
140
140
  # How can I generate assets for progressive loading
@@ -209,6 +209,8 @@ Call `getRaycastMesh(<your_mesh_object>)`
209
209
  # Extension
210
210
  Read more about the [NEEDLE_progressive extension](./NEEDLE_progressive/README.md)
211
211
 
212
+ # Documentation
213
+ Read more about Needle Progressive GLTF loading in the [Needle Engine documentation](https://docs.needle.tools/engine/gltf-progressive/)
212
214
 
213
215
  # Contact ✒️
214
216
  <b>[🌵 needle — tools for creators](https://needle.tools)</b> •
@@ -13,13 +13,13 @@
13
13
  <script type="importmap">
14
14
  {
15
15
  "imports": {
16
- "three": "https://unpkg.com/three/build/three.module.js",
17
- "three/": "https://unpkg.com/three/"
16
+ "three": "https://unpkg.com/three@0.184.0/build/three.module.js",
17
+ "three/": "https://unpkg.com/three@0.184.0/"
18
18
  }
19
19
  }
20
20
  </script>
21
21
  <script type="module"
22
- src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive/gltf-progressive.min.js"></script>
22
+ src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive@3.6.0-canary.5401de9/gltf-progressive.min.js"></script>
23
23
  <script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
24
24
  </head>
25
25
 
@@ -123,4 +123,4 @@
123
123
  }
124
124
  </style>
125
125
 
126
- </html>
126
+ </html>
@@ -7,14 +7,14 @@
7
7
  <script type="importmap">
8
8
  {
9
9
  "imports": {
10
- "three": "https://unpkg.com/three/build/three.module.js",
11
- "three/": "https://unpkg.com/three/"
10
+ "three": "https://unpkg.com/three@0.184.0/build/three.module.js",
11
+ "three/": "https://unpkg.com/three@0.184.0/"
12
12
  }
13
13
  }
14
14
  </script>
15
15
  <script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
16
16
  <script type="module"
17
- src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive/gltf-progressive.min.js"></script>
17
+ src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive@3.6.0-canary.5401de9/gltf-progressive.min.js"></script>
18
18
  </head>
19
19
 
20
20
  <model-viewer src="https://engine.needle.tools/demos/gltf-progressive/assets/church/model.glb" ar shadow-intensity="1"
@@ -31,4 +31,4 @@
31
31
  }
32
32
  </style>
33
33
 
34
- </html>
34
+ </html>
@@ -3,15 +3,22 @@ import {
3
3
  addLoadedScene,
4
4
  createOrbitControls,
5
5
  createExampleState,
6
+ createSceneChangeButton,
7
+ getInitialSceneIndex,
6
8
  getModelUrl,
7
9
  markError,
8
10
  markReady,
11
+ markSceneLoaded,
12
+ markSceneLoading,
13
+ normalizeSceneIndex,
9
14
  resizeRenderer,
10
15
  setupScene,
11
16
  setupRoomEnvironment,
17
+ trackLODChanges,
12
18
  } from "../shared/example-utils.js";
13
19
 
14
20
  const state = createExampleState("offscreen");
21
+ const params = new URLSearchParams(location.search);
15
22
 
16
23
  try {
17
24
  if (!globalThis.OffscreenCanvas) throw new Error("OffscreenCanvas is not available in this browser.");
@@ -30,6 +37,9 @@ try {
30
37
  const { scene, camera } = setupScene(THREE, width, height);
31
38
  setupRoomEnvironment(THREE, runtime.RoomEnvironment, renderer, scene);
32
39
  const controls = createOrbitControls(runtime.OrbitControls, camera, visibleCanvas);
40
+ let root = null;
41
+ let sceneIndex = getInitialSceneIndex(params);
42
+ let loadToken = 0;
33
43
 
34
44
  function resize() {
35
45
  width = window.innerWidth;
@@ -41,24 +51,46 @@ try {
41
51
  }
42
52
  resize();
43
53
 
44
- const loader = new runtime.GLTFLoader();
45
- runtime.useNeedleProgressive(loader, renderer);
46
- const root = await new Promise((resolve, reject) => {
47
- loader.load(getModelUrl(), gltf => resolve(addLoadedScene(THREE, scene, gltf, { camera, controls })), undefined, reject);
48
- });
54
+ const firstLoader = new runtime.GLTFLoader();
55
+ const lodsManager = runtime.useNeedleProgressive(firstLoader, renderer);
56
+ trackLODChanges(lodsManager, state);
57
+
58
+ async function loadScene(nextIndex) {
59
+ const token = ++loadToken;
60
+ sceneIndex = normalizeSceneIndex(nextIndex);
61
+ const url = getModelUrl(params, sceneIndex);
62
+ markSceneLoading(state, sceneIndex, url);
63
+
64
+ const loader = token === 1 ? firstLoader : new runtime.GLTFLoader();
65
+ if (token !== 1) runtime.useNeedleProgressive(loader, renderer);
66
+
67
+ const nextRoot = await new Promise((resolve, reject) => {
68
+ loader.load(url, gltf => resolve(addLoadedScene(THREE, scene, gltf, { camera, controls })), undefined, reject);
69
+ });
70
+
71
+ if (token !== loadToken) {
72
+ nextRoot.removeFromParent();
73
+ return;
74
+ }
75
+
76
+ root?.removeFromParent();
77
+ root = nextRoot;
78
+ markSceneLoaded(state, runtime, root);
79
+ markReady(state, "offscreen-webgl");
80
+ }
49
81
 
50
82
  window.addEventListener("resize", resize);
83
+ createSceneChangeButton(() => loadScene(sceneIndex + 1).catch(error => markError(state, error)));
51
84
 
52
85
  function render() {
53
86
  state.frames += 1;
54
- root.rotation.y += 0.01;
55
87
  controls.update();
56
88
  renderer.render(scene, camera);
57
89
  visibleContext.transferFromImageBitmap(offscreenCanvas.transferToImageBitmap());
58
90
  requestAnimationFrame(render);
59
91
  }
60
92
 
61
- markReady(state, "offscreen-webgl");
93
+ await loadScene(sceneIndex);
62
94
  render();
63
95
  }
64
96
  catch (error) {