three-mediapipe-rig 0.1.0 → 0.1.2

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.
Files changed (38) hide show
  1. package/README.md +7 -2
  2. package/dist/face-tracker-utils-xt9__vBF.js +16 -0
  3. package/dist/meshcap/atlas-builder.d.ts +10 -0
  4. package/dist/meshcap/atlas-builder.d.ts.map +1 -0
  5. package/dist/meshcap/constants.d.ts +3 -0
  6. package/dist/meshcap/constants.d.ts.map +1 -0
  7. package/dist/meshcap/material.d.ts +53 -0
  8. package/dist/meshcap/material.d.ts.map +1 -0
  9. package/dist/meshcap/meshcap.d.ts +5 -0
  10. package/dist/meshcap/meshcap.d.ts.map +1 -0
  11. package/dist/meshcap/parse-mcap-file.d.ts +8 -0
  12. package/dist/meshcap/parse-mcap-file.d.ts.map +1 -0
  13. package/dist/meshcap/types.d.ts +53 -0
  14. package/dist/meshcap/types.d.ts.map +1 -0
  15. package/dist/meshcap/write-mcap-file.d.ts +3 -0
  16. package/dist/meshcap/write-mcap-file.d.ts.map +1 -0
  17. package/dist/meshcap.d.ts +2 -0
  18. package/dist/meshcap.js +316 -0
  19. package/dist/module.d.ts +1 -0
  20. package/dist/module.d.ts.map +1 -1
  21. package/dist/rigger.d.ts +2 -0
  22. package/dist/rigger.js +853 -0
  23. package/dist/tracking/BoneMapping.d.ts.map +1 -1
  24. package/dist/tracking/FaceTracker.d.ts +13 -2
  25. package/dist/tracking/FaceTracker.d.ts.map +1 -1
  26. package/dist/tracking/HandTracker.d.ts +3 -3
  27. package/dist/tracking/HandTracker.d.ts.map +1 -1
  28. package/dist/tracking/PoseTracker.d.ts +1 -1
  29. package/dist/tracking/PoseTracker.d.ts.map +1 -1
  30. package/dist/tracking/TrackerManager.d.ts +118 -0
  31. package/dist/tracking/TrackerManager.d.ts.map +1 -0
  32. package/dist/tracking/recoding/recorder.d.ts +10 -8
  33. package/dist/tracking/recoding/recorder.d.ts.map +1 -1
  34. package/dist/tracking/util/face-tracker-utils.d.ts +9 -0
  35. package/dist/tracking/util/face-tracker-utils.d.ts.map +1 -0
  36. package/package.json +17 -12
  37. package/dist/three-mediapipe-rig.js +0 -830
  38. package/dist/three-mediapipe-rig.js.map +0 -1
package/dist/rigger.js ADDED
@@ -0,0 +1,853 @@
1
+ var Pe = Object.defineProperty;
2
+ var Ee = (l, o, e) => o in l ? Pe(l, o, { enumerable: !0, configurable: !0, writable: !0, value: e }) : l[o] = e;
3
+ var R = (l, o, e) => Ee(l, typeof o != "symbol" ? o + "" : o, e);
4
+ import { PoseLandmarker as we, HandLandmarker as I, FaceLandmarker as G, FilesetResolver as ge, DrawingUtils as We } from "@mediapipe/tasks-vision";
5
+ import * as u from "three/webgpu";
6
+ import { Vector3 as b, Quaternion as ye, VideoTexture as Q, SRGBColorSpace as Y, MeshPhysicalNodeMaterial as Fe } from "three/webgpu";
7
+ import * as _ from "three";
8
+ import { Bone as Ae } from "three";
9
+ import { uniform as C, attribute as Se, instancedArray as Me, varying as Ve, vec3 as Ne, float as Oe, texture as Te, vec2 as _e } from "three/tsl";
10
+ import { c as Ce, F as De } from "./face-tracker-utils-xt9__vBF.js";
11
+ import { GLTFExporter as ze } from "three/examples/jsm/Addons.js";
12
+ const z = new b(), Z = new b(), Be = new b(1, 0, 0), Ue = new b(-1, 0, 0), Ie = new b(0, 1, 0), Ge = new b(0, -1, 0), J = new b(0, 0, 1);
13
+ new b(0, 0, -1);
14
+ const ee = new b(), He = new b(), qe = new b(), te = new ye(), B = new ye();
15
+ function F(l, o, e, t = "+x") {
16
+ l.lookAt(o);
17
+ const n = t == "+x" ? Be : t == "-x" ? Ue : t == "+y" ? Ie : Ge;
18
+ l.getWorldPosition(Z), l.getWorldQuaternion(B), z.subVectors(e, Z).normalize(), ee.copy(n).applyQuaternion(B);
19
+ const s = ee, a = He.copy(J).applyQuaternion(B), i = z.clone().addScaledVector(a, -z.dot(a)).normalize(), r = qe.crossVectors(s, i), m = Math.atan2(r.dot(a), s.dot(i));
20
+ te.setFromAxisAngle(J, m), l.quaternion.multiply(te);
21
+ }
22
+ const D = new u.Vector3(), N = new u.Vector3(), U = new u.Vector3();
23
+ new u.Vector3();
24
+ class H {
25
+ constructor(o, e) {
26
+ R(this, "objectGhost");
27
+ R(this, "root");
28
+ /**
29
+ * per landmark index, it points to it's object3D equivalent.
30
+ */
31
+ R(this, "marks", {});
32
+ this.points = o, this.debugConnections = e, this.root = new u.Object3D(), this.objectGhost = /* @__PURE__ */ new Map();
33
+ for (let t in this.points)
34
+ this.marks[t] = new $e(), this.root.add(this.marks[t]);
35
+ }
36
+ updateLandmarks(o, e, t) {
37
+ for (let n in this.points) {
38
+ const s = this.points[n], a = this.marks[n];
39
+ a && (s instanceof Array ? (D.copy(o[s[0]]), a.position.copy(o[s[1]]).sub(D).divideScalar(2).add(o[s[0]]), s.length == 4 && (D.subVectors(
40
+ o[s[3]],
41
+ o[s[2]]
42
+ ).divideScalar(2).add(o[s[2]]).sub(a.position).divideScalar(2), a.position.add(D))) : a.position.copy(o[s]));
43
+ }
44
+ t && e && t.drawConnectors(
45
+ e,
46
+ this.debugConnections,
47
+ {
48
+ lineWidth: 1
49
+ }
50
+ );
51
+ }
52
+ getGhost(o) {
53
+ var e;
54
+ if (!this.objectGhost.has(o)) {
55
+ const t = new je();
56
+ t.position.copy(o.position), t.quaternion.copy(o.quaternion), (e = o.parent) == null || e.add(t), this.objectGhost.set(o, t);
57
+ }
58
+ return this.objectGhost.get(o);
59
+ }
60
+ predict(o, e) {
61
+ throw new Error("Method 'predict' must be implemented.");
62
+ }
63
+ sync(o, e) {
64
+ throw new Error("Method 'sync' must be implemented.");
65
+ }
66
+ test(o) {
67
+ this.marks[o].position.set(1, 2, 3);
68
+ }
69
+ syncObjects(o, e, t) {
70
+ for (const [n, s, a, i] of o) {
71
+ this.marks[a].getWorldPosition(U), this.marks[s].getWorldPosition(N);
72
+ const r = U.sub(N);
73
+ n.getWorldPosition(N), N.add(r);
74
+ const m = N, c = n.getWorldPosition(U).sub(t), f = this.getGhost(n);
75
+ F(f, m, c, i), f.rotateX(Math.PI / 2), n.position.lerp(f.position, e * 4), n.quaternion.slerp(f.quaternion, e * 4);
76
+ }
77
+ }
78
+ getBone(o, e) {
79
+ return o.getObjectByName(e.replace(/[\.\:]/g, ""));
80
+ }
81
+ }
82
+ class $e extends u.Mesh {
83
+ constructor() {
84
+ super(new u.SphereGeometry(0.01, 3, 3), new u.MeshStandardMaterial({ color: 16711680, wireframe: !0 }));
85
+ R(this, "_worldPosition", new u.Vector3());
86
+ this.add(new u.AxesHelper(1e-3));
87
+ }
88
+ get worldPosition() {
89
+ return this.getWorldPosition(this._worldPosition), this._worldPosition;
90
+ }
91
+ }
92
+ class je extends u.Object3D {
93
+ lerp(o, e, t = 8) {
94
+ o.position.lerp(this.position, e * t), o.quaternion.slerp(this.quaternion, e * t);
95
+ }
96
+ }
97
+ function W(l, o, e) {
98
+ return e.worldToLocal(o.getWorldPosition(l)), l;
99
+ }
100
+ function Ke(l) {
101
+ return l.replace(/[\.\:]/g, "");
102
+ }
103
+ function P(l, o) {
104
+ let e;
105
+ return o = Ke(o), l.traverse((t) => {
106
+ t.name.indexOf(o) === 0 && t instanceof Ae && (e = t);
107
+ }), e || console.log("Bone not found: ", o, l.name), e;
108
+ }
109
+ async function Xe(l, o) {
110
+ const e = await we.createFromOptions(l, {
111
+ baseOptions: {
112
+ modelAssetPath: (o == null ? void 0 : o.modelPath) ?? "pose_landmarker_lite.task",
113
+ //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task`,
114
+ //modelAssetPath: "https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_heavy/float16/latest/pose_landmarker_heavy.task",
115
+ delegate: "GPU"
116
+ },
117
+ runningMode: "VIDEO",
118
+ numPoses: 1
119
+ });
120
+ return new tt(e, o);
121
+ }
122
+ const Qe = {
123
+ hips: [24, 23],
124
+ neck: [12, 11],
125
+ leftLeg: 23,
126
+ leftKnee: 25,
127
+ leftFoot: 27,
128
+ leftToes: 31,
129
+ leftArm: 11,
130
+ leftElbow: 13,
131
+ leftWrist: 15,
132
+ rightLeg: 24,
133
+ rightKnee: 26,
134
+ rightFoot: 28,
135
+ rightToes: 32,
136
+ rightArm: 12,
137
+ rightElbow: 14,
138
+ rightWrist: 16,
139
+ head: [8, 7],
140
+ mouth: [10, 9],
141
+ torso: [24, 23, 12, 11],
142
+ leftEar: 7,
143
+ rightEar: 8
144
+ }, Ye = new u.Vector3(), oe = new u.Vector3(), Ze = new u.Vector3(), Je = new u.Vector3(), et = new u.Vector3(), ne = new u.Vector3(), se = new u.Vector3();
145
+ class tt extends H {
146
+ constructor(e, t) {
147
+ super(Qe, we.POSE_CONNECTIONS);
148
+ R(this, "_leftWristNormalizedPosition");
149
+ R(this, "_rightWristNormalizedPosition");
150
+ this.poseLandmarker = e, this.config = t, this.root.scale.y *= -2, this.root.scale.z *= -2, this.root.scale.x *= 2;
151
+ }
152
+ /**
153
+ * Position of the left wrist in normalized coordinates (0..1)
154
+ */
155
+ get leftWristNormalizedPosition() {
156
+ return this._leftWristNormalizedPosition;
157
+ }
158
+ /**
159
+ * Position of the right wrist in normalized coordinates (0..1)
160
+ */
161
+ get rightWristNormalizedPosition() {
162
+ return this._rightWristNormalizedPosition;
163
+ }
164
+ predict(e, t) {
165
+ this.poseLandmarker.detectForVideo(e, performance.now(), (n) => {
166
+ var s;
167
+ n.landmarks.length != 0 && (this.updateLandmarks(n.worldLandmarks[0], ((s = this.config) == null ? void 0 : s.drawLandmarks) === !1 ? void 0 : n.landmarks[0], t), this._leftWristNormalizedPosition = n.landmarks[0][this.points.leftWrist], this._rightWristNormalizedPosition = n.landmarks[0][this.points.rightWrist]);
168
+ });
169
+ }
170
+ // override sync ( delta:number, objects: BoneBinding[] ) {
171
+ // const hipsPos = this.marks.hips.getWorldPosition(C);
172
+ // this.marks.rightArm.getWorldPosition(A).sub(hipsPos);
173
+ // this.marks.leftArm.getWorldPosition(B).sub(hipsPos);
174
+ // const torsoNormal = C.crossVectors(A,B);
175
+ // this.syncObjects(objects, delta, torsoNormal);
176
+ // }
177
+ bind(e, t) {
178
+ var r;
179
+ const n = {
180
+ hips: P(e, t.hips),
181
+ neck: P(e, t.neck),
182
+ leftArm: P(e, t.armL),
183
+ leftElbow: P(e, t.forearmL),
184
+ leftWrist: P(e, t.handL),
185
+ rightArm: P(e, t.armR),
186
+ rightElbow: P(e, t.forearmR),
187
+ rightWrist: P(e, t.handR),
188
+ head: P(e, t.head),
189
+ torso: P(e, t.torso),
190
+ leftLeg: P(e, t.thighL),
191
+ leftKnee: P(e, t.shinL),
192
+ leftFoot: P(e, t.footL),
193
+ rightLeg: P(e, t.thighR),
194
+ rightKnee: P(e, t.shinR),
195
+ rightFoot: P(e, t.footR)
196
+ };
197
+ (r = this.config) != null && r.ignoreLegs && (delete n.leftLeg, delete n.leftKnee, delete n.leftFoot, delete n.leftToes, delete n.rightLeg, delete n.rightKnee, delete n.rightFoot, delete n.rightToes);
198
+ const s = new u.Vector3(), a = new u.Vector3(), i = (m, c, f, k, x, d) => {
199
+ if (!c) return;
200
+ const h = this.marks[k].getWorldPosition(s).sub(this.marks[f].getWorldPosition(a)).normalize();
201
+ W(ne, c, e).add(h).applyMatrix4(e.matrixWorld), W(se, c, e).add(x).applyMatrix4(e.matrixWorld);
202
+ const w = this.getGhost(c);
203
+ F(w, ne, se, d), w.rotateX(Math.PI / 2), w.lerp(c, m);
204
+ };
205
+ return {
206
+ update: (m) => {
207
+ const c = this.marks.leftLeg.getWorldPosition(Ye).sub(this.marks.rightLeg.getWorldPosition(oe)).normalize(), f = this.marks.leftArm.getWorldPosition(oe).sub(this.marks.rightArm.getWorldPosition(Ze)).normalize(), k = this.marks.leftEar.getWorldPosition(Je).sub(this.marks.rightEar.getWorldPosition(et)).normalize();
208
+ i(m, n.hips, "hips", "torso", c, "+x"), i(m, n.torso, "torso", "neck", f, "+x"), i(m, n.neck, "neck", "head", k, "+x"), i(m, n.head, "neck", "head", k, "+x"), i(m, n.leftArm, "leftArm", "leftElbow", f, "-x"), i(m, n.leftElbow, "leftElbow", "leftWrist", f, "-x"), i(m, n.leftLeg, "leftLeg", "leftKnee", c, "+x"), i(m, n.leftKnee, "leftKnee", "leftFoot", c, "+x"), i(m, n.leftFoot, "leftFoot", "leftToes", c, "+x"), i(m, n.rightArm, "rightArm", "rightElbow", f, "-x"), i(m, n.rightElbow, "rightElbow", "rightWrist", f, "-x"), i(m, n.rightLeg, "rightLeg", "rightKnee", c, "+x"), i(m, n.rightKnee, "rightKnee", "rightFoot", c, "+x"), i(m, n.rightFoot, "rightFoot", "rightToes", c, "+x");
209
+ }
210
+ };
211
+ }
212
+ }
213
+ const ie = new u.Vector2(), re = new u.Vector2();
214
+ async function ot(l, o) {
215
+ const e = await I.createFromOptions(l, {
216
+ baseOptions: {
217
+ modelAssetPath: o.modelPath ?? "hand_landmarker.task",
218
+ //modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,
219
+ delegate: "GPU"
220
+ },
221
+ runningMode: "VIDEO",
222
+ numHands: 2
223
+ }), t = (n, s, a) => {
224
+ try {
225
+ ie.copy(n()), re.copy(s());
226
+ } catch (i) {
227
+ return console.warn("No pose data... will just be optimitic and say yes to everything.", i), !0;
228
+ }
229
+ return ie.distanceTo(a) < re.distanceTo(a);
230
+ };
231
+ return {
232
+ left: new ue(e, "Left", t.bind(null, o.leftWrist, o.rightWrist), o.drawLandmarks),
233
+ right: new ue(e, "Right", t.bind(null, o.rightWrist, o.leftWrist), o.drawLandmarks)
234
+ };
235
+ }
236
+ const nt = {
237
+ wrist: 0,
238
+ palm: [9, 13],
239
+ thumb1: 1,
240
+ thumb2: 2,
241
+ thumb3: 3,
242
+ thumb4: 4,
243
+ index1: 5,
244
+ index2: 6,
245
+ index3: 7,
246
+ index4: 8,
247
+ middle1: 9,
248
+ middle2: 10,
249
+ middle3: 11,
250
+ middle4: 12,
251
+ ring1: 13,
252
+ ring2: 14,
253
+ ring3: 15,
254
+ ring4: 16,
255
+ pinky1: 17,
256
+ pinky2: 18,
257
+ pinky3: 19,
258
+ pinky4: 20
259
+ }, O = {
260
+ thumb: ["thumb1", "thumb2", "thumb3", "thumb4"],
261
+ index: ["index1", "index2", "index3", "index4"],
262
+ middle: ["middle1", "middle2", "middle3", "middle4"],
263
+ ring: ["ring1", "ring2", "ring3", "ring4"],
264
+ pinky: ["pinky1", "pinky2", "pinky3", "pinky4"]
265
+ }, st = new u.Vector3(), ae = new u.Vector3(), de = new u.Vector3(), ce = new u.Vector3(), le = new u.Vector3(), he = new u.Vector3();
266
+ new u.Vector3();
267
+ new u.Vector3();
268
+ new u.Vector3();
269
+ const me = new u.Vector3(), pe = Math.PI / 2, it = new u.Vector3(0, -1, 0);
270
+ class ue extends H {
271
+ constructor(e, t, n, s = !0) {
272
+ super(nt, I.HAND_CONNECTIONS);
273
+ R(this, "sign");
274
+ R(this, "isLeft");
275
+ /**
276
+ * the axis used to look at the pole
277
+ */
278
+ R(this, "lookAtPoleAxis");
279
+ this.handLandmarker = e, this.side = t, this.isMyWrist = n, this.drawLandmarks = s, 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;
280
+ }
281
+ predict(e, t) {
282
+ const n = this.handLandmarker.detectForVideo(e, performance.now());
283
+ if (n.landmarks.length)
284
+ for (let s = 0; s < n.landmarks.length; s++) {
285
+ const a = n.landmarks[s], i = a[this.points.wrist];
286
+ if (this.isMyWrist(i)) {
287
+ this.updateLandmarks(n.worldLandmarks[s]), this.drawLandmarks && (t.drawConnectors(a, I.HAND_CONNECTIONS, {
288
+ color: this.side == "Left" ? "#00FF00" : "#0000FF",
289
+ lineWidth: 4
290
+ }), t.drawLandmarks(a, { color: this.side == "Left" ? "#00FF00" : "#0000FF", lineWidth: 3, radius: 1 }));
291
+ break;
292
+ }
293
+ }
294
+ }
295
+ sync(e, t) {
296
+ throw new Error("Not used. Use syncHandBones instead");
297
+ }
298
+ /**
299
+ *
300
+ * @param delta time since last frame
301
+ * @param landmark2bones Array the same size as the umber of hand landmarks, and on each positionthe bone that belongs to that point.
302
+ * @see https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker
303
+ */
304
+ syncHandBones(e, t, n) {
305
+ const s = st.crossVectors(
306
+ ae.copy(this.marks.index1.worldPosition).sub(this.marks.wrist.worldPosition),
307
+ de.copy(this.marks.pinky1.worldPosition).sub(this.marks.wrist.worldPosition)
308
+ ).normalize(), a = ae.copy(this.marks.palm.worldPosition).sub(this.marks.wrist.worldPosition).normalize(), i = de.copy(this.marks.pinky1.worldPosition).sub(this.marks.index1.worldPosition).normalize();
309
+ if (!(a.dot(it) > 0.8)) {
310
+ if (t.wrist) {
311
+ const r = W(ce, t.wrist, n).add(a).applyMatrix4(n.matrixWorld), m = W(le, t.wrist, n).sub(i).applyMatrix4(n.matrixWorld), c = this.getGhost(t.wrist);
312
+ F(c, r, m, "-y"), c.rotateX(pe), c.lerp(t.wrist, e);
313
+ }
314
+ this.syncFinger(e, n, s, a, i, t, O.index, "middle1"), this.syncFinger(e, n, s, a, i, t, O.middle, "ring1"), this.syncFinger(e, n, s, a, i, t, O.ring, "pinky1"), this.syncFinger(e, n, s, a, i, t, O.pinky, "ring1", !0), this.syncFinger(e, n, s, a, i, t, O.thumb, "index1");
315
+ }
316
+ }
317
+ syncFinger(e, t, n, s, a, i, r, m, c = !1) {
318
+ for (let f = 0; f < r.length - 1; f++) {
319
+ const k = i[r[f]];
320
+ if (!k) continue;
321
+ const x = this.getGhost(k), d = ce.copy(this.marks[r[f + 1]].worldPosition).sub(this.marks[r[f]].worldPosition).normalize(), h = W(le, k, t);
322
+ if (f == 0) {
323
+ const w = he.copy(this.marks[m].worldPosition).sub(this.marks[r[0]].worldPosition).normalize();
324
+ c && w.negate(), me.copy(w), F(
325
+ x,
326
+ d.add(h).applyMatrix4(t.matrixWorld),
327
+ w.add(h).applyMatrix4(t.matrixWorld),
328
+ this.lookAtPoleAxis
329
+ );
330
+ } else
331
+ F(
332
+ x,
333
+ d.add(h).applyMatrix4(t.matrixWorld),
334
+ he.copy(me).add(h).applyMatrix4(t.matrixWorld),
335
+ this.lookAtPoleAxis
336
+ );
337
+ x.rotateX(pe), x.lerp(k, e);
338
+ }
339
+ }
340
+ bind(e, t) {
341
+ const n = {}, s = (a, i) => {
342
+ const r = P(e, a);
343
+ if (r)
344
+ return n[i] = r, i;
345
+ };
346
+ return s(this.isLeft ? t.handL : t.handR, "wrist"), s(this.isLeft ? t.index1L : t.index1R, "index1"), s(this.isLeft ? t.index2L : t.index2R, "index2"), s(this.isLeft ? t.index3L : t.index3R, "index3"), s(this.isLeft ? t.middle1L : t.middle1R, "middle1"), s(this.isLeft ? t.middle2L : t.middle2R, "middle2"), s(this.isLeft ? t.middle3L : t.middle3R, "middle3"), s(this.isLeft ? t.ring1L : t.ring1R, "ring1"), s(this.isLeft ? t.ring2L : t.ring2R, "ring2"), s(this.isLeft ? t.ring3L : t.ring3R, "ring3"), s(this.isLeft ? t.pinky1L : t.pinky1R, "pinky1"), s(this.isLeft ? t.pinky2L : t.pinky2R, "pinky2"), s(this.isLeft ? t.pinky3L : t.pinky3R, "pinky3"), s(this.isLeft ? t.thumb1L : t.thumb1R, "thumb1"), s(this.isLeft ? t.thumb2L : t.thumb2R, "thumb2"), s(this.isLeft ? t.thumb3L : t.thumb3R, "thumb3"), {
347
+ update: (a) => {
348
+ this.syncHandBones(a, n, e);
349
+ }
350
+ };
351
+ }
352
+ }
353
+ async function rt(l, o) {
354
+ const e = await G.createFromOptions(l, {
355
+ baseOptions: {
356
+ modelAssetPath: (o == null ? void 0 : o.modelPath) ?? "face_landmarker.task",
357
+ delegate: "GPU"
358
+ },
359
+ outputFaceBlendshapes: !0,
360
+ runningMode: "VIDEO",
361
+ numFaces: 1
362
+ });
363
+ return new mt(e, { ...o });
364
+ }
365
+ const at = {
366
+ eyeL: 473,
367
+ eyeR: 468,
368
+ eyeStartL: 463,
369
+ eyeStartR: 243,
370
+ eyeEndL: 263,
371
+ eyeEndR: 33,
372
+ earL: 454,
373
+ earR: 234,
374
+ noseTip: 4,
375
+ noseBone: 6,
376
+ chin: 152,
377
+ forehead: 10
378
+ }, dt = new b(), ct = new b(), Le = new b(), lt = new b(), ht = new b();
379
+ new b();
380
+ class mt extends H {
381
+ constructor(e, t) {
382
+ super(at, G.FACE_LANDMARKS_TESSELATION);
383
+ R(this, "blendshapeCategories");
384
+ R(this, "blendshapeMap", /* @__PURE__ */ new Map());
385
+ R(this, "smoothed", {});
386
+ R(this, "smoothing", 3e-4);
387
+ // lower = smoother but more lag, higher = more responsive
388
+ R(this, "_faceLandmarks", []);
389
+ this.faceLandmarker = e, this.cfg = t, this.root.scale.y *= -1, this.root.scale.z *= -1, this.root.scale.multiplyScalar(3);
390
+ }
391
+ predict(e, t) {
392
+ var s, a, i;
393
+ const n = this.faceLandmarker.detectForVideo(e, performance.now());
394
+ n.faceLandmarks[0] && (this.cfg.drawLandmarks && (t.drawConnectors(n.faceLandmarks[0], G.FACE_LANDMARKS_TESSELATION, { color: "#00fff2ff", lineWidth: 0.1 }), t.drawLandmarks(n.faceLandmarks[0], { color: "#00ff00", lineWidth: 0.1, radius: 0.4 })), this.updateLandmarks(n.faceLandmarks[0], n.faceLandmarks[0])), this._faceLandmarks = n.faceLandmarks[0], this.blendshapeCategories = (a = (s = n.faceBlendshapes) == null ? void 0 : s[0]) == null ? void 0 : a.categories, (i = this.blendshapeCategories) == null || i.forEach((r) => {
395
+ this.blendshapeMap.set(r.categoryName, r.score);
396
+ });
397
+ }
398
+ get lastKnownLandmarks() {
399
+ return this._faceLandmarks;
400
+ }
401
+ bindShapeKeys(e) {
402
+ const t = e.morphTargetDictionary;
403
+ return {
404
+ update: (n) => {
405
+ var s;
406
+ (s = this.blendshapeCategories) == null || s.forEach((a) => {
407
+ const { categoryName: i, score: r } = a;
408
+ if (!(t != null && t.hasOwnProperty(i))) return;
409
+ this.smoothed[i] === void 0 && (this.smoothed[i] = r);
410
+ const m = 1 - Math.pow(this.smoothing, n);
411
+ this.smoothed[i] += (r - this.smoothed[i]) * m, e.morphTargetInfluences[t[i]] = this.smoothed[i];
412
+ });
413
+ }
414
+ };
415
+ }
416
+ bind(e) {
417
+ const t = new fe(e, "L"), n = new fe(e, "R"), s = P(e, "head");
418
+ return {
419
+ update: (a) => {
420
+ if (t.update(a, this.blendshapeMap), n.update(a, this.blendshapeMap), !s) return;
421
+ const i = dt.copy(this.marks.earL.worldPosition), r = ct.copy(this.marks.earR.worldPosition), m = Le.subVectors(i, r).multiplyScalar(0.5).add(r), c = lt.subVectors(this.marks.noseTip.worldPosition, m), f = i.sub(r), k = W(ht, s, e), x = f.add(k).applyMatrix4(e.matrixWorld), d = c.add(k).applyMatrix4(e.matrixWorld);
422
+ F(s, d, x, "+x");
423
+ }
424
+ };
425
+ }
426
+ /**
427
+ * The mesh is assumed to be a canonical_face_model because we will be manipulating it's vertices.
428
+ *
429
+ * @see https://github.com/google-ai-edge/mediapipe/tree/master/mediapipe/modules/face_geometry
430
+ * @param mesh basically either the original or a clone of the canonical_face_model
431
+ * @returns an object with a disposeMaterial method that should be called when the mesh is disposed of.
432
+ */
433
+ bindGeometry(e, t) {
434
+ new b(), new b();
435
+ const n = new b();
436
+ new b();
437
+ const a = e.geometry.attributes.position;
438
+ C(new b(0.5, 0.5, 0.5)), Ce(e);
439
+ const i = Se("landmarkIndex", "uint"), r = Me(De, "vec3"), m = Ve(r.element(i)).xy;
440
+ let c;
441
+ const f = 116, k = 346, x = n.subVectors(
442
+ new b(a.getX(f), a.getY(f), a.getZ(f)),
443
+ new b(a.getX(k), a.getY(k), a.getZ(k))
444
+ ).lengthSq();
445
+ console.log("# mesh face reference (live): ", x);
446
+ const d = C(x), h = C(1);
447
+ let w;
448
+ return {
449
+ /**
450
+ * Disposes of the material and removes events listeners on the video element.
451
+ */
452
+ disposeMaterial: () => {
453
+ w == null || w();
454
+ },
455
+ /**
456
+ * asas
457
+ * @param delta asas
458
+ * @returns
459
+ */
460
+ update: (E) => {
461
+ var g, L;
462
+ if (!c) {
463
+ const p = (L = (g = this.cfg) == null ? void 0 : g.videoElementRef) == null ? void 0 : L.call(g);
464
+ if (!p || !p.videoWidth || !p.videoHeight) return;
465
+ c = p;
466
+ const A = new Q(c);
467
+ A.colorSpace = Y;
468
+ const T = C(c.videoWidth / c.videoHeight), S = r.element(k).sub(r.element(f)).lengthSq(), be = d.div(S).sqrt().mul(2), xe = r.element(234).xy, q = r.element(93).xy, Re = r.element(454).xy, $ = r.element(323).xy, j = xe.sub(q).div(2).add(q), ve = Re.sub($).div(2).add($).sub(j).div(2).add(j), K = r.element(i).sub(ve).xzy.mul(Ne(1, -1, Oe(1).div(T))).mul(be), M = Te(A, _e(m.x, m.y.oneMinus())), X = () => {
469
+ const V = new Q(c);
470
+ V.colorSpace = Y, M.value = V, M.needsUpdate = !0, T.value = c.videoWidth / c.videoHeight;
471
+ };
472
+ c.addEventListener("loadeddata", X), t ? t(K, M) : e.material = new Fe({
473
+ positionNode: K,
474
+ colorNode: M,
475
+ roughness: 0.93
476
+ }), w = () => {
477
+ var V;
478
+ M.value.dispose(), c == null || c.removeEventListener("loadeddata", X), (V = e.material) == null || V.dispose();
479
+ };
480
+ }
481
+ const y = this.lastKnownLandmarks;
482
+ if (!(y != null && y.length)) return;
483
+ h.value = n.subVectors(y[k], y[f]).lengthSq(), h.needsUpdate = !0;
484
+ const v = r.value.array;
485
+ for (let p = 0; p < y.length; p++)
486
+ v[p * 3] = y[p].x, v[p * 3 + 1] = y[p].y, v[p * 3 + 2] = y[p].z;
487
+ r.value.needsUpdate = !0;
488
+ }
489
+ };
490
+ }
491
+ }
492
+ class fe {
493
+ constructor(o, e) {
494
+ R(this, "eyeBone");
495
+ R(this, "eyeLookOut");
496
+ R(this, "eyeLookIn");
497
+ R(this, "eyeLookUp");
498
+ R(this, "eyeLookDown");
499
+ R(this, "sign", 1);
500
+ this.rig = o, this.side = e, this.eyeBone = o.getObjectByName(`eye${e}`);
501
+ const t = e == "L" ? "Left" : "Right";
502
+ this.eyeLookOut = `eyeLookOut${t}`, this.eyeLookIn = `eyeLookIn${t}`, this.eyeLookUp = `eyeLookUp${t}`, this.eyeLookDown = `eyeLookDown${t}`, this.sign = e == "L" ? -1 : 1;
503
+ }
504
+ update(o, e) {
505
+ if (!this.eyeBone) return;
506
+ W(Le, this.eyeBone, this.rig);
507
+ const t = e.get(this.eyeLookOut) ?? 0, n = e.get(this.eyeLookIn) ?? 0, s = e.get(this.eyeLookUp) ?? 0, a = e.get(this.eyeLookDown) ?? 0, i = n - t, r = a - s;
508
+ this.eyeBone.rotation.y = i * this.sign / 2, this.eyeBone.rotation.x = r / 2;
509
+ }
510
+ }
511
+ const ke = {
512
+ faceMesh: "face",
513
+ head: "head",
514
+ hips: "hips",
515
+ neck: "neck",
516
+ torso: "torso",
517
+ armL: "upper_armL",
518
+ forearmL: "forearmL",
519
+ armR: "upper_armR",
520
+ forearmR: "forearmR",
521
+ thighL: "thighL",
522
+ shinL: "shinL",
523
+ footL: "footL",
524
+ toesL: "toesL",
525
+ thighR: "thighR",
526
+ shinR: "shinR",
527
+ footR: "footR",
528
+ toesR: "toesR",
529
+ handL: "handL",
530
+ index1L: "index1L",
531
+ index2L: "index2L",
532
+ index3L: "index3L",
533
+ middle1L: "middle1L",
534
+ middle2L: "middle2L",
535
+ middle3L: "middle3L",
536
+ ring1L: "ring1L",
537
+ ring2L: "ring2L",
538
+ ring3L: "ring3L",
539
+ pinky1L: "pinky1L",
540
+ pinky2L: "pinky2L",
541
+ pinky3L: "pinky3L",
542
+ thumb1L: "thumb1L",
543
+ thumb2L: "thumb2L",
544
+ thumb3L: "thumb3L",
545
+ handR: "handR",
546
+ index1R: "index1R",
547
+ index2R: "index2R",
548
+ index3R: "index3R",
549
+ middle1R: "middle1R",
550
+ middle2R: "middle2R",
551
+ middle3R: "middle3R",
552
+ ring1R: "ring1R",
553
+ ring2R: "ring2R",
554
+ ring3R: "ring3R",
555
+ pinky1R: "pinky1R",
556
+ pinky2R: "pinky2R",
557
+ pinky3R: "pinky3R",
558
+ thumb1R: "thumb1R",
559
+ thumb2R: "thumb2R",
560
+ thumb3R: "thumb3R"
561
+ }, pt = [
562
+ "eyeBlinkLeft",
563
+ "eyeBlinkRight",
564
+ "eyeLookDownLeft",
565
+ "eyeLookDownRight",
566
+ "eyeLookInLeft",
567
+ "eyeLookInRight",
568
+ "eyeLookOutLeft",
569
+ "eyeLookOutRight",
570
+ "eyeLookUpLeft",
571
+ "eyeLookUpRight",
572
+ "eyeSquintLeft",
573
+ "eyeSquintRight",
574
+ "eyeWideLeft",
575
+ "eyeWideRight",
576
+ "browDownLeft",
577
+ "browDownRight",
578
+ "browInnerUp",
579
+ "browOuterUpLeft",
580
+ "browOuterUpRight",
581
+ "noseSneerLeft",
582
+ "noseSneerRight",
583
+ "cheekPuff",
584
+ "cheekSquintLeft",
585
+ "cheekSquintRight",
586
+ "jawForward",
587
+ "jawLeft",
588
+ "jawOpen",
589
+ "jawRight",
590
+ "mouthClose",
591
+ "mouthDimpleLeft",
592
+ "mouthDimpleRight",
593
+ "mouthFrownLeft",
594
+ "mouthFrownRight",
595
+ "mouthFunnel",
596
+ "mouthLeft",
597
+ "mouthLowerDownLeft",
598
+ "mouthLowerDownRight",
599
+ "mouthPressLeft",
600
+ "mouthPressRight",
601
+ "mouthPucker",
602
+ "mouthRight",
603
+ "mouthRollLower",
604
+ "mouthRollUpper",
605
+ "mouthShrugLower",
606
+ "mouthShrugUpper",
607
+ "mouthSmileLeft",
608
+ "mouthSmileRight",
609
+ "mouthStretchLeft",
610
+ "mouthStretchRight",
611
+ "mouthUpperUpLeft",
612
+ "mouthUpperUpRight",
613
+ "tongueOut"
614
+ ];
615
+ function ut(l, o, e = 30) {
616
+ const t = [], n = l.getObjectByName(
617
+ o.faceMesh
618
+ ), s = /* @__PURE__ */ new Set();
619
+ if (n != null && n.morphTargetDictionary)
620
+ for (const h in n.morphTargetDictionary)
621
+ pt.includes(h) && s.add(h);
622
+ const a = Object.keys(o);
623
+ l.traverse((h) => {
624
+ if (h instanceof _.Bone) {
625
+ const w = a.find((E) => h.name.indexOf(o[E]) === 0);
626
+ w && t.push({
627
+ ref: h,
628
+ name: h.name,
629
+ normalizedName: w
630
+ });
631
+ }
632
+ });
633
+ const i = [], r = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Map();
634
+ let c = !1, f = 0;
635
+ function k() {
636
+ r.clear(), m.clear(), i.length = 0, f = performance.now() / 1e3, c = !0;
637
+ }
638
+ function x() {
639
+ if (!c) return;
640
+ const h = performance.now() / 1e3 - f;
641
+ i.push(h);
642
+ for (const w of t) {
643
+ r.has(w.name) || r.set(w.name, []);
644
+ const E = r.get(w.name), y = w.ref.quaternion;
645
+ E.push(y.x, y.y, y.z, y.w);
646
+ }
647
+ for (const w of s) {
648
+ m.has(w) || m.set(w, []);
649
+ const E = m.get(w), y = n.morphTargetDictionary[w], v = n.morphTargetInfluences[y];
650
+ E.push(v);
651
+ }
652
+ }
653
+ function d(h = "RecordedClip") {
654
+ c = !1;
655
+ const w = [];
656
+ for (const [y, v] of r)
657
+ w.push(
658
+ new _.QuaternionKeyframeTrack(
659
+ `${y}.quaternion`,
660
+ i,
661
+ v
662
+ )
663
+ );
664
+ for (const [y, v] of m)
665
+ w.push(
666
+ new _.NumberKeyframeTrack(
667
+ `${ke.faceMesh}.morphTargetInfluences[${y}]`,
668
+ i,
669
+ v
670
+ )
671
+ );
672
+ const E = new _.AnimationClip(h, -1, w);
673
+ return {
674
+ clip: E,
675
+ saveToFile: () => {
676
+ new ze().parse(
677
+ l,
678
+ (v) => {
679
+ const g = new Blob([v], {
680
+ type: "model/gltf-binary"
681
+ }), L = URL.createObjectURL(g), p = document.createElement("a");
682
+ p.href = L, p.download = h + ".glb", p.click();
683
+ },
684
+ (v) => {
685
+ console.error(v);
686
+ },
687
+ {
688
+ binary: !0,
689
+ animations: [E]
690
+ }
691
+ );
692
+ }
693
+ };
694
+ }
695
+ return { start: k, captureFrame: x, stop: d, isRecording: () => c };
696
+ }
697
+ const ft = () => {
698
+ var l;
699
+ return !!((l = navigator.mediaDevices) != null && l.getUserMedia);
700
+ };
701
+ async function Pt(l) {
702
+ const o = {
703
+ debugFrame: void 0,
704
+ displayScale: 1,
705
+ ignoreLegs: !1,
706
+ debugVideo: void 0,
707
+ ignoreFace: !1,
708
+ onlyFace: !1,
709
+ drawLandmarksOverlay: !0,
710
+ modelPaths: {
711
+ vision: "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm",
712
+ pose: "https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task",
713
+ hand: "https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task",
714
+ face: "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task"
715
+ },
716
+ ...l
717
+ };
718
+ let e;
719
+ const t = await ge.forVisionTasks(o.modelPaths.vision ?? "/wasm"), n = o.onlyFace ? void 0 : await Xe(t, {
720
+ ignoreLegs: o.ignoreLegs,
721
+ modelPath: o.modelPaths.pose,
722
+ drawLandmarks: o.drawLandmarksOverlay
723
+ }), s = o.onlyFace ? void 0 : await ot(t, {
724
+ leftWrist: () => n.leftWristNormalizedPosition,
725
+ rightWrist: () => n.rightWristNormalizedPosition,
726
+ modelPath: o.modelPaths.hand,
727
+ drawLandmarks: o.drawLandmarksOverlay,
728
+ ...l == null ? void 0 : l.handsTrackerOptions
729
+ }), a = o.ignoreFace ? void 0 : await rt(t, { modelPath: o.modelPaths.face, videoElementRef: () => e, drawLandmarks: o.drawLandmarksOverlay }), i = document.createElement("div");
730
+ i.style.position = "absolute", i.style.top = "0px", i.style.left = "0px", i.style.zIndex = "21", i.style.maxWidth = "600px", i.style.width = "100%", i.classList.add("three-mediapipe-rig"), document.body.appendChild(i);
731
+ const r = document.createElement("canvas"), m = r.getContext("2d"), c = new We(m);
732
+ r.style.zIndex = "22", r.style.position = "absolute", r.style.top = "0px", r.style.left = "0px", r.style.pointerEvents = "none", r.style.maxWidth = "100%", i.appendChild(r);
733
+ function f(d) {
734
+ m.save(), m.clearRect(0, 0, r.width, r.height), n == null || n.predict(d, c), s == null || s.left.predict(d, c), s == null || s.right.predict(d, c), a == null || a.predict(d, c), m.restore();
735
+ }
736
+ function k() {
737
+ e = document.createElement("video"), i.appendChild(e);
738
+ let d = -1;
739
+ e.style.zIndex = "21", e.style.position = "absolute", e.style.top = "0px", e.style.left = "0px", e.style.height = "auto", e.style.maxWidth = "100%", e.style.display = "block", o.debugVideo && (e.src = o.debugVideo, e.controls = !0, e.loop = !0, e.muted = !0, e.controls = !0, e.play());
740
+ function h() {
741
+ d !== e.currentTime && e.readyState >= 2 && (f(e), d = e.currentTime), window.requestAnimationFrame(h);
742
+ }
743
+ e.addEventListener("loadeddata", () => {
744
+ e.width = e.videoWidth * o.displayScale, e.height = e.videoHeight * o.displayScale, r.width = e.videoWidth, r.height = e.videoHeight, r.style.height = e.height + "px", r.style.width = e.width + "px", window.requestAnimationFrame(h);
745
+ });
746
+ }
747
+ if (o.debugFrame) {
748
+ const d = document.createElement("img");
749
+ d.src = o.debugFrame, d.style.zIndex = "21", d.style.position = "absolute", d.style.top = "0px", d.style.left = "0px", i.appendChild(d), d.addEventListener("load", () => {
750
+ d.width = d.naturalWidth * o.displayScale, d.height = d.naturalHeight * o.displayScale, r.width = d.naturalWidth, r.height = d.naturalWidth, r.style.width = d.width + "px", r.style.height = d.height + "px";
751
+ function h() {
752
+ f(d);
753
+ }
754
+ window.requestAnimationFrame(h);
755
+ });
756
+ } else o.debugVideo && k();
757
+ let x;
758
+ return {
759
+ poseTracker: n,
760
+ handsTracker: s,
761
+ faceTracker: a,
762
+ video: e,
763
+ canvas: r,
764
+ domElement: i,
765
+ start: async () => {
766
+ let d = !1;
767
+ if (!ft())
768
+ throw new Error("Webcam not supported");
769
+ e || k();
770
+ let h;
771
+ function w(L) {
772
+ d || (console.warn("Camera track ended, attempting recovery..."), E(L), y(L));
773
+ }
774
+ function E(L) {
775
+ h == null || h.getVideoTracks().forEach((p) => p.stop()), h = void 0, L.srcObject = null;
776
+ }
777
+ async function y(L, p = 0) {
778
+ const T = Math.min(1e3 * 2 ** p, 16e3);
779
+ if (p >= 3)
780
+ throw new Error("Camera recovery failed after max attempts");
781
+ if (await new Promise((S) => setTimeout(S, T)), !d)
782
+ try {
783
+ await v(L);
784
+ } catch (S) {
785
+ await g(S, L, p + 1);
786
+ }
787
+ }
788
+ async function v(L) {
789
+ h = await navigator.mediaDevices.getUserMedia({ video: !0 }), L.srcObject = h, await L.play(), h.getVideoTracks().forEach((p) => {
790
+ p.addEventListener("ended", () => w(L));
791
+ });
792
+ }
793
+ async function g(L, p, A = 0) {
794
+ if (L instanceof DOMException)
795
+ switch (L.name) {
796
+ case "NotAllowedError":
797
+ throw new Error("Permission denied — prompt user to allow camera");
798
+ case "NotFoundError":
799
+ console.error("No camera found — retry when device is connected"), await y(p, A + 1);
800
+ break;
801
+ case "NotReadableError":
802
+ throw new Error("Camera in use by another app");
803
+ default:
804
+ throw new Error("Camera error: " + L.message);
805
+ }
806
+ else
807
+ throw new Error("Unknown camera error: " + L);
808
+ }
809
+ return await y(e), x = () => {
810
+ d = !0, E(e), x = void 0;
811
+ }, {
812
+ stop: x
813
+ };
814
+ },
815
+ bind: (d, h) => {
816
+ if (h = h || ke, !n) throw new Error("Pose tracker not initialized");
817
+ if (!s) throw new Error("Hands tracker not initialized");
818
+ if (!a) throw new Error("Face tracker not initialized");
819
+ const w = n.bind(d, h), E = s.left.bind(d, h), y = s.right.bind(d, h);
820
+ let v;
821
+ const g = a == null ? void 0 : a.bind(d);
822
+ d.traverse((p) => {
823
+ p instanceof u.Mesh && p.name.indexOf(h.faceMesh) === 0 && (p.frustumCulled = !1, v = a == null ? void 0 : a.bindShapeKeys(p));
824
+ });
825
+ const L = ut(d, h);
826
+ return {
827
+ /**
828
+ * Will save the tracked movement of the rig to an animation clip.
829
+ * Only the bones moved by the bone mapping will be recorded.
830
+ */
831
+ startRecording: L.start,
832
+ stopRecording: L.stop,
833
+ isRecording: () => L.isRecording(),
834
+ update: (p) => {
835
+ w.update(p), E.update(p), y.update(p), v == null || v.update(p), g == null || g.update(p), L.isRecording() && L.captureFrame();
836
+ }
837
+ };
838
+ },
839
+ setVideoFromSource: (d) => {
840
+ x == null || x(), e || k(), e.src = d instanceof File ? URL.createObjectURL(d) : d, e.controls = !0, e.loop = !0, e.muted = !0, e.controls = !0, e.play();
841
+ },
842
+ async setVideoFromWebcam() {
843
+ if (e || k(), x)
844
+ throw new Error("Webcam already started");
845
+ return await this.start();
846
+ }
847
+ };
848
+ }
849
+ export {
850
+ De as FACE_LANDMARKS_COUNT,
851
+ Ce as createFaceLandmarksIndexAttribute,
852
+ Pt as setupTracker
853
+ };