three-mediapipe-rig 0.0.3 → 0.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/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
 
2
2
  ![cover](cover.jpg)
3
3
 
4
- # three-mediapipe-rig
4
+ # Control a skeleton with the webcam
5
5
 
6
- Integrate [Google MediaPipe](https://ai.google.dev/edge/mediapipe/solutions/guide)'s **webcam motion tracking** with [Three.js](https://threejs.org/) skeletal rigs. Load a GLTF/GLB character, bind it, and drive its body, hands, and face from a webcam or video — in just a few lines of code.
6
+ Integrate [Google MediaPipe](https://ai.google.dev/edge/mediapipe/solutions/guide)'s **webcam motion tracking** with [Three.js](https://threejs.org/) skeletal rigs.
7
7
 
8
- Use your webcam ( or a video ) to drive a skeleton.
8
+ The motion from the webcam will be applied to a skeleton. Angle based so it works with any size skeleton.
9
9
 
10
10
  This will run 3 models: face, body, hands. So expect a FPS drop.
11
11
 
@@ -52,41 +52,32 @@ npm install three-mediapipe-rig
52
52
 
53
53
  ## Quick Start
54
54
 
55
- ```ts
56
- // 1. Create your renderer
57
- const renderer = new THREE.WebGPURenderer({ antialias: true });
58
- renderer.setSize(window.innerWidth, window.innerHeight);
59
- document.body.appendChild(renderer.domElement);
55
+ ```ts
60
56
 
61
- // 2. Initialize the tracker (loads MediaPipe models)
57
+ // 1. Initialize the tracker (loads MediaPipe models)
62
58
  await setupTracker({ ...config... })
63
59
 
64
60
  const rig = scene.getObjectByName("rig")!;
65
61
 
66
- // 3. Bind the rig to the tracker
62
+ // 2. Bind the rig to the tracker
67
63
  const binding = tracker.bind(rig);
68
64
 
69
65
 
70
- // 4. Start the webcam ( must be initialized by a user triggered event like a click )
71
- tracker.start();
72
-
73
- // 5. Update in your render loop
74
- const clock = new THREE.Timer();
75
- renderer.setAnimationLoop((time: number) => {
76
- const delta = clock.update(time).getDelta();
66
+ // 3. Start the webcam ( must be initialized by a user triggered event like a click )
67
+ button.addEventListener('click', () => {
68
+ tracker.start(); //<-- will ask webcam access!
69
+ })
77
70
 
78
- // 6. update the skeleton...
79
- binding?.update(delta);
80
71
 
81
- renderer.render(scene, camera);
82
- });
72
+ // 4. Update the rig in your render loop ( this keels the skeleton in-sync)
73
+ binding?.update(delta);
83
74
  ```
84
75
 
85
76
  ### Skeleton
86
- You can use the skeleton provided in `rig.blend` or use your own and provide a bone name mapping so we know where the bones are in the second argument for the `.bind` method. But pay attention to the bone role of the provided skeleton, as it is the one expected by this module.
77
+ You can use the skeleton provided in `rig.blend` or use your own and provide a bone name mapping so we know where the bones are in the second argument for the `.bind` method. But pay attention to the [**bone roll**](https://docs.blender.org/manual/en/latest/animation/armatures/bones/editing/bone_roll.html) of the provided skeleton, as it is the one expected by this module.
87
78
 
88
79
  ### Facial Animation
89
- Media Pipe provides blend shape keys for the face ( estimated from the webcam ). The face it is expected to be a separated mesh, just the face, with blend shape keys named as the ones provided by Media Pipe. See [Blend Shape Keys reference](/face-blendshapekeys.md) You don't have to have all of them, if they are not found, they will be ignored.
80
+ Media Pipe provides blend shape keys for the face ( estimated from the webcam ). The face it is expected to be a separated mesh with a name that starts with "face", with blend shape keys named as the ones provided by Media Pipe. See [Blend Shape Keys reference](/face-blendshapekeys.md) You don't have to have all of them, if they are not found, they will be ignored.
90
81
 
91
82
 
92
83
  ## API
@@ -1,24 +1,24 @@
1
- var de = Object.defineProperty;
2
- var he = (d, s, e) => s in d ? de(d, s, { enumerable: !0, configurable: !0, writable: !0, value: e }) : d[s] = e;
3
- var k = (d, s, e) => he(d, typeof s != "symbol" ? s + "" : s, e);
4
- import { PoseLandmarker as oe, HandLandmarker as D, FaceLandmarker as C, FilesetResolver as ce, DrawingUtils as le } from "@mediapipe/tasks-vision";
5
- import * as p from "three/webgpu";
6
- import { Vector3 as P, Quaternion as se } from "three/webgpu";
1
+ var he = Object.defineProperty;
2
+ var ce = (h, s, e) => s in h ? he(h, s, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[s] = e;
3
+ var k = (h, s, e) => ce(h, typeof s != "symbol" ? s + "" : s, e);
4
+ import { PoseLandmarker as se, HandLandmarker as D, FaceLandmarker as C, FilesetResolver as le, DrawingUtils as pe } from "@mediapipe/tasks-vision";
5
+ import * as l from "three/webgpu";
6
+ import { Vector3 as P, Quaternion as ie } from "three/webgpu";
7
7
  import * as S from "three";
8
- import { Bone as pe } from "three";
9
- import { GLTFExporter as me } from "three/examples/jsm/Addons.js";
10
- const V = new P(), z = new P(), ue = new P(1, 0, 0), fe = new P(-1, 0, 0), ye = new P(0, 1, 0), we = new P(0, -1, 0), B = new P(0, 0, 1);
8
+ import { Bone as me } from "three";
9
+ import { GLTFExporter as ue } from "three/examples/jsm/Addons.js";
10
+ const V = new P(), z = new P(), fe = new P(1, 0, 0), ye = new P(-1, 0, 0), we = new P(0, 1, 0), Le = new P(0, -1, 0), B = new P(0, 0, 1);
11
11
  new P(0, 0, -1);
12
- const I = new P(), Le = new P(), ke = new P(), U = new se(), O = new se();
13
- function A(d, s, e, t = "+x") {
14
- d.lookAt(s);
15
- const o = t == "+x" ? ue : t == "-x" ? fe : t == "+y" ? ye : we;
16
- d.getWorldPosition(z), d.getWorldQuaternion(O), V.subVectors(e, z).normalize(), I.copy(o).applyQuaternion(O);
17
- const i = I, r = Le.copy(B).applyQuaternion(O), n = V.clone().addScaledVector(r, -V.dot(r)).normalize(), a = ke.crossVectors(i, n), c = Math.atan2(a.dot(r), i.dot(n));
18
- U.setFromAxisAngle(B, c), d.quaternion.multiply(U);
12
+ const I = new P(), ke = new P(), be = new P(), U = new ie(), O = new ie();
13
+ function A(h, s, e, t = "+x") {
14
+ h.lookAt(s);
15
+ const o = t == "+x" ? fe : t == "-x" ? ye : t == "+y" ? we : Le;
16
+ h.getWorldPosition(z), h.getWorldQuaternion(O), V.subVectors(e, z).normalize(), I.copy(o).applyQuaternion(O);
17
+ const i = I, r = ke.copy(B).applyQuaternion(O), n = V.clone().addScaledVector(r, -V.dot(r)).normalize(), a = be.crossVectors(i, n), c = Math.atan2(a.dot(r), i.dot(n));
18
+ U.setFromAxisAngle(B, c), h.quaternion.multiply(U);
19
19
  }
20
- const N = new p.Vector3(), M = new p.Vector3(), T = new p.Vector3();
21
- new p.Vector3();
20
+ const N = new l.Vector3(), M = new l.Vector3(), T = new l.Vector3();
21
+ new l.Vector3();
22
22
  class _ {
23
23
  constructor(s, e) {
24
24
  k(this, "objectGhost");
@@ -27,9 +27,9 @@ class _ {
27
27
  * per landmark index, it points to it's object3D equivalent.
28
28
  */
29
29
  k(this, "marks", {});
30
- this.points = s, this.debugConnections = e, this.root = new p.Object3D(), this.objectGhost = /* @__PURE__ */ new Map();
30
+ this.points = s, this.debugConnections = e, this.root = new l.Object3D(), this.objectGhost = /* @__PURE__ */ new Map();
31
31
  for (let t in this.points)
32
- this.marks[t] = new be(), this.root.add(this.marks[t]);
32
+ this.marks[t] = new xe(), this.root.add(this.marks[t]);
33
33
  }
34
34
  updateLandmarks(s, e, t) {
35
35
  for (let o in this.points) {
@@ -50,7 +50,7 @@ class _ {
50
50
  getGhost(s) {
51
51
  var e;
52
52
  if (!this.objectGhost.has(s)) {
53
- const t = new xe();
53
+ const t = new Re();
54
54
  t.position.copy(s.position), t.quaternion.copy(s.quaternion), (e = s.parent) == null || e.add(t), this.objectGhost.set(s, t);
55
55
  }
56
56
  return this.objectGhost.get(s);
@@ -69,43 +69,43 @@ class _ {
69
69
  this.marks[r].getWorldPosition(T), this.marks[i].getWorldPosition(M);
70
70
  const a = T.sub(M);
71
71
  o.getWorldPosition(M), M.add(a);
72
- const c = M, l = o.getWorldPosition(T).sub(t), f = this.getGhost(o);
73
- A(f, c, l, n), f.rotateX(Math.PI / 2), o.position.lerp(f.position, e * 4), o.quaternion.slerp(f.quaternion, e * 4);
72
+ const c = M, p = o.getWorldPosition(T).sub(t), f = this.getGhost(o);
73
+ A(f, c, p, n), f.rotateX(Math.PI / 2), o.position.lerp(f.position, e * 4), o.quaternion.slerp(f.quaternion, e * 4);
74
74
  }
75
75
  }
76
76
  getBone(s, e) {
77
77
  return s.getObjectByName(e.replace(/[\.\:]/g, ""));
78
78
  }
79
79
  }
80
- class be extends p.Mesh {
80
+ class xe extends l.Mesh {
81
81
  constructor() {
82
- super(new p.SphereGeometry(0.01, 3, 3), new p.MeshStandardMaterial({ color: 16711680, wireframe: !0 }));
83
- k(this, "_worldPosition", new p.Vector3());
84
- this.add(new p.AxesHelper(1e-3));
82
+ super(new l.SphereGeometry(0.01, 3, 3), new l.MeshStandardMaterial({ color: 16711680, wireframe: !0 }));
83
+ k(this, "_worldPosition", new l.Vector3());
84
+ this.add(new l.AxesHelper(1e-3));
85
85
  }
86
86
  get worldPosition() {
87
87
  return this.getWorldPosition(this._worldPosition), this._worldPosition;
88
88
  }
89
89
  }
90
- class xe extends p.Object3D {
90
+ class Re extends l.Object3D {
91
91
  lerp(s, e, t = 8) {
92
92
  s.position.lerp(this.position, e * t), s.quaternion.slerp(this.quaternion, e * t);
93
93
  }
94
94
  }
95
- function F(d, s, e) {
96
- return e.worldToLocal(s.getWorldPosition(d)), d;
95
+ function F(h, s, e) {
96
+ return e.worldToLocal(s.getWorldPosition(h)), h;
97
97
  }
98
- function Re(d) {
99
- return d.replace(/[\.\:]/g, "");
98
+ function Pe(h) {
99
+ return h.replace(/[\.\:]/g, "");
100
100
  }
101
- function x(d, s) {
101
+ function x(h, s) {
102
102
  let e;
103
- return s = Re(s), d.traverse((t) => {
104
- t.name.indexOf(s) === 0 && t instanceof pe && (e = t);
105
- }), e || console.log("Bone not found: ", s, d.name), e;
103
+ return s = Pe(s), h.traverse((t) => {
104
+ t.name.indexOf(s) === 0 && t instanceof me && (e = t);
105
+ }), e || console.log("Bone not found: ", s, h.name), e;
106
106
  }
107
- async function Pe(d, s) {
108
- const e = await oe.createFromOptions(d, {
107
+ async function We(h, s) {
108
+ const e = await se.createFromOptions(h, {
109
109
  baseOptions: {
110
110
  modelAssetPath: (s == null ? void 0 : s.modelPath) ?? "pose_landmarker_lite.task",
111
111
  //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task`,
@@ -115,9 +115,9 @@ async function Pe(d, s) {
115
115
  runningMode: "VIDEO",
116
116
  numPoses: 1
117
117
  });
118
- return new ve(e, s);
118
+ return new ge(e, s);
119
119
  }
120
- const We = {
120
+ const Ee = {
121
121
  hips: [24, 23],
122
122
  neck: [12, 11],
123
123
  leftLeg: 23,
@@ -139,10 +139,10 @@ const We = {
139
139
  torso: [24, 23, 12, 11],
140
140
  leftEar: 7,
141
141
  rightEar: 8
142
- }, Ee = new p.Vector3(), G = new p.Vector3(), Fe = new p.Vector3(), Ae = new p.Vector3(), Me = new p.Vector3(), H = new p.Vector3(), $ = new p.Vector3();
143
- class ve extends _ {
142
+ }, Fe = new l.Vector3(), G = new l.Vector3(), Ae = new l.Vector3(), Me = new l.Vector3(), ve = new l.Vector3(), H = new l.Vector3(), $ = new l.Vector3();
143
+ class ge extends _ {
144
144
  constructor(e, t) {
145
- super(We, oe.POSE_CONNECTIONS);
145
+ super(Ee, se.POSE_CONNECTIONS);
146
146
  k(this, "_leftWristNormalizedPosition");
147
147
  k(this, "_rightWristNormalizedPosition");
148
148
  this.poseLandmarker = e, this.config = t, this.root.scale.y *= -2, this.root.scale.z *= -2, this.root.scale.x *= 2;
@@ -192,24 +192,24 @@ class ve extends _ {
192
192
  rightFoot: x(e, t.footR)
193
193
  };
194
194
  (a = this.config) != null && a.ignoreLegs && (delete o.leftLeg, delete o.leftKnee, delete o.leftFoot, delete o.leftToes, delete o.rightLeg, delete o.rightKnee, delete o.rightFoot, delete o.rightToes);
195
- const i = new p.Vector3(), r = new p.Vector3(), n = (c, l, f, R, h, m) => {
196
- if (!l) return;
197
- const w = this.marks[R].getWorldPosition(i).sub(this.marks[f].getWorldPosition(r)).normalize();
198
- F(H, l, e).add(w).applyMatrix4(e.matrixWorld), F($, l, e).add(h).applyMatrix4(e.matrixWorld);
199
- const u = this.getGhost(l);
200
- A(u, H, $, m), u.rotateX(Math.PI / 2), u.lerp(l, c);
195
+ const i = new l.Vector3(), r = new l.Vector3(), n = (c, p, f, R, d, m) => {
196
+ if (!p) return;
197
+ const L = this.marks[R].getWorldPosition(i).sub(this.marks[f].getWorldPosition(r)).normalize();
198
+ F(H, p, e).add(L).applyMatrix4(e.matrixWorld), F($, p, e).add(d).applyMatrix4(e.matrixWorld);
199
+ const u = this.getGhost(p);
200
+ A(u, H, $, m), u.rotateX(Math.PI / 2), u.lerp(p, c);
201
201
  };
202
202
  return {
203
203
  update: (c) => {
204
- const l = this.marks.leftLeg.getWorldPosition(Ee).sub(this.marks.rightLeg.getWorldPosition(G)).normalize(), f = this.marks.leftArm.getWorldPosition(G).sub(this.marks.rightArm.getWorldPosition(Fe)).normalize(), R = this.marks.leftEar.getWorldPosition(Ae).sub(this.marks.rightEar.getWorldPosition(Me)).normalize();
205
- n(c, o.hips, "hips", "torso", l, "+x"), n(c, o.torso, "torso", "neck", f, "+x"), n(c, o.neck, "neck", "head", R, "+x"), n(c, o.head, "neck", "head", R, "+x"), n(c, o.leftArm, "leftArm", "leftElbow", f, "-x"), n(c, o.leftElbow, "leftElbow", "leftWrist", f, "-x"), n(c, o.leftLeg, "leftLeg", "leftKnee", l, "+x"), n(c, o.leftKnee, "leftKnee", "leftFoot", l, "+x"), n(c, o.leftFoot, "leftFoot", "leftToes", l, "+x"), n(c, o.rightArm, "rightArm", "rightElbow", f, "-x"), n(c, o.rightElbow, "rightElbow", "rightWrist", f, "-x"), n(c, o.rightLeg, "rightLeg", "rightKnee", l, "+x"), n(c, o.rightKnee, "rightKnee", "rightFoot", l, "+x"), n(c, o.rightFoot, "rightFoot", "rightToes", l, "+x");
204
+ const p = this.marks.leftLeg.getWorldPosition(Fe).sub(this.marks.rightLeg.getWorldPosition(G)).normalize(), f = this.marks.leftArm.getWorldPosition(G).sub(this.marks.rightArm.getWorldPosition(Ae)).normalize(), R = this.marks.leftEar.getWorldPosition(Me).sub(this.marks.rightEar.getWorldPosition(ve)).normalize();
205
+ n(c, o.hips, "hips", "torso", p, "+x"), n(c, o.torso, "torso", "neck", f, "+x"), n(c, o.neck, "neck", "head", R, "+x"), n(c, o.head, "neck", "head", R, "+x"), n(c, o.leftArm, "leftArm", "leftElbow", f, "-x"), n(c, o.leftElbow, "leftElbow", "leftWrist", f, "-x"), n(c, o.leftLeg, "leftLeg", "leftKnee", p, "+x"), n(c, o.leftKnee, "leftKnee", "leftFoot", p, "+x"), n(c, o.leftFoot, "leftFoot", "leftToes", p, "+x"), n(c, o.rightArm, "rightArm", "rightElbow", f, "-x"), n(c, o.rightElbow, "rightElbow", "rightWrist", f, "-x"), n(c, o.rightLeg, "rightLeg", "rightKnee", p, "+x"), n(c, o.rightKnee, "rightKnee", "rightFoot", p, "+x"), n(c, o.rightFoot, "rightFoot", "rightToes", p, "+x");
206
206
  }
207
207
  };
208
208
  }
209
209
  }
210
- const j = new p.Vector2(), q = new p.Vector2();
211
- async function ge(d, s) {
212
- const e = await D.createFromOptions(d, {
210
+ const j = new l.Vector2(), q = new l.Vector2();
211
+ async function Se(h, s) {
212
+ const e = await D.createFromOptions(h, {
213
213
  baseOptions: {
214
214
  modelAssetPath: s.modelPath ?? "hand_landmarker.task",
215
215
  //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,
@@ -217,13 +217,20 @@ async function ge(d, s) {
217
217
  },
218
218
  runningMode: "VIDEO",
219
219
  numHands: 2
220
- }), t = (o, i, r) => (j.copy(o()), q.copy(i()), j.distanceTo(r) < q.distanceTo(r));
220
+ }), t = (o, i, r) => {
221
+ try {
222
+ j.copy(o()), q.copy(i());
223
+ } catch (n) {
224
+ return console.warn("No pose data... will just be optimitic and say yes to everything.", n), !0;
225
+ }
226
+ return j.distanceTo(r) < q.distanceTo(r);
227
+ };
221
228
  return {
222
- left: new ee(e, "Left", t.bind(null, s.leftWrist, s.rightWrist)),
223
- right: new ee(e, "Right", t.bind(null, s.rightWrist, s.leftWrist))
229
+ left: new te(e, "Left", t.bind(null, s.leftWrist, s.rightWrist)),
230
+ right: new te(e, "Right", t.bind(null, s.rightWrist, s.leftWrist))
224
231
  };
225
232
  }
226
- const Se = {
233
+ const Ne = {
227
234
  wrist: 0,
228
235
  palm: [9, 13],
229
236
  thumb1: 1,
@@ -252,20 +259,21 @@ const Se = {
252
259
  middle: ["middle1", "middle2", "middle3", "middle4"],
253
260
  ring: ["ring1", "ring2", "ring3", "ring4"],
254
261
  pinky: ["pinky1", "pinky2", "pinky3", "pinky4"]
255
- }, Ne = new p.Vector3(), K = new p.Vector3(), X = new p.Vector3(), Q = new p.Vector3(), Y = new p.Vector3(), Ve = new p.Vector3();
256
- new p.Vector3();
257
- new p.Vector3();
258
- const Z = new p.Vector3(), J = Math.PI / 2, Oe = new p.Vector3(0, -1, 0);
259
- class ee extends _ {
262
+ }, Ve = new l.Vector3(), K = new l.Vector3(), X = new l.Vector3(), Q = new l.Vector3(), Y = new l.Vector3(), Z = new l.Vector3();
263
+ new l.Vector3();
264
+ new l.Vector3();
265
+ new l.Vector3();
266
+ const J = new l.Vector3(), ee = Math.PI / 2, Oe = new l.Vector3(0, -1, 0);
267
+ class te extends _ {
260
268
  constructor(e, t, o) {
261
- super(Se, D.HAND_CONNECTIONS);
269
+ super(Ne, D.HAND_CONNECTIONS);
262
270
  k(this, "sign");
263
271
  k(this, "isLeft");
264
272
  /**
265
273
  * the axis used to look at the pole
266
274
  */
267
275
  k(this, "lookAtPoleAxis");
268
- this.handLandmarker = e, this.side = t, this.isMyWrist = o, this.sign = this.side == "Left" ? -1 : 1, this.isLeft = this.side == "Left", this.lookAtPoleAxis = this.sign < 0 ? "+x" : "-x", this.root.scale.setScalar(2), this.root.scale.y *= -1, this.root.scale.z *= -1;
276
+ this.handLandmarker = e, this.side = t, this.isMyWrist = o, this.sign = this.side == "Left" ? -1 : 1, this.isLeft = this.side == "Left", this.lookAtPoleAxis = this.sign < 0 ? "+x" : "-x", this.root.scale.setScalar(7), this.root.scale.y *= -1, this.root.scale.z *= -1;
269
277
  }
270
278
  predict(e, t) {
271
279
  const o = this.handLandmarker.detectForVideo(e, performance.now());
@@ -291,42 +299,46 @@ class ee extends _ {
291
299
  * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker
292
300
  */
293
301
  syncHandBones(e, t, o) {
294
- const i = Ne.crossVectors(
302
+ const i = Ve.crossVectors(
295
303
  K.copy(this.marks.index1.worldPosition).sub(this.marks.wrist.worldPosition),
296
304
  X.copy(this.marks.pinky1.worldPosition).sub(this.marks.wrist.worldPosition)
297
305
  ).normalize(), r = K.copy(this.marks.palm.worldPosition).sub(this.marks.wrist.worldPosition).normalize(), n = X.copy(this.marks.pinky1.worldPosition).sub(this.marks.index1.worldPosition).normalize();
298
306
  if (!(r.dot(Oe) > 0.8)) {
299
307
  if (t.wrist) {
300
- const a = F(Q, t.wrist, o).add(r).applyMatrix4(o.matrixWorld), c = F(Y, t.wrist, o).sub(n).applyMatrix4(o.matrixWorld), l = this.getGhost(t.wrist);
301
- A(l, a, c, "-y"), l.rotateX(J), l.lerp(t.wrist, e);
308
+ const a = F(Q, t.wrist, o).add(r).applyMatrix4(o.matrixWorld), c = F(Y, t.wrist, o).sub(n).applyMatrix4(o.matrixWorld), p = this.getGhost(t.wrist);
309
+ A(p, a, c, "-y"), p.rotateX(ee), p.lerp(t.wrist, e);
302
310
  }
303
- this.syncFinger(e, o, i, r, n, t, v.index, "middle1"), this.syncFinger(e, o, i, r, n, t, v.middle, "ring1"), this.syncFinger(e, o, i, r, n, t, v.ring, "pinky1"), this.syncFinger(e, o, i, r, n, t, v.pinky, "ring1"), this.syncFinger(e, o, i, r, n, t, v.thumb, "index1");
311
+ this.syncFinger(e, o, i, r, n, t, v.index, "middle1"), this.syncFinger(e, o, i, r, n, t, v.middle, "ring1"), this.syncFinger(e, o, i, r, n, t, v.ring, "pinky1"), this.syncFinger(e, o, i, r, n, t, v.pinky, "ring1", !0), this.syncFinger(e, o, i, r, n, t, v.thumb, "index1");
304
312
  }
305
313
  }
306
- syncFinger(e, t, o, i, r, n, a, c, l = !1) {
314
+ syncFinger(e, t, o, i, r, n, a, c, p = !1) {
307
315
  for (let f = 0; f < a.length - 1; f++) {
308
316
  const R = n[a[f]];
309
317
  if (!R) continue;
310
- const h = Q.copy(this.marks[a[f + 1]].worldPosition).sub(this.marks[a[f]].worldPosition).normalize(), m = F(Y, R, t), w = Ve.copy(m).add(r);
311
- l && w.negate();
312
- const u = this.getGhost(R);
313
- f == 0 ? (Z.copy(w), A(
314
- u,
315
- h.add(m).applyMatrix4(t.matrixWorld),
316
- w.add(m).applyMatrix4(t.matrixWorld),
317
- this.lookAtPoleAxis
318
- )) : (w.copy(Z), A(
319
- u,
320
- h.add(m).applyMatrix4(t.matrixWorld),
321
- w.add(m).applyMatrix4(t.matrixWorld),
322
- this.lookAtPoleAxis
323
- )), u.rotateX(J), u.lerp(R, e);
318
+ const d = this.getGhost(R), m = Q.copy(this.marks[a[f + 1]].worldPosition).sub(this.marks[a[f]].worldPosition).normalize(), L = F(Y, R, t);
319
+ if (f == 0) {
320
+ const u = Z.copy(this.marks[c].worldPosition).sub(this.marks[a[0]].worldPosition).normalize();
321
+ p && u.negate(), J.copy(u), A(
322
+ d,
323
+ m.add(L).applyMatrix4(t.matrixWorld),
324
+ u.add(L).applyMatrix4(t.matrixWorld),
325
+ this.lookAtPoleAxis
326
+ );
327
+ } else
328
+ A(
329
+ d,
330
+ m.add(L).applyMatrix4(t.matrixWorld),
331
+ Z.copy(J).add(L).applyMatrix4(t.matrixWorld),
332
+ this.lookAtPoleAxis
333
+ );
334
+ d.rotateX(ee), d.lerp(R, e);
324
335
  }
325
336
  }
326
337
  bind(e, t) {
327
338
  const o = {}, i = (r, n) => {
328
339
  const a = x(e, r);
329
- a && (o[n] = a);
340
+ if (a)
341
+ return o[n] = a, n;
330
342
  };
331
343
  return i(this.isLeft ? t.handL : t.handR, "wrist"), i(this.isLeft ? t.index1L : t.index1R, "index1"), i(this.isLeft ? t.index2L : t.index2R, "index2"), i(this.isLeft ? t.index3L : t.index3R, "index3"), i(this.isLeft ? t.middle1L : t.middle1R, "middle1"), i(this.isLeft ? t.middle2L : t.middle2R, "middle2"), i(this.isLeft ? t.middle3L : t.middle3R, "middle3"), i(this.isLeft ? t.ring1L : t.ring1R, "ring1"), i(this.isLeft ? t.ring2L : t.ring2R, "ring2"), i(this.isLeft ? t.ring3L : t.ring3R, "ring3"), i(this.isLeft ? t.pinky1L : t.pinky1R, "pinky1"), i(this.isLeft ? t.pinky2L : t.pinky2R, "pinky2"), i(this.isLeft ? t.pinky3L : t.pinky3R, "pinky3"), i(this.isLeft ? t.thumb1L : t.thumb1R, "thumb1"), i(this.isLeft ? t.thumb2L : t.thumb2R, "thumb2"), i(this.isLeft ? t.thumb3L : t.thumb3R, "thumb3"), {
332
344
  update: (r) => {
@@ -335,8 +347,8 @@ class ee extends _ {
335
347
  };
336
348
  }
337
349
  }
338
- async function Te(d, s) {
339
- const e = await C.createFromOptions(d, {
350
+ async function Te(h, s) {
351
+ const e = await C.createFromOptions(h, {
340
352
  baseOptions: {
341
353
  modelAssetPath: (s == null ? void 0 : s.modelPath) ?? "face_landmarker.task",
342
354
  delegate: "GPU"
@@ -360,7 +372,7 @@ const De = {
360
372
  noseBone: 6,
361
373
  chin: 152,
362
374
  forehead: 10
363
- }, Ce = new P(), _e = new P(), ie = new P(), ze = new P(), Be = new P();
375
+ }, Ce = new P(), _e = new P(), ne = new P(), ze = new P(), Be = new P();
364
376
  new P();
365
377
  class Ie extends _ {
366
378
  // lower = smoother but more lag, higher = more responsive
@@ -395,17 +407,17 @@ class Ie extends _ {
395
407
  };
396
408
  }
397
409
  bind(e) {
398
- const t = new te(e, "L"), o = new te(e, "R"), i = x(e, "head");
410
+ const t = new oe(e, "L"), o = new oe(e, "R"), i = x(e, "head");
399
411
  return {
400
412
  update: (r) => {
401
413
  if (t.update(r, this.blendshapeMap), o.update(r, this.blendshapeMap), !i) return;
402
- const n = Ce.copy(this.marks.earL.worldPosition), a = _e.copy(this.marks.earR.worldPosition), c = ie.subVectors(n, a).multiplyScalar(0.5).add(a), l = ze.subVectors(this.marks.noseTip.worldPosition, c), f = n.sub(a), R = F(Be, i, e), h = f.add(R).applyMatrix4(e.matrixWorld), m = l.add(R).applyMatrix4(e.matrixWorld);
403
- A(i, m, h, "+x");
414
+ const n = Ce.copy(this.marks.earL.worldPosition), a = _e.copy(this.marks.earR.worldPosition), c = ne.subVectors(n, a).multiplyScalar(0.5).add(a), p = ze.subVectors(this.marks.noseTip.worldPosition, c), f = n.sub(a), R = F(Be, i, e), d = f.add(R).applyMatrix4(e.matrixWorld), m = p.add(R).applyMatrix4(e.matrixWorld);
415
+ A(i, m, d, "+x");
404
416
  }
405
417
  };
406
418
  }
407
419
  }
408
- class te {
420
+ class oe {
409
421
  constructor(s, e) {
410
422
  k(this, "eyeBone");
411
423
  k(this, "eyeLookOut");
@@ -419,12 +431,12 @@ class te {
419
431
  }
420
432
  update(s, e) {
421
433
  if (!this.eyeBone) return;
422
- F(ie, this.eyeBone, this.rig);
434
+ F(ne, this.eyeBone, this.rig);
423
435
  const t = e.get(this.eyeLookOut) ?? 0, o = e.get(this.eyeLookIn) ?? 0, i = e.get(this.eyeLookUp) ?? 0, r = e.get(this.eyeLookDown) ?? 0, n = o - t, a = r - i;
424
436
  this.eyeBone.rotation.y = n * this.sign / 2, this.eyeBone.rotation.x = a / 2;
425
437
  }
426
438
  }
427
- const ne = {
439
+ const re = {
428
440
  faceMesh: "face",
429
441
  head: "head",
430
442
  hips: "hips",
@@ -526,33 +538,33 @@ const ne = {
526
538
  "mouthUpperUpRight",
527
539
  "tongueOut"
528
540
  ];
529
- function Ge(d, s, e = 30) {
530
- const t = [], o = d.getObjectByName(
541
+ function Ge(h, s, e = 30) {
542
+ const t = [], o = h.getObjectByName(
531
543
  s.faceMesh
532
544
  ), i = /* @__PURE__ */ new Set();
533
545
  if (o != null && o.morphTargetDictionary)
534
- for (const w in o.morphTargetDictionary)
535
- Ue.includes(w) && i.add(w);
546
+ for (const L in o.morphTargetDictionary)
547
+ Ue.includes(L) && i.add(L);
536
548
  const r = Object.keys(s);
537
- d.traverse((w) => {
538
- if (w instanceof S.Bone) {
539
- const u = r.find((W) => w.name.indexOf(s[W]) === 0);
549
+ h.traverse((L) => {
550
+ if (L instanceof S.Bone) {
551
+ const u = r.find((W) => L.name.indexOf(s[W]) === 0);
540
552
  u && t.push({
541
- ref: w,
542
- name: w.name,
553
+ ref: L,
554
+ name: L.name,
543
555
  normalizedName: u
544
556
  });
545
557
  }
546
558
  });
547
559
  const n = [], a = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map();
548
- let l = !1, f = 0;
560
+ let p = !1, f = 0;
549
561
  function R() {
550
- a.clear(), c.clear(), n.length = 0, f = performance.now() / 1e3, l = !0;
562
+ a.clear(), c.clear(), n.length = 0, f = performance.now() / 1e3, p = !0;
551
563
  }
552
- function h() {
553
- if (!l) return;
554
- const w = performance.now() / 1e3 - f;
555
- n.push(w);
564
+ function d() {
565
+ if (!p) return;
566
+ const L = performance.now() / 1e3 - f;
567
+ n.push(L);
556
568
  for (const u of t) {
557
569
  a.has(u.name) || a.set(u.name, []);
558
570
  const W = a.get(u.name), b = u.ref.quaternion;
@@ -564,8 +576,8 @@ function Ge(d, s, e = 30) {
564
576
  W.push(E);
565
577
  }
566
578
  }
567
- function m(w = "RecordedClip") {
568
- l = !1;
579
+ function m(L = "RecordedClip") {
580
+ p = !1;
569
581
  const u = [];
570
582
  for (const [b, E] of a)
571
583
  u.push(
@@ -578,22 +590,22 @@ function Ge(d, s, e = 30) {
578
590
  for (const [b, E] of c)
579
591
  u.push(
580
592
  new S.NumberKeyframeTrack(
581
- `${ne.faceMesh}.morphTargetInfluences[${b}]`,
593
+ `${re.faceMesh}.morphTargetInfluences[${b}]`,
582
594
  n,
583
595
  E
584
596
  )
585
597
  );
586
- const W = new S.AnimationClip(w, -1, u);
598
+ const W = new S.AnimationClip(L, -1, u);
587
599
  return {
588
600
  clip: W,
589
601
  saveToFile: () => {
590
- new me().parse(
591
- d,
602
+ new ue().parse(
603
+ h,
592
604
  (E) => {
593
- const L = new Blob([E], {
605
+ const w = new Blob([E], {
594
606
  type: "model/gltf-binary"
595
- }), y = URL.createObjectURL(L), g = document.createElement("a");
596
- g.href = y, g.download = w + ".glb", g.click();
607
+ }), y = URL.createObjectURL(w), g = document.createElement("a");
608
+ g.href = y, g.download = L + ".glb", g.click();
597
609
  },
598
610
  (E) => {
599
611
  console.error(E);
@@ -606,13 +618,13 @@ function Ge(d, s, e = 30) {
606
618
  }
607
619
  };
608
620
  }
609
- return { start: R, captureFrame: h, stop: m, isRecording: () => l };
621
+ return { start: R, captureFrame: d, stop: m, isRecording: () => p };
610
622
  }
611
623
  const He = () => {
612
- var d;
613
- return !!((d = navigator.mediaDevices) != null && d.getUserMedia);
624
+ var h;
625
+ return !!((h = navigator.mediaDevices) != null && h.getUserMedia);
614
626
  };
615
- async function Qe(d) {
627
+ async function Qe(h) {
616
628
  const s = {
617
629
  debugFrame: void 0,
618
630
  displayScale: 1,
@@ -625,41 +637,41 @@ async function Qe(d) {
625
637
  hand: "https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task",
626
638
  face: "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task"
627
639
  },
628
- ...d
640
+ ...h
629
641
  };
630
642
  let e;
631
- const t = await ce.forVisionTasks(s.modelPaths.vision ?? "/wasm"), o = await Pe(t, {
643
+ const t = await le.forVisionTasks(s.modelPaths.vision ?? "/wasm"), o = await We(t, {
632
644
  ignoreLegs: s.ignoreLegs,
633
645
  modelPath: s.modelPaths.pose
634
- }), i = await ge(t, {
646
+ }), i = await Se(t, {
635
647
  leftWrist: () => o.leftWristNormalizedPosition,
636
648
  rightWrist: () => o.rightWristNormalizedPosition,
637
649
  modelPath: s.modelPaths.hand,
638
- ...d == null ? void 0 : d.handsTrackerOptions
650
+ ...h == null ? void 0 : h.handsTrackerOptions
639
651
  }), r = s.ignoreFace ? void 0 : await Te(t, { modelPath: s.modelPaths.face }), n = document.createElement("div");
640
652
  n.style.position = "absolute", n.style.top = "0px", n.style.left = "0px", n.style.zIndex = "21", n.classList.add("three-mediapipe-rig"), document.body.appendChild(n);
641
- const a = document.createElement("canvas"), c = a.getContext("2d"), l = new le(c);
653
+ const a = document.createElement("canvas"), c = a.getContext("2d"), p = new pe(c);
642
654
  a.style.zIndex = "22", a.style.position = "absolute", a.style.top = "0px", a.style.left = "0px", a.style.pointerEvents = "none", n.appendChild(a);
643
- function f(h) {
644
- c.save(), c.clearRect(0, 0, a.width, a.height), o == null || o.predict(h, l), i == null || i.left.predict(h, l), i == null || i.right.predict(h, l), r == null || r.predict(h, l), c.restore();
655
+ function f(d) {
656
+ c.save(), c.clearRect(0, 0, a.width, a.height), o == null || o.predict(d, p), i == null || i.left.predict(d, p), i == null || i.right.predict(d, p), r == null || r.predict(d, p), c.restore();
645
657
  }
646
658
  function R() {
647
659
  e = document.createElement("video"), n.appendChild(e);
648
- let h = -1;
660
+ let d = -1;
649
661
  e.style.zIndex = "21", e.style.position = "absolute", e.style.top = "0px", e.style.left = "0px", s.debugVideo && (e.src = s.debugVideo, e.controls = !0, e.loop = !0, e.muted = !0, e.controls = !0, e.play());
650
662
  function m() {
651
- h !== e.currentTime && (f(e), h = e.currentTime), window.requestAnimationFrame(m);
663
+ d !== e.currentTime && (f(e), d = e.currentTime), window.requestAnimationFrame(m);
652
664
  }
653
665
  e.addEventListener("loadeddata", () => {
654
666
  e.width = e.videoWidth * s.displayScale, e.height = e.videoHeight * s.displayScale, a.width = e.videoWidth, a.height = e.videoHeight, a.style.height = e.height + "px", a.style.width = e.width + "px", window.requestAnimationFrame(m);
655
667
  });
656
668
  }
657
669
  if (s.debugFrame) {
658
- const h = document.createElement("img");
659
- h.src = s.debugFrame, h.style.zIndex = "21", h.style.position = "absolute", h.style.top = "0px", h.style.left = "0px", document.body.appendChild(h), h.addEventListener("load", () => {
660
- h.width = h.naturalWidth * s.displayScale, h.height = h.naturalHeight * s.displayScale, a.width = h.naturalWidth, a.height = h.naturalWidth, a.style.width = h.width + "px", a.style.height = h.height + "px";
670
+ const d = document.createElement("img");
671
+ d.src = s.debugFrame, d.style.zIndex = "21", d.style.position = "absolute", d.style.top = "0px", d.style.left = "0px", n.appendChild(d), d.addEventListener("load", () => {
672
+ d.width = d.naturalWidth * s.displayScale, d.height = d.naturalHeight * s.displayScale, a.width = d.naturalWidth, a.height = d.naturalWidth, a.style.width = d.width + "px", a.style.height = d.height + "px";
661
673
  function m() {
662
- f(h);
674
+ f(d);
663
675
  }
664
676
  window.requestAnimationFrame(m);
665
677
  });
@@ -677,40 +689,40 @@ async function Qe(d) {
677
689
  * Start the webcam feed. This must be initiated by a user triggered event ( a click on a button ) due to security reasons.
678
690
  */
679
691
  start: async () => {
680
- let h = !1;
692
+ let d = !1;
681
693
  if (!He())
682
694
  throw new Error("Webcam not supported");
683
695
  e || R();
684
696
  let m;
685
- function w(L) {
686
- console.warn("Camera track ended, attempting recovery..."), u(L), W(L);
697
+ function L(w) {
698
+ console.warn("Camera track ended, attempting recovery..."), u(w), W(w);
687
699
  }
688
- function u(L) {
689
- m == null || m.getTracks().forEach((y) => y.stop()), m = void 0, L.srcObject = null;
700
+ function u(w) {
701
+ m == null || m.getTracks().forEach((y) => y.stop()), m = void 0, w.srcObject = null;
690
702
  }
691
- async function W(L, y = 0) {
692
- const re = Math.min(1e3 * 2 ** y, 16e3);
703
+ async function W(w, y = 0) {
704
+ const ae = Math.min(1e3 * 2 ** y, 16e3);
693
705
  if (y >= 5)
694
706
  throw new Error("Camera recovery failed after max attempts");
695
- if (await new Promise((ae) => setTimeout(ae, re)), !h)
707
+ if (await new Promise((de) => setTimeout(de, ae)), !d)
696
708
  try {
697
- await b(L), console.log("Camera recovered successfully");
709
+ await b(w), console.log("Camera recovered successfully");
698
710
  } catch {
699
- W(L, y + 1);
711
+ W(w, y + 1);
700
712
  }
701
713
  }
702
- async function b(L) {
714
+ async function b(w) {
703
715
  try {
704
- m = await navigator.mediaDevices.getUserMedia({ video: !0 }), L.srcObject = m, await L.play(), m.getVideoTracks().forEach((y) => {
705
- y.addEventListener("ended", () => w(L));
716
+ m = await navigator.mediaDevices.getUserMedia({ video: !0 }), w.srcObject = m, await w.play(), m.getVideoTracks().forEach((y) => {
717
+ y.addEventListener("ended", () => L(w));
706
718
  });
707
719
  } catch (y) {
708
- E(y, L);
720
+ E(y, w);
709
721
  }
710
722
  }
711
- function E(L, y) {
712
- if (L instanceof DOMException)
713
- switch (L.name) {
723
+ function E(w, y) {
724
+ if (w instanceof DOMException)
725
+ switch (w.name) {
714
726
  case "NotAllowedError":
715
727
  throw new Error("Permission denied — prompt user to allow camera");
716
728
  case "NotFoundError":
@@ -720,12 +732,12 @@ async function Qe(d) {
720
732
  console.error("Camera in use by another app"), W(y);
721
733
  break;
722
734
  default:
723
- console.error("Camera error:", L.message), W(y);
735
+ console.error("Camera error:", w.message), W(y);
724
736
  }
725
737
  }
726
738
  return await b(e), {
727
739
  stop: () => {
728
- h = !0, u(e);
740
+ d = !0, u(e);
729
741
  }
730
742
  };
731
743
  },
@@ -734,25 +746,25 @@ async function Qe(d) {
734
746
  * @param rig The rig that contains all the bones and skinned meshes of your character.
735
747
  * @param magging The bone mapping to use for the rig.
736
748
  */
737
- bind: (h, m) => {
738
- m = m || ne;
739
- const w = o.bind(h, m), u = i.left.bind(h, m), W = i.right.bind(h, m);
749
+ bind: (d, m) => {
750
+ m = m || re;
751
+ const L = o.bind(d, m), u = i.left.bind(d, m), W = i.right.bind(d, m);
740
752
  let b;
741
- const E = r == null ? void 0 : r.bind(h);
742
- h.traverse((y) => {
743
- y instanceof p.Mesh && y.name.indexOf(m.faceMesh) === 0 && (y.frustumCulled = !1, b = r == null ? void 0 : r.bindShapeKeys(y));
753
+ const E = r == null ? void 0 : r.bind(d);
754
+ d.traverse((y) => {
755
+ y instanceof l.Mesh && y.name.indexOf(m.faceMesh) === 0 && (y.frustumCulled = !1, b = r == null ? void 0 : r.bindShapeKeys(y));
744
756
  });
745
- const L = Ge(h, m);
757
+ const w = Ge(d, m);
746
758
  return {
747
759
  /**
748
760
  * Will save the tracked movement of the rig to an animation clip.
749
761
  * Only the bones moved by the bone mapping will be recorded.
750
762
  */
751
- startRecording: L.start,
752
- stopRecording: L.stop,
753
- isRecording: () => L.isRecording(),
763
+ startRecording: w.start,
764
+ stopRecording: w.stop,
765
+ isRecording: () => w.isRecording(),
754
766
  update: (y) => {
755
- w.update(y), u.update(y), W.update(y), b == null || b.update(y), E == null || E.update(y), L.isRecording() && L.captureFrame();
767
+ L.update(y), u.update(y), W.update(y), b == null || b.update(y), E == null || E.update(y), w.isRecording() && w.captureFrame();
756
768
  }
757
769
  };
758
770
  }
@@ -1 +1 @@
1
- {"version":3,"file":"three-mediapipe-rig.js","sources":["../src/tracking/util/lookAt.ts","../src/tracking/Tracker.ts","../src/tracking/util/getRootPosition.ts","../src/tracking/util/cleanBoneName.ts","../src/tracking/util/getBoneByName.ts","../src/tracking/PoseTracker.ts","../src/tracking/HandTracker.ts","../src/tracking/FaceTracker.ts","../src/tracking/BoneMapping.ts","../src/tracking/blendShapeKeyNames.ts","../src/tracking/recoding/recorder.ts","../src/tracking/TrackerManager.ts"],"sourcesContent":["import { Object3D, Quaternion, Vector3 } from \"three/webgpu\";\n\nconst poleDir = new Vector3();\nconst objectPosition = new Vector3();\n\nconst XAxis = new Vector3(1,0,0);\nconst XAxisNeg = new Vector3(-1,0,0);\nconst YAxis = new Vector3(0,1,0); \nconst YAxisNeg = new Vector3(0,-1,0); \nconst ZAxis = new Vector3(0,0,1); \nconst ZAxisNeg = new Vector3(0,0,-1); \n\nconst pole = new Vector3();\nconst lookDir = new Vector3();\n\nconst v = new Vector3();\nconst correction = new Quaternion();\nconst worldQuat = new Quaternion();\n\nexport type LookAtPoleAxis = \"+x\"|\"+y\"|\"-x\"|\"-y\"\n\n/**\n * Will point the Z axis of object at target and the X or Y axis in the general direction of the pole target\n * @param object The object to rotate\n * @param target The point to look at ( in world coord )\n * @param poleTarget The goal of the pole axis ( in world coord )\n * @param poleAxis The axis to use as the pole axis ( z is the one pointing at the target )\n */\nexport function lookAt( object:Object3D, target:Vector3, poleTarget:Vector3, poleAxis:LookAtPoleAxis = \"+x\" )\n{ \n\t//\n\t// look at target (handles parent transforms internally)\n\t// \n\tobject.lookAt(target);\n\n\tconst axis = poleAxis==\"+x\"?XAxis: poleAxis==\"-x\"?XAxisNeg: poleAxis==\"+y\"?YAxis: YAxisNeg;\n\n\tobject.getWorldPosition(objectPosition);\n\tobject.getWorldQuaternion(worldQuat);\n\n\tpoleDir.subVectors(poleTarget, objectPosition).normalize();\n\n\t// direction in which the pole axis is currently pointing (in world space)\n\tpole.copy(axis).applyQuaternion(worldQuat);\n\n\tconst currentPole = pole;\n\n\t// look direction in world space\n\tconst lookAxisDir = lookDir.copy( ZAxis ).applyQuaternion(worldQuat);\n\n\t// project desired pole direction onto the plane perpendicular to the look axis\n\tconst desiredPoleDir = poleDir.clone().addScaledVector(lookAxisDir, -poleDir.dot(lookAxisDir)).normalize();\n\n\t// signed angle between current pole and desired pole around the look axis\n\tconst cross = v.crossVectors(currentPole, desiredPoleDir);\n\tconst angle = Math.atan2(cross.dot(lookAxisDir), currentPole.dot(desiredPoleDir));\n\n\t// The correction is a spin around the look axis (local Z after lookAt).\n\t// Since lookAt aligned local Z to the target, we can apply around the local Z axis directly.\n\tcorrection.setFromAxisAngle(ZAxis, angle);\n\tobject.quaternion.multiply(correction);\n}","import * as THREE from \"three/webgpu\";\nimport {\n Landmark,\n NormalizedLandmark,\n\tDrawingUtils, \n} from \"@mediapipe/tasks-vision\"; \nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\n\n \n\nconst v = new THREE.Vector3();\nconst A = new THREE.Vector3();\nconst B = new THREE.Vector3();\nconst C = new THREE.Vector3();\n\nexport class Tracker<T extends Record<string, number|number[]> > {\n\tprivate objectGhost : Map<THREE.Object3D, Ghost> ;\n\treadonly root:THREE.Object3D;\n\n\t/**\n\t * per landmark index, it points to it's object3D equivalent.\n\t */\n\tprotected marks: { [name in keyof T]: Mark } = {} as { [name in keyof T]: Mark };\n\n\tconstructor( protected readonly points:T, private readonly debugConnections?:{start:number,end:number}[] ){\n\t\tthis.root = new THREE.Object3D();\n\t\tthis.objectGhost = new Map();\n\n\t\t// por each key in points\n\t\tfor( let key in this.points ){\n\t\t\tthis.marks[key] = new Mark();\n \n\t\t\tthis.root.add(this.marks[key]);\n\t\t}\n\t}\n\n\tprotected updateLandmarks( landmarks:Landmark[], debugLandmarks?:NormalizedLandmark[], debugDrawer?:DrawingUtils ) {\n\t\tfor( let key in this.points ){\n\t\t\tconst point = this.points[key];\n\t\t\tconst mark = this.marks[key];\n\t\t\tif( mark ){\n\t\t\t\tif( point instanceof Array )\n\t\t\t\t{\n\t\t\t\t\t\n\t\t\t\t\tv.copy( landmarks[ point[0] ] ) \n\t\t\t\t\tmark.position.copy( landmarks[ point[1] ] ).sub( v ).divideScalar(2).add(landmarks[ point[0] ]);\n\t\t\t\t\t\n\t\t\t\t\tif( point.length==4 )\n\t\t\t\t\t{\n\t\t\t\t\t\tv.subVectors(\n\t\t\t\t\t\t\tlandmarks[ point[3] ],\n\t\t\t\t\t\t\tlandmarks[ point[2] ]\n\t\t\t\t\t\t).divideScalar(2).add(landmarks[ point[2] ]) \n\n\t\t\t\t\t\t.sub( mark.position )\n\t\t\t\t\t\t.divideScalar(2) \n\n\t\t\t\t\t\tmark.position.add( v );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\telse \n\t\t\t\t{\n\t\t\t\t\tmark.position.copy( landmarks[ point as number ] )\n\t\t\t\t}\n \n\t\t\t}\n\t\t}\n\n\t\tif( debugDrawer && debugLandmarks )\n\t\t{ \n\t\t\t// debugDrawer.drawLandmarks(debugLandmarks, {\n\t\t\t// \tradius: (data) =>\n\t\t\t// \t\tDrawingUtils.lerp(data.from!.z, -0.15, 0.1, 5, 1),\n\t\t\t// \tlineWidth:1\n\t\t\t// });\n\t\t\tdebugDrawer.drawConnectors(\n\t\t\t\tdebugLandmarks,\n\t\t\t\tthis.debugConnections,\n\t\t\t\t{\n\t\t\t\t\tlineWidth:1\n\t\t\t\t}\n\t\t\t); \n\t\t}\n\t}\n\n\tprotected getGhost( object:THREE.Object3D ){\n\t\tif( !this.objectGhost.has(object)) \n\t\t{\n\t\t\tconst o = new Ghost()\n\n\t\t\to.position.copy(object.position)\n\t\t\to.quaternion.copy(object.quaternion)\n\t\t\tobject.parent?.add(o);\n\n\t\t\tthis.objectGhost.set(object, o)\n\t\t} \n\t\treturn this.objectGhost.get(object)!;\n\t}\n\n\tpredict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tthrow new Error(\"Method 'predict' must be implemented.\");\n\t}\n\n\tsync ( delta:number, objects: [THREE.Object3D, keyof T, keyof T, LookAtPoleAxis][] ) {\n\t\tthrow new Error(\"Method 'sync' must be implemented.\"); \n\t}\n\n\ttest( key:keyof T ){\n\t\tthis.marks[key]!.position.set(1,2,3)\n\t}\n\n\tprotected syncObjects(objects: [THREE.Object3D, keyof T, keyof T,LookAtPoleAxis][], delta:number, normal:THREE.Vector3 ){\n\t\tfor( const [object, root, target, poleAxis] of objects ){\n\n\t\t\t//\n\t\t\t// position A and B where the landmarks are\n\t\t\t//\n\t\t\tthis.marks[target].getWorldPosition(B)\n\t\t\tthis.marks[root].getWorldPosition(A)\n\n\t\t\t//\n\t\t\t// calcuate the offset\n\t\t\t//\n\t\t\tconst offset = B.sub(A); // offset from root to taget in world units\n\n\t\t\t//\n\t\t\t// now position A in object position\n\t\t\t//\n\t\t\tobject.getWorldPosition(A)\n\n\t\t\t//\n\t\t\t// and displace it by the offset ( this will be the look at target )\n\t\t\t//\n\t\t\tA.add(offset);\n\n\t\t\t \n\t\t\tconst objectLookAtGoal = A;\n\t\t\tconst polePosition = object.getWorldPosition(B).sub( normal )\n\n\t\t\tconst ghost = this.getGhost(object);\n \n\n\t\t\t \n\t\t\t\tlookAt( ghost, objectLookAtGoal, polePosition, poleAxis);\n\n\t\t\t\tghost.rotateX( Math.PI/2) \n\t\t\t\n\t\t\t//ghost.rotateY( Math.PI/2)\n\n\t\t\tobject.position.lerp(ghost.position, delta * 4)\n\t\t\tobject.quaternion.slerp(ghost.quaternion, delta * 4) \n\t\t}\n\t}\n\n\tprotected getBone( rig:THREE.Object3D, name:string ){\n\t\treturn rig.getObjectByName(name.replace(/[\\.\\:]/g,\"\")) ;\n\t}\n}\n\n// const t = {\n// \tpepe:[1,2]\n// }\n// const d = new Tracker(t)\n// d.test(\"pepe\")\n\nclass Mark extends THREE.Mesh {\n\tprivate _worldPosition = new THREE.Vector3();\n\tconstructor() {\n\t\tsuper(new THREE.SphereGeometry(0.01,3,3), new THREE.MeshStandardMaterial({ color: 0xff0000, wireframe:true }));\n\t\tthis.add( new THREE.AxesHelper(0.001))\n\t}\n\n\tget worldPosition(){\n\t\tthis.getWorldPosition(this._worldPosition);\n\t\treturn this._worldPosition;\n\t}\n}\n\nclass Ghost extends THREE.Object3D { \n\tlerp( target:THREE.Object3D, delta:number, speed = 8 )\n\t{\n\t\ttarget.position.lerp(this.position, delta * speed)\n\t\ttarget.quaternion.slerp(this.quaternion, delta * speed) \n\t}\n}","import { Object3D, Vector3 } from \"three/webgpu\";\n\n\n/**\n * Gets the position of `object` relative to `root`.\n * @param out \n * @param object \n * @param root \n * @returns \n */\nexport function rootPosition( out:Vector3, object:Object3D, root:Object3D ) {\n\n\troot.worldToLocal( object.getWorldPosition(out) )\n\n\treturn out;\n}","export function cleanBoneName(name:string) {\n\treturn name.replace(/[\\.\\:]/g,\"\")\n}","import { Bone, Object3D } from \"three\";\nimport { cleanBoneName } from \"./cleanBoneName\";\n\nexport function getBoneByName(rig:Object3D, name:string) {\n\tlet bone:Bone|undefined;\n\tname = cleanBoneName(name); \n\t\n\trig.traverse( (o:Object3D) => {\n\t\tif( o.name.indexOf(name)===0 && o instanceof Bone ) bone = o as Bone;\n\t})\n\n\tif( !bone ) console.log(\"Bone not found: \", name, rig.name)\n\n\treturn bone;\n}","import {\n DrawingUtils,\n NormalizedLandmark,\n PoseLandmarker,\n} from \"@mediapipe/tasks-vision\"; \nimport * as THREE from \"three/webgpu\";\nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { BoneMap } from \"./BoneMapping\";\n\nexport async function loadPoseTracker(vision: any, config?:Partial<PoseTrackerConfig>) {\n\tconst poseLandmarker = await PoseLandmarker.createFromOptions(vision, {\n baseOptions: { \n\t\t\tmodelAssetPath: config?.modelPath ?? \"pose_landmarker_lite.task\",\n //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task`,\n //modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_heavy/float16/latest/pose_landmarker_heavy.task\",\n delegate: \"GPU\",\n },\n runningMode: \"VIDEO\",\n numPoses: 1,\n });\n\n\treturn new PoseTracker(poseLandmarker, config);\n} \n\n/**\n * Points derived from https://ai.google.dev/static/mediapipe/images/solutions/pose_landmarks_index.png\n * If the array has 2 elements, the point is between those 2 landmarks.\n * If it has 4, the point is at the center of those 4 landmarks.\n */\nconst poseMarks = {\n\t\t\thips: [24,23],\n\t\t\tneck: [12,11],\n\t\t\tleftLeg: 23,\n\t\t\tleftKnee:25,\n\t\t\tleftFoot: 27,\n\t\t\tleftToes: 31,\n\t\t\tleftArm: 11,\n\t\t\tleftElbow: 13,\n\t\t\tleftWrist: 15,\n\t\t\trightLeg: 24,\n\t\t\trightKnee: 26,\n\t\t\trightFoot: 28,\n\t\t\trightToes: 32,\n\t\t\trightArm: 12,\n\t\t\trightElbow: 14,\n\t\t\trightWrist: 16, \n\t\t\thead: [8,7] //between the ears\n\t\t\t, mouth:[10,9]\n\t\t\t, torso: [24,23, 12,11] //at the center of the torso\n\t\t\t, leftEar: 7\n\t\t\t, rightEar: 8\n\t\t} ;\n\ntype MarkKey = keyof typeof poseMarks;\n\ntype BoneBinding = [THREE.Object3D, MarkKey, MarkKey,LookAtPoleAxis]\n\nconst A = new THREE.Vector3();\nconst B = new THREE.Vector3();\nconst C = new THREE.Vector3();\nconst D = new THREE.Vector3();\nconst E = new THREE.Vector3();\nconst lookGoal = new THREE.Vector3();\nconst poleGoal = new THREE.Vector3();\n\ntype PoseTrackerConfig = {\n\tignoreLegs:boolean\n\tmodelPath:string\n}\n\n/**\n * @see https://ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker\n */\nclass PoseTracker extends Tracker<typeof poseMarks> {\n\tprivate _leftWristNormalizedPosition!:NormalizedLandmark;\n\tprivate _rightWristNormalizedPosition!:NormalizedLandmark;\n\n\t/**\n\t * Position of the left wrist in normalized coordinates (0..1)\n\t */\n\tget leftWristNormalizedPosition() { return this._leftWristNormalizedPosition; }\n\n\t/**\n\t * Position of the right wrist in normalized coordinates (0..1)\n\t */\n\tget rightWristNormalizedPosition() { return this._rightWristNormalizedPosition; }\n\n\tconstructor(private readonly poseLandmarker:PoseLandmarker, private readonly config?:Partial<PoseTrackerConfig>){ \n\n\t\tsuper(poseMarks, PoseLandmarker.POSE_CONNECTIONS)\n\t\t\n\t\tthis.root.scale.y *= -2\n\t\tthis.root.scale.z *= -2\n\t\tthis.root.scale.x *= 2 \n\t}\n\n\toverride predict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tthis.poseLandmarker.detectForVideo( source, performance.now(), (result) => {\n\n\t\t\tif( result.landmarks.length==0 )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n \n\t\t\tthis.updateLandmarks( result.worldLandmarks[0], result.landmarks[0], drawingUtils );\n\n\t\t\t\n\t\t\tthis._leftWristNormalizedPosition = result.landmarks[0][ this.points.leftWrist ];\n\t\t\tthis._rightWristNormalizedPosition = result.landmarks[0][ this.points.rightWrist ];\n\t\t} );\n\t}\n\n\t// override sync ( delta:number, objects: BoneBinding[] ) {\n\n\t// \tconst hipsPos = this.marks.hips.getWorldPosition(C); \n\n\t// \tthis.marks.rightArm.getWorldPosition(A).sub(hipsPos);\n\t// \tthis.marks.leftArm.getWorldPosition(B).sub(hipsPos); \n\n\t// \tconst torsoNormal = C.crossVectors(A,B);\n\n\t// \tthis.syncObjects(objects, delta, torsoNormal); \n\n\t// }\n\t\n\n\tbind( rig:THREE.Object3D, magging:BoneMap )\n\t{ \n\t\t \n\t\tconst map : { [key in MarkKey]?:THREE.Object3D } = {\n\t\t\t\"hips\": getBoneByName(rig, magging.hips),\n\t\t\t\"neck\": getBoneByName(rig, magging.neck),\n\t\t\t\"leftArm\": getBoneByName(rig, magging.armL),\n\t\t\t\"leftElbow\": getBoneByName(rig, magging.forearmL),\n\t\t\t\"leftWrist\": getBoneByName(rig, magging.handL),\n\t\t\t\"rightArm\": getBoneByName(rig, magging.armR),\n\t\t\t\"rightElbow\": getBoneByName(rig, magging.forearmR),\n\t\t\t\"rightWrist\": getBoneByName(rig, magging.handR),\n\t\t\t\"head\": getBoneByName(rig, magging.head), \n\t\t\t\"torso\": getBoneByName(rig, magging.torso),\n\t\t\t\"leftLeg\": getBoneByName(rig, magging.thighL),\n\t\t\t\"leftKnee\": getBoneByName(rig, magging.shinL),\n\t\t\t\"leftFoot\": getBoneByName(rig, magging.footL),\n\t\t\t\"rightLeg\": getBoneByName(rig, magging.thighR),\n\t\t\t\"rightKnee\": getBoneByName(rig, magging.shinR),\n\t\t\t\"rightFoot\": getBoneByName(rig, magging.footR),\n\t\t} \n\n\t\tif( this.config?.ignoreLegs ){\n\t\t\tdelete map.leftLeg\n\t\t\tdelete map.leftKnee\n\t\t\tdelete map.leftFoot\n\t\t\tdelete map.leftToes\n\t\t\tdelete map.rightLeg\n\t\t\tdelete map.rightKnee\n\t\t\tdelete map.rightFoot\n\t\t\tdelete map.rightToes\n\t\t}\n\n\t\tconst v = new THREE.Vector3();\n\t\tconst v2 = new THREE.Vector3();\n\n\t\tconst syncBone = ( delta:number, bone:THREE.Object3D|undefined, from:MarkKey, to:MarkKey, sideAxis:THREE.Vector3, poleAxis:LookAtPoleAxis ) => {\n\t\t\tif( !bone ) return;\n\n\t\t\tconst hipsDir = this.marks[to].getWorldPosition(v).sub(this.marks[from].getWorldPosition(v2)).normalize(); \n\n\t\t \n\t\t\trootPosition(lookGoal, bone, rig).add( hipsDir ).applyMatrix4(rig.matrixWorld) ;\n\t\t\trootPosition(poleGoal, bone, rig).add( sideAxis ).applyMatrix4(rig.matrixWorld) ; \n\n\t\t\tconst ghost = this.getGhost(bone)\n\n\t\t\tlookAt(ghost, lookGoal, poleGoal, poleAxis)\n\t\t\tghost.rotateX(Math.PI/2)\n\t\t\t \n\n\t\t\tghost.lerp(bone, delta)\n\t\t}\n\n\t\treturn {\n\t\t\tupdate: (delta:number)=>{\n \n\t\t\t\tconst sideHips = this.marks.leftLeg.getWorldPosition(A).sub(this.marks.rightLeg.getWorldPosition(B)).normalize();\n\t\t\t\tconst sideShoulders = this.marks.leftArm.getWorldPosition(B).sub(this.marks.rightArm.getWorldPosition(C)).normalize();\n\t\t\t\tconst sideHead = this.marks.leftEar.getWorldPosition(D).sub(this.marks.rightEar.getWorldPosition(E)).normalize();\n\n\t\t\t\tsyncBone(delta, map.hips, \"hips\", \"torso\", sideHips, \"+x\")\n\t\t\t\tsyncBone(delta, map.torso, \"torso\", \"neck\", sideShoulders, \"+x\")\n\t\t\t\tsyncBone(delta, map.neck, \"neck\", \"head\", sideHead, \"+x\")\n\t\t\t\tsyncBone(delta, map.head, \"neck\", \"head\", sideHead, \"+x\")\n\n\t\t\t\tsyncBone(delta, map.leftArm, \"leftArm\", \"leftElbow\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.leftElbow, \"leftElbow\", \"leftWrist\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.leftLeg, \"leftLeg\", \"leftKnee\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.leftKnee, \"leftKnee\", \"leftFoot\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.leftFoot, \"leftFoot\", \"leftToes\", sideHips, \"+x\") \n\n\t\t\t\tsyncBone(delta, map.rightArm, \"rightArm\", \"rightElbow\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.rightElbow, \"rightElbow\", \"rightWrist\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.rightLeg, \"rightLeg\", \"rightKnee\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.rightKnee, \"rightKnee\", \"rightFoot\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.rightFoot, \"rightFoot\", \"rightToes\", sideHips, \"+x\") \n\t\t\t\t\n\t\t\t}\n\t\t}\n\t}\n}\n ","import {\n\tDrawingUtils,\n HandLandmarker,\n\tHandLandmarkerOptions,\n\tNormalizedLandmark,\n} from \"@mediapipe/tasks-vision\";\nimport * as THREE from \"three/webgpu\";\nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { BoneMap } from \"./BoneMapping\";\n\nexport type HandsTrackerConfig = {\n\tleftWrist: ()=>NormalizedLandmark;\n\trightWrist: ()=>NormalizedLandmark;\n\tmodelPath?:string\n} & Partial<HandLandmarkerOptions>;\n\nconst A = new THREE.Vector2();\nconst B = new THREE.Vector2();\n\nexport async function loadHandTracker(vision: any, config:HandsTrackerConfig ) {\n const landmarker = await HandLandmarker.createFromOptions(vision, {\n baseOptions: {\n modelAssetPath: config.modelPath ?? \"hand_landmarker.task\",\n //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,\n delegate: \"GPU\",\n },\n runningMode: \"VIDEO\",\n numHands: 2,\n });\n\n\tconst isMyWrist = ( myWrist:()=>NormalizedLandmark, otherWrist:()=>NormalizedLandmark, handWrist:NormalizedLandmark ) => {\n\t\tA.copy(myWrist());\n\t\tB.copy(otherWrist());\n\t\treturn A.distanceTo(handWrist) < B.distanceTo(handWrist);\n\t}\n\n return {\n\t\tleft:new HandsTracker(landmarker, \"Left\", isMyWrist.bind(null, config.leftWrist, config.rightWrist) ),\n\t\tright:new HandsTracker(landmarker, \"Right\", isMyWrist.bind(null, config.rightWrist, config.leftWrist) )\n\t};\n}\n\nconst handMarks = {\n wrist: 0,\n\tpalm: [9,13],\n\n thumb1: 1,\n thumb2: 2,\n thumb3: 3,\n thumb4: 4,\n\n index1: 5,\n index2: 6,\n index3: 7,\n index4: 8,\n\n middle1: 9,\n middle2: 10,\n middle3: 11,\n middle4: 12,\n\n ring1: 13,\n ring2: 14,\n ring3: 15,\n ring4: 16,\n\n pinky1: 17,\n pinky2: 18,\n pinky3: 19,\n pinky4: 20,\n};\n\nexport type HandMarkName = keyof typeof handMarks;\n\nconst fingerKeys = {\n\tthumb: [\"thumb1\",\"thumb2\",\"thumb3\",\"thumb4\"],\n\tindex: [\"index1\",\"index2\",\"index3\",\"index4\"],\n\tmiddle: [\"middle1\",\"middle2\",\"middle3\",\"middle4\"],\n\tring: [\"ring1\",\"ring2\",\"ring3\",\"ring4\"],\n\tpinky: [\"pinky1\",\"pinky2\",\"pinky3\",\"pinky4\"]\n} as { [key:string]: HandMarkName[]} ;\n\n\ntype HandSide = \"Left\" | \"Right\"\nexport type Mark2Bone = Partial<{ [key in HandMarkName]: THREE.Object3D }>;\n\nconst v1 = new THREE.Vector3();\nconst v2 = new THREE.Vector3();\nconst v3 = new THREE.Vector3();\nconst v4 = new THREE.Vector3();\nconst v5 = new THREE.Vector3();\nconst v6 = new THREE.Vector3();\n\nconst currNormal = new THREE.Vector3();\nconst currForward = new THREE.Vector3();\nconst currSide = new THREE.Vector3();\nconst HALF_PI = Math.PI/2\nconst DOWN = new THREE.Vector3(0,-1,0);\n\nclass HandsTracker extends Tracker<typeof handMarks> {\n\tprivate readonly sign:number;\n\tprivate readonly isLeft:boolean;\n\t/**\n\t * the axis used to look at the pole\n\t */\n\tprivate readonly lookAtPoleAxis:LookAtPoleAxis;\n\n\tconstructor(private readonly handLandmarker:HandLandmarker, private readonly side:HandSide, private readonly isMyWrist:( handWrist:NormalizedLandmark )=>boolean ){\n\t\tsuper(handMarks, HandLandmarker.HAND_CONNECTIONS)\n\n\t\tthis.sign = this.side==\"Left\" ? -1 : 1;\n\t\tthis.isLeft = this.side==\"Left\";\n\t\tthis.lookAtPoleAxis = this.sign<0? \"+x\" : \"-x\";\n\t\tthis.root.scale.setScalar(2)\n\t\tthis.root.scale.y *= -1\n\t\tthis.root.scale.z *= -1\n\t}\n\n\toverride predict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tconst result = this.handLandmarker.detectForVideo(source, performance.now());\n\n\t\tif( result.landmarks.length )\n\t\t{\n\t\t\t//console.log(`DETECTED ${result.landmarks.length} hands`, result.handedness)\n\n\n\t\t\tfor(let i=0; i<result.landmarks.length; i++){\n\t\t\t\tconst hand = result.landmarks[i];\n\t\t\t\tconst wrist = hand[this.points.wrist];\n\t\t\t\tconst isMyWrist = this.isMyWrist(wrist);\n\t\t\t\tif( isMyWrist ){\n\t\t\t\t\tthis.updateLandmarks( result.worldLandmarks[i] );\n\n\t\t\t\t\tdrawingUtils.drawConnectors(hand, HandLandmarker.HAND_CONNECTIONS, {\n\t\t\t\t\t\tcolor: this.side==\"Left\" ? \"#00FF00\" : \"#0000FF\",\n\t\t\t\t\t\tlineWidth: 4\n\t\t\t\t\t});\n\t\t\t\t\tdrawingUtils.drawLandmarks(hand, { color: this.side==\"Left\" ? \"#00FF00\" : \"#0000FF\", lineWidth: 3, radius: 1 }); \n\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} \n \n \n\t\t} \n\t}\n\n\toverride sync ( delta:number, objects: [THREE.Object3D, HandMarkName, HandMarkName, LookAtPoleAxis][] ) {\n\n\t\tthrow new Error(\"Not used. Use syncHandBones instead\");\n\t}\n\t\t\n\t/**\n\t * \n\t * @param delta time since last frame\n\t * @param landmark2bones Array the same size as the umber of hand landmarks, and on each positionthe bone that belongs to that point.\n\t * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker\n\t */\n\tsyncHandBones( delta:number, markToBone:Mark2Bone, rig:THREE.Object3D )\n\t{ \n\t\tconst palmNormal = v1.crossVectors(\n\t\t\tv2.copy(this.marks.index1.worldPosition).sub(this.marks.wrist.worldPosition),\n\t\t\tv3.copy(this.marks.pinky1.worldPosition).sub(this.marks.wrist.worldPosition)\n\t\t).normalize();\n\n\t\tconst parlmDir = v2.copy(this.marks.palm.worldPosition).sub(this.marks.wrist.worldPosition).normalize();\n\t\tconst palmSide = v3.copy(this.marks.pinky1.worldPosition).sub(this.marks.index1.worldPosition).normalize();\n\t\t \n\t\tif( parlmDir.dot(DOWN)>0.8 )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif( markToBone.wrist )\n\t\t{\n\t\t\tconst palmLookAt = rootPosition(v4, markToBone.wrist, rig ).add( parlmDir ).applyMatrix4(rig.matrixWorld) //markToBone.wrist.getWorldPosition(v4).add( parlmDir );\n\t\t\tconst polPosition = rootPosition(v5, markToBone.wrist, rig ).sub( palmSide ).applyMatrix4(rig.matrixWorld) //markToBone.wrist.getWorldPosition(v5).sub( palmSide );\n\n\t\t\tconst palmGhost = this.getGhost(markToBone.wrist)\n\n\t\t\tlookAt( palmGhost, palmLookAt, polPosition, \"-y\" );\n\t\t\tpalmGhost.rotateX( HALF_PI ) ; \n\n\t\t\tpalmGhost.lerp(markToBone.wrist, delta)\n\t\t}\n\t\t\n\n\t\t// palmLookAtOffset.normalize();\n\n\t\t \n\t\t// const palmSide = v3.crossVectors(palmNormal, palmLookAtOffset).normalize();\n \n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.index, \"middle1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.middle, \"ring1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.ring, \"pinky1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.pinky, \"ring1\" )\n\n\t\t// //thumb...\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.thumb, \"index1\" )\n\n\t\t\n\t}\n\n\tprivate syncFinger( delta:number, rig:THREE.Object3D, palmNormal:THREE.Vector3, palmForward:THREE.Vector3, palmSide:THREE.Vector3, markToBone:Mark2Bone, fingerKeys:HandMarkName[], sideGoal:HandMarkName, negateSideGoal:boolean=false ){\n\t \n\t\tlet signMult = 1;\n\n\t\tfor(let i=0; i<fingerKeys.length-1;i++) { \n\t\t\t\n\t\t\tconst bone = markToBone[fingerKeys[i]];\n\t\t\t//const bonePole = markToBone[sideGoal];\n\n\t\t\tif(!bone ) continue;\n\n\t\t\tconst myDir = v4.copy( this.marks[fingerKeys[i+1]].worldPosition ).sub( this.marks[fingerKeys[i]].worldPosition).normalize(); \n\t\t\t\n\t\t\tconst bonePos = rootPosition(v5, bone, rig) //bone.getWorldPosition(v5);\n\t\t\tconst poleOffset = v6.copy(bonePos).add(palmSide) //rootPosition(v6, bonePole, rig).sub( bonePos );//bonePole.getWorldPosition(v6).sub( bonePos );\n\n\t\t\tif( negateSideGoal ) poleOffset.negate();\n\n\t\t\tconst fingerGhost = this.getGhost(bone)\n\n\n\t\t\tif( i==0 )\n\t\t\t{ \n\n\t\t\t\tcurrSide.copy(poleOffset);\n\n\t\t\t\t\n\t\t\t\tlookAt( fingerGhost, \n\t\t\t\t\tmyDir.add( bonePos ).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tpoleOffset.add(bonePos).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tthis.lookAtPoleAxis );\n\n\t\t\t\t\n\t\t\t}\n\t\t\telse \n\t\t\t{ \n\t\t\t\tpoleOffset.copy( currSide );\n\t\t\t\tlookAt( fingerGhost, \n\t\t\t\t\tmyDir.add( bonePos ).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tpoleOffset.add(bonePos).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tthis.lookAtPoleAxis );\n\t\t\t} \n\n\t\t\tfingerGhost.rotateX( HALF_PI ); \n\n\t\t\tfingerGhost.lerp(bone, delta)\n\n\t\t}\n\n \n\t}\n \n\tbind( rig:THREE.Object3D, magging:BoneMap ){\n\n\t\tconst map:Mark2Bone = {\n\t\t\t\n\t\t}\t \n\n\t\tconst addBind = ( boneName:string, markName:HandMarkName ) => {\n\t\t\t//const bone = rig.getObjectByName( cleanBoneName( boneName.replace(\"X\", this.sign<0 ? \"L\" : \"R\") ));\n\n\t\t\tconst bone = getBoneByName(rig, boneName );\n\n\t\t\tif( bone ){\n\t\t\t\tmap[markName] = bone;\n\t\t\t}\n\t\t}\n\n\t\taddBind( this.isLeft ? magging.handL : magging.handR, \"wrist\" )\n\t\taddBind( this.isLeft ? magging.index1L : magging.index1R, \"index1\" )\n\t\taddBind( this.isLeft ? magging.index2L : magging.index2R, \"index2\" )\n\t\taddBind( this.isLeft ? magging.index3L : magging.index3R, \"index3\" ) \n\n\t\taddBind( this.isLeft ? magging.middle1L : magging.middle1R, \"middle1\" )\n\t\taddBind( this.isLeft ? magging.middle2L : magging.middle2R, \"middle2\" )\n\t\taddBind( this.isLeft ? magging.middle3L : magging.middle3R, \"middle3\" ) \n\n\t\taddBind( this.isLeft ? magging.ring1L : magging.ring1R, \"ring1\" )\n\t\taddBind( this.isLeft ? magging.ring2L : magging.ring2R, \"ring2\" )\n\t\taddBind( this.isLeft ? magging.ring3L : magging.ring3R, \"ring3\" ) \n\n\t\taddBind( this.isLeft ? magging.pinky1L : magging.pinky1R, \"pinky1\" )\n\t\taddBind( this.isLeft ? magging.pinky2L : magging.pinky2R, \"pinky2\" )\n\t\taddBind( this.isLeft ? magging.pinky3L : magging.pinky3R, \"pinky3\" ) \n\n\t\taddBind( this.isLeft ? magging.thumb1L : magging.thumb1R, \"thumb1\" )\n\t\taddBind( this.isLeft ? magging.thumb2L : magging.thumb2R, \"thumb2\" )\n\t\taddBind( this.isLeft ? magging.thumb3L : magging.thumb3R, \"thumb3\" ) \n\n\t\treturn {\n\t\t\tupdate: ( delta:number )=> { \n\t\t\t\tthis.syncHandBones(delta, map, rig);\n\t\t\t}\n\t\t}\t\n\t}\n}\n","import {\n Category,\n DrawingUtils,\n FaceLandmarker\n} from \"@mediapipe/tasks-vision\";\nimport { Mesh, Object3D, Vector3 } from \"three/webgpu\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { lookAt } from \"./util/lookAt\";\n\nexport async function loadFaceTracker(vision: any, cfg?: { modelPath?: string }) {\n const faceLandmarker = await FaceLandmarker.createFromOptions(vision, {\n baseOptions: {\n modelAssetPath: cfg?.modelPath ?? \"face_landmarker.task\",\n\t\t\tdelegate: \"GPU\", \n },\n\t\toutputFaceBlendshapes: true,\n runningMode: \"VIDEO\",\n\t\tnumFaces: 1,\n });\n\n\treturn new FaceTracker(faceLandmarker);\n}\n\n/**\n * @see https://storage.googleapis.com/mediapipe-assets/documentation/mediapipe_face_landmark_fullsize.png\n */\nconst faceMarks = {\n\teyeL: 473,\n\teyeR: 468,\n\teyeStartL: 463,\n\teyeStartR: 243,\n\teyeEndL: 263,\n\teyeEndR: 33, \n\n\tearL: 454,\n\tearR: 234,\n\tnoseTip: 4,\n\tnoseBone:6,\n\tchin:152,\n\tforehead: 10\n\n}\n\ntype MarkKey = keyof typeof faceMarks;\nconst v = new Vector3();\nconst v2 = new Vector3();\nconst v3 = new Vector3();\nconst v4 = new Vector3();\nconst v5 = new Vector3();\nconst v6 = new Vector3();\n\nclass FaceTracker extends Tracker<typeof faceMarks> {\n\tprivate blendshapeCategories: Category[] | undefined;\n\tprivate blendshapeMap: Map<string, number> = new Map();\n\tprivate smoothed: Record<string, number> = {};\n\tprivate smoothing =.0003; // lower = smoother but more lag, higher = more responsive\n\n\tconstructor(private faceLandmarker: FaceLandmarker) {\n\t\tsuper(faceMarks, FaceLandmarker.FACE_LANDMARKS_TESSELATION)\n\n\t\tthis.root.scale.y*=-1\n\t\tthis.root.scale.z*=-1\n\t\tthis.root.scale.multiplyScalar(3)\n\t}\n\n\toverride predict(frame: TexImageSource, drawingUtils: DrawingUtils) {\n\t\tconst result = this.faceLandmarker.detectForVideo(frame, performance.now());\n\t\tif (result.faceLandmarks[0]) {\n\t\t\tdrawingUtils.drawConnectors(result.faceLandmarks[0], FaceLandmarker.FACE_LANDMARKS_TESSELATION, { color: \"#00fff2ff\", lineWidth: .1 });\n\t\t\tdrawingUtils.drawLandmarks(result.faceLandmarks[0], { color: \"#00ff00\", lineWidth: .1, radius: .4 });\t\n\n\t\t\tthis.updateLandmarks(result.faceLandmarks[0], result.faceLandmarks[0] );\n\t\t}\n\n\t\tthis.blendshapeCategories = result.faceBlendshapes?.[0]?.categories; \n\n\t\tthis.blendshapeCategories?.forEach((category) => {\n\t\t\tthis.blendshapeMap.set(category.categoryName, category.score);\n\t\t});\n\t\t\n\t}\n\n\tbindShapeKeys(mesh: Mesh) {\n\t\tconst meshKeys = mesh.morphTargetDictionary; \n\n\t\treturn {\n\t\t\tupdate: (delta: number) => {\n\t\t\t\tthis.blendshapeCategories?.forEach((category) => {\n\t\t\t\t\tconst { categoryName, score } = category;\n\n\t\t\t\t\tif (!meshKeys?.hasOwnProperty(categoryName)) return;\n\n\t\t\t\t\t// Initialize if first time seeing this key\n\t\t\t\t\tif (this.smoothed[categoryName] === undefined)\n\t\t\t\t\t\tthis.smoothed[categoryName] = score;\n\n\t\t\t\t\t// Lerp toward target score\n\t\t\t\t\tconst factor = 1 - Math.pow(this.smoothing, delta);\n\t\t\t\t\tthis.smoothed[categoryName] += (score - this.smoothed[categoryName]) * factor;\n\n\t\t\t\t\tmesh.morphTargetInfluences![meshKeys[categoryName]] = this.smoothed[categoryName];\n\t\t\t\t});\n\n\t\t\t\t//eyes\n\t\t\t}\n\t\t}\n\t}\n\n\tbind( rig:Object3D ) {\n\n\t\tconst eyeL = new EyeRig(rig, \"L\");\n\t\tconst eyeR = new EyeRig(rig, \"R\");\n\t\tconst headBone = getBoneByName(rig, \"head\") ;\n \n\t\treturn {\n\t\t\tupdate: ( delta:number )=> {\n\t\t\t\t \n\t\t\t\teyeL.update(delta, this.blendshapeMap);\n\t\t\t\teyeR.update(delta, this.blendshapeMap); \n\t\t\t\t\n\t\t\t\tif(!headBone) return;\n\n\t\t\t\t//\n\t\t\t\tconst markEarL = v.copy( this.marks.earL.worldPosition );\n\t\t\t\tconst markEarR = v2.copy( this.marks.earR.worldPosition );\n\t\t\t\tconst headcenter = v3.subVectors(markEarL, markEarR).multiplyScalar(.5).add(markEarR);\n\t\t\t\tconst headForward = v4.subVectors(this.marks.noseTip.worldPosition, headcenter) ;\n\t\t\t\tconst headSideNormal = markEarL.sub(markEarR) ;\n\n\t\t\t\t\n\t\t\t\tconst headPosition = rootPosition( v5, headBone, rig); \n\n\t\t\t\tconst poleLookAt = headSideNormal.add( headPosition ).applyMatrix4(rig.matrixWorld);\n\t\t\t\tconst faceLookAt = headForward.add( headPosition ).applyMatrix4(rig.matrixWorld);\n\n\t\t\t\tlookAt( headBone, faceLookAt, poleLookAt,\"+x\" );\n\t\t\t\t \n\n\t\t\t\t// headLookAtPos.applyMatrix4(rig.matrixWorld);\n\t\t\t\t//headBone.lookAt( headLookAtPos );\n\t\t\t\t// \n\t\t\t}\n\t\t}\n\t\t\n\t}\n}\n\nclass EyeRig {\n\tprivate eyeBone:Object3D|undefined; \n\n\tprivate eyeLookOut:string;\n\tprivate eyeLookIn:string;\n\tprivate eyeLookUp:string;\n\tprivate eyeLookDown:string;\n\tprivate sign = 1;\n\t\n\tconstructor( readonly rig:Object3D, readonly side:\"L\"|\"R\" ) {\n\t\tthis.eyeBone = rig.getObjectByName(`eye${side}`) as Object3D; \n\n\t\tconst sideName = side == \"L\" ? \"Left\" : \"Right\";\n\t\tthis.eyeLookOut = `eyeLookOut${sideName}`;\n\t\tthis.eyeLookIn = `eyeLookIn${sideName}`;\n\t\tthis.eyeLookUp = `eyeLookUp${sideName}`;\n\t\tthis.eyeLookDown = `eyeLookDown${sideName}`;\n\n\t\tthis.sign = side == \"L\" ? -1 : 1;\n\t}\n\n\tupdate( delta:number, blendshapes: Map<string, number> ) {\n\t\tif( !this.eyeBone ) return; \n \n\t\tconst eye = rootPosition(v3, this.eyeBone, this.rig); \n\n\t\t\n\t\t\n\t\t// From MediaPipe blendshapes\n\t\tconst lookLeft = blendshapes.get(this.eyeLookOut) ?? 0; // or eyeLookInRight\n\t\tconst lookRight = blendshapes.get(this.eyeLookIn) ?? 0; // or eyeLookOutRight\n\t\tconst lookUp = blendshapes.get(this.eyeLookUp) ?? 0;\n\t\tconst lookDown = blendshapes.get(this.eyeLookDown) ?? 0;\n\n\t\t\n\t\t// Map to a -1..1 range\n\t\tconst sideMovement = lookRight - lookLeft // horizontal\n\t\tconst verticalMovement = lookDown - lookUp // vertical\n \n\n\t\tthis.eyeBone.rotation.y =( sideMovement * this.sign) / 2; \n\t\tthis.eyeBone.rotation.x = verticalMovement / 2; \n\t\t// // Then drive your rig bone with a target offset\n\t\t// const lookAtPos = eyeCenter\n\t\t// .add(eyeHorizontalDir ) // -sideMovement * eyeRange)\n\t\t// //.addScaledVector(eyeVerticalDir, verticalMovement * eyeRange/3)\n\t\t// .applyMatrix4(this.rig.matrixWorld);\n\n\t\t// this.eyeBone.lookAt(lookAtPos);\n\t\t// this.eyeBone.rotateX(Math.PI/2)\n\t}\n}","/**\n * The bone mapping to use for the rig.\n */\nexport type BoneMap = {\n\tfaceMesh:string\n\thead: string;\n\thips:string\n\tneck:string\n\ttorso:string\n\tarmL:string\n\tforearmL:string\n\n\tarmR:string\n\tforearmR:string\n\n\tthighL:string\n\tshinL:string\n\tfootL:string\n\ttoesL:string\n\n\tthighR:string\n\tshinR:string\n\tfootR:string\n\ttoesR:string\n\t \n\t\n\thandL:string\n\tindex1L:string\n\tindex2L:string\n\tindex3L:string\n\n\tmiddle1L:string\n\tmiddle2L:string\n\tmiddle3L:string\n\n\tring1L:string\n\tring2L:string\n\tring3L:string\n\n\tpinky1L:string\n\tpinky2L:string\n\tpinky3L:string\n\n\tthumb1L:string\n\tthumb2L:string\n\tthumb3L:string\n\n\thandR:string\n\tindex1R:string\n\tindex2R:string\n\tindex3R:string\n\n\tmiddle1R:string\n\tmiddle2R:string\n\tmiddle3R:string\n\n\tring1R:string\n\tring2R:string\n\tring3R:string\n\n\tpinky1R:string\n\tpinky2R:string\n\tpinky3R:string\n\n\tthumb1R:string\n\tthumb2R:string\n\tthumb3R:string\n \n}\n\nexport const defaultBoneMap:BoneMap = {\n\tfaceMesh:\"face\",\n\t\n\thead: \"head\",\n\thips:\"hips\",\n\tneck:\"neck\",\n\ttorso:\"torso\",\n\n\tarmL:\"upper_armL\",\n\tforearmL:\"forearmL\",\n\n\tarmR:\"upper_armR\",\n\tforearmR:\"forearmR\",\n\n\tthighL:\"thighL\",\n\tshinL:\"shinL\",\n\tfootL:\"footL\",\n\n\tthighR:\"thighR\",\n\tshinR:\"shinR\",\n\tfootR:\"footR\",\n\t \n\t\n\thandL:\"handL\",\n\tindex1L:\"index1L\",\n\tindex2L:\"index2L\",\n\tindex3L:\"index3L\",\n\n\tmiddle1L:\"middle1L\",\n\tmiddle2L:\"middle2L\",\n\tmiddle3L:\"middle3L\",\n\n\tring1L:\"ring1L\",\n\tring2L:\"ring2L\",\n\tring3L:\"ring3L\",\n\n\tpinky1L:\"pinky1L\",\n\tpinky2L:\"pinky2L\",\n\tpinky3L:\"pinky3L\",\n\n\tthumb1L:\"thumb1L\",\n\tthumb2L:\"thumb2L\",\n\tthumb3L:\"thumb3L\",\n\n\thandR:\"handR\",\n\tindex1R:\"index1R\",\n\tindex2R:\"index2R\",\n\tindex3R:\"index3R\",\n\n\tmiddle1R:\"middle1R\",\n\tmiddle2R:\"middle2R\",\n\tmiddle3R:\"middle3R\",\n\n\tring1R:\"ring1R\",\n\tring2R:\"ring2R\",\n\tring3R:\"ring3R\",\n\n\tpinky1R:\"pinky1R\",\n\tpinky2R:\"pinky2R\",\n\tpinky3R:\"pinky3R\",\n\n\tthumb1R:\"thumb1R\",\n\tthumb2R:\"thumb2R\",\n\tthumb3R:\"thumb3R\",\n \n}","/**\n * A list of blend shape key names that are used by mediapipe face mesh. \n */\nexport const blendShapeKeyNames = [\n \"eyeBlinkLeft\",\n \"eyeBlinkRight\",\n \"eyeLookDownLeft\",\n \"eyeLookDownRight\",\n \"eyeLookInLeft\",\n \"eyeLookInRight\",\n \"eyeLookOutLeft\",\n \"eyeLookOutRight\",\n \"eyeLookUpLeft\",\n \"eyeLookUpRight\",\n \"eyeSquintLeft\",\n \"eyeSquintRight\",\n \"eyeWideLeft\",\n \"eyeWideRight\",\n \"browDownLeft\",\n \"browDownRight\",\n \"browInnerUp\",\n \"browOuterUpLeft\",\n \"browOuterUpRight\",\n \"noseSneerLeft\",\n \"noseSneerRight\",\n \"cheekPuff\",\n \"cheekSquintLeft\",\n \"cheekSquintRight\",\n \"jawForward\",\n \"jawLeft\",\n \"jawOpen\",\n \"jawRight\",\n \"mouthClose\",\n \"mouthDimpleLeft\",\n \"mouthDimpleRight\",\n \"mouthFrownLeft\",\n \"mouthFrownRight\",\n \"mouthFunnel\",\n \"mouthLeft\",\n \"mouthLowerDownLeft\",\n \"mouthLowerDownRight\",\n \"mouthPressLeft\",\n \"mouthPressRight\",\n \"mouthPucker\",\n \"mouthRight\",\n \"mouthRollLower\",\n \"mouthRollUpper\",\n \"mouthShrugLower\",\n \"mouthShrugUpper\",\n \"mouthSmileLeft\",\n \"mouthSmileRight\",\n \"mouthStretchLeft\",\n \"mouthStretchRight\",\n \"mouthUpperUpLeft\",\n \"mouthUpperUpRight\",\n \"tongueOut\"\n]","import * as THREE from \"three\";\nimport { BoneMap, defaultBoneMap } from \"../BoneMapping\";\nimport { GLTFExporter } from \"three/examples/jsm/Addons.js\";\nimport { blendShapeKeyNames } from \"../blendShapeKeyNames\";\n\ntype BoneRef = {\n ref: THREE.Bone;\n name: string;\n\tnormalizedName: string;\n};\n\n/**\n * Records the local rotation of the bones in the rig. The name used will be the normalized bone name.\n * @param rigRoot\n * @param magging\n * @param fps\n * @returns\n */\nexport function createRigRecorder(\n rigRoot: THREE.Object3D,\n magging: BoneMap,\n fps = 30,\n) {\n const bones: BoneRef[] = [];\n const faceMesh = rigRoot.getObjectByName(\n magging.faceMesh,\n ) as THREE.SkinnedMesh;\n const usedBlendShapeKeys = new Set<string>();\n\n //\n // collect used blend shape keys...\n //\n if (faceMesh?.morphTargetDictionary) {\n for (const key in faceMesh.morphTargetDictionary) {\n if (blendShapeKeyNames.includes(key)) {\n usedBlendShapeKeys.add(key);\n }\n }\n }\n\n\n\t//\n\t// look for the bones\n\t//\n\tconst boneKeys = Object.keys(magging);\n\trigRoot.traverse( o => {\n\t\tif(o instanceof THREE.Bone)\n\t\t{\n\t\t\t// check if the bone name is in the mapping\n\t\t\tconst key = boneKeys.find(k => o.name.indexOf( magging[k as keyof typeof magging] )=== 0 );\n\t\t\tif(key)\n\t\t\t{\n\t\t\t\tbones.push({\n\t\t\t\t\tref: o,\n\t\t\t\t\tname: o.name, \n\t\t\t\t\tnormalizedName: key,\n\t\t\t\t}); \n\t\t\t}\n\t\t}\n\t});\n \n\n\tconst times :number[] = [];\n const boneTracks = new Map<\n string,\n number[] //vec4 array\n >();\n\n\tconst blendShapeTracks = new Map<\n\t\tstring,\n\t\tnumber[]\n\t>();\n\n let recording = false;\n let startTime = 0;\n\n function start() {\n boneTracks.clear();\n\t\tblendShapeTracks.clear();\n\t\ttimes.length = 0;\n startTime = performance.now() / 1000;\n recording = true;\n }\n\n function captureFrame() {\n if (!recording) return;\n\n const time = performance.now() / 1000 - startTime;\n\n\t\ttimes.push(time);\n\n for (const bone of bones) {\n if (!boneTracks.has(bone.name)) {\n boneTracks.set(bone.name, []);\n }\n\n const track = boneTracks.get(bone.name)!; \n\t\t\t \n const q = bone.ref.quaternion;\n track.push(q.x, q.y, q.z, q.w);\n } \n\n\t\tfor (const key of usedBlendShapeKeys) {\n\t\t\tif (!blendShapeTracks.has(key)) {\n\t\t\t\tblendShapeTracks.set(key, []);\n\t\t\t}\n\n\t\t\tconst track = blendShapeTracks.get(key)!; \n\n\t\t\tconst keyIndex = faceMesh.morphTargetDictionary![key];\n\t\t\tconst v = faceMesh.morphTargetInfluences![keyIndex];\n\t\t\ttrack.push(v);\n\t\t}\n }\n\n\t/** \n\t * @param name name of the resulting clip\n\t * @returns \n\t */\n function stop(name = \"RecordedClip\") {\n recording = false;\n\n const keyframeTracks: THREE.KeyframeTrack[] = [];\n\n\t\t\n \n for (const [boneName, data] of boneTracks) {\n keyframeTracks.push(\n new THREE.QuaternionKeyframeTrack(\n `${boneName}.quaternion`,\n times,\n data,\n ),\n );\n } \n\n\t\tfor (const [key, data] of blendShapeTracks) {\n\t\t\tkeyframeTracks.push(\n\t\t\t\tnew THREE.NumberKeyframeTrack(\n\t\t\t\t\t`${defaultBoneMap.faceMesh}.morphTargetInfluences[${key}]`,\n\t\t\t\t\ttimes,\n\t\t\t\t\tdata,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n const clip = new THREE.AnimationClip(name, -1, keyframeTracks);\n \n\n return {\n\t\t\tclip,\n\t\t\tsaveToFile:() => {\n\t const exporter = new GLTFExporter();\n\t exporter.parse(\n\t rigRoot,\n\t (gltf) => {\n\t // binary .glb\n\t const blob = new Blob([gltf], {\n\t type: \"model/gltf-binary\",\n\t });\n\t const url = URL.createObjectURL(blob);\n\n\t const a = document.createElement(\"a\");\n\t a.href = url;\n\t a.download = name + \".glb\";\n\t a.click();\n\t },\n\t (error) => {\n\t console.error(error);\n\t },\n\t {\n\t binary: true,\n\t animations: [clip],\n\t },\n\t );\n\t }\n\t\t};\n }\n\n return { start, captureFrame, stop, isRecording: () => recording };\n}\n","import {\n DrawingUtils,\n FilesetResolver,\n HandLandmarkerOptions,\n PoseLandmarker,\n} from \"@mediapipe/tasks-vision\";\nimport * as THREE from \"three/webgpu\";\nimport { loadPoseTracker } from \"./PoseTracker\";\nimport { loadHandTracker } from \"./HandTracker\"; \nimport { loadFaceTracker } from \"./FaceTracker\";\nimport { BoneMap, defaultBoneMap } from \"./BoneMapping\";\nimport { createRigRecorder } from \"./recoding/recorder\";\n\nexport type TrackerConfig = {\n /**\n * Use an image file. Useful to test a particular pose.\n */\n debugFrame?: string;\n\n /**\n * Scale of the video display\n */\n displayScale: number;\n\n /**\n * If the body pose should ignore the legs\n */\n ignoreLegs: boolean;\n\n /**\n * Use a video file instead of the webcam\n */\n debugVideo?: string;\n\n /**\n * Don't track the face\n */\n ignoreFace: boolean;\n\n /**\n * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker/web_js#configuration_options\n */\n handsTrackerOptions: HandLandmarkerOptions | undefined;\n\n\tmodelPaths?: {\n\t\tvision?:string;\n\t\tpose?: string;\n\t\thand?: string;\n\t\tface?: string;\n\t}\n};\n\nexport interface BindingHandler {\n\n\t/**\n\t * Updates the rig with the latest landmarks.\n\t * @param delta The time elapsed since the last frame in seconds.\n\t */\n update: (delta: number) => void;\n\n}\n\nexport interface RecorderHandler { \n\t/**\n\t * Starts recording the rig's movement and active shape keys ( from media pipe ).\n\t */\n\tstartRecording: VoidFunction;\n\n\t/**\n\t * Stops recording the rig's movement.\n\t * @returns A function that can be called to SAVE the recording to a file.\n\t */\n\tstopRecording: ReturnType<typeof createRigRecorder>['stop'];\n\n\t/**\n\t * Checks if the rig is currently recording.\n\t * @returns True if the rig is recording, false otherwise.\n\t */\n\tisRecording: () => boolean;\n}\n\nexport interface RecordableBindingHandler extends BindingHandler, RecorderHandler {}\n\n// Check if webcam access is supported.\nconst hasGetUserMedia = () => !!navigator.mediaDevices?.getUserMedia;\n\nexport async function setupTracker(config?: Partial<TrackerConfig>) {\n const $cfg = {\n debugFrame: undefined,\n displayScale: 1,\n ignoreLegs: false,\n debugVideo: undefined,\n ignoreFace: false,\n\t\tmodelPaths: {\n\t\t\tvision: \"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm\",\n\t\t\tpose: \"https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task\",\n\t\t\thand: \"https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task\",\n\t\t\tface: \"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task\",\n\t\t},\n ...config,\n };\n let video: HTMLVideoElement | undefined;\n const vision = await FilesetResolver.forVisionTasks( $cfg.modelPaths.vision ?? \"/wasm\" );\n const poseTracker = await loadPoseTracker(vision, {\n ignoreLegs: $cfg.ignoreLegs,\n\t\tmodelPath: $cfg.modelPaths.pose!,\n });\n const handsTracker = await loadHandTracker(vision, {\n leftWrist: () => poseTracker.leftWristNormalizedPosition,\n rightWrist: () => poseTracker.rightWristNormalizedPosition,\n\t\tmodelPath: $cfg.modelPaths.hand!,\n ...config?.handsTrackerOptions,\n });\n const faceTracker = $cfg.ignoreFace\n ? undefined\n : await loadFaceTracker(vision, { modelPath: $cfg.modelPaths.face! });\n\n //#region setup Camera and Canvas...\n\tconst viewport = document.createElement(\"div\");\n\tviewport.style.position = \"absolute\";\n\tviewport.style.top = \"0px\";\n\tviewport.style.left = \"0px\"; \n\tviewport.style.zIndex = \"21\";\n\tviewport.classList.add(\"three-mediapipe-rig\")\n\tdocument.body.appendChild(viewport);\n\n const canvasElement = document.createElement(\"canvas\");\n const canvasCtx = canvasElement.getContext(\"2d\")!;\n const drawingUtils = new DrawingUtils(canvasCtx);\n\n canvasElement.style.zIndex = \"22\";\n canvasElement.style.position = \"absolute\";\n canvasElement.style.top = \"0px\";\n canvasElement.style.left = \"0px\";\n canvasElement.style.pointerEvents = \"none\";\n viewport.appendChild(canvasElement);\n\n function predict(source: TexImageSource) {\n canvasCtx.save();\n canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);\n poseTracker?.predict(source, drawingUtils);\n handsTracker?.left.predict(source, drawingUtils);\n handsTracker?.right.predict(source, drawingUtils);\n faceTracker?.predict(source, drawingUtils);\n canvasCtx.restore();\n }\n\n function initializeVideo() {\n video = document.createElement(\"video\");\n viewport.appendChild(video);\n\n let lastVideoTime = -1;\n\n video.style.zIndex = \"21\";\n video.style.position = \"absolute\";\n video.style.top = \"0px\";\n video.style.left = \"0px\";\n\n if ($cfg.debugVideo) {\n video.src = $cfg.debugVideo;\n video.controls = true;\n video.loop = true;\n video.muted = true;\n video.controls = true;\n video.play();\n }\n\n function predictWebcam() {\n if (lastVideoTime !== video!.currentTime) {\n predict(video!);\n lastVideoTime = video!.currentTime;\n }\n window.requestAnimationFrame(predictWebcam);\n }\n\n video.addEventListener(\"loadeddata\", () => {\n video!.width = video!.videoWidth * $cfg.displayScale;\n video!.height = video!.videoHeight * $cfg.displayScale;\n canvasElement.width = video!.videoWidth;\n canvasElement.height = video!.videoHeight;\n canvasElement.style.height = video!.height + \"px\";\n canvasElement.style.width = video!.width + \"px\";\n\n window.requestAnimationFrame(predictWebcam);\n });\n }\n\n if ($cfg.debugFrame) {\n //#region Debug Frame mode — use a static image\n const img = document.createElement(\"img\");\n img.src = $cfg.debugFrame;\n img.style.zIndex = \"21\";\n img.style.position = \"absolute\";\n img.style.top = \"0px\";\n img.style.left = \"0px\";\n document.body.appendChild(img);\n\n img.addEventListener(\"load\", () => {\n img.width = img.naturalWidth * $cfg.displayScale;\n img.height = img.naturalHeight * $cfg.displayScale;\n canvasElement.width = img.naturalWidth;\n canvasElement.height = img.naturalWidth;\n canvasElement.style.width = img.width + \"px\";\n canvasElement.style.height = img.height + \"px\";\n\n function predictFrame() {\n predict(img);\n }\n\n window.requestAnimationFrame(predictFrame);\n });\n //#endregion\n } else if( $cfg.debugVideo ) {\n //#region Video mode\n initializeVideo();\n //#endregion\n } \n\n return {\n poseTracker,\n handsTracker,\n faceTracker,\n video,\n\n\t\t/**\n\t\t * A div that contains the video and canvas used to display the landmarks stacked on top of each other.\n\t\t */\n\t\tdomElement: viewport,\n\n\t\t/**\n\t\t * Start the webcam feed. This must be initiated by a user triggered event ( a click on a button ) due to security reasons. \n\t\t */\n start: async () => {\n\t\t\tlet stopped = false;\n\n if (!hasGetUserMedia()) {\n throw new Error(\"Webcam not supported\");\n }\n\n if (!video) {\n initializeVideo();\n }\n\n let stream: Awaited<MediaStream> | undefined;\n\n\t\t\tfunction onTrackEnded(video: HTMLVideoElement): void {\n\t\t\t\tconsole.warn('Camera track ended, attempting recovery...');\n\t\t\t\tstopCamera(video);\n\t\t\t\tretryWithBackoff(video);\n\t\t\t}\n\n\t\t\tfunction stopCamera(video: HTMLVideoElement): void {\n\t\t\t\tstream?.getTracks().forEach(t => t.stop());\n\t\t\t\tstream = undefined;\n\t\t\t\tvideo.srcObject = null;\n\t\t\t}\n\n\t\t\tasync function retryWithBackoff(video: HTMLVideoElement, attempt = 0): Promise<void> {\n\t\t\t const MAX_ATTEMPTS = 5;\n\t\t\t const delay = Math.min(1000 * 2 ** attempt, 16000); // 1s, 2s, 4s, 8s, 16s\n\n\t\t\t if (attempt >= MAX_ATTEMPTS) { \n\t\t\t throw new Error('Camera recovery failed after max attempts');\n\t\t\t }\n\n\t\t\t await new Promise(res => setTimeout(res, delay)); \n\n\t\t\t if(stopped) return;\n\n\t\t\t try {\n\t\t\t await startCamera(video);\n\t\t\t console.log('Camera recovered successfully');\n\t\t\t } catch {\n\t\t\t retryWithBackoff(video, attempt + 1);\n\t\t\t }\n\t\t\t}\n\n\t\t\tasync function startCamera(video: HTMLVideoElement): Promise<void> {\n\t\t\t try {\n\t\t\t stream = await navigator.mediaDevices.getUserMedia({ video: true });\n\t\t\t video.srcObject = stream;\n\t\t\t await video.play();\n\n\t\t\t // Listen for track ending (camera disconnected / permission revoked)\n\t\t\t stream.getVideoTracks().forEach(track => {\n\t\t\t track.addEventListener('ended', () => onTrackEnded(video));\n\t\t\t });\n\n\t\t\t } catch (err) {\n\t\t\t handleCameraError(err, video);\n\t\t\t }\n\t\t\t}\n\n\t\t\tfunction handleCameraError(err: unknown, video: HTMLVideoElement): void {\n\t\t\t if (err instanceof DOMException) {\n\t\t\t switch (err.name) {\n\t\t\t case 'NotAllowedError':\n\t\t\t throw new Error('Permission denied — prompt user to allow camera');\n\t\t\t break;\n\t\t\t case 'NotFoundError':\n\t\t\t console.error('No camera found — retry when device is connected');\n\t\t\t retryWithBackoff(video); // device might be plugged in later\n\t\t\t break;\n\t\t\t case 'NotReadableError':\n\t\t\t console.error('Camera in use by another app');\n\t\t\t retryWithBackoff(video);\n\t\t\t break;\n\t\t\t default:\n\t\t\t console.error('Camera error:', err.message);\n\t\t\t retryWithBackoff(video);\n\t\t\t }\n\t\t\t }\n\t\t\t} \n\n await startCamera(video!);\n\n\t\t\treturn {\n\t\t\t\tstop:()=>{\n\t\t\t\t\tstopped = true;\n\t\t\t\t\tstopCamera(video!);\n\t\t\t\t}\n\t\t\t}\n },\n\n /**\n * Binds the bones of the rig to the landmarks provided by media pipe.\n * @param rig The rig that contains all the bones and skinned meshes of your character.\n\t\t * @param magging The bone mapping to use for the rig.\n */\n bind: ( rig: THREE.Object3D, magging?:BoneMap ) => {\n\n\t\t\tmagging = magging || defaultBoneMap;\n\n const bodyBindin = poseTracker.bind(rig, magging);\n const leftHandBinding = handsTracker.left.bind(rig, magging);\n const rightHandBinding = handsTracker.right.bind(rig, magging);\n let faceKeys: BindingHandler | undefined;\n const faceRig = faceTracker?.bind(rig);\n\n rig.traverse((child) => {\n if (\n child instanceof THREE.Mesh &&\n child.name.indexOf( magging.faceMesh ) === 0\n ) {\n child.frustumCulled = false;\n faceKeys = faceTracker?.bindShapeKeys(child);\n }\n });\n\n\t\t\tconst recorder = createRigRecorder(rig, magging)\n\n return {\n\n\t\t\t\t/**\n\t\t\t\t * Will save the tracked movement of the rig to an animation clip.\n\t\t\t\t * Only the bones moved by the bone mapping will be recorded.\n\t\t\t\t */\n\t\t\t\tstartRecording: recorder.start,\n\t\t\t\tstopRecording: recorder.stop,\n\t\t\t\tisRecording: () => recorder.isRecording(),\n\n update: (delta: number) => {\n bodyBindin.update(delta);\n leftHandBinding.update(delta);\n rightHandBinding.update(delta);\n faceKeys?.update(delta);\n faceRig?.update(delta);\n\n\t\t\t\t\tif( recorder.isRecording() ) {\n\t\t\t\t\t\trecorder.captureFrame()\n\t\t\t\t\t}\n },\n } as RecordableBindingHandler;\n },\n };\n}\n"],"names":["poleDir","Vector3","objectPosition","XAxis","XAxisNeg","YAxis","YAxisNeg","ZAxis","pole","lookDir","v","correction","Quaternion","worldQuat","lookAt","object","target","poleTarget","poleAxis","axis","currentPole","lookAxisDir","desiredPoleDir","cross","angle","THREE","A","B","Tracker","points","debugConnections","__publicField","key","Mark","landmarks","debugLandmarks","debugDrawer","point","mark","o","Ghost","_a","source","drawingUtils","delta","objects","normal","root","offset","objectLookAtGoal","polePosition","ghost","rig","name","speed","rootPosition","out","cleanBoneName","getBoneByName","bone","Bone","loadPoseTracker","vision","config","poseLandmarker","PoseLandmarker","PoseTracker","poseMarks","C","D","E","lookGoal","poleGoal","result","magging","map","v2","syncBone","from","to","sideAxis","hipsDir","sideHips","sideShoulders","sideHead","loadHandTracker","landmarker","HandLandmarker","isMyWrist","myWrist","otherWrist","handWrist","HandsTracker","handMarks","fingerKeys","v1","v3","v4","v5","v6","currSide","HALF_PI","DOWN","handLandmarker","side","hand","wrist","markToBone","palmNormal","parlmDir","palmSide","palmLookAt","polPosition","palmGhost","palmForward","sideGoal","negateSideGoal","i","myDir","bonePos","poleOffset","fingerGhost","addBind","boneName","markName","loadFaceTracker","cfg","faceLandmarker","FaceLandmarker","FaceTracker","faceMarks","frame","_b","_c","category","mesh","meshKeys","categoryName","score","factor","eyeL","EyeRig","eyeR","headBone","markEarL","markEarR","headcenter","headForward","headSideNormal","headPosition","poleLookAt","faceLookAt","sideName","blendshapes","lookLeft","lookRight","lookUp","lookDown","sideMovement","verticalMovement","defaultBoneMap","blendShapeKeyNames","createRigRecorder","rigRoot","fps","bones","faceMesh","usedBlendShapeKeys","boneKeys","k","times","boneTracks","blendShapeTracks","recording","startTime","start","captureFrame","time","track","q","keyIndex","stop","keyframeTracks","data","clip","GLTFExporter","gltf","blob","url","a","error","hasGetUserMedia","setupTracker","$cfg","video","FilesetResolver","poseTracker","handsTracker","faceTracker","viewport","canvasElement","canvasCtx","DrawingUtils","predict","initializeVideo","lastVideoTime","predictWebcam","img","predictFrame","stopped","stream","onTrackEnded","stopCamera","retryWithBackoff","t","attempt","delay","res","startCamera","err","handleCameraError","bodyBindin","leftHandBinding","rightHandBinding","faceKeys","faceRig","child","recorder"],"mappings":"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"}
1
+ {"version":3,"file":"three-mediapipe-rig.js","sources":["../src/tracking/util/lookAt.ts","../src/tracking/Tracker.ts","../src/tracking/util/getRootPosition.ts","../src/tracking/util/cleanBoneName.ts","../src/tracking/util/getBoneByName.ts","../src/tracking/PoseTracker.ts","../src/tracking/HandTracker.ts","../src/tracking/FaceTracker.ts","../src/tracking/BoneMapping.ts","../src/tracking/blendShapeKeyNames.ts","../src/tracking/recoding/recorder.ts","../src/tracking/TrackerManager.ts"],"sourcesContent":["import { Object3D, Quaternion, Vector3 } from \"three/webgpu\";\n\nconst poleDir = new Vector3();\nconst objectPosition = new Vector3();\n\nconst XAxis = new Vector3(1,0,0);\nconst XAxisNeg = new Vector3(-1,0,0);\nconst YAxis = new Vector3(0,1,0); \nconst YAxisNeg = new Vector3(0,-1,0); \nconst ZAxis = new Vector3(0,0,1); \nconst ZAxisNeg = new Vector3(0,0,-1); \n\nconst pole = new Vector3();\nconst lookDir = new Vector3();\n\nconst v = new Vector3();\nconst correction = new Quaternion();\nconst worldQuat = new Quaternion();\n\nexport type LookAtPoleAxis = \"+x\"|\"+y\"|\"-x\"|\"-y\"\n\n/**\n * Will point the Z axis of object at target and the X or Y axis in the general direction of the pole target\n * @param object The object to rotate\n * @param target The point to look at ( in world coord )\n * @param poleTarget The goal of the pole axis ( in world coord )\n * @param poleAxis The axis to use as the pole axis ( z is the one pointing at the target )\n */\nexport function lookAt( object:Object3D, target:Vector3, poleTarget:Vector3, poleAxis:LookAtPoleAxis = \"+x\" )\n{ \n\t//\n\t// look at target (handles parent transforms internally)\n\t// \n\tobject.lookAt(target);\n\n\tconst axis = poleAxis==\"+x\"?XAxis: poleAxis==\"-x\"?XAxisNeg: poleAxis==\"+y\"?YAxis: YAxisNeg;\n\n\tobject.getWorldPosition(objectPosition);\n\tobject.getWorldQuaternion(worldQuat);\n\n\tpoleDir.subVectors(poleTarget, objectPosition).normalize();\n\n\t// direction in which the pole axis is currently pointing (in world space)\n\tpole.copy(axis).applyQuaternion(worldQuat);\n\n\tconst currentPole = pole;\n\n\t// look direction in world space\n\tconst lookAxisDir = lookDir.copy( ZAxis ).applyQuaternion(worldQuat);\n\n\t// project desired pole direction onto the plane perpendicular to the look axis\n\tconst desiredPoleDir = poleDir.clone().addScaledVector(lookAxisDir, -poleDir.dot(lookAxisDir)).normalize();\n\n\t// signed angle between current pole and desired pole around the look axis\n\tconst cross = v.crossVectors(currentPole, desiredPoleDir);\n\tconst angle = Math.atan2(cross.dot(lookAxisDir), currentPole.dot(desiredPoleDir));\n\n\t// The correction is a spin around the look axis (local Z after lookAt).\n\t// Since lookAt aligned local Z to the target, we can apply around the local Z axis directly.\n\tcorrection.setFromAxisAngle(ZAxis, angle);\n\tobject.quaternion.multiply(correction);\n}","import * as THREE from \"three/webgpu\";\nimport {\n Landmark,\n NormalizedLandmark,\n\tDrawingUtils, \n} from \"@mediapipe/tasks-vision\"; \nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\n\n \n\nconst v = new THREE.Vector3();\nconst A = new THREE.Vector3();\nconst B = new THREE.Vector3();\nconst C = new THREE.Vector3();\n\nexport class Tracker<T extends Record<string, number|number[]> > {\n\tprivate objectGhost : Map<THREE.Object3D, Ghost> ;\n\treadonly root:THREE.Object3D;\n\n\t/**\n\t * per landmark index, it points to it's object3D equivalent.\n\t */\n\tprotected marks: { [name in keyof T]: Mark } = {} as { [name in keyof T]: Mark };\n\n\tconstructor( protected readonly points:T, private readonly debugConnections?:{start:number,end:number}[] ){\n\t\tthis.root = new THREE.Object3D();\n\t\tthis.objectGhost = new Map();\n\n\t\t// por each key in points\n\t\tfor( let key in this.points ){\n\t\t\tthis.marks[key] = new Mark();\n \n\t\t\tthis.root.add(this.marks[key]);\n\t\t}\n\t}\n\n\tprotected updateLandmarks( landmarks:Landmark[], debugLandmarks?:NormalizedLandmark[], debugDrawer?:DrawingUtils ) {\n\t\tfor( let key in this.points ){\n\t\t\tconst point = this.points[key];\n\t\t\tconst mark = this.marks[key];\n\t\t\tif( mark ){\n\t\t\t\tif( point instanceof Array )\n\t\t\t\t{\n\t\t\t\t\t\n\t\t\t\t\tv.copy( landmarks[ point[0] ] ) \n\t\t\t\t\tmark.position.copy( landmarks[ point[1] ] ).sub( v ).divideScalar(2).add(landmarks[ point[0] ]);\n\t\t\t\t\t\n\t\t\t\t\tif( point.length==4 )\n\t\t\t\t\t{\n\t\t\t\t\t\tv.subVectors(\n\t\t\t\t\t\t\tlandmarks[ point[3] ],\n\t\t\t\t\t\t\tlandmarks[ point[2] ]\n\t\t\t\t\t\t).divideScalar(2).add(landmarks[ point[2] ]) \n\n\t\t\t\t\t\t.sub( mark.position )\n\t\t\t\t\t\t.divideScalar(2) \n\n\t\t\t\t\t\tmark.position.add( v );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\telse \n\t\t\t\t{\n\t\t\t\t\tmark.position.copy( landmarks[ point as number ] )\n\t\t\t\t}\n \n\t\t\t}\n\t\t}\n\n\t\tif( debugDrawer && debugLandmarks )\n\t\t{ \n\t\t\t// debugDrawer.drawLandmarks(debugLandmarks, {\n\t\t\t// \tradius: (data) =>\n\t\t\t// \t\tDrawingUtils.lerp(data.from!.z, -0.15, 0.1, 5, 1),\n\t\t\t// \tlineWidth:1\n\t\t\t// });\n\t\t\tdebugDrawer.drawConnectors(\n\t\t\t\tdebugLandmarks,\n\t\t\t\tthis.debugConnections,\n\t\t\t\t{\n\t\t\t\t\tlineWidth:1\n\t\t\t\t}\n\t\t\t); \n\t\t}\n\t}\n\n\tprotected getGhost( object:THREE.Object3D ){\n\t\tif( !this.objectGhost.has(object)) \n\t\t{\n\t\t\tconst o = new Ghost()\n\n\t\t\to.position.copy(object.position)\n\t\t\to.quaternion.copy(object.quaternion)\n\t\t\tobject.parent?.add(o);\n\n\t\t\tthis.objectGhost.set(object, o)\n\t\t} \n\t\treturn this.objectGhost.get(object)!;\n\t}\n\n\tpredict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tthrow new Error(\"Method 'predict' must be implemented.\");\n\t}\n\n\tsync ( delta:number, objects: [THREE.Object3D, keyof T, keyof T, LookAtPoleAxis][] ) {\n\t\tthrow new Error(\"Method 'sync' must be implemented.\"); \n\t}\n\n\ttest( key:keyof T ){\n\t\tthis.marks[key]!.position.set(1,2,3)\n\t}\n\n\tprotected syncObjects(objects: [THREE.Object3D, keyof T, keyof T,LookAtPoleAxis][], delta:number, normal:THREE.Vector3 ){\n\t\tfor( const [object, root, target, poleAxis] of objects ){\n\n\t\t\t//\n\t\t\t// position A and B where the landmarks are\n\t\t\t//\n\t\t\tthis.marks[target].getWorldPosition(B)\n\t\t\tthis.marks[root].getWorldPosition(A)\n\n\t\t\t//\n\t\t\t// calcuate the offset\n\t\t\t//\n\t\t\tconst offset = B.sub(A); // offset from root to taget in world units\n\n\t\t\t//\n\t\t\t// now position A in object position\n\t\t\t//\n\t\t\tobject.getWorldPosition(A)\n\n\t\t\t//\n\t\t\t// and displace it by the offset ( this will be the look at target )\n\t\t\t//\n\t\t\tA.add(offset);\n\n\t\t\t \n\t\t\tconst objectLookAtGoal = A;\n\t\t\tconst polePosition = object.getWorldPosition(B).sub( normal )\n\n\t\t\tconst ghost = this.getGhost(object);\n \n\n\t\t\t \n\t\t\t\tlookAt( ghost, objectLookAtGoal, polePosition, poleAxis);\n\n\t\t\t\tghost.rotateX( Math.PI/2) \n\t\t\t\n\t\t\t//ghost.rotateY( Math.PI/2)\n\n\t\t\tobject.position.lerp(ghost.position, delta * 4)\n\t\t\tobject.quaternion.slerp(ghost.quaternion, delta * 4) \n\t\t}\n\t}\n\n\tprotected getBone( rig:THREE.Object3D, name:string ){\n\t\treturn rig.getObjectByName(name.replace(/[\\.\\:]/g,\"\")) ;\n\t}\n}\n\n// const t = {\n// \tpepe:[1,2]\n// }\n// const d = new Tracker(t)\n// d.test(\"pepe\")\n\nclass Mark extends THREE.Mesh {\n\tprivate _worldPosition = new THREE.Vector3();\n\tconstructor() {\n\t\tsuper(new THREE.SphereGeometry(0.01,3,3), new THREE.MeshStandardMaterial({ color: 0xff0000, wireframe:true }));\n\t\tthis.add( new THREE.AxesHelper(0.001))\n\t}\n\n\tget worldPosition(){\n\t\tthis.getWorldPosition(this._worldPosition);\n\t\treturn this._worldPosition;\n\t}\n}\n\nclass Ghost extends THREE.Object3D { \n\tlerp( target:THREE.Object3D, delta:number, speed = 8 )\n\t{\n\t\ttarget.position.lerp(this.position, delta * speed)\n\t\ttarget.quaternion.slerp(this.quaternion, delta * speed) \n\t}\n}","import { Object3D, Vector3 } from \"three/webgpu\";\n\n\n/**\n * Gets the position of `object` relative to `root`.\n * @param out \n * @param object \n * @param root \n * @returns \n */\nexport function rootPosition( out:Vector3, object:Object3D, root:Object3D ) {\n\n\troot.worldToLocal( object.getWorldPosition(out) )\n\n\treturn out;\n}","export function cleanBoneName(name:string) {\n\treturn name.replace(/[\\.\\:]/g,\"\")\n}","import { Bone, Object3D } from \"three\";\nimport { cleanBoneName } from \"./cleanBoneName\";\n\nexport function getBoneByName(rig:Object3D, name:string) {\n\tlet bone:Bone|undefined;\n\tname = cleanBoneName(name); \n\t\n\trig.traverse( (o:Object3D) => {\n\t\tif( o.name.indexOf(name)===0 && o instanceof Bone ) bone = o as Bone;\n\t})\n\n\tif( !bone ) console.log(\"Bone not found: \", name, rig.name)\n\n\treturn bone;\n}","import {\n DrawingUtils,\n NormalizedLandmark,\n PoseLandmarker,\n} from \"@mediapipe/tasks-vision\"; \nimport * as THREE from \"three/webgpu\";\nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { BoneMap } from \"./BoneMapping\";\n\nexport async function loadPoseTracker(vision: any, config?:Partial<PoseTrackerConfig>) {\n\tconst poseLandmarker = await PoseLandmarker.createFromOptions(vision, {\n baseOptions: { \n\t\t\tmodelAssetPath: config?.modelPath ?? \"pose_landmarker_lite.task\",\n //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task`,\n //modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_heavy/float16/latest/pose_landmarker_heavy.task\",\n delegate: \"GPU\",\n },\n runningMode: \"VIDEO\",\n numPoses: 1,\n });\n\n\treturn new PoseTracker(poseLandmarker, config);\n} \n\n/**\n * Points derived from https://ai.google.dev/static/mediapipe/images/solutions/pose_landmarks_index.png\n * If the array has 2 elements, the point is between those 2 landmarks.\n * If it has 4, the point is at the center of those 4 landmarks.\n */\nconst poseMarks = {\n\t\t\thips: [24,23],\n\t\t\tneck: [12,11],\n\t\t\tleftLeg: 23,\n\t\t\tleftKnee:25,\n\t\t\tleftFoot: 27,\n\t\t\tleftToes: 31,\n\t\t\tleftArm: 11,\n\t\t\tleftElbow: 13,\n\t\t\tleftWrist: 15,\n\t\t\trightLeg: 24,\n\t\t\trightKnee: 26,\n\t\t\trightFoot: 28,\n\t\t\trightToes: 32,\n\t\t\trightArm: 12,\n\t\t\trightElbow: 14,\n\t\t\trightWrist: 16, \n\t\t\thead: [8,7] //between the ears\n\t\t\t, mouth:[10,9]\n\t\t\t, torso: [24,23, 12,11] //at the center of the torso\n\t\t\t, leftEar: 7\n\t\t\t, rightEar: 8\n\t\t} ;\n\ntype MarkKey = keyof typeof poseMarks;\n\ntype BoneBinding = [THREE.Object3D, MarkKey, MarkKey,LookAtPoleAxis]\n\nconst A = new THREE.Vector3();\nconst B = new THREE.Vector3();\nconst C = new THREE.Vector3();\nconst D = new THREE.Vector3();\nconst E = new THREE.Vector3();\nconst lookGoal = new THREE.Vector3();\nconst poleGoal = new THREE.Vector3();\n\ntype PoseTrackerConfig = {\n\tignoreLegs:boolean\n\tmodelPath:string\n}\n\n/**\n * @see https://ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker\n */\nclass PoseTracker extends Tracker<typeof poseMarks> {\n\tprivate _leftWristNormalizedPosition!:NormalizedLandmark;\n\tprivate _rightWristNormalizedPosition!:NormalizedLandmark;\n\n\t/**\n\t * Position of the left wrist in normalized coordinates (0..1)\n\t */\n\tget leftWristNormalizedPosition() { return this._leftWristNormalizedPosition; }\n\n\t/**\n\t * Position of the right wrist in normalized coordinates (0..1)\n\t */\n\tget rightWristNormalizedPosition() { return this._rightWristNormalizedPosition; }\n\n\tconstructor(private readonly poseLandmarker:PoseLandmarker, private readonly config?:Partial<PoseTrackerConfig>){ \n\n\t\tsuper(poseMarks, PoseLandmarker.POSE_CONNECTIONS)\n\t\t\n\t\tthis.root.scale.y *= -2\n\t\tthis.root.scale.z *= -2\n\t\tthis.root.scale.x *= 2 \n\t}\n\n\toverride predict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tthis.poseLandmarker.detectForVideo( source, performance.now(), (result) => {\n\n\t\t\tif( result.landmarks.length==0 )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n \n\t\t\tthis.updateLandmarks( result.worldLandmarks[0], result.landmarks[0], drawingUtils );\n\n\t\t\t\n\t\t\tthis._leftWristNormalizedPosition = result.landmarks[0][ this.points.leftWrist ];\n\t\t\tthis._rightWristNormalizedPosition = result.landmarks[0][ this.points.rightWrist ];\n\t\t} );\n\t}\n\n\t// override sync ( delta:number, objects: BoneBinding[] ) {\n\n\t// \tconst hipsPos = this.marks.hips.getWorldPosition(C); \n\n\t// \tthis.marks.rightArm.getWorldPosition(A).sub(hipsPos);\n\t// \tthis.marks.leftArm.getWorldPosition(B).sub(hipsPos); \n\n\t// \tconst torsoNormal = C.crossVectors(A,B);\n\n\t// \tthis.syncObjects(objects, delta, torsoNormal); \n\n\t// }\n\t\n\n\tbind( rig:THREE.Object3D, magging:BoneMap )\n\t{ \n\t\t \n\t\tconst map : { [key in MarkKey]?:THREE.Object3D } = {\n\t\t\t\"hips\": getBoneByName(rig, magging.hips),\n\t\t\t\"neck\": getBoneByName(rig, magging.neck),\n\t\t\t\"leftArm\": getBoneByName(rig, magging.armL),\n\t\t\t\"leftElbow\": getBoneByName(rig, magging.forearmL),\n\t\t\t\"leftWrist\": getBoneByName(rig, magging.handL),\n\t\t\t\"rightArm\": getBoneByName(rig, magging.armR),\n\t\t\t\"rightElbow\": getBoneByName(rig, magging.forearmR),\n\t\t\t\"rightWrist\": getBoneByName(rig, magging.handR),\n\t\t\t\"head\": getBoneByName(rig, magging.head), \n\t\t\t\"torso\": getBoneByName(rig, magging.torso),\n\t\t\t\"leftLeg\": getBoneByName(rig, magging.thighL),\n\t\t\t\"leftKnee\": getBoneByName(rig, magging.shinL),\n\t\t\t\"leftFoot\": getBoneByName(rig, magging.footL),\n\t\t\t\"rightLeg\": getBoneByName(rig, magging.thighR),\n\t\t\t\"rightKnee\": getBoneByName(rig, magging.shinR),\n\t\t\t\"rightFoot\": getBoneByName(rig, magging.footR),\n\t\t} \n\n\t\tif( this.config?.ignoreLegs ){\n\t\t\tdelete map.leftLeg\n\t\t\tdelete map.leftKnee\n\t\t\tdelete map.leftFoot\n\t\t\tdelete map.leftToes\n\t\t\tdelete map.rightLeg\n\t\t\tdelete map.rightKnee\n\t\t\tdelete map.rightFoot\n\t\t\tdelete map.rightToes\n\t\t}\n\n\t\tconst v = new THREE.Vector3();\n\t\tconst v2 = new THREE.Vector3();\n\n\t\tconst syncBone = ( delta:number, bone:THREE.Object3D|undefined, from:MarkKey, to:MarkKey, sideAxis:THREE.Vector3, poleAxis:LookAtPoleAxis ) => {\n\t\t\tif( !bone ) return;\n\n\t\t\tconst hipsDir = this.marks[to].getWorldPosition(v).sub(this.marks[from].getWorldPosition(v2)).normalize(); \n\n\t\t \n\t\t\trootPosition(lookGoal, bone, rig).add( hipsDir ).applyMatrix4(rig.matrixWorld) ;\n\t\t\trootPosition(poleGoal, bone, rig).add( sideAxis ).applyMatrix4(rig.matrixWorld) ; \n\n\t\t\tconst ghost = this.getGhost(bone)\n\n\t\t\tlookAt(ghost, lookGoal, poleGoal, poleAxis)\n\t\t\tghost.rotateX(Math.PI/2)\n\t\t\t \n\n\t\t\tghost.lerp(bone, delta)\n\t\t}\n\n\t\treturn {\n\t\t\tupdate: (delta:number)=>{\n \n\t\t\t\tconst sideHips = this.marks.leftLeg.getWorldPosition(A).sub(this.marks.rightLeg.getWorldPosition(B)).normalize();\n\t\t\t\tconst sideShoulders = this.marks.leftArm.getWorldPosition(B).sub(this.marks.rightArm.getWorldPosition(C)).normalize();\n\t\t\t\tconst sideHead = this.marks.leftEar.getWorldPosition(D).sub(this.marks.rightEar.getWorldPosition(E)).normalize();\n\n\t\t\t\tsyncBone(delta, map.hips, \"hips\", \"torso\", sideHips, \"+x\")\n\t\t\t\tsyncBone(delta, map.torso, \"torso\", \"neck\", sideShoulders, \"+x\")\n\t\t\t\tsyncBone(delta, map.neck, \"neck\", \"head\", sideHead, \"+x\")\n\t\t\t\tsyncBone(delta, map.head, \"neck\", \"head\", sideHead, \"+x\")\n\n\t\t\t\tsyncBone(delta, map.leftArm, \"leftArm\", \"leftElbow\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.leftElbow, \"leftElbow\", \"leftWrist\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.leftLeg, \"leftLeg\", \"leftKnee\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.leftKnee, \"leftKnee\", \"leftFoot\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.leftFoot, \"leftFoot\", \"leftToes\", sideHips, \"+x\") \n\n\t\t\t\tsyncBone(delta, map.rightArm, \"rightArm\", \"rightElbow\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.rightElbow, \"rightElbow\", \"rightWrist\", sideShoulders, \"-x\")\n\t\t\t\tsyncBone(delta, map.rightLeg, \"rightLeg\", \"rightKnee\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.rightKnee, \"rightKnee\", \"rightFoot\", sideHips, \"+x\") \n\t\t\t\tsyncBone(delta, map.rightFoot, \"rightFoot\", \"rightToes\", sideHips, \"+x\") \n\t\t\t\t\n\t\t\t}\n\t\t}\n\t}\n}\n ","import {\n\tDrawingUtils,\n HandLandmarker,\n\tHandLandmarkerOptions,\n\tNormalizedLandmark,\n} from \"@mediapipe/tasks-vision\";\nimport * as THREE from \"three/webgpu\";\nimport { lookAt, LookAtPoleAxis } from \"./util/lookAt\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { BoneMap } from \"./BoneMapping\";\n\nexport type HandsTrackerConfig = {\n\tleftWrist: ()=>NormalizedLandmark;\n\trightWrist: ()=>NormalizedLandmark;\n\tmodelPath?:string\n} & Partial<HandLandmarkerOptions>;\n\nconst A = new THREE.Vector2();\nconst B = new THREE.Vector2();\n\nexport async function loadHandTracker(vision: any, config:HandsTrackerConfig ) {\n const landmarker = await HandLandmarker.createFromOptions(vision, {\n baseOptions: {\n modelAssetPath: config.modelPath ?? \"hand_landmarker.task\",\n //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,\n delegate: \"GPU\",\n },\n runningMode: \"VIDEO\",\n numHands: 2,\n });\n\n\tconst isMyWrist = ( myWrist:()=>NormalizedLandmark, otherWrist:()=>NormalizedLandmark, handWrist:NormalizedLandmark ) => {\n\n\t\ttry{\n\t\t\tA.copy(myWrist());\n\t\t\tB.copy(otherWrist());\n\t\t}catch(e){\n\t\t\tconsole.warn(\"No pose data... will just be optimitic and say yes to everything.\", e);\n\t\t\treturn true;\n\t\t}\n\t\treturn A.distanceTo(handWrist) < B.distanceTo(handWrist);\n\t}\n\n return {\n\t\tleft:new HandsTracker(landmarker, \"Left\", isMyWrist.bind(null, config.leftWrist, config.rightWrist) ),\n\t\tright:new HandsTracker(landmarker, \"Right\", isMyWrist.bind(null, config.rightWrist, config.leftWrist) )\n\t};\n}\n\nconst handMarks = {\n wrist: 0,\n\tpalm: [9,13],\n\n thumb1: 1,\n thumb2: 2,\n thumb3: 3,\n thumb4: 4,\n\n index1: 5,\n index2: 6,\n index3: 7,\n index4: 8,\n\n middle1: 9,\n middle2: 10,\n middle3: 11,\n middle4: 12,\n\n ring1: 13,\n ring2: 14,\n ring3: 15,\n ring4: 16,\n\n pinky1: 17,\n pinky2: 18,\n pinky3: 19,\n pinky4: 20,\n};\n\nexport type HandMarkName = keyof typeof handMarks;\n\nconst fingerKeys = {\n\tthumb: [\"thumb1\",\"thumb2\",\"thumb3\",\"thumb4\"],\n\tindex: [\"index1\",\"index2\",\"index3\",\"index4\"],\n\tmiddle: [\"middle1\",\"middle2\",\"middle3\",\"middle4\"],\n\tring: [\"ring1\",\"ring2\",\"ring3\",\"ring4\"],\n\tpinky: [\"pinky1\",\"pinky2\",\"pinky3\",\"pinky4\"]\n} as { [key:string]: HandMarkName[]} ;\n\n\ntype HandSide = \"Left\" | \"Right\"\nexport type Mark2Bone = Partial<{ [key in HandMarkName]: THREE.Object3D }>;\n\nconst v1 = new THREE.Vector3();\nconst v2 = new THREE.Vector3();\nconst v3 = new THREE.Vector3();\nconst v4 = new THREE.Vector3();\nconst v5 = new THREE.Vector3();\nconst v6 = new THREE.Vector3();\nconst v7 = new THREE.Vector3();\n\nconst currNormal = new THREE.Vector3();\nconst currForward = new THREE.Vector3();\nconst currSide = new THREE.Vector3();\nconst HALF_PI = Math.PI/2\nconst DOWN = new THREE.Vector3(0,-1,0);\n\nclass HandsTracker extends Tracker<typeof handMarks> {\n\tprivate readonly sign:number;\n\tprivate readonly isLeft:boolean;\n\t/**\n\t * the axis used to look at the pole\n\t */\n\tprivate readonly lookAtPoleAxis:LookAtPoleAxis;\n\n\tconstructor(private readonly handLandmarker:HandLandmarker, private readonly side:HandSide, private readonly isMyWrist:( handWrist:NormalizedLandmark )=>boolean ){\n\t\tsuper(handMarks, HandLandmarker.HAND_CONNECTIONS)\n\n\t\tthis.sign = this.side==\"Left\" ? -1 : 1;\n\t\tthis.isLeft = this.side==\"Left\";\n\t\tthis.lookAtPoleAxis = this.sign<0? \"+x\" : \"-x\";\n\t\tthis.root.scale.setScalar(7)\n\t\tthis.root.scale.y *= -1\n\t\tthis.root.scale.z *= -1\n\t}\n\n\toverride predict( source:TexImageSource, drawingUtils:DrawingUtils ){\n\t\tconst result = this.handLandmarker.detectForVideo(source, performance.now());\n\n\t\tif( result.landmarks.length )\n\t\t{\n\t\t\t//console.log(`DETECTED ${result.landmarks.length} hands`, result.handedness)\n\n\n\t\t\tfor(let i=0; i<result.landmarks.length; i++){\n\t\t\t\tconst hand = result.landmarks[i];\n\t\t\t\tconst wrist = hand[this.points.wrist];\n\t\t\t\tconst isMyWrist = this.isMyWrist(wrist);\n\t\t\t\tif( isMyWrist ){\n\t\t\t\t\tthis.updateLandmarks( result.worldLandmarks[i] );\n\n\t\t\t\t\tdrawingUtils.drawConnectors(hand, HandLandmarker.HAND_CONNECTIONS, {\n\t\t\t\t\t\tcolor: this.side==\"Left\" ? \"#00FF00\" : \"#0000FF\",\n\t\t\t\t\t\tlineWidth: 4\n\t\t\t\t\t});\n\t\t\t\t\tdrawingUtils.drawLandmarks(hand, { color: this.side==\"Left\" ? \"#00FF00\" : \"#0000FF\", lineWidth: 3, radius: 1 }); \n\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} \n \n \n\t\t} \n\t}\n\n\toverride sync ( delta:number, objects: [THREE.Object3D, HandMarkName, HandMarkName, LookAtPoleAxis][] ) {\n\n\t\tthrow new Error(\"Not used. Use syncHandBones instead\");\n\t}\n\t\t\n\t/**\n\t * \n\t * @param delta time since last frame\n\t * @param landmark2bones Array the same size as the umber of hand landmarks, and on each positionthe bone that belongs to that point.\n\t * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker\n\t */\n\tsyncHandBones( delta:number, markToBone:Mark2Bone, rig:THREE.Object3D )\n\t{ \n\t\tconst palmNormal = v1.crossVectors(\n\t\t\tv2.copy(this.marks.index1.worldPosition).sub(this.marks.wrist.worldPosition),\n\t\t\tv3.copy(this.marks.pinky1.worldPosition).sub(this.marks.wrist.worldPosition)\n\t\t).normalize();\n\n\t\tconst parlmDir = v2.copy(this.marks.palm.worldPosition).sub(this.marks.wrist.worldPosition).normalize();\n\t\tconst palmSide = v3.copy(this.marks.pinky1.worldPosition).sub(this.marks.index1.worldPosition).normalize();\n\t\t \n\t\tif( parlmDir.dot(DOWN)>0.8 )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\t//\n\t\t// positioning of the palm's bone\n\t\t//\n\t\tif( markToBone.wrist )\n\t\t{\n\t\t\tconst palmLookAt = rootPosition(v4, markToBone.wrist, rig ).add( parlmDir ).applyMatrix4(rig.matrixWorld) //markToBone.wrist.getWorldPosition(v4).add( parlmDir );\n\t\t\tconst polPosition = rootPosition(v5, markToBone.wrist, rig ).sub( palmSide ).applyMatrix4(rig.matrixWorld) //markToBone.wrist.getWorldPosition(v5).sub( palmSide );\n\n\t\t\tconst palmGhost = this.getGhost(markToBone.wrist)\n\n\t\t\tlookAt( palmGhost, palmLookAt, polPosition, \"-y\" );\n\t\t\tpalmGhost.rotateX( HALF_PI ) ; \n\n\t\t\tpalmGhost.lerp(markToBone.wrist, delta)\n\t\t}\n\n\t\t// palmLookAtOffset.normalize();\n\t\t// const palmSide = v3.crossVectors(palmNormal, palmLookAtOffset).normalize();\n \n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.index, \"middle1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.middle, \"ring1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.ring, \"pinky1\" )\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.pinky, \"ring1\", true )\n\n\t\t// //thumb...\n\t\tthis.syncFinger( delta, rig, palmNormal, parlmDir, palmSide, markToBone, fingerKeys.thumb, \"index1\" )\n\n\t\t\n\t}\n\n\tprivate syncFinger( delta:number, rig:THREE.Object3D, palmNormal:THREE.Vector3, palmForward:THREE.Vector3, palmSide:THREE.Vector3, markToBone:Mark2Bone, fingerKeys:HandMarkName[], sideGoal:HandMarkName, negateSideGoal:boolean=false ){\n\t \n\t\tlet signMult = 1;\n\n\t\tfor(let i=0; i<fingerKeys.length-1;i++) { \n\t\t\t\n\t\t\tconst bone = markToBone[fingerKeys[i]];\n\t\t\t//const bonePole = markToBone[sideGoal];\n\n\t\t\tif(!bone ) continue;\n\n\t\t\tconst fingerGhost = this.getGhost(bone)\n\n\t\t\t// finger's direction\n\t\t\tconst myDir = v4.copy( this.marks[fingerKeys[i+1]].worldPosition ).sub( this.marks[fingerKeys[i]].worldPosition).normalize() ; \n\t\t\t\n\t\t\tconst bonePos = rootPosition(v5, bone, rig) //bone.getWorldPosition(v5); \n\n\n\t\t\t//const poleOffset = v6.copy(bonePos).add(palmSide) //rootPosition(v6, bonePole, rig).sub( bonePos );//bonePole.getWorldPosition(v6).sub( bonePos );\n\n\t\t\t//if( negateSideGoal ) poleOffset.negate(); \n\n\n\t\t\tif( i==0 )\n\t\t\t{ \n\t\t\t\tconst fingerSideNormal = v6.copy(this.marks[sideGoal].worldPosition).sub(this.marks[fingerKeys[0]].worldPosition).normalize() ;\n \n\t\t\t\tif( negateSideGoal )\n\t\t\t\t\tfingerSideNormal.negate();\n \n\n\t\t\t\t// if( this.isLeft )\n\t\t\t\t// \tsideDir.negate();\n\n\t\t\t\tcurrSide.copy(fingerSideNormal);\n\n\t\t\t\t\n\t\t\t\tlookAt( fingerGhost, \n\t\t\t\t\tmyDir.add( bonePos ).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tfingerSideNormal.add(bonePos).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tthis.lookAtPoleAxis ); \n\n\t\t\t\t\n\t\t\t}\n\t\t\telse \n\t\t\t{ \n\t\t\t\tlookAt( fingerGhost, \n\t\t\t\t\tmyDir.add( bonePos ).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tv6.copy(currSide).add(bonePos).applyMatrix4(rig.matrixWorld), \n\t\t\t\t\tthis.lookAtPoleAxis );\n\t\t\t} \n\n\t\t\tfingerGhost.rotateX( HALF_PI ); \n\n\t\t\tfingerGhost.lerp(bone, delta)\n\n\t\t}\n\n \n\t}\n \n\tbind( rig:THREE.Object3D, magging:BoneMap ){\n\n\t\tconst map:Mark2Bone = {\n\t\t\t\n\t\t}\t \n\n\t\tconst addBind = ( boneName:string, markName:HandMarkName ) => {\n\t\t\t//const bone = rig.getObjectByName( cleanBoneName( boneName.replace(\"X\", this.sign<0 ? \"L\" : \"R\") ));\n\n\t\t\tconst bone = getBoneByName(rig, boneName );\n\n\t\t\tif( bone ){\n\t\t\t\tmap[markName] = bone;\n\t\t\t\treturn markName;\n\t\t\t}\n\t\t}\n\n\t\taddBind( this.isLeft ? magging.handL : magging.handR, \"wrist\" )\n\t\taddBind( this.isLeft ? magging.index1L : magging.index1R, \"index1\" )\n\t\taddBind( this.isLeft ? magging.index2L : magging.index2R, \"index2\" )\n\t\taddBind( this.isLeft ? magging.index3L : magging.index3R, \"index3\" ) \n\n\t\taddBind( this.isLeft ? magging.middle1L : magging.middle1R, \"middle1\" )\n\t\taddBind( this.isLeft ? magging.middle2L : magging.middle2R, \"middle2\" )\n\t\taddBind( this.isLeft ? magging.middle3L : magging.middle3R, \"middle3\" ) \n\n\t\taddBind( this.isLeft ? magging.ring1L : magging.ring1R, \"ring1\" )\n\t\taddBind( this.isLeft ? magging.ring2L : magging.ring2R, \"ring2\" )\n\t\taddBind( this.isLeft ? magging.ring3L : magging.ring3R, \"ring3\" ) \n\n\t\taddBind( this.isLeft ? magging.pinky1L : magging.pinky1R, \"pinky1\" )\n\t\taddBind( this.isLeft ? magging.pinky2L : magging.pinky2R, \"pinky2\" )\n\t\taddBind( this.isLeft ? magging.pinky3L : magging.pinky3R, \"pinky3\" ) \n\n\t\taddBind( this.isLeft ? magging.thumb1L : magging.thumb1R, \"thumb1\" )\n\t\taddBind( this.isLeft ? magging.thumb2L : magging.thumb2R, \"thumb2\" )\n\t\taddBind( this.isLeft ? magging.thumb3L : magging.thumb3R, \"thumb3\" ) \n\n\t\treturn {\n\t\t\tupdate: ( delta:number )=> { \n\t\t\t\tthis.syncHandBones(delta, map, rig);\n\t\t\t}\n\t\t}\t\n\t}\n}\n","import {\n Category,\n DrawingUtils,\n FaceLandmarker\n} from \"@mediapipe/tasks-vision\";\nimport { Mesh, Object3D, Vector3 } from \"three/webgpu\";\nimport { Tracker } from \"./Tracker\";\nimport { rootPosition } from \"./util/getRootPosition\";\nimport { getBoneByName } from \"./util/getBoneByName\";\nimport { lookAt } from \"./util/lookAt\";\n\nexport async function loadFaceTracker(vision: any, cfg?: { modelPath?: string }) {\n const faceLandmarker = await FaceLandmarker.createFromOptions(vision, {\n baseOptions: {\n modelAssetPath: cfg?.modelPath ?? \"face_landmarker.task\",\n\t\t\tdelegate: \"GPU\", \n },\n\t\toutputFaceBlendshapes: true,\n runningMode: \"VIDEO\",\n\t\tnumFaces: 1,\n });\n\n\treturn new FaceTracker(faceLandmarker);\n}\n\n/**\n * @see https://storage.googleapis.com/mediapipe-assets/documentation/mediapipe_face_landmark_fullsize.png\n */\nconst faceMarks = {\n\teyeL: 473,\n\teyeR: 468,\n\teyeStartL: 463,\n\teyeStartR: 243,\n\teyeEndL: 263,\n\teyeEndR: 33, \n\n\tearL: 454,\n\tearR: 234,\n\tnoseTip: 4,\n\tnoseBone:6,\n\tchin:152,\n\tforehead: 10\n\n}\n\ntype MarkKey = keyof typeof faceMarks;\nconst v = new Vector3();\nconst v2 = new Vector3();\nconst v3 = new Vector3();\nconst v4 = new Vector3();\nconst v5 = new Vector3();\nconst v6 = new Vector3();\n\nclass FaceTracker extends Tracker<typeof faceMarks> {\n\tprivate blendshapeCategories: Category[] | undefined;\n\tprivate blendshapeMap: Map<string, number> = new Map();\n\tprivate smoothed: Record<string, number> = {};\n\tprivate smoothing =.0003; // lower = smoother but more lag, higher = more responsive\n\n\tconstructor(private faceLandmarker: FaceLandmarker) {\n\t\tsuper(faceMarks, FaceLandmarker.FACE_LANDMARKS_TESSELATION)\n\n\t\tthis.root.scale.y*=-1\n\t\tthis.root.scale.z*=-1\n\t\tthis.root.scale.multiplyScalar(3)\n\t}\n\n\toverride predict(frame: TexImageSource, drawingUtils: DrawingUtils) {\n\t\tconst result = this.faceLandmarker.detectForVideo(frame, performance.now());\n\t\tif (result.faceLandmarks[0]) {\n\t\t\tdrawingUtils.drawConnectors(result.faceLandmarks[0], FaceLandmarker.FACE_LANDMARKS_TESSELATION, { color: \"#00fff2ff\", lineWidth: .1 });\n\t\t\tdrawingUtils.drawLandmarks(result.faceLandmarks[0], { color: \"#00ff00\", lineWidth: .1, radius: .4 });\t\n\n\t\t\tthis.updateLandmarks(result.faceLandmarks[0], result.faceLandmarks[0] );\n\t\t}\n\n\t\tthis.blendshapeCategories = result.faceBlendshapes?.[0]?.categories; \n\n\t\tthis.blendshapeCategories?.forEach((category) => {\n\t\t\tthis.blendshapeMap.set(category.categoryName, category.score);\n\t\t});\n\t\t\n\t}\n\n\tbindShapeKeys(mesh: Mesh) {\n\t\tconst meshKeys = mesh.morphTargetDictionary; \n\n\t\treturn {\n\t\t\tupdate: (delta: number) => {\n\t\t\t\tthis.blendshapeCategories?.forEach((category) => {\n\t\t\t\t\tconst { categoryName, score } = category;\n\n\t\t\t\t\tif (!meshKeys?.hasOwnProperty(categoryName)) return;\n\n\t\t\t\t\t// Initialize if first time seeing this key\n\t\t\t\t\tif (this.smoothed[categoryName] === undefined)\n\t\t\t\t\t\tthis.smoothed[categoryName] = score;\n\n\t\t\t\t\t// Lerp toward target score\n\t\t\t\t\tconst factor = 1 - Math.pow(this.smoothing, delta);\n\t\t\t\t\tthis.smoothed[categoryName] += (score - this.smoothed[categoryName]) * factor;\n\n\t\t\t\t\tmesh.morphTargetInfluences![meshKeys[categoryName]] = this.smoothed[categoryName];\n\t\t\t\t});\n\n\t\t\t\t//eyes\n\t\t\t}\n\t\t}\n\t}\n\n\tbind( rig:Object3D ) {\n\n\t\tconst eyeL = new EyeRig(rig, \"L\");\n\t\tconst eyeR = new EyeRig(rig, \"R\");\n\t\tconst headBone = getBoneByName(rig, \"head\") ;\n \n\t\treturn {\n\t\t\tupdate: ( delta:number )=> {\n\t\t\t\t \n\t\t\t\teyeL.update(delta, this.blendshapeMap);\n\t\t\t\teyeR.update(delta, this.blendshapeMap); \n\t\t\t\t\n\t\t\t\tif(!headBone) return;\n\n\t\t\t\t//\n\t\t\t\tconst markEarL = v.copy( this.marks.earL.worldPosition );\n\t\t\t\tconst markEarR = v2.copy( this.marks.earR.worldPosition );\n\t\t\t\tconst headcenter = v3.subVectors(markEarL, markEarR).multiplyScalar(.5).add(markEarR);\n\t\t\t\tconst headForward = v4.subVectors(this.marks.noseTip.worldPosition, headcenter) ;\n\t\t\t\tconst headSideNormal = markEarL.sub(markEarR) ;\n\n\t\t\t\t\n\t\t\t\tconst headPosition = rootPosition( v5, headBone, rig); \n\n\t\t\t\tconst poleLookAt = headSideNormal.add( headPosition ).applyMatrix4(rig.matrixWorld);\n\t\t\t\tconst faceLookAt = headForward.add( headPosition ).applyMatrix4(rig.matrixWorld);\n\n\t\t\t\tlookAt( headBone, faceLookAt, poleLookAt,\"+x\" );\n\t\t\t\t \n\n\t\t\t\t// headLookAtPos.applyMatrix4(rig.matrixWorld);\n\t\t\t\t//headBone.lookAt( headLookAtPos );\n\t\t\t\t// \n\t\t\t}\n\t\t}\n\t\t\n\t}\n}\n\nclass EyeRig {\n\tprivate eyeBone:Object3D|undefined; \n\n\tprivate eyeLookOut:string;\n\tprivate eyeLookIn:string;\n\tprivate eyeLookUp:string;\n\tprivate eyeLookDown:string;\n\tprivate sign = 1;\n\t\n\tconstructor( readonly rig:Object3D, readonly side:\"L\"|\"R\" ) {\n\t\tthis.eyeBone = rig.getObjectByName(`eye${side}`) as Object3D; \n\n\t\tconst sideName = side == \"L\" ? \"Left\" : \"Right\";\n\t\tthis.eyeLookOut = `eyeLookOut${sideName}`;\n\t\tthis.eyeLookIn = `eyeLookIn${sideName}`;\n\t\tthis.eyeLookUp = `eyeLookUp${sideName}`;\n\t\tthis.eyeLookDown = `eyeLookDown${sideName}`;\n\n\t\tthis.sign = side == \"L\" ? -1 : 1;\n\t}\n\n\tupdate( delta:number, blendshapes: Map<string, number> ) {\n\t\tif( !this.eyeBone ) return; \n \n\t\tconst eye = rootPosition(v3, this.eyeBone, this.rig); \n\n\t\t\n\t\t\n\t\t// From MediaPipe blendshapes\n\t\tconst lookLeft = blendshapes.get(this.eyeLookOut) ?? 0; // or eyeLookInRight\n\t\tconst lookRight = blendshapes.get(this.eyeLookIn) ?? 0; // or eyeLookOutRight\n\t\tconst lookUp = blendshapes.get(this.eyeLookUp) ?? 0;\n\t\tconst lookDown = blendshapes.get(this.eyeLookDown) ?? 0;\n\n\t\t\n\t\t// Map to a -1..1 range\n\t\tconst sideMovement = lookRight - lookLeft // horizontal\n\t\tconst verticalMovement = lookDown - lookUp // vertical\n \n\n\t\tthis.eyeBone.rotation.y =( sideMovement * this.sign) / 2; \n\t\tthis.eyeBone.rotation.x = verticalMovement / 2; \n\t\t// // Then drive your rig bone with a target offset\n\t\t// const lookAtPos = eyeCenter\n\t\t// .add(eyeHorizontalDir ) // -sideMovement * eyeRange)\n\t\t// //.addScaledVector(eyeVerticalDir, verticalMovement * eyeRange/3)\n\t\t// .applyMatrix4(this.rig.matrixWorld);\n\n\t\t// this.eyeBone.lookAt(lookAtPos);\n\t\t// this.eyeBone.rotateX(Math.PI/2)\n\t}\n}","/**\n * The bone mapping to use for the rig.\n */\nexport type BoneMap = {\n\tfaceMesh:string\n\thead: string;\n\thips:string\n\tneck:string\n\ttorso:string\n\tarmL:string\n\tforearmL:string\n\n\tarmR:string\n\tforearmR:string\n\n\tthighL:string\n\tshinL:string\n\tfootL:string\n\ttoesL:string\n\n\tthighR:string\n\tshinR:string\n\tfootR:string\n\ttoesR:string\n\t \n\t\n\thandL:string\n\tindex1L:string\n\tindex2L:string\n\tindex3L:string\n\n\tmiddle1L:string\n\tmiddle2L:string\n\tmiddle3L:string\n\n\tring1L:string\n\tring2L:string\n\tring3L:string\n\n\tpinky1L:string\n\tpinky2L:string\n\tpinky3L:string\n\n\tthumb1L:string\n\tthumb2L:string\n\tthumb3L:string\n\n\thandR:string\n\tindex1R:string\n\tindex2R:string\n\tindex3R:string\n\n\tmiddle1R:string\n\tmiddle2R:string\n\tmiddle3R:string\n\n\tring1R:string\n\tring2R:string\n\tring3R:string\n\n\tpinky1R:string\n\tpinky2R:string\n\tpinky3R:string\n\n\tthumb1R:string\n\tthumb2R:string\n\tthumb3R:string\n \n}\n\nexport const defaultBoneMap:BoneMap = {\n\tfaceMesh:\"face\",\n\t\n\thead: \"head\",\n\thips:\"hips\",\n\tneck:\"neck\",\n\ttorso:\"torso\",\n\n\tarmL:\"upper_armL\",\n\tforearmL:\"forearmL\",\n\n\tarmR:\"upper_armR\",\n\tforearmR:\"forearmR\",\n\n\tthighL:\"thighL\",\n\tshinL:\"shinL\",\n\tfootL:\"footL\",\n\n\tthighR:\"thighR\",\n\tshinR:\"shinR\",\n\tfootR:\"footR\",\n\t \n\t\n\thandL:\"handL\",\n\tindex1L:\"index1L\",\n\tindex2L:\"index2L\",\n\tindex3L:\"index3L\",\n\n\tmiddle1L:\"middle1L\",\n\tmiddle2L:\"middle2L\",\n\tmiddle3L:\"middle3L\",\n\n\tring1L:\"ring1L\",\n\tring2L:\"ring2L\",\n\tring3L:\"ring3L\",\n\n\tpinky1L:\"pinky1L\",\n\tpinky2L:\"pinky2L\",\n\tpinky3L:\"pinky3L\",\n\n\tthumb1L:\"thumb1L\",\n\tthumb2L:\"thumb2L\",\n\tthumb3L:\"thumb3L\",\n\n\thandR:\"handR\",\n\tindex1R:\"index1R\",\n\tindex2R:\"index2R\",\n\tindex3R:\"index3R\",\n\n\tmiddle1R:\"middle1R\",\n\tmiddle2R:\"middle2R\",\n\tmiddle3R:\"middle3R\",\n\n\tring1R:\"ring1R\",\n\tring2R:\"ring2R\",\n\tring3R:\"ring3R\",\n\n\tpinky1R:\"pinky1R\",\n\tpinky2R:\"pinky2R\",\n\tpinky3R:\"pinky3R\",\n\n\tthumb1R:\"thumb1R\",\n\tthumb2R:\"thumb2R\",\n\tthumb3R:\"thumb3R\",\n \n}","/**\n * A list of blend shape key names that are used by mediapipe face mesh. \n */\nexport const blendShapeKeyNames = [\n \"eyeBlinkLeft\",\n \"eyeBlinkRight\",\n \"eyeLookDownLeft\",\n \"eyeLookDownRight\",\n \"eyeLookInLeft\",\n \"eyeLookInRight\",\n \"eyeLookOutLeft\",\n \"eyeLookOutRight\",\n \"eyeLookUpLeft\",\n \"eyeLookUpRight\",\n \"eyeSquintLeft\",\n \"eyeSquintRight\",\n \"eyeWideLeft\",\n \"eyeWideRight\",\n \"browDownLeft\",\n \"browDownRight\",\n \"browInnerUp\",\n \"browOuterUpLeft\",\n \"browOuterUpRight\",\n \"noseSneerLeft\",\n \"noseSneerRight\",\n \"cheekPuff\",\n \"cheekSquintLeft\",\n \"cheekSquintRight\",\n \"jawForward\",\n \"jawLeft\",\n \"jawOpen\",\n \"jawRight\",\n \"mouthClose\",\n \"mouthDimpleLeft\",\n \"mouthDimpleRight\",\n \"mouthFrownLeft\",\n \"mouthFrownRight\",\n \"mouthFunnel\",\n \"mouthLeft\",\n \"mouthLowerDownLeft\",\n \"mouthLowerDownRight\",\n \"mouthPressLeft\",\n \"mouthPressRight\",\n \"mouthPucker\",\n \"mouthRight\",\n \"mouthRollLower\",\n \"mouthRollUpper\",\n \"mouthShrugLower\",\n \"mouthShrugUpper\",\n \"mouthSmileLeft\",\n \"mouthSmileRight\",\n \"mouthStretchLeft\",\n \"mouthStretchRight\",\n \"mouthUpperUpLeft\",\n \"mouthUpperUpRight\",\n \"tongueOut\"\n]","import * as THREE from \"three\";\nimport { BoneMap, defaultBoneMap } from \"../BoneMapping\";\nimport { GLTFExporter } from \"three/examples/jsm/Addons.js\";\nimport { blendShapeKeyNames } from \"../blendShapeKeyNames\";\n\ntype BoneRef = {\n ref: THREE.Bone;\n name: string;\n\tnormalizedName: string;\n};\n\n/**\n * Records the local rotation of the bones in the rig. The name used will be the normalized bone name.\n * @param rigRoot\n * @param magging\n * @param fps\n * @returns\n */\nexport function createRigRecorder(\n rigRoot: THREE.Object3D,\n magging: BoneMap,\n fps = 30,\n) {\n const bones: BoneRef[] = [];\n const faceMesh = rigRoot.getObjectByName(\n magging.faceMesh,\n ) as THREE.SkinnedMesh;\n const usedBlendShapeKeys = new Set<string>();\n\n //\n // collect used blend shape keys...\n //\n if (faceMesh?.morphTargetDictionary) {\n for (const key in faceMesh.morphTargetDictionary) {\n if (blendShapeKeyNames.includes(key)) {\n usedBlendShapeKeys.add(key);\n }\n }\n }\n\n\n\t//\n\t// look for the bones\n\t//\n\tconst boneKeys = Object.keys(magging);\n\trigRoot.traverse( o => {\n\t\tif(o instanceof THREE.Bone)\n\t\t{\n\t\t\t// check if the bone name is in the mapping\n\t\t\tconst key = boneKeys.find(k => o.name.indexOf( magging[k as keyof typeof magging] )=== 0 );\n\t\t\tif(key)\n\t\t\t{\n\t\t\t\tbones.push({\n\t\t\t\t\tref: o,\n\t\t\t\t\tname: o.name, \n\t\t\t\t\tnormalizedName: key,\n\t\t\t\t}); \n\t\t\t}\n\t\t}\n\t});\n \n\n\tconst times :number[] = [];\n const boneTracks = new Map<\n string,\n number[] //vec4 array\n >();\n\n\tconst blendShapeTracks = new Map<\n\t\tstring,\n\t\tnumber[]\n\t>();\n\n let recording = false;\n let startTime = 0;\n\n function start() {\n boneTracks.clear();\n\t\tblendShapeTracks.clear();\n\t\ttimes.length = 0;\n startTime = performance.now() / 1000;\n recording = true;\n }\n\n function captureFrame() {\n if (!recording) return;\n\n const time = performance.now() / 1000 - startTime;\n\n\t\ttimes.push(time);\n\n for (const bone of bones) {\n if (!boneTracks.has(bone.name)) {\n boneTracks.set(bone.name, []);\n }\n\n const track = boneTracks.get(bone.name)!; \n\t\t\t \n const q = bone.ref.quaternion;\n track.push(q.x, q.y, q.z, q.w);\n } \n\n\t\tfor (const key of usedBlendShapeKeys) {\n\t\t\tif (!blendShapeTracks.has(key)) {\n\t\t\t\tblendShapeTracks.set(key, []);\n\t\t\t}\n\n\t\t\tconst track = blendShapeTracks.get(key)!; \n\n\t\t\tconst keyIndex = faceMesh.morphTargetDictionary![key];\n\t\t\tconst v = faceMesh.morphTargetInfluences![keyIndex];\n\t\t\ttrack.push(v);\n\t\t}\n }\n\n\t/** \n\t * @param name name of the resulting clip\n\t * @returns \n\t */\n function stop(name = \"RecordedClip\") {\n recording = false;\n\n const keyframeTracks: THREE.KeyframeTrack[] = [];\n\n\t\t\n \n for (const [boneName, data] of boneTracks) {\n keyframeTracks.push(\n new THREE.QuaternionKeyframeTrack(\n `${boneName}.quaternion`,\n times,\n data,\n ),\n );\n } \n\n\t\tfor (const [key, data] of blendShapeTracks) {\n\t\t\tkeyframeTracks.push(\n\t\t\t\tnew THREE.NumberKeyframeTrack(\n\t\t\t\t\t`${defaultBoneMap.faceMesh}.morphTargetInfluences[${key}]`,\n\t\t\t\t\ttimes,\n\t\t\t\t\tdata,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n const clip = new THREE.AnimationClip(name, -1, keyframeTracks);\n \n\n return {\n\t\t\tclip,\n\t\t\tsaveToFile:() => {\n\t const exporter = new GLTFExporter();\n\t exporter.parse(\n\t rigRoot,\n\t (gltf) => {\n\t // binary .glb\n\t const blob = new Blob([gltf], {\n\t type: \"model/gltf-binary\",\n\t });\n\t const url = URL.createObjectURL(blob);\n\n\t const a = document.createElement(\"a\");\n\t a.href = url;\n\t a.download = name + \".glb\";\n\t a.click();\n\t },\n\t (error) => {\n\t console.error(error);\n\t },\n\t {\n\t binary: true,\n\t animations: [clip],\n\t },\n\t );\n\t }\n\t\t};\n }\n\n return { start, captureFrame, stop, isRecording: () => recording };\n}\n","import {\n DrawingUtils,\n FilesetResolver,\n HandLandmarkerOptions,\n PoseLandmarker,\n} from \"@mediapipe/tasks-vision\";\nimport * as THREE from \"three/webgpu\";\nimport { loadPoseTracker } from \"./PoseTracker\";\nimport { loadHandTracker } from \"./HandTracker\"; \nimport { loadFaceTracker } from \"./FaceTracker\";\nimport { BoneMap, defaultBoneMap } from \"./BoneMapping\";\nimport { createRigRecorder } from \"./recoding/recorder\";\n\nexport type TrackerConfig = {\n /**\n * Use an image file. Useful to test a particular pose.\n */\n debugFrame?: string;\n\n /**\n * Scale of the video display\n */\n displayScale: number;\n\n /**\n * If the body pose should ignore the legs\n */\n ignoreLegs: boolean;\n\n /**\n * Use a video file instead of the webcam\n */\n debugVideo?: string;\n\n /**\n * Don't track the face\n */\n ignoreFace: boolean;\n\n /**\n * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker/web_js#configuration_options\n */\n handsTrackerOptions: HandLandmarkerOptions | undefined;\n\n\tmodelPaths?: {\n\t\tvision?:string;\n\t\tpose?: string;\n\t\thand?: string;\n\t\tface?: string;\n\t}\n};\n\nexport interface BindingHandler {\n\n\t/**\n\t * Updates the rig with the latest landmarks.\n\t * @param delta The time elapsed since the last frame in seconds.\n\t */\n update: (delta: number) => void;\n\n}\n\nexport interface RecorderHandler { \n\t/**\n\t * Starts recording the rig's movement and active shape keys ( from media pipe ).\n\t */\n\tstartRecording: VoidFunction;\n\n\t/**\n\t * Stops recording the rig's movement.\n\t * @returns A function that can be called to SAVE the recording to a file.\n\t */\n\tstopRecording: ReturnType<typeof createRigRecorder>['stop'];\n\n\t/**\n\t * Checks if the rig is currently recording.\n\t * @returns True if the rig is recording, false otherwise.\n\t */\n\tisRecording: () => boolean;\n}\n\nexport interface RecordableBindingHandler extends BindingHandler, RecorderHandler {}\n\n// Check if webcam access is supported.\nconst hasGetUserMedia = () => !!navigator.mediaDevices?.getUserMedia;\n\nexport async function setupTracker(config?: Partial<TrackerConfig>) {\n const $cfg = {\n debugFrame: undefined,\n displayScale: 1,\n ignoreLegs: false,\n debugVideo: undefined,\n ignoreFace: false,\n\t\tmodelPaths: {\n\t\t\tvision: \"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm\",\n\t\t\tpose: \"https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task\",\n\t\t\thand: \"https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task\",\n\t\t\tface: \"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task\",\n\t\t},\n ...config,\n };\n let video: HTMLVideoElement | undefined;\n const vision = await FilesetResolver.forVisionTasks( $cfg.modelPaths.vision ?? \"/wasm\" );\n const poseTracker = await loadPoseTracker(vision, {\n ignoreLegs: $cfg.ignoreLegs,\n\t\tmodelPath: $cfg.modelPaths.pose!,\n });\n const handsTracker = await loadHandTracker(vision, {\n leftWrist: () => poseTracker.leftWristNormalizedPosition,\n rightWrist: () => poseTracker.rightWristNormalizedPosition,\n\t\tmodelPath: $cfg.modelPaths.hand!,\n ...config?.handsTrackerOptions,\n });\n const faceTracker = $cfg.ignoreFace\n ? undefined\n : await loadFaceTracker(vision, { modelPath: $cfg.modelPaths.face! });\n\n //#region setup Camera and Canvas...\n\tconst viewport = document.createElement(\"div\");\n\tviewport.style.position = \"absolute\";\n\tviewport.style.top = \"0px\";\n\tviewport.style.left = \"0px\"; \n\tviewport.style.zIndex = \"21\";\n\tviewport.classList.add(\"three-mediapipe-rig\")\n\tdocument.body.appendChild(viewport);\n\n const canvasElement = document.createElement(\"canvas\");\n const canvasCtx = canvasElement.getContext(\"2d\")!;\n const drawingUtils = new DrawingUtils(canvasCtx);\n\n canvasElement.style.zIndex = \"22\";\n canvasElement.style.position = \"absolute\";\n canvasElement.style.top = \"0px\";\n canvasElement.style.left = \"0px\";\n canvasElement.style.pointerEvents = \"none\";\n viewport.appendChild(canvasElement);\n\n function predict(source: TexImageSource) {\n canvasCtx.save();\n canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);\n poseTracker?.predict(source, drawingUtils);\n handsTracker?.left.predict(source, drawingUtils);\n handsTracker?.right.predict(source, drawingUtils);\n faceTracker?.predict(source, drawingUtils);\n canvasCtx.restore();\n }\n\n function initializeVideo() {\n video = document.createElement(\"video\");\n viewport.appendChild(video);\n\n let lastVideoTime = -1;\n\n video.style.zIndex = \"21\";\n video.style.position = \"absolute\";\n video.style.top = \"0px\";\n video.style.left = \"0px\";\n\n if ($cfg.debugVideo) {\n video.src = $cfg.debugVideo;\n video.controls = true;\n video.loop = true;\n video.muted = true;\n video.controls = true;\n video.play();\n }\n\n function predictWebcam() {\n if (lastVideoTime !== video!.currentTime) {\n predict(video!);\n lastVideoTime = video!.currentTime;\n }\n window.requestAnimationFrame(predictWebcam);\n }\n\n video.addEventListener(\"loadeddata\", () => {\n video!.width = video!.videoWidth * $cfg.displayScale;\n video!.height = video!.videoHeight * $cfg.displayScale;\n canvasElement.width = video!.videoWidth;\n canvasElement.height = video!.videoHeight;\n canvasElement.style.height = video!.height + \"px\";\n canvasElement.style.width = video!.width + \"px\";\n\n window.requestAnimationFrame(predictWebcam);\n });\n }\n\n if ($cfg.debugFrame) {\n //#region Debug Frame mode — use a static image\n const img = document.createElement(\"img\");\n img.src = $cfg.debugFrame;\n img.style.zIndex = \"21\";\n img.style.position = \"absolute\";\n img.style.top = \"0px\";\n img.style.left = \"0px\";\n\t\tviewport.appendChild(img);\n\n img.addEventListener(\"load\", () => {\n img.width = img.naturalWidth * $cfg.displayScale;\n img.height = img.naturalHeight * $cfg.displayScale;\n canvasElement.width = img.naturalWidth;\n canvasElement.height = img.naturalWidth;\n canvasElement.style.width = img.width + \"px\";\n canvasElement.style.height = img.height + \"px\";\n\n function predictFrame() {\n predict(img);\n\t\t\t\t//window.requestAnimationFrame(predictFrame);\n }\n\n window.requestAnimationFrame(predictFrame);\n });\n //#endregion\n } else if( $cfg.debugVideo ) {\n //#region Video mode\n initializeVideo();\n //#endregion\n } \n\n return {\n poseTracker,\n handsTracker,\n faceTracker,\n video,\n\n\t\t/**\n\t\t * A div that contains the video and canvas used to display the landmarks stacked on top of each other.\n\t\t */\n\t\tdomElement: viewport,\n\n\t\t/**\n\t\t * Start the webcam feed. This must be initiated by a user triggered event ( a click on a button ) due to security reasons. \n\t\t */\n start: async () => {\n\t\t\tlet stopped = false;\n\n if (!hasGetUserMedia()) {\n throw new Error(\"Webcam not supported\");\n }\n\n if (!video) {\n initializeVideo();\n }\n\n let stream: Awaited<MediaStream> | undefined;\n\n\t\t\tfunction onTrackEnded(video: HTMLVideoElement): void {\n\t\t\t\tconsole.warn('Camera track ended, attempting recovery...');\n\t\t\t\tstopCamera(video);\n\t\t\t\tretryWithBackoff(video);\n\t\t\t}\n\n\t\t\tfunction stopCamera(video: HTMLVideoElement): void {\n\t\t\t\tstream?.getTracks().forEach(t => t.stop());\n\t\t\t\tstream = undefined;\n\t\t\t\tvideo.srcObject = null;\n\t\t\t}\n\n\t\t\tasync function retryWithBackoff(video: HTMLVideoElement, attempt = 0): Promise<void> {\n\t\t\t const MAX_ATTEMPTS = 5;\n\t\t\t const delay = Math.min(1000 * 2 ** attempt, 16000); // 1s, 2s, 4s, 8s, 16s\n\n\t\t\t if (attempt >= MAX_ATTEMPTS) { \n\t\t\t throw new Error('Camera recovery failed after max attempts');\n\t\t\t }\n\n\t\t\t await new Promise(res => setTimeout(res, delay)); \n\n\t\t\t if(stopped) return;\n\n\t\t\t try {\n\t\t\t await startCamera(video);\n\t\t\t console.log('Camera recovered successfully');\n\t\t\t } catch {\n\t\t\t retryWithBackoff(video, attempt + 1);\n\t\t\t }\n\t\t\t}\n\n\t\t\tasync function startCamera(video: HTMLVideoElement): Promise<void> {\n\t\t\t try {\n\t\t\t stream = await navigator.mediaDevices.getUserMedia({ video: true });\n\t\t\t video.srcObject = stream;\n\t\t\t await video.play();\n\n\t\t\t // Listen for track ending (camera disconnected / permission revoked)\n\t\t\t stream.getVideoTracks().forEach(track => {\n\t\t\t track.addEventListener('ended', () => onTrackEnded(video));\n\t\t\t });\n\n\t\t\t } catch (err) {\n\t\t\t handleCameraError(err, video);\n\t\t\t }\n\t\t\t}\n\n\t\t\tfunction handleCameraError(err: unknown, video: HTMLVideoElement): void {\n\t\t\t if (err instanceof DOMException) {\n\t\t\t switch (err.name) {\n\t\t\t case 'NotAllowedError':\n\t\t\t throw new Error('Permission denied — prompt user to allow camera');\n\t\t\t break;\n\t\t\t case 'NotFoundError':\n\t\t\t console.error('No camera found — retry when device is connected');\n\t\t\t retryWithBackoff(video); // device might be plugged in later\n\t\t\t break;\n\t\t\t case 'NotReadableError':\n\t\t\t console.error('Camera in use by another app');\n\t\t\t retryWithBackoff(video);\n\t\t\t break;\n\t\t\t default:\n\t\t\t console.error('Camera error:', err.message);\n\t\t\t retryWithBackoff(video);\n\t\t\t }\n\t\t\t }\n\t\t\t} \n\n await startCamera(video!);\n\n\t\t\treturn {\n\t\t\t\tstop:()=>{\n\t\t\t\t\tstopped = true;\n\t\t\t\t\tstopCamera(video!);\n\t\t\t\t}\n\t\t\t}\n },\n\n /**\n * Binds the bones of the rig to the landmarks provided by media pipe.\n * @param rig The rig that contains all the bones and skinned meshes of your character.\n\t\t * @param magging The bone mapping to use for the rig.\n */\n bind: ( rig: THREE.Object3D, magging?:BoneMap ) => {\n\n\t\t\tmagging = magging || defaultBoneMap;\n\n const bodyBindin = poseTracker.bind(rig, magging);\n const leftHandBinding = handsTracker.left.bind(rig, magging);\n const rightHandBinding = handsTracker.right.bind(rig, magging);\n let faceKeys: BindingHandler | undefined;\n const faceRig = faceTracker?.bind(rig);\n\n rig.traverse((child) => {\n if (\n child instanceof THREE.Mesh &&\n child.name.indexOf( magging.faceMesh ) === 0\n ) {\n child.frustumCulled = false;\n faceKeys = faceTracker?.bindShapeKeys(child);\n }\n });\n\n\t\t\tconst recorder = createRigRecorder(rig, magging)\n\n return {\n\n\t\t\t\t/**\n\t\t\t\t * Will save the tracked movement of the rig to an animation clip.\n\t\t\t\t * Only the bones moved by the bone mapping will be recorded.\n\t\t\t\t */\n\t\t\t\tstartRecording: recorder.start,\n\t\t\t\tstopRecording: recorder.stop,\n\t\t\t\tisRecording: () => recorder.isRecording(),\n\n update: (delta: number) => {\n bodyBindin.update(delta);\n leftHandBinding.update(delta);\n rightHandBinding.update(delta);\n faceKeys?.update(delta);\n faceRig?.update(delta);\n\n\t\t\t\t\tif( recorder.isRecording() ) {\n\t\t\t\t\t\trecorder.captureFrame()\n\t\t\t\t\t}\n },\n } as RecordableBindingHandler;\n },\n };\n}\n"],"names":["poleDir","Vector3","objectPosition","XAxis","XAxisNeg","YAxis","YAxisNeg","ZAxis","pole","lookDir","v","correction","Quaternion","worldQuat","lookAt","object","target","poleTarget","poleAxis","axis","currentPole","lookAxisDir","desiredPoleDir","cross","angle","THREE","A","B","Tracker","points","debugConnections","__publicField","key","Mark","landmarks","debugLandmarks","debugDrawer","point","mark","o","Ghost","_a","source","drawingUtils","delta","objects","normal","root","offset","objectLookAtGoal","polePosition","ghost","rig","name","speed","rootPosition","out","cleanBoneName","getBoneByName","bone","Bone","loadPoseTracker","vision","config","poseLandmarker","PoseLandmarker","PoseTracker","poseMarks","C","D","E","lookGoal","poleGoal","result","magging","map","v2","syncBone","from","to","sideAxis","hipsDir","sideHips","sideShoulders","sideHead","loadHandTracker","landmarker","HandLandmarker","isMyWrist","myWrist","otherWrist","handWrist","e","HandsTracker","handMarks","fingerKeys","v1","v3","v4","v5","v6","currSide","HALF_PI","DOWN","handLandmarker","side","hand","wrist","markToBone","palmNormal","parlmDir","palmSide","palmLookAt","polPosition","palmGhost","palmForward","sideGoal","negateSideGoal","i","fingerGhost","myDir","bonePos","fingerSideNormal","addBind","boneName","markName","loadFaceTracker","cfg","faceLandmarker","FaceLandmarker","FaceTracker","faceMarks","frame","_b","_c","category","mesh","meshKeys","categoryName","score","factor","eyeL","EyeRig","eyeR","headBone","markEarL","markEarR","headcenter","headForward","headSideNormal","headPosition","poleLookAt","faceLookAt","sideName","blendshapes","lookLeft","lookRight","lookUp","lookDown","sideMovement","verticalMovement","defaultBoneMap","blendShapeKeyNames","createRigRecorder","rigRoot","fps","bones","faceMesh","usedBlendShapeKeys","boneKeys","k","times","boneTracks","blendShapeTracks","recording","startTime","start","captureFrame","time","track","q","keyIndex","stop","keyframeTracks","data","clip","GLTFExporter","gltf","blob","url","a","error","hasGetUserMedia","setupTracker","$cfg","video","FilesetResolver","poseTracker","handsTracker","faceTracker","viewport","canvasElement","canvasCtx","DrawingUtils","predict","initializeVideo","lastVideoTime","predictWebcam","img","predictFrame","stopped","stream","onTrackEnded","stopCamera","retryWithBackoff","t","attempt","delay","res","startCamera","err","handleCameraError","bodyBindin","leftHandBinding","rightHandBinding","faceKeys","faceRig","child","recorder"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"HandTracker.d.ts","sourceRoot":"","sources":["../../src/tracking/HandTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACT,cAAc,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAU,cAAc,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,MAAM,kBAAkB,GAAG;IAChC,SAAS,EAAE,MAAI,kBAAkB,CAAC;IAClC,UAAU,EAAE,MAAI,kBAAkB,CAAC;IACnC,SAAS,CAAC,EAAC,MAAM,CAAA;CACjB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAKnC,wBAAsB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAC,kBAAkB;;;GAqB3E;AAED,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;CA4Bd,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,SAAS,CAAC;AAWlD,KAAK,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAA;AAChC,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC;KAAG,GAAG,IAAI,YAAY,GAAG,KAAK,CAAC,QAAQ;CAAE,CAAC,CAAC;AAe3E,cAAM,YAAa,SAAQ,OAAO,CAAC,OAAO,SAAS,CAAC;IAQvC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAAiB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAW,OAAO,CAAC,QAAQ,CAAC,SAAS;IAPtH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAQ;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;gBAElB,cAAc,EAAC,cAAc,EAAmB,IAAI,EAAC,QAAQ,EAAmB,SAAS,EAAC,CAAE,SAAS,EAAC,kBAAkB,KAAI,OAAO;IAWvJ,OAAO,CAAE,MAAM,EAAC,cAAc,EAAE,YAAY,EAAC,YAAY;IA8BzD,IAAI,CAAG,KAAK,EAAC,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE;IAKrG;;;;;OAKG;IACH,aAAa,CAAE,KAAK,EAAC,MAAM,EAAE,UAAU,EAAC,SAAS,EAAE,GAAG,EAAC,KAAK,CAAC,QAAQ;IA6CrE,OAAO,CAAC,UAAU;IAoDlB,IAAI,CAAE,GAAG,EAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAC,OAAO;wBAsCvB,MAAM;;CAKxB"}
1
+ {"version":3,"file":"HandTracker.d.ts","sourceRoot":"","sources":["../../src/tracking/HandTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACT,cAAc,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAU,cAAc,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,MAAM,kBAAkB,GAAG;IAChC,SAAS,EAAE,MAAI,kBAAkB,CAAC;IAClC,UAAU,EAAE,MAAI,kBAAkB,CAAC;IACnC,SAAS,CAAC,EAAC,MAAM,CAAA;CACjB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAKnC,wBAAsB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAC,kBAAkB;;;GA2B3E;AAED,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;CA4Bd,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,SAAS,CAAC;AAWlD,KAAK,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAA;AAChC,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC;KAAG,GAAG,IAAI,YAAY,GAAG,KAAK,CAAC,QAAQ;CAAE,CAAC,CAAC;AAgB3E,cAAM,YAAa,SAAQ,OAAO,CAAC,OAAO,SAAS,CAAC;IAQvC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAAiB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAW,OAAO,CAAC,QAAQ,CAAC,SAAS;IAPtH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAQ;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;gBAElB,cAAc,EAAC,cAAc,EAAmB,IAAI,EAAC,QAAQ,EAAmB,SAAS,EAAC,CAAE,SAAS,EAAC,kBAAkB,KAAI,OAAO;IAWvJ,OAAO,CAAE,MAAM,EAAC,cAAc,EAAE,YAAY,EAAC,YAAY;IA8BzD,IAAI,CAAG,KAAK,EAAC,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE;IAKrG;;;;;OAKG;IACH,aAAa,CAAE,KAAK,EAAC,MAAM,EAAE,UAAU,EAAC,SAAS,EAAE,GAAG,EAAC,KAAK,CAAC,QAAQ;IA6CrE,OAAO,CAAC,UAAU;IA8DlB,IAAI,CAAE,GAAG,EAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAC,OAAO;wBAuCvB,MAAM;;CAKxB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-mediapipe-rig",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "description": "Easy setup of a skeletal rig that responds to the motion tracker provided by google's mediapipe webwam feed.",
6
6
  "repository": {