@needle-tools/three-animation-pointer 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,5 +4,5 @@ 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.0] - 2025-08-27
7
+ ## [1.0.1] - 2025-08-27
8
8
  - Initial release
package/README.md CHANGED
@@ -16,7 +16,7 @@ import { GLTFAnimationPointerExtension } from "@needle-tools/three-animation-poi
16
16
  const loader = new GLTFLoader();
17
17
  loader.register(p => {
18
18
  return new GLTFAnimationPointerExtension(p);
19
- }
19
+ });
20
20
  ```
21
21
 
22
22
  ## Links
@@ -0,0 +1,343 @@
1
+ import { SkinnedMesh as S, InterpolateDiscrete as M, InterpolateLinear as F, AnimationClip as W, PropertyBinding as C, QuaternionKeyframeTrack as w, ColorKeyframeTrack as D, VectorKeyframeTrack as E, NumberKeyframeTrack as O } from "three";
2
+ const f = {
3
+ node: "node",
4
+ material: "material",
5
+ camera: "camera",
6
+ light: "light"
7
+ }, R = "KHR_animation_pointer", U = {
8
+ // We use a custom interpolant (GLTFCubicSplineInterpolation) for CUBICSPLINE tracks. Each
9
+ // keyframe track will be initialized with a default interpolation type, then modified.
10
+ CUBICSPLINE: void 0,
11
+ LINEAR: F,
12
+ STEP: M
13
+ };
14
+ class j {
15
+ /** @type {import("three/examples/jsm/loaders/GLTFLoader").GLTFParser} */
16
+ constructor(r) {
17
+ this.name = R, this.parser = r, this.animationPointerResolver = null;
18
+ }
19
+ /**
20
+ * @param {import("..").AnimationPointerResolver | null} animationPointerResolver
21
+ */
22
+ setAnimationPointerResolver(r) {
23
+ return this.animationPointerResolver = r, this;
24
+ }
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);
29
+ }
30
+ loadAnimationTargetFromChannelWithAnimationPointer(r) {
31
+ var c;
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];
38
+ let o = m.pointer;
39
+ if (!o) {
40
+ console.warn("Invalid path", m, s);
41
+ return;
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);
45
+ return;
46
+ }
47
+ switch (t) {
48
+ case f.material:
49
+ const x = ("/materials/" + n.toString() + "/").length, h = o.substring(0, x);
50
+ switch (e = o.substring(x), e) {
51
+ case "pbrMetallicRoughness/baseColorFactor":
52
+ e = "color";
53
+ break;
54
+ case "pbrMetallicRoughness/roughnessFactor":
55
+ e = "roughness";
56
+ break;
57
+ case "pbrMetallicRoughness/metallicFactor":
58
+ e = "metalness";
59
+ break;
60
+ case "emissiveFactor":
61
+ e = "emissive";
62
+ break;
63
+ case "alphaCutoff":
64
+ e = "alphaTest";
65
+ break;
66
+ case "occlusionTexture/strength":
67
+ e = "aoMapIntensity";
68
+ break;
69
+ case "normalTexture/scale":
70
+ e = "normalScale";
71
+ break;
72
+ case "pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/scale":
73
+ e = "map/repeat";
74
+ break;
75
+ case "pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/offset":
76
+ e = "map/offset";
77
+ break;
78
+ case "emissiveTexture/extensions/KHR_texture_transform/scale":
79
+ e = "emissiveMap/repeat";
80
+ break;
81
+ case "emissiveTexture/extensions/KHR_texture_transform/offset":
82
+ e = "emissiveMap/offset";
83
+ break;
84
+ case "extensions/KHR_materials_emissive_strength/emissiveStrength":
85
+ e = "emissiveIntensity";
86
+ break;
87
+ case "extensions/KHR_materials_transmission/transmissionFactor":
88
+ e = "transmission";
89
+ break;
90
+ case "extensions/KHR_materials_ior/ior":
91
+ e = "ior";
92
+ break;
93
+ case "extensions/KHR_materials_volume/thicknessFactor":
94
+ e = "thickness";
95
+ break;
96
+ case "extensions/KHR_materials_volume/attenuationColor":
97
+ e = "attenuationColor";
98
+ break;
99
+ case "extensions/KHR_materials_volume/attenuationDistance":
100
+ e = "attenuationDistance";
101
+ break;
102
+ case "extensions/KHR_materials_iridescence/iridescenceFactor":
103
+ e = "iridescence";
104
+ break;
105
+ case "extensions/KHR_materials_iridescence/iridescenceIor":
106
+ e = "iridescenceIOR";
107
+ break;
108
+ case "extensions/KHR_materials_iridescence/iridescenceThicknessMinimum":
109
+ e = "iridescenceThicknessRange[0]";
110
+ break;
111
+ case "extensions/KHR_materials_iridescence/iridescenceThicknessMaximum":
112
+ e = "iridescenceThicknessRange[1]";
113
+ break;
114
+ case "extensions/KHR_materials_clearcoat/clearcoatFactor":
115
+ e = "clearcoat";
116
+ break;
117
+ case "extensions/KHR_materials_clearcoat/clearcoatRoughnessFactor":
118
+ e = "clearcoatRoughness";
119
+ break;
120
+ case "extensions/KHR_materials_sheen/sheenColorFactor":
121
+ e = "sheenColor";
122
+ break;
123
+ case "extensions/KHR_materials_sheen/sheenRoughnessFactor":
124
+ e = "sheenRoughness";
125
+ break;
126
+ case "extensions/KHR_materials_specular/specularFactor":
127
+ e = "specularIntensity";
128
+ break;
129
+ case "extensions/KHR_materials_specular/specularColorFactor":
130
+ e = "specularColor";
131
+ break;
132
+ }
133
+ o = h + e;
134
+ break;
135
+ case f.node:
136
+ const u = ("/nodes/" + n.toString() + "/").length, l = o.substring(0, u);
137
+ switch (e = o.substring(u), e) {
138
+ case "translation":
139
+ e = "position";
140
+ break;
141
+ case "rotation":
142
+ e = "quaternion";
143
+ break;
144
+ case "scale":
145
+ e = "scale";
146
+ break;
147
+ case "weights":
148
+ e = "morphTargetInfluences";
149
+ break;
150
+ }
151
+ o = l + e;
152
+ break;
153
+ case f.light:
154
+ const p = ("/extensions/KHR_lights_punctual/lights/" + n.toString() + "/").length;
155
+ switch (e = o.substring(p), e) {
156
+ case "color":
157
+ break;
158
+ case "intensity":
159
+ break;
160
+ case "spot/innerConeAngle":
161
+ e = "penumbra";
162
+ break;
163
+ case "spot/outerConeAngle":
164
+ e = "angle";
165
+ break;
166
+ case "range":
167
+ e = "distance";
168
+ break;
169
+ }
170
+ o = "/lights/" + n.toString() + "/" + e;
171
+ break;
172
+ case f.camera:
173
+ const g = ("/cameras/" + n.toString() + "/").length, b = o.substring(0, g);
174
+ switch (e = o.substring(g), e) {
175
+ case "perspective/yfov":
176
+ e = "fov";
177
+ break;
178
+ case "perspective/znear":
179
+ case "orthographic/znear":
180
+ e = "near";
181
+ break;
182
+ case "perspective/zfar":
183
+ case "orthographic/zfar":
184
+ e = "far";
185
+ break;
186
+ case "perspective/aspect":
187
+ e = "aspect";
188
+ break;
189
+ case "orthographic/xmag":
190
+ e = "zoom";
191
+ break;
192
+ case "orthographic/ymag":
193
+ e = "zoom";
194
+ break;
195
+ }
196
+ o = b + e;
197
+ break;
198
+ }
199
+ (c = this.animationPointerResolver) != null && c.resolvePath && (o = this.animationPointerResolver.resolvePath(o)), s.extensions[R].pointer = o;
200
+ }
201
+ if (n == null || isNaN(n)) {
202
+ console.warn("Failed resolving animation node id: " + n, s);
203
+ return;
204
+ }
205
+ 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;
207
+ }
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
+ if (!i) return null;
212
+ const c = [];
213
+ i = i.replaceAll("/", ".");
214
+ 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
+ u instanceof S && u.morphTargetInfluences && (m[3] = u.name, m[4] = "morphTargetInfluences", h(this.parser));
219
+ return c;
220
+ }
221
+ h(this.parser);
222
+ function h(u) {
223
+ i = m.join(".");
224
+ let l;
225
+ switch (a.itemSize) {
226
+ case 1:
227
+ l = O;
228
+ break;
229
+ case 2:
230
+ case 3:
231
+ l = E;
232
+ break;
233
+ case 4:
234
+ i.endsWith(".quaternion") ? l = w : l = D;
235
+ break;
236
+ }
237
+ if (!l) {
238
+ console.warn("Unsupported output accessor format", a);
239
+ return;
240
+ }
241
+ const p = e.interpolation !== void 0 ? U[e.interpolation] : F;
242
+ let g = u._getArrayFromAccessor(a);
243
+ i.endsWith(".fov") && (g = g.map((k) => k / Math.PI * 180));
244
+ const b = new l(
245
+ i,
246
+ s.array,
247
+ g,
248
+ p
249
+ );
250
+ if (p === "CUBICSPLINE" && u._createCubicSplineTrackInterpolant(b), c.push(b), i && a.itemSize === 4 && i.startsWith(".materials.") && i.endsWith(".color")) {
251
+ const k = new Float32Array(g.length / 4);
252
+ for (let T = 0, _ = g.length / 4; T < _; T += 1)
253
+ k[T] = g[T * 4 + 3];
254
+ const d = new l(
255
+ i.replace(".color", ".opacity"),
256
+ s.array,
257
+ k,
258
+ p
259
+ );
260
+ p === "CUBICSPLINE" && u._createCubicSplineTrackInterpolant(b), c.push(d);
261
+ }
262
+ }
263
+ return c;
264
+ }
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
+ }
269
+ /* MOSTLY DUPLICATE of GLTFLoader.loadAnimation, but also tries to resolve KHR_animation_pointer. */
270
+ /**
271
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
272
+ * @param {number} animationIndex
273
+ * @return {Promise<AnimationClip>}
274
+ */
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);
281
+ }
282
+ return Promise.all([
283
+ Promise.all(i),
284
+ Promise.all(c),
285
+ Promise.all(m),
286
+ Promise.all(o),
287
+ Promise.all(x)
288
+ ]).then(function(h) {
289
+ const u = h[0], l = h[1], p = h[2], g = h[3], b = h[4], k = [];
290
+ 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];
292
+ if (_ === void 0) continue;
293
+ _.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]);
298
+ }
299
+ return new W(n, void 0, k);
300
+ });
301
+ }
302
+ }
303
+ let H = !1, z = null;
304
+ function B() {
305
+ if (H) return;
306
+ H = !0;
307
+ 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(".");
317
+ 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;
325
+ c >= 0 && (m = c), e = e[m];
326
+ } else {
327
+ const c = r.getObjectByName(n);
328
+ c && (e = c);
329
+ }
330
+ }
331
+ 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;
334
+ }
335
+ return e;
336
+ }
337
+ return I(r, s);
338
+ };
339
+ }
340
+ export {
341
+ j as GLTFAnimationPointerExtension,
342
+ j as default
343
+ };
package/package.json CHANGED
@@ -1,17 +1,21 @@
1
1
  {
2
2
  "name": "@needle-tools/three-animation-pointer",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "KHR_animation_pointer support for three.js",
5
5
  "type": "module",
6
- "main": "src/index.js",
6
+ "main": "dist/three-animation-pointer.js",
7
+ "module": "dist/three-animation-pointer.js",
7
8
  "types": "types/index.d.ts",
8
9
  "exports": {
9
10
  ".": {
10
- "import": "./src/index.js"
11
+ "types": "./types/index.d.ts",
12
+ "import": "./src/index.js",
13
+ "require": "./src/index.js"
11
14
  }
12
15
  },
13
16
  "files": [
14
17
  "src",
18
+ "dist",
15
19
  "types",
16
20
  "package.json",
17
21
  "README.md",
@@ -27,8 +31,13 @@
27
31
  "url": "https://github.com/needle-tools/three-animation-pointer"
28
32
  },
29
33
  "license": "MIT",
34
+ "scripts": {
35
+ "build": "vite build",
36
+ "prepublishOnly": "npm run build"
37
+ },
30
38
  "devDependencies": {
31
- "three": ">=0.179.1"
39
+ "three": ">=0.179.1",
40
+ "vite": "^5.0.0"
32
41
  },
33
42
  "peerDependencies": {
34
43
  "three": ">=0.165.0"