@needle-tools/three-animation-pointer 1.0.2 → 1.0.4

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,5 +4,11 @@ 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
+ ## [1.0.4] - 2025-10-08
8
+ - Add: KHR_node_visibility extension
9
+
10
+ ## [1.0.3] - 2025-09-11
11
+ - Fix: Handle undefined path if AnimationClip tracks have invalid/unexpected names. Fallback to default three implementation
12
+
7
13
  ## [1.0.1] - 2025-08-27
8
14
  - Initial release
@@ -13,40 +13,40 @@ const f = {
13
13
  };
14
14
  class j {
15
15
  /** @type {import("three/examples/jsm/loaders/GLTFLoader").GLTFParser} */
16
- constructor(r) {
17
- this.name = R, this.parser = r, this.animationPointerResolver = null;
16
+ constructor(a) {
17
+ this.name = R, this.parser = a, this.animationPointerResolver = null;
18
18
  }
19
19
  /**
20
20
  * @param {import("..").AnimationPointerResolver | null} animationPointerResolver
21
21
  */
22
- setAnimationPointerResolver(r) {
23
- return this.animationPointerResolver = r, this;
22
+ setAnimationPointerResolver(a) {
23
+ return this.animationPointerResolver = a, this;
24
24
  }
25
25
  /* DUPLICATE of functionality in GLTFLoader */
26
- loadAnimationTargetFromChannel(r) {
27
- const s = r.target, a = s.node !== void 0 ? s.node : s.id;
28
- return this.parser.getDependency("node", a);
26
+ loadAnimationTargetFromChannel(a) {
27
+ const t = a.target, r = t.node !== void 0 ? t.node : t.id;
28
+ return this.parser.getDependency("node", r);
29
29
  }
30
- loadAnimationTargetFromChannelWithAnimationPointer(r) {
30
+ loadAnimationTargetFromChannelWithAnimationPointer(a) {
31
31
  var c;
32
32
  B();
33
- const s = r.target, a = s.extensions && s.extensions[R] && s.path && s.path === "pointer";
34
- if (!a) return null;
35
- let e, t = f.node, n;
36
- if (a) {
37
- const m = s.extensions[R];
33
+ const t = a.target, r = t.extensions && t.extensions[R] && t.path && t.path === "pointer";
34
+ if (!r) return null;
35
+ let e, n = f.node, s;
36
+ if (r) {
37
+ const m = t.extensions[R];
38
38
  let o = m.pointer;
39
39
  if (!o) {
40
- console.warn("Invalid path", m, s);
40
+ console.warn("Invalid path", m, t);
41
41
  return;
42
42
  }
43
- if (o.startsWith("/materials/") ? t = f.material : o.startsWith("/extensions/KHR_lights_punctual/lights/") ? t = f.light : o.startsWith("/cameras/") && (t = f.camera), n = this._tryResolveTargetId(o, t), n === null || isNaN(n)) {
44
- console.warn("Failed resolving animation node id: " + n, o);
43
+ if (o.startsWith("/materials/") ? n = f.material : o.startsWith("/extensions/KHR_lights_punctual/lights/") ? n = f.light : o.startsWith("/cameras/") && (n = f.camera), s = this._tryResolveTargetId(o, n), s === null || isNaN(s)) {
44
+ console.warn("Failed resolving animation node id: " + s, o);
45
45
  return;
46
46
  }
47
- switch (t) {
47
+ switch (n) {
48
48
  case f.material:
49
- const x = ("/materials/" + n.toString() + "/").length, h = o.substring(0, x);
49
+ const x = ("/materials/" + s.toString() + "/").length, h = o.substring(0, x);
50
50
  switch (e = o.substring(x), e) {
51
51
  case "pbrMetallicRoughness/baseColorFactor":
52
52
  e = "color";
@@ -133,7 +133,7 @@ class j {
133
133
  o = h + e;
134
134
  break;
135
135
  case f.node:
136
- const u = ("/nodes/" + n.toString() + "/").length, l = o.substring(0, u);
136
+ const u = ("/nodes/" + s.toString() + "/").length, l = o.substring(0, u);
137
137
  switch (e = o.substring(u), e) {
138
138
  case "translation":
139
139
  e = "position";
@@ -147,11 +147,14 @@ class j {
147
147
  case "weights":
148
148
  e = "morphTargetInfluences";
149
149
  break;
150
+ case "KHR_node_visibility/visible":
151
+ e = "visible";
152
+ break;
150
153
  }
151
154
  o = l + e;
152
155
  break;
153
156
  case f.light:
154
- const p = ("/extensions/KHR_lights_punctual/lights/" + n.toString() + "/").length;
157
+ const p = ("/extensions/KHR_lights_punctual/lights/" + s.toString() + "/").length;
155
158
  switch (e = o.substring(p), e) {
156
159
  case "color":
157
160
  break;
@@ -167,10 +170,10 @@ class j {
167
170
  e = "distance";
168
171
  break;
169
172
  }
170
- o = "/lights/" + n.toString() + "/" + e;
173
+ o = "/lights/" + s.toString() + "/" + e;
171
174
  break;
172
175
  case f.camera:
173
- const g = ("/cameras/" + n.toString() + "/").length, b = o.substring(0, g);
176
+ const g = ("/cameras/" + s.toString() + "/").length, b = o.substring(0, g);
174
177
  switch (e = o.substring(g), e) {
175
178
  case "perspective/yfov":
176
179
  e = "fov";
@@ -196,25 +199,25 @@ class j {
196
199
  o = b + e;
197
200
  break;
198
201
  }
199
- (c = this.animationPointerResolver) != null && c.resolvePath && (o = this.animationPointerResolver.resolvePath(o)), s.extensions[R].pointer = o;
202
+ (c = this.animationPointerResolver) != null && c.resolvePath && (o = this.animationPointerResolver.resolvePath(o)), t.extensions[R].pointer = o;
200
203
  }
201
- if (n == null || isNaN(n)) {
202
- console.warn("Failed resolving animation node id: " + n, s);
204
+ if (s == null || isNaN(s)) {
205
+ console.warn("Failed resolving animation node id: " + s, t);
203
206
  return;
204
207
  }
205
208
  let i;
206
- return t === f.node ? i = this.parser.getDependency("node", n) : t === f.material ? i = this.parser.getDependency("material", n) : t === f.light ? i = this.parser.getDependency("light", n) : t === f.camera ? i = this.parser.getDependency("camera", n) : console.error("Unhandled type", t), i;
209
+ return n === f.node ? i = this.parser.getDependency("node", s) : n === f.material ? i = this.parser.getDependency("material", s) : n === f.light ? i = this.parser.getDependency("light", s) : n === f.camera ? i = this.parser.getDependency("camera", s) : console.error("Unhandled type", n), i;
207
210
  }
208
- createAnimationTracksWithAnimationPointer(r, s, a, e, t) {
209
- if (!(t.extensions && t.extensions[R] && t.path && t.path === "pointer")) return null;
210
- let i = t.extensions[R].pointer;
211
+ createAnimationTracksWithAnimationPointer(a, t, r, e, n) {
212
+ if (!(n.extensions && n.extensions[R] && n.path && n.path === "pointer")) return null;
213
+ let i = n.extensions[R].pointer;
211
214
  if (!i) return null;
212
215
  const c = [];
213
216
  i = i.replaceAll("/", ".");
214
217
  const m = i.split(".");
215
- var x = r.name !== void 0 && r.name !== null ? r.name : r.uuid;
216
- if (m[2] = x, m[3] === "morphTargetInfluences" && r.type === "Group") {
217
- for (const u of r.children)
218
+ var x = a.name !== void 0 && a.name !== null ? a.name : a.uuid;
219
+ if (m[2] = x, m[3] === "morphTargetInfluences" && a.type === "Group") {
220
+ for (const u of a.children)
218
221
  u instanceof S && u.morphTargetInfluences && (m[3] = u.name, m[4] = "morphTargetInfluences", h(this.parser));
219
222
  return c;
220
223
  }
@@ -222,7 +225,7 @@ class j {
222
225
  function h(u) {
223
226
  i = m.join(".");
224
227
  let l;
225
- switch (a.itemSize) {
228
+ switch (r.itemSize) {
226
229
  case 1:
227
230
  l = O;
228
231
  break;
@@ -235,25 +238,25 @@ class j {
235
238
  break;
236
239
  }
237
240
  if (!l) {
238
- console.warn("Unsupported output accessor format", a);
241
+ console.warn("Unsupported output accessor format", r);
239
242
  return;
240
243
  }
241
244
  const p = e.interpolation !== void 0 ? U[e.interpolation] : F;
242
- let g = u._getArrayFromAccessor(a);
245
+ let g = u._getArrayFromAccessor(r);
243
246
  i.endsWith(".fov") && (g = g.map((k) => k / Math.PI * 180));
244
247
  const b = new l(
245
248
  i,
246
- s.array,
249
+ t.array,
247
250
  g,
248
251
  p
249
252
  );
250
- if (p === "CUBICSPLINE" && u._createCubicSplineTrackInterpolant(b), c.push(b), i && a.itemSize === 4 && i.startsWith(".materials.") && i.endsWith(".color")) {
253
+ if (p === "CUBICSPLINE" && u._createCubicSplineTrackInterpolant(b), c.push(b), i && r.itemSize === 4 && i.startsWith(".materials.") && i.endsWith(".color")) {
251
254
  const k = new Float32Array(g.length / 4);
252
255
  for (let T = 0, _ = g.length / 4; T < _; T += 1)
253
256
  k[T] = g[T * 4 + 3];
254
257
  const d = new l(
255
258
  i.replace(".color", ".opacity"),
256
- s.array,
259
+ t.array,
257
260
  k,
258
261
  p
259
262
  );
@@ -262,9 +265,9 @@ class j {
262
265
  }
263
266
  return c;
264
267
  }
265
- _tryResolveTargetId(r, s) {
266
- let a = "";
267
- return s === "node" ? a = r.substring(7) : s === "material" ? a = r.substring(11) : s === "light" ? a = r.substring(39) : s === "camera" && (a = r.substring(9)), a = a.substring(0, a.indexOf("/")), Number.parseInt(a);
268
+ _tryResolveTargetId(a, t) {
269
+ let r = "";
270
+ return t === "node" ? r = a.substring(7) : t === "material" ? r = a.substring(11) : t === "light" ? r = a.substring(39) : t === "camera" && (r = a.substring(9)), r = r.substring(0, r.indexOf("/")), Number.parseInt(r);
268
271
  }
269
272
  /* MOSTLY DUPLICATE of GLTFLoader.loadAnimation, but also tries to resolve KHR_animation_pointer. */
270
273
  /**
@@ -272,12 +275,12 @@ class j {
272
275
  * @param {number} animationIndex
273
276
  * @return {Promise<AnimationClip>}
274
277
  */
275
- loadAnimation(r) {
276
- const s = this, a = this.parser.json, e = this.parser, t = a.animations[r], n = t.name ? t.name : "animation_" + r, i = [], c = [], m = [], o = [], x = [];
277
- for (let h = 0, u = t.channels.length; h < u; h++) {
278
- const l = t.channels[h], p = t.samplers[l.sampler], g = l.target, b = t.parameters !== void 0 ? t.parameters[p.input] : p.input, k = t.parameters !== void 0 ? t.parameters[p.output] : p.output;
279
- let d = s.loadAnimationTargetFromChannelWithAnimationPointer(l);
280
- d || (d = s.loadAnimationTargetFromChannel(l)), i.push(d), c.push(e.getDependency("accessor", b)), m.push(e.getDependency("accessor", k)), o.push(p), x.push(g);
278
+ loadAnimation(a) {
279
+ const t = this, r = this.parser.json, e = this.parser, n = r.animations[a], s = n.name ? n.name : "animation_" + a, i = [], c = [], m = [], o = [], x = [];
280
+ for (let h = 0, u = n.channels.length; h < u; h++) {
281
+ const l = n.channels[h], p = n.samplers[l.sampler], g = l.target, b = n.parameters !== void 0 ? n.parameters[p.input] : p.input, k = n.parameters !== void 0 ? n.parameters[p.output] : p.output;
282
+ let d = t.loadAnimationTargetFromChannelWithAnimationPointer(l);
283
+ d || (d = t.loadAnimationTargetFromChannel(l)), i.push(d), c.push(e.getDependency("accessor", b)), m.push(e.getDependency("accessor", k)), o.push(p), x.push(g);
281
284
  }
282
285
  return Promise.all([
283
286
  Promise.all(i),
@@ -288,15 +291,15 @@ class j {
288
291
  ]).then(function(h) {
289
292
  const u = h[0], l = h[1], p = h[2], g = h[3], b = h[4], k = [];
290
293
  for (let d = 0, T = u.length; d < T; d++) {
291
- const _ = u[d], v = l[d], A = p[d], N = g[d], K = b[d];
294
+ const _ = u[d], P = l[d], A = p[d], K = g[d], N = b[d];
292
295
  if (_ === void 0) continue;
293
296
  _.updateMatrix && (_.updateMatrix(), _.matrixAutoUpdate = !0);
294
- let y = s.createAnimationTracksWithAnimationPointer(_, v, A, N, K);
295
- if (y || (y = e._createAnimationTracks(_, v, A, N, K)), y)
296
- for (let P = 0; P < y.length; P++)
297
- k.push(y[P]);
297
+ let y = t.createAnimationTracksWithAnimationPointer(_, P, A, K, N);
298
+ if (y || (y = e._createAnimationTracks(_, P, A, K, N)), y)
299
+ for (let v = 0; v < y.length; v++)
300
+ k.push(y[v]);
298
301
  }
299
- return new W(n, void 0, k);
302
+ return new W(s, void 0, k);
300
303
  });
301
304
  }
302
305
  }
@@ -305,36 +308,37 @@ function B() {
305
308
  if (H) return;
306
309
  H = !0;
307
310
  const I = z || (z = C.findNode);
308
- C.findNode = function(r, s) {
309
- if (s.startsWith(".materials.")) {
310
- const a = s.substring(11).substring(s.indexOf(".")), e = a.indexOf("."), t = e < 0 ? a : a.substring(0, e);
311
- let n = null;
312
- return r.traverse((i) => {
313
- n !== null || i.type !== "Mesh" && i.type !== "SkinnedMesh" || i.material && (i.material.uuid === t || i.material.name === t) && (n = i.material, n !== null && (a.endsWith(".map") ? n = n.map : a.endsWith(".emissiveMap") && (n = n.emissiveMap)));
314
- }), n;
315
- } else if (s.startsWith(".nodes.") || s.startsWith(".lights.") || s.startsWith(".cameras.")) {
316
- const a = s.split(".");
311
+ C.findNode = function(a, t) {
312
+ if (!t) return I(a, t);
313
+ if (t.startsWith(".materials.")) {
314
+ const r = t.substring(11).substring(t.indexOf(".")), e = r.indexOf("."), n = e < 0 ? r : r.substring(0, e);
315
+ let s = null;
316
+ return a.traverse((i) => {
317
+ s !== null || i.type !== "Mesh" && i.type !== "SkinnedMesh" || i.material && (i.material.uuid === n || i.material.name === n) && (s = i.material, s !== null && (r.endsWith(".map") ? s = s.map : r.endsWith(".emissiveMap") && (s = s.emissiveMap)));
318
+ }), s;
319
+ } else if (t.startsWith(".nodes.") || t.startsWith(".lights.") || t.startsWith(".cameras.")) {
320
+ const r = t.split(".");
317
321
  let e;
318
- for (let t = 1; t < a.length; t++) {
319
- const n = a[t];
320
- if (n.length == 36)
321
- e = r.getObjectByProperty("uuid", n);
322
- else if (e && e[n]) {
323
- const c = Number.parseInt(n);
324
- let m = n;
322
+ for (let n = 1; n < r.length; n++) {
323
+ const s = r[n];
324
+ if (s.length == 36)
325
+ e = a.getObjectByProperty("uuid", s);
326
+ else if (e && e[s]) {
327
+ const c = Number.parseInt(s);
328
+ let m = s;
325
329
  c >= 0 && (m = c), e = e[m];
326
330
  } else {
327
- const c = r.getObjectByName(n);
331
+ const c = a.getObjectByName(s);
328
332
  c && (e = c);
329
333
  }
330
334
  }
331
335
  if (!e) {
332
- const t = I(r, a[2]);
333
- return t || console.warn(R + ": Property binding not found", s, r, r.name, a), t;
336
+ const n = I(a, r[2]);
337
+ return n || console.warn(R + ": Property binding not found", t, a, a.name, r), n;
334
338
  }
335
339
  return e;
336
340
  }
337
- return I(r, s);
341
+ return I(a, t);
338
342
  };
339
343
  }
340
344
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/three-animation-pointer",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "KHR_animation_pointer support for three.js",
5
5
  "type": "module",
6
6
  "main": "dist/three-animation-pointer.js",
@@ -260,7 +260,9 @@ export class GLTFAnimationPointerExtension {
260
260
  case 'weights':
261
261
  targetProperty = 'morphTargetInfluences';
262
262
  break;
263
-
263
+ case "KHR_node_visibility/visible":
264
+ targetProperty = 'visible';
265
+ break;
264
266
  }
265
267
 
266
268
  path = pathStartNode + targetProperty;
@@ -657,6 +659,10 @@ function _ensurePropertyBindingPatch() {
657
659
  // "path" is the animated property path, just with translated material names.
658
660
  PropertyBinding.findNode = function (node, path) {
659
661
 
662
+ // if the binding is empty fallback to original
663
+ if (!path) return findNode(node, path);
664
+
665
+
660
666
  if (path.startsWith('.materials.')) {
661
667
 
662
668
  if (_animationPointerDebug) console.log('FIND', path);