@needle-tools/three-animation-pointer 1.0.0-next.edc289e → 1.0.1-next.1a466a6

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
@@ -2,7 +2,25 @@
2
2
 
3
3
  This package adds a [three.js](https://github.com/mrdoob/three.js) GLTFLoader plugin for [KHR_animation_pointer](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_animation_pointer) support.
4
4
 
5
- ### Usage
5
+ ### Animate anything
6
+ - all material properties 💎 (including texture transforms)
7
+ - cameras 🎥
8
+ - lights 💡
9
+ - custom code/scripts 📄
10
+
11
+
12
+ ### Three.js Example
13
+ <a href="https://threejs.org/examples/?q=gltf#webgl_loader_gltf_animation_pointer" target="_blank">
14
+ <img width="1240" height="696" alt="image" src="https://github.com/user-attachments/assets/baa109d8-974b-4c97-9ae9-31a4391e651b" />
15
+ </a>
16
+
17
+ https://github.com/user-attachments/assets/13fe4102-00ee-430f-9a17-9611fa543f77
18
+
19
+ [three.js Example](https://threejs.org/examples/?q=gltf#webgl_loader_gltf_animation_pointer)
20
+
21
+
22
+
23
+ ### How to use
6
24
 
7
25
  Install the package:
8
26
  `npm i @needle-tools/three-animation-pointer`
@@ -16,9 +34,26 @@ import { GLTFAnimationPointerExtension } from "@needle-tools/three-animation-poi
16
34
  const loader = new GLTFLoader();
17
35
  loader.register(p => {
18
36
  return new GLTFAnimationPointerExtension(p);
19
- }
37
+ });
20
38
  ```
21
39
 
40
+ ### How to create glTF files using KHR_animation_pointer
41
+
42
+ You can use one of the listed tools below to export glTF animations in the right format
43
+
44
+ - [Blender 4.3](https://www.blender.org/) and newer - *experimental KHR_animation_pointer support, currently only in 'scene animation' mode ([#2285](https://github.com/KhronosGroup/glTF-Blender-IO/issues/2285))*
45
+ - [Needle Engine for Unity](https://engine.needle.tools/docs/unity/) - defaults to KHR_animation_pointer and battle tested since 2022
46
+ - [UnityGLTF](https://github.com/KhronosGroup/UnityGLTF)
47
+
48
+
49
+ **Mini Unity Tutorial**
50
+
51
+ https://github.com/user-attachments/assets/e118a33d-9725-4313-b1d4-b4dbfc7a5a48
52
+
53
+ *Note: If you use UnityGLTF for exporting the glTF file make sure to enable the `KHR_animation_pointer` option in the UnityGLTF export settings.*
54
+
55
+
56
+
22
57
  ## Links
23
58
 
24
59
  - [Khronos KHR_animation_pointer spec](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_animation_pointer)
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@needle-tools/three-animation-pointer",
3
- "version": "1.0.0-next.edc289e",
3
+ "version": "1.0.1-next.1a466a6",
4
4
  "description": "KHR_animation_pointer support for three.js",
5
5
  "type": "module",
6
- "main": "dist/three-animation-pointer.umd.js",
7
- "module": "dist/three-animation-pointer.es.js",
6
+ "main": "dist/three-animation-pointer.js",
7
+ "module": "dist/three-animation-pointer.js",
8
8
  "types": "types/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
11
  "types": "./types/index.d.ts",
12
- "import": "./dist/three-animation-pointer.es.js",
13
- "require": "./dist/three-animation-pointer.umd.js"
12
+ "import": "./src/index.js",
13
+ "require": "./src/index.js"
14
14
  }
15
15
  },
16
16
  "files": [
@@ -1 +0,0 @@
1
- (function(x,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],u):(x=typeof globalThis<"u"?globalThis:x||self,u(x.ThreeAnimationPointer={},x.THREE))})(this,function(x,u){"use strict";const b={node:"node",material:"material",camera:"camera",light:"light"},R="KHR_animation_pointer",M={CUBICSPLINE:void 0,LINEAR:u.InterpolateLinear,STEP:u.InterpolateDiscrete};class N{constructor(r){this.name=R,this.parser=r,this.animationPointerResolver=null}setAnimationPointerResolver(r){return this.animationPointerResolver=r,this}loadAnimationTargetFromChannel(r){const s=r.target,a=s.node!==void 0?s.node:s.id;return this.parser.getDependency("node",a)}loadAnimationTargetFromChannelWithAnimationPointer(r){var c;w();const s=r.target,a=s.extensions&&s.extensions[R]&&s.path&&s.path==="pointer";if(!a)return null;let e,t=b.node,n;if(a){const p=s.extensions[R];let o=p.pointer;if(!o){console.warn("Invalid path",p,s);return}if(o.startsWith("/materials/")?t=b.material:o.startsWith("/extensions/KHR_lights_punctual/lights/")?t=b.light:o.startsWith("/cameras/")&&(t=b.camera),n=this._tryResolveTargetId(o,t),n===null||isNaN(n)){console.warn("Failed resolving animation node id: "+n,o);return}switch(t){case b.material:const y=("/materials/"+n.toString()+"/").length,h=o.substring(0,y);switch(e=o.substring(y),e){case"pbrMetallicRoughness/baseColorFactor":e="color";break;case"pbrMetallicRoughness/roughnessFactor":e="roughness";break;case"pbrMetallicRoughness/metallicFactor":e="metalness";break;case"emissiveFactor":e="emissive";break;case"alphaCutoff":e="alphaTest";break;case"occlusionTexture/strength":e="aoMapIntensity";break;case"normalTexture/scale":e="normalScale";break;case"pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/scale":e="map/repeat";break;case"pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/offset":e="map/offset";break;case"emissiveTexture/extensions/KHR_texture_transform/scale":e="emissiveMap/repeat";break;case"emissiveTexture/extensions/KHR_texture_transform/offset":e="emissiveMap/offset";break;case"extensions/KHR_materials_emissive_strength/emissiveStrength":e="emissiveIntensity";break;case"extensions/KHR_materials_transmission/transmissionFactor":e="transmission";break;case"extensions/KHR_materials_ior/ior":e="ior";break;case"extensions/KHR_materials_volume/thicknessFactor":e="thickness";break;case"extensions/KHR_materials_volume/attenuationColor":e="attenuationColor";break;case"extensions/KHR_materials_volume/attenuationDistance":e="attenuationDistance";break;case"extensions/KHR_materials_iridescence/iridescenceFactor":e="iridescence";break;case"extensions/KHR_materials_iridescence/iridescenceIor":e="iridescenceIOR";break;case"extensions/KHR_materials_iridescence/iridescenceThicknessMinimum":e="iridescenceThicknessRange[0]";break;case"extensions/KHR_materials_iridescence/iridescenceThicknessMaximum":e="iridescenceThicknessRange[1]";break;case"extensions/KHR_materials_clearcoat/clearcoatFactor":e="clearcoat";break;case"extensions/KHR_materials_clearcoat/clearcoatRoughnessFactor":e="clearcoatRoughness";break;case"extensions/KHR_materials_sheen/sheenColorFactor":e="sheenColor";break;case"extensions/KHR_materials_sheen/sheenRoughnessFactor":e="sheenRoughness";break;case"extensions/KHR_materials_specular/specularFactor":e="specularIntensity";break;case"extensions/KHR_materials_specular/specularColorFactor":e="specularColor";break}o=h+e;break;case b.node:const m=("/nodes/"+n.toString()+"/").length,l=o.substring(0,m);switch(e=o.substring(m),e){case"translation":e="position";break;case"rotation":e="quaternion";break;case"scale":e="scale";break;case"weights":e="morphTargetInfluences";break}o=l+e;break;case b.light:const d=("/extensions/KHR_lights_punctual/lights/"+n.toString()+"/").length;switch(e=o.substring(d),e){case"color":break;case"intensity":break;case"spot/innerConeAngle":e="penumbra";break;case"spot/outerConeAngle":e="angle";break;case"range":e="distance";break}o="/lights/"+n.toString()+"/"+e;break;case b.camera:const f=("/cameras/"+n.toString()+"/").length,k=o.substring(0,f);switch(e=o.substring(f),e){case"perspective/yfov":e="fov";break;case"perspective/znear":case"orthographic/znear":e="near";break;case"perspective/zfar":case"orthographic/zfar":e="far";break;case"perspective/aspect":e="aspect";break;case"orthographic/xmag":e="zoom";break;case"orthographic/ymag":e="zoom";break}o=k+e;break}(c=this.animationPointerResolver)!=null&&c.resolvePath&&(o=this.animationPointerResolver.resolvePath(o)),s.extensions[R].pointer=o}if(n==null||isNaN(n)){console.warn("Failed resolving animation node id: "+n,s);return}let i;return t===b.node?i=this.parser.getDependency("node",n):t===b.material?i=this.parser.getDependency("material",n):t===b.light?i=this.parser.getDependency("light",n):t===b.camera?i=this.parser.getDependency("camera",n):console.error("Unhandled type",t),i}createAnimationTracksWithAnimationPointer(r,s,a,e,t){if(!(t.extensions&&t.extensions[R]&&t.path&&t.path==="pointer"))return null;let i=t.extensions[R].pointer;if(!i)return null;const c=[];i=i.replaceAll("/",".");const p=i.split(".");var y=r.name!==void 0&&r.name!==null?r.name:r.uuid;if(p[2]=y,p[3]==="morphTargetInfluences"&&r.type==="Group"){for(const m of r.children)m instanceof u.SkinnedMesh&&m.morphTargetInfluences&&(p[3]=m.name,p[4]="morphTargetInfluences",h(this.parser));return c}h(this.parser);function h(m){i=p.join(".");let l;switch(a.itemSize){case 1:l=u.NumberKeyframeTrack;break;case 2:case 3:l=u.VectorKeyframeTrack;break;case 4:i.endsWith(".quaternion")?l=u.QuaternionKeyframeTrack:l=u.ColorKeyframeTrack;break}if(!l){console.warn("Unsupported output accessor format",a);return}const d=e.interpolation!==void 0?M[e.interpolation]:u.InterpolateLinear;let f=m._getArrayFromAccessor(a);i.endsWith(".fov")&&(f=f.map(_=>_/Math.PI*180));const k=new l(i,s.array,f,d);if(d==="CUBICSPLINE"&&m._createCubicSplineTrackInterpolant(k),c.push(k),i&&a.itemSize===4&&i.startsWith(".materials.")&&i.endsWith(".color")){const _=new Float32Array(f.length/4);for(let P=0,T=f.length/4;P<T;P+=1)_[P]=f[P*4+3];const g=new l(i.replace(".color",".opacity"),s.array,_,d);d==="CUBICSPLINE"&&m._createCubicSplineTrackInterpolant(k),c.push(g)}}return c}_tryResolveTargetId(r,s){let a="";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)}loadAnimation(r){const s=this,a=this.parser.json,e=this.parser,t=a.animations[r],n=t.name?t.name:"animation_"+r,i=[],c=[],p=[],o=[],y=[];for(let h=0,m=t.channels.length;h<m;h++){const l=t.channels[h],d=t.samplers[l.sampler],f=l.target,k=t.parameters!==void 0?t.parameters[d.input]:d.input,_=t.parameters!==void 0?t.parameters[d.output]:d.output;let g=s.loadAnimationTargetFromChannelWithAnimationPointer(l);g||(g=s.loadAnimationTargetFromChannel(l)),i.push(g),c.push(e.getDependency("accessor",k)),p.push(e.getDependency("accessor",_)),o.push(d),y.push(f)}return Promise.all([Promise.all(i),Promise.all(c),Promise.all(p),Promise.all(o),Promise.all(y)]).then(function(h){const m=h[0],l=h[1],d=h[2],f=h[3],k=h[4],_=[];for(let g=0,P=m.length;g<P;g++){const T=m[g],C=l[g],H=d[g],F=f[g],S=k[g];if(T===void 0)continue;T.updateMatrix&&(T.updateMatrix(),T.matrixAutoUpdate=!0);let I=s.createAnimationTracksWithAnimationPointer(T,C,H,F,S);if(I||(I=e._createAnimationTracks(T,C,H,F,S)),I)for(let A=0;A<I.length;A++)_.push(I[A])}return new u.AnimationClip(n,void 0,_)})}}let K=!1,W=null;function w(){if(K)return;K=!0;const v=W||(W=u.PropertyBinding.findNode);u.PropertyBinding.findNode=function(r,s){if(s.startsWith(".materials.")){const a=s.substring(11).substring(s.indexOf(".")),e=a.indexOf("."),t=e<0?a:a.substring(0,e);let n=null;return r.traverse(i=>{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)))}),n}else if(s.startsWith(".nodes.")||s.startsWith(".lights.")||s.startsWith(".cameras.")){const a=s.split(".");let e;for(let t=1;t<a.length;t++){const n=a[t];if(n.length==36)e=r.getObjectByProperty("uuid",n);else if(e&&e[n]){const c=Number.parseInt(n);let p=n;c>=0&&(p=c),e=e[p]}else{const c=r.getObjectByName(n);c&&(e=c)}}if(!e){const t=v(r,a[2]);return t||console.warn(R+": Property binding not found",s,r,r.name,a),t}return e}return v(r,s)}}x.GLTFAnimationPointerExtension=N,x.default=N,Object.defineProperties(x,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});