@sage-rsc/talking-head-react 1.2.2 → 1.3.0
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/dist/index.cjs +2 -2
- package/dist/index.js +947 -890
- package/package.json +1 -1
- package/src/components/SimpleTalkingAvatar.jsx +116 -2
- package/src/utils/animationLoader.js +94 -0
package/dist/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { jsxs as Pe, jsx as
|
|
2
|
-
import { forwardRef as Me, useRef as
|
|
3
|
-
import * as
|
|
1
|
+
import { jsxs as Pe, jsx as ye } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as Me, useRef as W, useState as pe, useEffect as ce, useCallback as N, useImperativeHandle as Fe, useLayoutEffect as Xe } from "react";
|
|
3
|
+
import * as y from "three";
|
|
4
4
|
import { OrbitControls as Ye } from "three/addons/controls/OrbitControls.js";
|
|
5
5
|
import { GLTFLoader as je } from "three/addons/loaders/GLTFLoader.js";
|
|
6
6
|
import { DRACOLoader as Qe } from "three/addons/loaders/DRACOLoader.js";
|
|
7
7
|
import { FBXLoader as De } from "three/addons/loaders/FBXLoader.js";
|
|
8
8
|
import { RoomEnvironment as qe } from "three/addons/environments/RoomEnvironment.js";
|
|
9
9
|
import _e from "three/addons/libs/stats.module.js";
|
|
10
|
-
let m,
|
|
11
|
-
const
|
|
12
|
-
new
|
|
13
|
-
new
|
|
14
|
-
new
|
|
15
|
-
const
|
|
16
|
-
new
|
|
17
|
-
const He = new
|
|
10
|
+
let m, ue, he;
|
|
11
|
+
const C = [0, 0, 0, 0], T = new y.Vector3(), ze = new y.Vector3(), ae = new y.Vector3(), Ce = new y.Vector3();
|
|
12
|
+
new y.Plane();
|
|
13
|
+
new y.Ray();
|
|
14
|
+
new y.Euler();
|
|
15
|
+
const re = new y.Quaternion(), Oe = new y.Quaternion(), fe = new y.Matrix4(), xe = new y.Matrix4();
|
|
16
|
+
new y.Vector3();
|
|
17
|
+
const He = new y.Vector3(0, 0, 1), Ke = new y.Vector3(1, 0, 0), Je = new y.Vector3(0, 1, 0), $e = new y.Vector3(0, 0, 1);
|
|
18
18
|
class et {
|
|
19
19
|
constructor(t = null) {
|
|
20
20
|
this.opt = Object.assign({
|
|
@@ -338,7 +338,7 @@ class et {
|
|
|
338
338
|
ea: [0, 0, 0, 0]
|
|
339
339
|
// External acceleration [m/s^2]
|
|
340
340
|
};
|
|
341
|
-
u.boneParent.matrixWorld.decompose(T,
|
|
341
|
+
u.boneParent.matrixWorld.decompose(T, re, ae), T.copy(He).applyQuaternion(re).setY(0).normalize(), re.premultiply(Oe.setFromUnitVectors(He, T).invert()).normalize(), u.qWorldInverseYaw = re.clone().normalize(), this.data.push(u), this.dict[h] = u;
|
|
342
342
|
try {
|
|
343
343
|
this.setValue(h, "type", s.type), this.setValue(h, "stiffness", s.stiffness), this.setValue(h, "damping", s.damping), this.setValue(h, "external", s.external), this.setValue(h, "limits", s.limits), this.setValue(h, "excludes", s.excludes), this.setValue(h, "deltaLocal", s.deltaLocal), this.setValue(h, "deltaWorld", s.deltaWorld), this.setValue(h, "pivot", s.pivot), this.setValue(h, "helper", s.helper);
|
|
344
344
|
} catch (a) {
|
|
@@ -356,22 +356,22 @@ class et {
|
|
|
356
356
|
for (this.timerMs += t, t > 1e3 && (this.timerMs = 0), t /= 1e3, e = 0, i = this.objectsUpdate.length; e < i; e++)
|
|
357
357
|
o = this.objectsUpdate[e], o.updateMatrix(), o.parent === null ? o.matrixWorld.copy(o.matrix) : o.matrixWorld.multiplyMatrices(o.parent.matrixWorld, o.matrix), o.matrixWorldNeedsUpdate = !1;
|
|
358
358
|
for (e = 0, i = this.data.length; e < i; e++) {
|
|
359
|
-
if (o = this.data[e], T.copy(o.vWorld), fe.copy(o.boneParent.matrixWorld), xe.copy(fe).invert(), o.vWorld.setFromMatrixPosition(fe), T.applyMatrix4(xe), T.length() > 0.5 && (console.info("Info: Unrealistic jump of " + T.length().toFixed(2) + " meters."), T.setLength(0.5)), T.applyQuaternion(o.bone.quaternion),
|
|
359
|
+
if (o = this.data[e], T.copy(o.vWorld), fe.copy(o.boneParent.matrixWorld), xe.copy(fe).invert(), o.vWorld.setFromMatrixPosition(fe), T.applyMatrix4(xe), T.length() > 0.5 && (console.info("Info: Unrealistic jump of " + T.length().toFixed(2) + " meters."), T.setLength(0.5)), T.applyQuaternion(o.bone.quaternion), C[0] = T.x, C[1] = T.y, C[2] = -T.z, C[3] = T.length() / 3, o.children)
|
|
360
360
|
for (n = 0, s = o.children.length; n < s; n++)
|
|
361
|
-
m = o.children[n],
|
|
362
|
-
if (m = this.opt.sensitivityFactor,
|
|
363
|
-
o.vBasis.x +
|
|
364
|
-
o.vBasis.y +
|
|
365
|
-
o.vBasis.z +
|
|
366
|
-
), T.applyMatrix4(fe), T.x += m[0], T.y += m[1], T.z += m[2], T.applyMatrix4(xe),
|
|
361
|
+
m = o.children[n], C[0] -= m.v[0] * t / 3, C[1] -= m.v[1] * t / 3, C[2] += m.v[2] * t / 3, C[3] -= m.v[3] * t / 3;
|
|
362
|
+
if (m = this.opt.sensitivityFactor, C[0] *= o.ext * m, C[1] *= o.ext * m, C[2] *= o.ext * m, C[3] *= o.ext * m, o.isX && (m = C[0] / t, o.ea[0] = (m - o.ev[0]) / t, o.ev[0] = m, o.a[0] = -o.k[0] * o.p[0] - o.c[0] * o.v[0] - o.ea[0], o.p[0] += o.v[0] * t + o.a[0] * t * t / 2 + C[0], m = o.v[0] + o.a[0] * t / 2, m = -o.k[0] * o.p[0] - o.c[0] * m - o.ea[0], o.v[0] = o.v[0] + (m + o.a[0]) * t / 2), o.isY && (m = C[1] / t, o.ea[1] = (m - o.ev[1]) / t, o.ev[1] = m, o.a[1] = -o.k[1] * o.p[1] - o.c[1] * o.v[1] - o.ea[1], o.p[1] += o.v[1] * t + o.a[1] * t * t / 2 + C[1], m = o.v[1] + o.a[1] * t / 2, m = -o.k[1] * o.p[1] - o.c[1] * m - o.ea[1], o.v[1] = o.v[1] + (m + o.a[1]) * t / 2), o.isZ && (m = C[2] / t, o.ea[2] = (m - o.ev[2]) / t, o.ev[2] = m, o.a[2] = -o.k[2] * o.p[2] - o.c[2] * o.v[2] - o.ea[2], o.p[2] += o.v[2] * t + o.a[2] * t * t / 2 + C[2], m = o.v[2] + o.a[2] * t / 2, m = -o.k[2] * o.p[2] - o.c[2] * m - o.ea[2], o.v[2] = o.v[2] + (m + o.a[2]) * t / 2), o.isT && (m = C[3] / t, o.ea[3] = (m - o.ev[3]) / t, o.ev[3] = m, o.a[3] = -o.k[3] * o.p[3] - o.c[3] * o.v[3] - o.ea[3], o.p[3] += o.v[3] * t + o.a[3] * t * t / 2 + C[3], m = o.v[3] + o.a[3] * t / 2, m = -o.k[3] * o.p[3] - o.c[3] * m - o.ea[3], o.v[3] = o.v[3] + (m + o.a[3]) * t / 2), this.timerMs < this.opt.warmupMs && (o.v[0] *= 1e-4, o.p[0] *= 1e-4, o.v[1] *= 1e-4, o.p[1] *= 1e-4, o.v[2] *= 1e-4, o.p[2] *= 1e-4, o.v[3] *= 1e-4, o.p[3] *= 1e-4), C[0] = o.p[0], C[1] = o.p[1], C[2] = o.p[2], C[3] = o.p[3], m = this.opt.movementFactor, C[0] *= m, C[1] *= m, C[2] *= m, C[3] *= m, o.dl && (m = o.dl, C[0] += m[0], C[1] += m[1], C[2] += m[2]), o.dw && (m = o.dw, T.set(
|
|
363
|
+
o.vBasis.x + C[0],
|
|
364
|
+
o.vBasis.y + C[1],
|
|
365
|
+
o.vBasis.z + C[2]
|
|
366
|
+
), T.applyMatrix4(fe), T.x += m[0], T.y += m[1], T.z += m[2], T.applyMatrix4(xe), C[0] += T.x - o.vBasis.x, C[1] += T.y - o.vBasis.y, C[2] += T.z - o.vBasis.z), o.limits && this.opt.isLimits && (m = o.limits, m[0] && (m[0][0] !== null && C[0] < m[0][0] && (C[0] = m[0][0]), m[0][1] !== null && C[0] > m[0][1] && (C[0] = m[0][1])), m[1] && (m[1][0] !== null && C[1] < m[1][0] && (C[1] = m[1][0]), m[1][1] !== null && C[1] > m[1][1] && (C[1] = m[1][1])), m[2] && (m[2][0] !== null && C[2] < m[2][0] && (C[2] = m[2][0]), m[2][1] !== null && C[2] > m[2][1] && (C[2] = m[2][1])), m[3] && (m[3][0] !== null && C[3] < m[3][0] && (C[3] = m[3][0]), m[3][1] !== null && C[3] > m[3][1] && (C[3] = m[3][1]))), o.isPoint)
|
|
367
367
|
o.bone.position.set(
|
|
368
|
-
o.vBasis.x +
|
|
369
|
-
o.vBasis.y +
|
|
370
|
-
o.vBasis.z -
|
|
368
|
+
o.vBasis.x + C[0],
|
|
369
|
+
o.vBasis.y + C[1],
|
|
370
|
+
o.vBasis.z - C[2]
|
|
371
371
|
);
|
|
372
|
-
else if (o.boneParent.quaternion.copy(o.qBasis), o.pivot && this.opt.isPivots && (o.boneParent.updateWorldMatrix(!1, !1), o.boneParent.matrixWorld.decompose(T,
|
|
372
|
+
else if (o.boneParent.quaternion.copy(o.qBasis), o.pivot && this.opt.isPivots && (o.boneParent.updateWorldMatrix(!1, !1), o.boneParent.matrixWorld.decompose(T, re, ae), T.copy(He).applyQuaternion(re).setY(0).normalize(), re.premultiply(Oe.setFromUnitVectors(He, T).invert()).normalize(), o.boneParent.quaternion.multiply(re.invert()), o.boneParent.quaternion.multiply(o.qWorldInverseYaw)), o.isZ && (m = Math.atan(C[0] / o.l), re.setFromAxisAngle($e, -m), o.boneParent.quaternion.multiply(re)), o.isY && (m = o.l / 3, m = m * Math.tanh(C[1] / m), o.bone.position.setLength(o.l + m)), o.isX && (m = Math.atan(C[2] / o.l), re.setFromAxisAngle(Ke, -m), o.boneParent.quaternion.multiply(re)), o.isT && (m = 1.5 * Math.tanh(C[3] * 1.5), re.setFromAxisAngle(Je, -m), o.boneParent.quaternion.multiply(re)), o.boneParent.updateWorldMatrix(!1, !0), o.excludes && this.opt.isExcludes)
|
|
373
373
|
for (n = 0, s = o.excludes.length; n < s; n++)
|
|
374
|
-
m = o.excludes[n],
|
|
374
|
+
m = o.excludes[n], ae.set(0, 0, 0), m.deltaLocal && (ae.x += m.deltaLocal[0], ae.y += m.deltaLocal[1], ae.z += m.deltaLocal[2]), ae.applyMatrix4(m.bone.matrixWorld), xe.copy(o.boneParent.matrixWorld).invert(), ae.applyMatrix4(xe), T.copy(o.bone.position), !(T.distanceToSquared(ae) >= m.radiusSq) && (he = T.length(), ue = ae.length(), !(ue > m.radius + he) && (ue < Math.abs(m.radius - he) || (ue = (ue * ue + he * he - m.radiusSq) / (2 * ue), ae.normalize(), Ce.copy(ae).multiplyScalar(ue), ue = Math.sqrt(he * he - ue * ue), T.subVectors(T, Ce).projectOnPlane(ae).normalize().multiplyScalar(ue), ze.subVectors(o.vBasis, Ce).projectOnPlane(ae).normalize(), he = ze.dot(T), he < 0 && (he = Math.sqrt(ue * ue - he * he), ze.multiplyScalar(he), T.add(ze)), T.add(Ce).normalize(), ae.copy(o.bone.position).normalize(), re.setFromUnitVectors(ae, T), o.boneParent.quaternion.premultiply(re), o.boneParent.updateWorldMatrix(!1, !0))));
|
|
375
375
|
}
|
|
376
376
|
this.helpers.isActive && this.updateHelpers();
|
|
377
377
|
}
|
|
@@ -393,7 +393,7 @@ class et {
|
|
|
393
393
|
i || (m.excludes.bones.push(n.bone), m.excludes.radii.push(n.radius), m.excludes.deltaLocals.push(n.deltaLocal ? [...n.deltaLocal] : null), m.excludes.objects.push(null));
|
|
394
394
|
}));
|
|
395
395
|
}), m = this.helpers.excludes, this.opt.isExcludes && m.bones.length && m.bones.forEach((e, n) => {
|
|
396
|
-
const i = new
|
|
396
|
+
const i = new y.SphereGeometry(m.radii[n], 6, 6), s = new y.MeshBasicMaterial({
|
|
397
397
|
depthTest: !1,
|
|
398
398
|
depthWrite: !1,
|
|
399
399
|
toneMapped: !1,
|
|
@@ -401,18 +401,18 @@ class et {
|
|
|
401
401
|
wireframe: !0,
|
|
402
402
|
color: this.opt.helperExcludesColor
|
|
403
403
|
});
|
|
404
|
-
m.objects[n] = new
|
|
404
|
+
m.objects[n] = new y.Mesh(i, s), m.objects[n].renderOrder = 997, e.add(m.objects[n]), m.deltaLocals[n] && m.objects[n].position.set(
|
|
405
405
|
m.deltaLocals[n][0],
|
|
406
406
|
m.deltaLocals[n][1],
|
|
407
407
|
m.deltaLocals[n][2]
|
|
408
408
|
);
|
|
409
409
|
}), m = this.helpers.points, m.bones.length) {
|
|
410
410
|
this.helpers.isActive = !0;
|
|
411
|
-
const e = new
|
|
412
|
-
e.setAttribute("position", new
|
|
413
|
-
const i = new
|
|
414
|
-
e.setAttribute("color", new
|
|
415
|
-
const l = new
|
|
411
|
+
const e = new y.BufferGeometry(), n = m.bones.map((h) => [0, 0, 0]).flat();
|
|
412
|
+
e.setAttribute("position", new y.Float32BufferAttribute(n, 3));
|
|
413
|
+
const i = new y.Color(this.opt.helperBoneColor1), s = new y.Color(this.opt.helperBoneColor2), o = m.pivots.map((h) => h && this.opt.isPivots ? [s.r, s.g, s.b] : [i.r, i.g, i.b]).flat();
|
|
414
|
+
e.setAttribute("color", new y.Float32BufferAttribute(o, 3));
|
|
415
|
+
const l = new y.PointsMaterial({
|
|
416
416
|
depthTest: !1,
|
|
417
417
|
depthWrite: !1,
|
|
418
418
|
toneMapped: !1,
|
|
@@ -420,21 +420,21 @@ class et {
|
|
|
420
420
|
size: 0.2,
|
|
421
421
|
vertexColors: !0
|
|
422
422
|
});
|
|
423
|
-
m.object = new
|
|
423
|
+
m.object = new y.Points(e, l), m.object.renderOrder = 998, m.object.matrix = this.armature.matrixWorld, m.object.matrixAutoUpdate = !1, this.scene.add(m.object);
|
|
424
424
|
}
|
|
425
425
|
if (m = this.helpers.lines, m.bones.length) {
|
|
426
|
-
const e = new
|
|
427
|
-
e.setAttribute("position", new
|
|
428
|
-
const i = new
|
|
429
|
-
e.setAttribute("color", new
|
|
430
|
-
const l = new
|
|
426
|
+
const e = new y.BufferGeometry(), n = m.bones.map((h) => [0, 0, 0, 0, 0, 0]).flat();
|
|
427
|
+
e.setAttribute("position", new y.Float32BufferAttribute(n, 3));
|
|
428
|
+
const i = new y.Color(this.opt.helperLinkColor1), s = new y.Color(this.opt.helperLinkColor2), o = m.bones.map((h) => [i.r, i.g, i.b, s.r, s.g, s.b]).flat();
|
|
429
|
+
e.setAttribute("color", new y.Float32BufferAttribute(o, 3));
|
|
430
|
+
const l = new y.LineBasicMaterial({
|
|
431
431
|
vertexColors: !0,
|
|
432
432
|
depthTest: !1,
|
|
433
433
|
depthWrite: !1,
|
|
434
434
|
toneMapped: !1,
|
|
435
435
|
transparent: !0
|
|
436
436
|
});
|
|
437
|
-
m.object = new
|
|
437
|
+
m.object = new y.LineSegments(e, l), m.object.renderOrder = 999, m.object.matrix = this.armature.matrixWorld, m.object.matrixAutoUpdate = !1, this.scene.add(m.object);
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
440
|
/**
|
|
@@ -606,10 +606,10 @@ class tt {
|
|
|
606
606
|
for (let h = 0; h < e; h += i) {
|
|
607
607
|
let r = 1, u = 0;
|
|
608
608
|
for (let a = 0; a < i / 2; a++) {
|
|
609
|
-
const d = n[(h + a) * 2], c = n[(h + a) * 2 + 1], g = n[(h + a + i / 2) * 2] * r - n[(h + a + i / 2) * 2 + 1] * u,
|
|
610
|
-
n[(h + a) * 2] = d + g, n[(h + a) * 2 + 1] = c +
|
|
611
|
-
const
|
|
612
|
-
r =
|
|
609
|
+
const d = n[(h + a) * 2], c = n[(h + a) * 2 + 1], g = n[(h + a + i / 2) * 2] * r - n[(h + a + i / 2) * 2 + 1] * u, x = n[(h + a + i / 2) * 2] * u + n[(h + a + i / 2) * 2 + 1] * r;
|
|
610
|
+
n[(h + a) * 2] = d + g, n[(h + a) * 2 + 1] = c + x, n[(h + a + i / 2) * 2] = d - g, n[(h + a + i / 2) * 2 + 1] = c - x;
|
|
611
|
+
const f = r * o - u * l, k = r * l + u * o;
|
|
612
|
+
r = f, u = k;
|
|
613
613
|
}
|
|
614
614
|
}
|
|
615
615
|
}
|
|
@@ -2629,14 +2629,14 @@ const ct = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
|
2629
2629
|
fr: rt,
|
|
2630
2630
|
fi: ut,
|
|
2631
2631
|
lt: ct
|
|
2632
|
-
},
|
|
2633
|
-
new
|
|
2634
|
-
new
|
|
2635
|
-
new
|
|
2636
|
-
new
|
|
2637
|
-
const mt = new
|
|
2638
|
-
new
|
|
2639
|
-
new
|
|
2632
|
+
}, J = new y.Quaternion(), G = new y.Euler(), ve = new y.Vector3(), Re = new y.Vector3(), We = new y.Box3();
|
|
2633
|
+
new y.Matrix4();
|
|
2634
|
+
new y.Matrix4();
|
|
2635
|
+
new y.Vector3();
|
|
2636
|
+
new y.Vector3(0, 0, 1);
|
|
2637
|
+
const mt = new y.Vector3(1, 0, 0);
|
|
2638
|
+
new y.Vector3(0, 1, 0);
|
|
2639
|
+
new y.Vector3(0, 0, 1);
|
|
2640
2640
|
class Be {
|
|
2641
2641
|
/**
|
|
2642
2642
|
* Avatar.
|
|
@@ -4073,22 +4073,22 @@ class Be {
|
|
|
4073
4073
|
if (this.isAvatarOnly = this.opt.avatarOnly, this.isAvatarOnly)
|
|
4074
4074
|
this.scene = this.opt.avatarOnlyScene, this.camera = this.opt.avatarOnlyCamera;
|
|
4075
4075
|
else {
|
|
4076
|
-
this.renderer = new
|
|
4077
|
-
new
|
|
4076
|
+
this.renderer = new y.WebGLRenderer({ antialias: !0, alpha: !0 }), this.renderer.setPixelRatio(this.opt.modelPixelRatio * window.devicePixelRatio), this.renderer.setSize(this.nodeAvatar.clientWidth, this.nodeAvatar.clientHeight), this.renderer.outputColorSpace = y.SRGBColorSpace, this.renderer.toneMapping = y.ACESFilmicToneMapping, this.renderer.shadowMap.enabled = !1, this.nodeAvatar.appendChild(this.renderer.domElement), this.camera = new y.PerspectiveCamera(10, this.nodeAvatar.clientWidth / this.nodeAvatar.clientHeight, 0.1, 2e3), this.scene = new y.Scene(), this.lightAmbient = new y.AmbientLight(
|
|
4077
|
+
new y.Color(this.opt.lightAmbientColor),
|
|
4078
4078
|
this.opt.lightAmbientIntensity
|
|
4079
|
-
), this.lightDirect = new
|
|
4080
|
-
new
|
|
4079
|
+
), this.lightDirect = new y.DirectionalLight(
|
|
4080
|
+
new y.Color(this.opt.lightDirectColor),
|
|
4081
4081
|
this.opt.lightDirectIntensity
|
|
4082
|
-
), this.lightSpot = new
|
|
4083
|
-
new
|
|
4082
|
+
), this.lightSpot = new y.SpotLight(
|
|
4083
|
+
new y.Color(this.opt.lightSpotColor),
|
|
4084
4084
|
this.opt.lightSpotIntensity,
|
|
4085
4085
|
0,
|
|
4086
4086
|
this.opt.lightSpotDispersion
|
|
4087
4087
|
), this.setLighting(this.opt);
|
|
4088
|
-
const l = new
|
|
4088
|
+
const l = new y.PMREMGenerator(this.renderer);
|
|
4089
4089
|
l.compileEquirectangularShader(), this.scene.environment = l.fromScene(new qe()).texture, this.resizeobserver = new ResizeObserver(this.onResize.bind(this)), this.resizeobserver.observe(this.nodeAvatar), this.controls = new Ye(this.camera, this.renderer.domElement), this.controls.enableZoom = this.opt.cameraZoomEnable, this.controls.enableRotate = this.opt.cameraRotateEnable, this.controls.enablePan = this.opt.cameraPanEnable, this.controls.minDistance = 2, this.controls.maxDistance = 2e3, this.controls.autoRotateSpeed = 0, this.controls.autoRotate = !1, this.controls.update(), this.cameraClock = null;
|
|
4090
4090
|
}
|
|
4091
|
-
this.ikMesh = new
|
|
4091
|
+
this.ikMesh = new y.SkinnedMesh();
|
|
4092
4092
|
const s = {
|
|
4093
4093
|
LeftShoulder: null,
|
|
4094
4094
|
LeftArm: "LeftShoulder",
|
|
@@ -4102,9 +4102,9 @@ class Be {
|
|
|
4102
4102
|
RightHandMiddle1: "RightHand"
|
|
4103
4103
|
}, o = [];
|
|
4104
4104
|
Object.entries(s).forEach((l, h) => {
|
|
4105
|
-
const r = new
|
|
4105
|
+
const r = new y.Bone();
|
|
4106
4106
|
r.name = l[0], l[1] ? this.ikMesh.getObjectByName(l[1]).add(r) : this.ikMesh.add(r), o.push(r);
|
|
4107
|
-
}), this.ikMesh.bind(new
|
|
4107
|
+
}), this.ikMesh.bind(new y.Skeleton(o)), this.dynamicbones = new et(), this.isStreaming = !1, this.streamWorkletNode = null, this.streamAudioStartTime = null, this.streamWaitForAudioChunks = !0, this.streamLipsyncLang = null, this.streamLipsyncType = "visemes", this.streamLipsyncQueue = [];
|
|
4108
4108
|
}
|
|
4109
4109
|
/**
|
|
4110
4110
|
* Helper that re/creates the audio context and the other nodes.
|
|
@@ -4194,7 +4194,7 @@ class Be {
|
|
|
4194
4194
|
for (let [n, i] of Object.entries(t)) {
|
|
4195
4195
|
const s = n.split(".");
|
|
4196
4196
|
let o = Array.isArray(i.x) ? this.gaussianRandom(...i.x) : i.x, l = Array.isArray(i.y) ? this.gaussianRandom(...i.y) : i.y, h = Array.isArray(i.z) ? this.gaussianRandom(...i.z) : i.z;
|
|
4197
|
-
s[1] === "position" || s[1] === "scale" ? e[n] = new
|
|
4197
|
+
s[1] === "position" || s[1] === "scale" ? e[n] = new y.Vector3(o, l, h) : s[1] === "rotation" ? (n = s[0] + ".quaternion", e[n] = new y.Quaternion().setFromEuler(new y.Euler(o, l, h, "XYZ")).normalize()) : s[1] === "quaternion" && (e[n] = new y.Quaternion(o, l, h, i.w).normalize());
|
|
4198
4198
|
}
|
|
4199
4199
|
return e;
|
|
4200
4200
|
}
|
|
@@ -4226,15 +4226,15 @@ class Be {
|
|
|
4226
4226
|
for (const [r, u] of Object.entries(n))
|
|
4227
4227
|
if (s.morphTargetDictionary.hasOwnProperty(r)) {
|
|
4228
4228
|
const a = s.morphTargetDictionary[r], d = o.morphAttributes.position[a], c = o.morphAttributes.normal?.[a];
|
|
4229
|
-
l || (l = new
|
|
4229
|
+
l || (l = new y.Float32BufferAttribute(d.count * 3, 3), c && (h = new y.Float32BufferAttribute(d.count * 3, 3)));
|
|
4230
4230
|
for (let g = 0; g < d.count; g++) {
|
|
4231
|
-
const
|
|
4232
|
-
l.setXYZ(g,
|
|
4231
|
+
const x = l.getX(g) + d.getX(g) * u, f = l.getY(g) + d.getY(g) * u, k = l.getZ(g) + d.getZ(g) * u;
|
|
4232
|
+
l.setXYZ(g, x, f, k);
|
|
4233
4233
|
}
|
|
4234
4234
|
if (c)
|
|
4235
4235
|
for (let g = 0; g < d.count; g++) {
|
|
4236
|
-
const
|
|
4237
|
-
h.setXYZ(g,
|
|
4236
|
+
const x = h.getX(g) + c.getX(g) * u, f = h.getY(g) + c.getY(g) * u, k = h.getZ(g) + c.getZ(g) * u;
|
|
4237
|
+
h.setXYZ(g, x, f, k);
|
|
4238
4238
|
}
|
|
4239
4239
|
}
|
|
4240
4240
|
if (l) {
|
|
@@ -4314,7 +4314,7 @@ class Be {
|
|
|
4314
4314
|
console.error("Dynamic bones setup failed: " + r);
|
|
4315
4315
|
}
|
|
4316
4316
|
this.objectLeftToeBase = this.armature.getObjectByName("LeftToeBase"), this.objectRightToeBase = this.armature.getObjectByName("RightToeBase"), this.objectLeftEye = this.armature.getObjectByName("LeftEye"), this.objectRightEye = this.armature.getObjectByName("RightEye"), this.objectLeftArm = this.armature.getObjectByName("LeftArm"), this.objectRightArm = this.armature.getObjectByName("RightArm"), this.objectHips = this.armature.getObjectByName("Hips"), this.objectHead = this.armature.getObjectByName("Head"), this.objectNeck = this.armature.getObjectByName("Neck");
|
|
4317
|
-
const h = new
|
|
4317
|
+
const h = new y.Vector3();
|
|
4318
4318
|
this.objectLeftEye.getWorldPosition(h), this.avatarHeight = h.y + 0.2, this.viewName || this.setView(this.opt.cameraView), this.setMood(this.avatar.avatarMood || this.moodName || this.opt.avatarMood), this.avatar.body === "M" && this.poseTemplates.wide && (this.poseName = "wide", this.setPoseFromTemplate(this.poseTemplates.wide, 0), console.log("Set initial male-appropriate pose: wide")), this.initializeFBXAnimationLoader(), this.bodyMovement && this.bodyMovement !== "idle" && this.applyBodyMovementAnimation(), this.start();
|
|
4319
4319
|
}
|
|
4320
4320
|
/**
|
|
@@ -4358,14 +4358,14 @@ class Be {
|
|
|
4358
4358
|
default:
|
|
4359
4359
|
a += 12, u = u * a;
|
|
4360
4360
|
}
|
|
4361
|
-
r = r * a, this.controlsEnd = new
|
|
4361
|
+
r = r * a, this.controlsEnd = new y.Vector3(r, u, 0), this.cameraEnd = new y.Vector3(r, u, a).applyEuler(new y.Euler(o, l, 0)), this.cameraClock === null && (this.controls.target.copy(this.controlsEnd), this.camera.position.copy(this.cameraEnd)), this.controlsStart = this.controls.target.clone(), this.cameraStart = this.camera.position.clone(), this.cameraClock = 0;
|
|
4362
4362
|
}
|
|
4363
4363
|
/**
|
|
4364
4364
|
* Change light colors and intensities.
|
|
4365
4365
|
* @param {Object} opt Options
|
|
4366
4366
|
*/
|
|
4367
4367
|
setLighting(t) {
|
|
4368
|
-
this.isAvatarOnly || (t = t || {}, t.hasOwnProperty("lightAmbientColor") && this.lightAmbient.color.set(new
|
|
4368
|
+
this.isAvatarOnly || (t = t || {}, t.hasOwnProperty("lightAmbientColor") && this.lightAmbient.color.set(new y.Color(t.lightAmbientColor)), t.hasOwnProperty("lightAmbientIntensity") && (this.lightAmbient.intensity = t.lightAmbientIntensity, this.lightAmbient.visible = t.lightAmbientIntensity !== 0), t.hasOwnProperty("lightDirectColor") && this.lightDirect.color.set(new y.Color(t.lightDirectColor)), t.hasOwnProperty("lightDirectIntensity") && (this.lightDirect.intensity = t.lightDirectIntensity, this.lightDirect.visible = t.lightDirectIntensity !== 0), t.hasOwnProperty("lightDirectPhi") && t.hasOwnProperty("lightDirectTheta") && this.lightDirect.position.setFromSphericalCoords(2, t.lightDirectPhi, t.lightDirectTheta), t.hasOwnProperty("lightSpotColor") && this.lightSpot.color.set(new y.Color(t.lightSpotColor)), t.hasOwnProperty("lightSpotIntensity") && (this.lightSpot.intensity = t.lightSpotIntensity, this.lightSpot.visible = t.lightSpotIntensity !== 0), t.hasOwnProperty("lightSpotPhi") && t.hasOwnProperty("lightSpotTheta") && (this.lightSpot.position.setFromSphericalCoords(2, t.lightSpotPhi, t.lightSpotTheta), this.lightSpot.position.add(new y.Vector3(0, 1.5, 0))), t.hasOwnProperty("lightSpotDispersion") && (this.lightSpot.angle = t.lightSpotDispersion));
|
|
4369
4369
|
}
|
|
4370
4370
|
/**
|
|
4371
4371
|
* Render scene.
|
|
@@ -4398,9 +4398,9 @@ class Be {
|
|
|
4398
4398
|
updatePoseDelta() {
|
|
4399
4399
|
for (const [t, e] of Object.entries(this.poseDelta.props)) {
|
|
4400
4400
|
if (e.x === 0 && e.y === 0 && e.z === 0) continue;
|
|
4401
|
-
|
|
4401
|
+
G.set(e.x, e.y, e.z);
|
|
4402
4402
|
const n = this.poseAvatar.props[t];
|
|
4403
|
-
n.isQuaternion ? (
|
|
4403
|
+
n.isQuaternion ? (J.setFromEuler(G), n.multiply(J)) : n.isVector3 && n.add(G);
|
|
4404
4404
|
}
|
|
4405
4405
|
}
|
|
4406
4406
|
/**
|
|
@@ -4480,7 +4480,7 @@ class Be {
|
|
|
4480
4480
|
return Object.entries(t).forEach((i, s) => {
|
|
4481
4481
|
const o = i[0].split(".");
|
|
4482
4482
|
if (o[1] === "position" || o[1] === "rotation" || o[1] === "quaternion") {
|
|
4483
|
-
const l = o[1] === "quaternion" ? o[0] + ".rotation" : i[0], h = i[1].isQuaternion ? new
|
|
4483
|
+
const l = o[1] === "quaternion" ? o[0] + ".rotation" : i[0], h = i[1].isQuaternion ? new y.Euler().setFromQuaternion(i[1]) : i[1];
|
|
4484
4484
|
n += (s ? ", " : "") + "'" + l + "':{", n += "x:" + Math.round(h.x * e) / e, n += ", y:" + Math.round(h.y * e) / e, n += ", z:" + Math.round(h.z * e) / e, n += "}";
|
|
4485
4485
|
}
|
|
4486
4486
|
}), n += "}", n;
|
|
@@ -5107,9 +5107,9 @@ class Be {
|
|
|
5107
5107
|
g.newvalue = c[i];
|
|
5108
5108
|
else {
|
|
5109
5109
|
g.newvalue = c[i + 1];
|
|
5110
|
-
const
|
|
5111
|
-
let
|
|
5112
|
-
|
|
5110
|
+
const x = a.ts[i + 1] - a.ts[i];
|
|
5111
|
+
let f = 1;
|
|
5112
|
+
x > 1e-4 && (f = (this.animClock - a.ts[i]) / x), f < 1 && (g.easing && (f = g.easing(f)), g.newvalue = (1 - f) * c[i] + f * g.newvalue), g.ref && g.ref !== a.vs && g.ref.hasOwnProperty(d) && delete g.ref[d], g.ref = a.vs;
|
|
5113
5113
|
}
|
|
5114
5114
|
if (l)
|
|
5115
5115
|
switch (d) {
|
|
@@ -5157,7 +5157,7 @@ class Be {
|
|
|
5157
5157
|
{ link: "LeftForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -0.5, maxz: 3 },
|
|
5158
5158
|
{ link: "LeftArm", minx: -1.5, maxx: 1.5, miny: 0, maxy: 0, minz: -1, maxz: 3 }
|
|
5159
5159
|
]
|
|
5160
|
-
}, i.x ? new
|
|
5160
|
+
}, i.x ? new y.Vector3(i.x, i.y, i.z) : null, !0, i.d);
|
|
5161
5161
|
break;
|
|
5162
5162
|
case "handRight":
|
|
5163
5163
|
this.ikSolve({
|
|
@@ -5169,10 +5169,10 @@ class Be {
|
|
|
5169
5169
|
{ link: "RightForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -3, maxz: 0.5, maxAngle: 0.2 },
|
|
5170
5170
|
{ link: "RightArm", minx: -1.5, maxx: 1.5, miny: 0, maxy: 0, minz: -1, maxz: 3 }
|
|
5171
5171
|
]
|
|
5172
|
-
}, i.x ? new
|
|
5172
|
+
}, i.x ? new y.Vector3(i.x, i.y, i.z) : null, !0, i.d);
|
|
5173
5173
|
break;
|
|
5174
5174
|
}
|
|
5175
|
-
if ((h || r) && (
|
|
5175
|
+
if ((h || r) && (G.setFromQuaternion(this.poseAvatar.props["Head.quaternion"]), G.x = Math.max(-0.9, Math.min(0.9, 2 * G.x - 0.5)), G.y = Math.max(-0.9, Math.min(0.9, -2.5 * G.y)), h ? (Object.assign(this.mtAvatar.eyesLookDown, { system: G.x < 0 ? -G.x : 0, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyesLookUp, { system: G.x < 0 ? 0 : G.x, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookInLeft, { system: G.y < 0 ? -G.y : 0, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookOutLeft, { system: G.y < 0 ? 0 : G.y, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookInRight, { system: G.y < 0 ? 0 : G.y, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookOutRight, { system: G.y < 0 ? -G.y : 0, needsUpdate: !0 }), r && (n = -this.mtAvatar.bodyRotateY.value, i = this.gaussianRandom(-0.2, 0.2), this.animQueue.push(this.animFactory({
|
|
5176
5176
|
name: "headmove",
|
|
5177
5177
|
dt: [[1e3, 2e3], [1e3, 2e3, 1, 2], [1e3, 2e3], [1e3, 2e3, 1, 2]],
|
|
5178
5178
|
vs: {
|
|
@@ -5193,12 +5193,12 @@ class Be {
|
|
|
5193
5193
|
eyeLookOutRight: [null, 0],
|
|
5194
5194
|
eyeContact: [0]
|
|
5195
5195
|
}
|
|
5196
|
-
})))), e > 2 * this.animFrameDur && (e = 2 * this.animFrameDur), (this.viewName !== "full" || this.isAvatarOnly) && (n = this.mtRandomized[Math.floor(Math.random() * this.mtRandomized.length)], i = this.mtAvatar[n], i.needsUpdate || Object.assign(i, { base: (this.mood.baseline[n] || 0) + (1 + l / 255) * Math.random() / 5, needsUpdate: !0 })), this.updatePoseBase(this.animClock), this.mixer && this.mixer.update(e / 1e3 * this.mixer.timeScale), this.updatePoseDelta(), (this.isSpeaking || this.isListening) && h ? l > this.volumeMax ? (this.volumeHeadBase = 0.05, Math.random() > 0.6 && (this.volumeHeadTarget = -0.05 - Math.random() / 15), this.volumeMax = l) : (this.volumeMax *= 0.92, this.volumeHeadTarget = this.volumeHeadBase - 0.9 * (this.volumeHeadBase - this.volumeHeadTarget)) : (this.volumeHeadTarget = 0, this.volumeMax = 0), n = this.volumeHeadTarget - this.volumeHeadCurrent, i = Math.abs(n), i > 1e-4 && (o = i * (this.volumeHeadEasing(Math.min(1, this.volumeHeadVelocity * e / 1e3 / i) / 2 + 0.5) - 0.5), this.volumeHeadCurrent += Math.sign(n) * Math.min(i, o)), Math.abs(this.volumeHeadCurrent) > 1e-4 && (
|
|
5196
|
+
})))), e > 2 * this.animFrameDur && (e = 2 * this.animFrameDur), (this.viewName !== "full" || this.isAvatarOnly) && (n = this.mtRandomized[Math.floor(Math.random() * this.mtRandomized.length)], i = this.mtAvatar[n], i.needsUpdate || Object.assign(i, { base: (this.mood.baseline[n] || 0) + (1 + l / 255) * Math.random() / 5, needsUpdate: !0 })), this.updatePoseBase(this.animClock), this.mixer && this.mixer.update(e / 1e3 * this.mixer.timeScale), this.updatePoseDelta(), (this.isSpeaking || this.isListening) && h ? l > this.volumeMax ? (this.volumeHeadBase = 0.05, Math.random() > 0.6 && (this.volumeHeadTarget = -0.05 - Math.random() / 15), this.volumeMax = l) : (this.volumeMax *= 0.92, this.volumeHeadTarget = this.volumeHeadBase - 0.9 * (this.volumeHeadBase - this.volumeHeadTarget)) : (this.volumeHeadTarget = 0, this.volumeMax = 0), n = this.volumeHeadTarget - this.volumeHeadCurrent, i = Math.abs(n), i > 1e-4 && (o = i * (this.volumeHeadEasing(Math.min(1, this.volumeHeadVelocity * e / 1e3 / i) / 2 + 0.5) - 0.5), this.volumeHeadCurrent += Math.sign(n) * Math.min(i, o)), Math.abs(this.volumeHeadCurrent) > 1e-4 && (J.setFromAxisAngle(mt, this.volumeHeadCurrent), this.objectNeck.quaternion.multiply(J)), We.setFromObject(this.armature), this.objectLeftToeBase.getWorldPosition(ve), ve.sub(this.armature.position), this.objectRightToeBase.getWorldPosition(Re), Re.sub(this.armature.position), this.objectHips.position.y -= We.min.y / 2, this.objectHips.position.x -= (ve.x + Re.x) / 4, this.objectHips.position.z -= (ve.z + Re.z) / 2, this.dynamicbones.update(e), this.fbxAnimationLoader && this.fbxAnimationLoader.update(), this.opt.update && this.opt.update(e), this.updateMorphTargets(e), this.isAvatarOnly)
|
|
5197
5197
|
this.stats && this.stats.end();
|
|
5198
5198
|
else {
|
|
5199
5199
|
if (this.cameraClock !== null && this.cameraClock < 1e3) {
|
|
5200
5200
|
this.cameraClock += e, this.cameraClock > 1e3 && (this.cameraClock = 1e3);
|
|
5201
|
-
let a = new
|
|
5201
|
+
let a = new y.Spherical().setFromVector3(this.cameraStart), d = new y.Spherical().setFromVector3(this.cameraEnd);
|
|
5202
5202
|
a.phi += this.easing(this.cameraClock / 1e3) * (d.phi - a.phi), a.theta += this.easing(this.cameraClock / 1e3) * (d.theta - a.theta), a.radius += this.easing(this.cameraClock / 1e3) * (d.radius - a.radius), a.makeSafe(), this.camera.position.setFromSpherical(a), this.controlsStart.x !== this.controlsEnd.x ? this.controls.target.copy(this.controlsStart.lerp(this.controlsEnd, this.easing(this.cameraClock / 1e3))) : (a.setFromVector3(this.controlsStart), d.setFromVector3(this.controlsEnd), a.phi += this.easing(this.cameraClock / 1e3) * (d.phi - a.phi), a.theta += this.easing(this.cameraClock / 1e3) * (d.theta - a.theta), a.radius += this.easing(this.cameraClock / 1e3) * (d.radius - a.radius), a.makeSafe(), this.controls.target.setFromSpherical(a)), this.controls.update();
|
|
5203
5203
|
}
|
|
5204
5204
|
this.controls.autoRotate && this.controls.update(), this.stats && this.stats.end(), this.render();
|
|
@@ -5262,12 +5262,12 @@ class Be {
|
|
|
5262
5262
|
e = e || {};
|
|
5263
5263
|
const s = /[!\.\?\n\p{Extended_Pictographic}]/ug, o = /[ ]/ug, l = /[\p{L}\p{N},\.\p{Quotation_Mark}!€\$\+\p{Dash_Punctuation}%&\?]/ug, h = /[\p{Extended_Pictographic}]/ug, r = e.lipsyncLang || this.avatar.lipsyncLang || this.opt.lipsyncLang;
|
|
5264
5264
|
let u = "", a = "", d = 0, c = [], g = [];
|
|
5265
|
-
const
|
|
5266
|
-
for (let
|
|
5267
|
-
const
|
|
5268
|
-
let p =
|
|
5269
|
-
const
|
|
5270
|
-
if (p && !
|
|
5265
|
+
const x = Array.from(this.segmenter.segment(t), (f) => f.segment);
|
|
5266
|
+
for (let f = 0; f < x.length; f++) {
|
|
5267
|
+
const k = f === x.length - 1, O = x[f].match(l);
|
|
5268
|
+
let p = x[f].match(s);
|
|
5269
|
+
const B = x[f].match(h), H = x[f].match(o);
|
|
5270
|
+
if (p && !k && !B && x[f + 1].match(s) && (p = !1), n && (u += x[f]), O && (!i || i.every((v) => f < v[0] || f > v[1])) && (a += x[f]), (H || p || k) && (a.length && (a = this.lipsyncPreProcessText(a, r), a.length && c.push({
|
|
5271
5271
|
mark: d,
|
|
5272
5272
|
word: a
|
|
5273
5273
|
})), u.length && (g.push({
|
|
@@ -5278,31 +5278,31 @@ class Be {
|
|
|
5278
5278
|
subtitles: [u]
|
|
5279
5279
|
}
|
|
5280
5280
|
}), u = ""), a.length)) {
|
|
5281
|
-
const
|
|
5282
|
-
if (
|
|
5283
|
-
const
|
|
5284
|
-
for (let
|
|
5281
|
+
const v = this.lipsyncWordsToVisemes(a, r);
|
|
5282
|
+
if (v && v.visemes && v.visemes.length) {
|
|
5283
|
+
const L = v.times[v.visemes.length - 1] + v.durations[v.visemes.length - 1];
|
|
5284
|
+
for (let I = 0; I < v.visemes.length; I++)
|
|
5285
5285
|
g.push({
|
|
5286
5286
|
mark: d,
|
|
5287
5287
|
template: { name: "viseme" },
|
|
5288
|
-
ts: [(
|
|
5288
|
+
ts: [(v.times[I] - 0.6) / L, (v.times[I] + 0.5) / L, (v.times[I] + v.durations[I] + 0.5) / L],
|
|
5289
5289
|
vs: {
|
|
5290
|
-
["viseme_" +
|
|
5290
|
+
["viseme_" + v.visemes[I]]: [null, v.visemes[I] === "PP" || v.visemes[I] === "FF" ? 0.9 : 0.6, 0]
|
|
5291
5291
|
}
|
|
5292
5292
|
});
|
|
5293
5293
|
}
|
|
5294
5294
|
a = "", d++;
|
|
5295
5295
|
}
|
|
5296
|
-
if (p ||
|
|
5297
|
-
if (c.length ||
|
|
5298
|
-
const
|
|
5296
|
+
if (p || k) {
|
|
5297
|
+
if (c.length || k && g.length) {
|
|
5298
|
+
const v = {
|
|
5299
5299
|
anim: g
|
|
5300
5300
|
};
|
|
5301
|
-
n && (
|
|
5301
|
+
n && (v.onSubtitles = n), c.length && !e.avatarMute && (v.text = c, e.avatarMood && (v.mood = e.avatarMood), e.ttsLang && (v.lang = e.ttsLang), e.ttsVoice && (v.voice = e.ttsVoice), e.ttsRate && (v.rate = e.ttsRate), e.ttsVoice && (v.pitch = e.ttsPitch), e.ttsVolume && (v.volume = e.ttsVolume)), this.speechQueue.push(v), c = [], a = "", d = 0, g = [];
|
|
5302
5302
|
}
|
|
5303
|
-
if (
|
|
5304
|
-
let
|
|
5305
|
-
|
|
5303
|
+
if (B) {
|
|
5304
|
+
let v = this.animEmojis[x[f]];
|
|
5305
|
+
v && v.link && (v = this.animEmojis[v.link]), v && this.speechQueue.push({ emoji: v });
|
|
5306
5306
|
}
|
|
5307
5307
|
this.speechQueue.push({ break: 100 });
|
|
5308
5308
|
}
|
|
@@ -5395,15 +5395,15 @@ class Be {
|
|
|
5395
5395
|
const a = this.lipsyncPreProcessText(h, i), d = this.lipsyncWordsToVisemes(a, i);
|
|
5396
5396
|
if (d && d.visemes && d.visemes.length) {
|
|
5397
5397
|
const c = d.times[d.visemes.length - 1] + d.durations[d.visemes.length - 1], g = Math.min(u, Math.max(0, u - d.visemes.length * 150));
|
|
5398
|
-
let
|
|
5398
|
+
let x = 0.6 + this.convertRange(g, [0, u], [0, 0.4]);
|
|
5399
5399
|
if (u = Math.min(u, d.visemes.length * 200), c > 0)
|
|
5400
|
-
for (let
|
|
5401
|
-
const
|
|
5400
|
+
for (let f = 0; f < d.visemes.length; f++) {
|
|
5401
|
+
const k = r + d.times[f] / c * u, O = d.durations[f] / c * u;
|
|
5402
5402
|
o.push({
|
|
5403
5403
|
template: { name: "viseme" },
|
|
5404
|
-
ts: [
|
|
5404
|
+
ts: [k - Math.min(60, 2 * O / 3), k + Math.min(25, O / 2), k + O + Math.min(60, O / 2)],
|
|
5405
5405
|
vs: {
|
|
5406
|
-
["viseme_" + d.visemes[
|
|
5406
|
+
["viseme_" + d.visemes[f]]: [null, d.visemes[f] === "PP" || d.visemes[f] === "FF" ? 0.9 : x, 0]
|
|
5407
5407
|
}
|
|
5408
5408
|
});
|
|
5409
5409
|
}
|
|
@@ -5483,34 +5483,34 @@ class Be {
|
|
|
5483
5483
|
s.lang = o, s.rate = Math.max(0.1, Math.min(10, l)), s.pitch = Math.max(0, Math.min(2, h)), s.volume = Math.max(0, Math.min(1, r));
|
|
5484
5484
|
const u = speechSynthesis.getVoices(), a = t.voice || this.avatar.ttsVoice || this.opt.ttsVoice;
|
|
5485
5485
|
if (a && u.length > 0) {
|
|
5486
|
-
const p = u.find((
|
|
5486
|
+
const p = u.find((B) => B.name.includes(a) || B.lang === o);
|
|
5487
5487
|
p && (s.voice = p);
|
|
5488
5488
|
}
|
|
5489
|
-
const d = i.length * 100 / s.rate, c = this.audioCtx.createBuffer(1, this.audioCtx.sampleRate * (d / 1e3), this.audioCtx.sampleRate), g = this.avatar.lipsyncLang || this.opt.lipsyncLang || "en",
|
|
5489
|
+
const d = i.length * 100 / s.rate, c = this.audioCtx.createBuffer(1, this.audioCtx.sampleRate * (d / 1e3), this.audioCtx.sampleRate), g = this.avatar.lipsyncLang || this.opt.lipsyncLang || "en", x = this.lipsyncPreProcessText(i, g), f = this.lipsyncWordsToVisemes(x, g);
|
|
5490
5490
|
console.log("Browser TTS Lip-sync Debug:", {
|
|
5491
5491
|
text: i,
|
|
5492
5492
|
lipsyncLang: g,
|
|
5493
|
-
processedText:
|
|
5494
|
-
lipsyncData:
|
|
5495
|
-
hasVisemes:
|
|
5493
|
+
processedText: x,
|
|
5494
|
+
lipsyncData: f,
|
|
5495
|
+
hasVisemes: f && f.visemes && f.visemes.length > 0,
|
|
5496
5496
|
estimatedDuration: d
|
|
5497
5497
|
});
|
|
5498
|
-
const
|
|
5499
|
-
if (
|
|
5500
|
-
const p =
|
|
5501
|
-
for (let
|
|
5502
|
-
const
|
|
5503
|
-
|
|
5498
|
+
const k = [];
|
|
5499
|
+
if (f && f.visemes && f.visemes.length > 0) {
|
|
5500
|
+
const p = f.times[f.visemes.length - 1] + f.durations[f.visemes.length - 1];
|
|
5501
|
+
for (let B = 0; B < f.visemes.length; B++) {
|
|
5502
|
+
const H = f.visemes[B], v = f.times[B] / p, L = f.durations[B] / p, I = v * d, z = L * d;
|
|
5503
|
+
k.push({
|
|
5504
5504
|
template: { name: "viseme" },
|
|
5505
|
-
ts: [
|
|
5505
|
+
ts: [I - Math.min(60, 2 * z / 3), I + Math.min(25, z / 2), I + z + Math.min(60, z / 2)],
|
|
5506
5506
|
vs: {
|
|
5507
|
-
["viseme_" +
|
|
5507
|
+
["viseme_" + H]: [null, H === "PP" || H === "FF" ? 0.9 : 0.6, 0]
|
|
5508
5508
|
}
|
|
5509
5509
|
});
|
|
5510
5510
|
}
|
|
5511
5511
|
}
|
|
5512
|
-
const
|
|
5513
|
-
this.audioPlaylist.push({ anim:
|
|
5512
|
+
const O = [...t.anim, ...k];
|
|
5513
|
+
this.audioPlaylist.push({ anim: O, audio: c }), this.onSubtitles = t.onSubtitles || null, this.resetLips(), t.mood && this.setMood(t.mood), this.playAudio(), s.onend = () => {
|
|
5514
5514
|
e();
|
|
5515
5515
|
}, s.onerror = (p) => {
|
|
5516
5516
|
console.error("Speech synthesis error:", p.error), n(p.error);
|
|
@@ -5559,10 +5559,10 @@ class Be {
|
|
|
5559
5559
|
hasVisemes: c && c.visemes && c.visemes.length > 0
|
|
5560
5560
|
}), c && c.visemes && c.visemes.length > 0)
|
|
5561
5561
|
r = {
|
|
5562
|
-
visemes: c.visemes.map((g,
|
|
5562
|
+
visemes: c.visemes.map((g, x) => ({
|
|
5563
5563
|
viseme: g,
|
|
5564
|
-
startTime:
|
|
5565
|
-
endTime: (
|
|
5564
|
+
startTime: x * l.duration / c.visemes.length,
|
|
5565
|
+
endTime: (x + 1) * l.duration / c.visemes.length,
|
|
5566
5566
|
duration: l.duration / c.visemes.length,
|
|
5567
5567
|
intensity: 0.7
|
|
5568
5568
|
})),
|
|
@@ -5575,16 +5575,16 @@ class Be {
|
|
|
5575
5575
|
} catch (d) {
|
|
5576
5576
|
console.error("Text-based lip-sync failed, using fallback:", d);
|
|
5577
5577
|
const c = e.toLowerCase().split(/\s+/), g = [];
|
|
5578
|
-
for (const
|
|
5579
|
-
for (const
|
|
5580
|
-
let
|
|
5581
|
-
"aeiou".includes(
|
|
5578
|
+
for (const x of c)
|
|
5579
|
+
for (const f of x) {
|
|
5580
|
+
let k = "aa";
|
|
5581
|
+
"aeiou".includes(f) ? k = "aa" : "bp".includes(f) ? k = "PP" : "fv".includes(f) ? k = "FF" : "st".includes(f) ? k = "SS" : "dln".includes(f) ? k = "DD" : "kg".includes(f) ? k = "kk" : "rw".includes(f) && (k = "RR"), g.push(k);
|
|
5582
5582
|
}
|
|
5583
5583
|
r = {
|
|
5584
|
-
visemes: g.map((
|
|
5585
|
-
viseme:
|
|
5586
|
-
startTime:
|
|
5587
|
-
endTime: (
|
|
5584
|
+
visemes: g.map((x, f) => ({
|
|
5585
|
+
viseme: x,
|
|
5586
|
+
startTime: f * l.duration / g.length,
|
|
5587
|
+
endTime: (f + 1) * l.duration / g.length,
|
|
5588
5588
|
duration: l.duration / g.length,
|
|
5589
5589
|
intensity: 0.6
|
|
5590
5590
|
})),
|
|
@@ -5609,12 +5609,12 @@ class Be {
|
|
|
5609
5609
|
if (r.visemes && r.visemes.length > 0) {
|
|
5610
5610
|
console.log("ElevenLabs: Generating lip-sync animation from", r.visemes.length, "visemes");
|
|
5611
5611
|
for (let d = 0; d < r.visemes.length; d++) {
|
|
5612
|
-
const c = r.visemes[d], g = c.startTime * 1e3,
|
|
5612
|
+
const c = r.visemes[d], g = c.startTime * 1e3, x = c.duration * 1e3, f = c.intensity;
|
|
5613
5613
|
u.push({
|
|
5614
5614
|
template: { name: "viseme" },
|
|
5615
|
-
ts: [g - Math.min(60, 2 *
|
|
5615
|
+
ts: [g - Math.min(60, 2 * x / 3), g + Math.min(25, x / 2), g + x + Math.min(60, x / 2)],
|
|
5616
5616
|
vs: {
|
|
5617
|
-
["viseme_" + c.viseme]: [null,
|
|
5617
|
+
["viseme_" + c.viseme]: [null, f, 0]
|
|
5618
5618
|
}
|
|
5619
5619
|
});
|
|
5620
5620
|
}
|
|
@@ -5657,10 +5657,10 @@ class Be {
|
|
|
5657
5657
|
hasVisemes: c && c.visemes && c.visemes.length > 0
|
|
5658
5658
|
}), c && c.visemes && c.visemes.length > 0)
|
|
5659
5659
|
r = {
|
|
5660
|
-
visemes: c.visemes.map((g,
|
|
5660
|
+
visemes: c.visemes.map((g, x) => ({
|
|
5661
5661
|
viseme: g,
|
|
5662
|
-
startTime:
|
|
5663
|
-
endTime: (
|
|
5662
|
+
startTime: x * l.duration / c.visemes.length,
|
|
5663
|
+
endTime: (x + 1) * l.duration / c.visemes.length,
|
|
5664
5664
|
duration: l.duration / c.visemes.length,
|
|
5665
5665
|
intensity: 0.7
|
|
5666
5666
|
})),
|
|
@@ -5673,16 +5673,16 @@ class Be {
|
|
|
5673
5673
|
} catch (d) {
|
|
5674
5674
|
console.error("Text-based lip-sync failed, using fallback:", d);
|
|
5675
5675
|
const c = e.toLowerCase().split(/\s+/), g = [];
|
|
5676
|
-
for (const
|
|
5677
|
-
for (const
|
|
5678
|
-
let
|
|
5679
|
-
"aeiou".includes(
|
|
5676
|
+
for (const x of c)
|
|
5677
|
+
for (const f of x) {
|
|
5678
|
+
let k = "aa";
|
|
5679
|
+
"aeiou".includes(f) ? k = "aa" : "bp".includes(f) ? k = "PP" : "fv".includes(f) ? k = "FF" : "st".includes(f) ? k = "SS" : "dln".includes(f) ? k = "DD" : "kg".includes(f) ? k = "kk" : "rw".includes(f) && (k = "RR"), g.push(k);
|
|
5680
5680
|
}
|
|
5681
5681
|
r = {
|
|
5682
|
-
visemes: g.map((
|
|
5683
|
-
viseme:
|
|
5684
|
-
startTime:
|
|
5685
|
-
endTime: (
|
|
5682
|
+
visemes: g.map((x, f) => ({
|
|
5683
|
+
viseme: x,
|
|
5684
|
+
startTime: f * l.duration / g.length,
|
|
5685
|
+
endTime: (f + 1) * l.duration / g.length,
|
|
5686
5686
|
duration: l.duration / g.length,
|
|
5687
5687
|
intensity: 0.6
|
|
5688
5688
|
})),
|
|
@@ -5707,12 +5707,12 @@ class Be {
|
|
|
5707
5707
|
if (r.visemes && r.visemes.length > 0) {
|
|
5708
5708
|
console.log("Deepgram: Generating lip-sync animation from", r.visemes.length, "visemes");
|
|
5709
5709
|
for (let d = 0; d < r.visemes.length; d++) {
|
|
5710
|
-
const c = r.visemes[d], g = c.startTime * 1e3,
|
|
5710
|
+
const c = r.visemes[d], g = c.startTime * 1e3, x = c.duration * 1e3, f = c.intensity;
|
|
5711
5711
|
u.push({
|
|
5712
5712
|
template: { name: "viseme" },
|
|
5713
|
-
ts: [g - Math.min(60, 2 *
|
|
5713
|
+
ts: [g - Math.min(60, 2 * x / 3), g + Math.min(25, x / 2), g + x + Math.min(60, x / 2)],
|
|
5714
5714
|
vs: {
|
|
5715
|
-
["viseme_" + c.viseme]: [null,
|
|
5715
|
+
["viseme_" + c.viseme]: [null, f, 0]
|
|
5716
5716
|
}
|
|
5717
5717
|
});
|
|
5718
5718
|
}
|
|
@@ -5759,12 +5759,12 @@ class Be {
|
|
|
5759
5759
|
});
|
|
5760
5760
|
const r = [];
|
|
5761
5761
|
for (let a = 0; a < h.visemes.length; a++) {
|
|
5762
|
-
const d = h.visemes[a], c = d.startTime * 1e3, g = d.duration * 1e3,
|
|
5762
|
+
const d = h.visemes[a], c = d.startTime * 1e3, g = d.duration * 1e3, x = d.intensity;
|
|
5763
5763
|
r.push({
|
|
5764
5764
|
template: { name: "viseme" },
|
|
5765
5765
|
ts: [c - Math.min(60, 2 * g / 3), c + Math.min(25, g / 2), c + g + Math.min(60, g / 2)],
|
|
5766
5766
|
vs: {
|
|
5767
|
-
["viseme_" + d.viseme]: [null,
|
|
5767
|
+
["viseme_" + d.viseme]: [null, x, 0]
|
|
5768
5768
|
}
|
|
5769
5769
|
});
|
|
5770
5770
|
}
|
|
@@ -6050,10 +6050,10 @@ class Be {
|
|
|
6050
6050
|
let d = 0.6 + this.convertRange(a, [0, o], [0, 0.4]);
|
|
6051
6051
|
if (o = Math.min(o, r.visemes.length * 200), u > 0)
|
|
6052
6052
|
for (let c = 0; c < r.visemes.length; c++) {
|
|
6053
|
-
const g = e + s + r.times[c] / u * o,
|
|
6053
|
+
const g = e + s + r.times[c] / u * o, x = r.durations[c] / u * o;
|
|
6054
6054
|
this.animQueue.push({
|
|
6055
6055
|
template: { name: "viseme" },
|
|
6056
|
-
ts: [g - Math.min(60, 2 *
|
|
6056
|
+
ts: [g - Math.min(60, 2 * x / 3), g + Math.min(25, x / 2), g + x + Math.min(60, x / 2)],
|
|
6057
6057
|
vs: {
|
|
6058
6058
|
["viseme_" + r.visemes[c]]: [null, r.visemes[c] === "PP" || r.visemes[c] === "FF" ? 0.9 : d, 0]
|
|
6059
6059
|
}
|
|
@@ -6146,7 +6146,7 @@ class Be {
|
|
|
6146
6146
|
*/
|
|
6147
6147
|
lookAtCamera(t) {
|
|
6148
6148
|
let e;
|
|
6149
|
-
if (this.speakTo && (e = new
|
|
6149
|
+
if (this.speakTo && (e = new y.Vector3(), this.speakTo.objectLeftEye?.isObject3D ? (this.speakTo.armature.objectHead, this.speakTo.objectLeftEye.updateMatrixWorld(!0), this.speakTo.objectRightEye.updateMatrixWorld(!0), ve.setFromMatrixPosition(this.speakTo.objectLeftEye.matrixWorld), Re.setFromMatrixPosition(this.speakTo.objectRightEye.matrixWorld), e.addVectors(ve, Re).divideScalar(2)) : this.speakTo.isObject3D ? this.speakTo.getWorldPosition(e) : this.speakTo.isVector3 ? e.set(this.speakTo) : this.speakTo.x && this.speakTo.y && this.speakTo.z && e.set(this.speakTo.x, this.speakTo.y, this.speakTo.z)), !e) {
|
|
6150
6150
|
if (this.avatar.hasOwnProperty("avatarIgnoreCamera")) {
|
|
6151
6151
|
if (this.avatar.avatarIgnoreCamera) {
|
|
6152
6152
|
this.lookAhead(t);
|
|
@@ -6159,16 +6159,16 @@ class Be {
|
|
|
6159
6159
|
this.lookAt(null, null, t);
|
|
6160
6160
|
return;
|
|
6161
6161
|
}
|
|
6162
|
-
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0), ve.setFromMatrixPosition(this.objectLeftEye.matrixWorld), Re.setFromMatrixPosition(this.objectRightEye.matrixWorld), ve.add(Re).divideScalar(2),
|
|
6163
|
-
const n = new
|
|
6164
|
-
|
|
6165
|
-
const l = new
|
|
6166
|
-
|
|
6167
|
-
let r =
|
|
6162
|
+
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0), ve.setFromMatrixPosition(this.objectLeftEye.matrixWorld), Re.setFromMatrixPosition(this.objectRightEye.matrixWorld), ve.add(Re).divideScalar(2), J.copy(this.armature.quaternion), J.multiply(this.poseTarget.props["Hips.quaternion"]), J.multiply(this.poseTarget.props["Spine.quaternion"]), J.multiply(this.poseTarget.props["Spine1.quaternion"]), J.multiply(this.poseTarget.props["Spine2.quaternion"]), J.multiply(this.poseTarget.props["Neck.quaternion"]), J.multiply(this.poseTarget.props["Head.quaternion"]);
|
|
6163
|
+
const n = new y.Vector3().subVectors(e, ve).normalize(), i = Math.atan2(n.x, n.z), s = Math.asin(-n.y);
|
|
6164
|
+
G.set(s, i, 0, "YXZ");
|
|
6165
|
+
const l = new y.Quaternion().setFromEuler(G), h = new y.Quaternion().copy(l).multiply(J.clone().invert());
|
|
6166
|
+
G.setFromQuaternion(h, "YXZ");
|
|
6167
|
+
let r = G.x / (40 / 24) + 0.2, u = G.y / (9 / 4), a = Math.min(0.6, Math.max(-0.3, r)), d = Math.min(0.8, Math.max(-0.8, u)), c = (Math.random() - 0.5) / 4, g = (Math.random() - 0.5) / 4;
|
|
6168
6168
|
if (t) {
|
|
6169
|
-
let
|
|
6170
|
-
|
|
6171
|
-
const
|
|
6169
|
+
let x = this.animQueue.findIndex((k) => k.template.name === "lookat");
|
|
6170
|
+
x !== -1 && this.animQueue.splice(x, 1);
|
|
6171
|
+
const f = {
|
|
6172
6172
|
name: "lookat",
|
|
6173
6173
|
dt: [750, t],
|
|
6174
6174
|
vs: {
|
|
@@ -6183,7 +6183,7 @@ class Be {
|
|
|
6183
6183
|
headMove: [0]
|
|
6184
6184
|
}
|
|
6185
6185
|
};
|
|
6186
|
-
this.animQueue.push(this.animFactory(
|
|
6186
|
+
this.animQueue.push(this.animFactory(f));
|
|
6187
6187
|
}
|
|
6188
6188
|
}
|
|
6189
6189
|
/**
|
|
@@ -6196,23 +6196,23 @@ class Be {
|
|
|
6196
6196
|
if (!this.camera) return;
|
|
6197
6197
|
const i = this.nodeAvatar.getBoundingClientRect();
|
|
6198
6198
|
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0);
|
|
6199
|
-
const s = new
|
|
6199
|
+
const s = new y.Vector3().setFromMatrixPosition(this.objectLeftEye.matrixWorld), o = new y.Vector3().setFromMatrixPosition(this.objectRightEye.matrixWorld), l = new y.Vector3().addVectors(s, o).divideScalar(2);
|
|
6200
6200
|
l.project(this.camera);
|
|
6201
6201
|
let h = (l.x + 1) / 2 * i.width + i.left, r = -(l.y - 1) / 2 * i.height + i.top;
|
|
6202
|
-
t === null && (t = h), e === null && (e = r),
|
|
6203
|
-
let u =
|
|
6204
|
-
|
|
6205
|
-
let
|
|
6202
|
+
t === null && (t = h), e === null && (e = r), J.copy(this.armature.quaternion), J.multiply(this.poseTarget.props["Hips.quaternion"]), J.multiply(this.poseTarget.props["Spine.quaternion"]), J.multiply(this.poseTarget.props["Spine1.quaternion"]), J.multiply(this.poseTarget.props["Spine2.quaternion"]), J.multiply(this.poseTarget.props["Neck.quaternion"]), J.multiply(this.poseTarget.props["Head.quaternion"]), G.setFromQuaternion(J);
|
|
6203
|
+
let u = G.x / (40 / 24), a = G.y / (9 / 4), d = Math.min(0.4, Math.max(-0.4, this.camera.rotation.x)), c = Math.min(0.4, Math.max(-0.4, this.camera.rotation.y)), g = Math.max(window.innerWidth - h, h), x = Math.max(window.innerHeight - r, r), f = this.convertRange(e, [r - x, r + x], [-0.3, 0.6]) - u + d, k = this.convertRange(t, [h - g, h + g], [-0.8, 0.8]) - a + c;
|
|
6204
|
+
f = Math.min(0.6, Math.max(-0.3, f)), k = Math.min(0.8, Math.max(-0.8, k));
|
|
6205
|
+
let O = (Math.random() - 0.5) / 4, p = (Math.random() - 0.5) / 4;
|
|
6206
6206
|
if (n) {
|
|
6207
|
-
let
|
|
6208
|
-
|
|
6209
|
-
const
|
|
6207
|
+
let B = this.animQueue.findIndex((v) => v.template.name === "lookat");
|
|
6208
|
+
B !== -1 && this.animQueue.splice(B, 1);
|
|
6209
|
+
const H = {
|
|
6210
6210
|
name: "lookat",
|
|
6211
6211
|
dt: [750, n],
|
|
6212
6212
|
vs: {
|
|
6213
|
-
bodyRotateX: [
|
|
6214
|
-
bodyRotateY: [
|
|
6215
|
-
eyesRotateX: [-3 *
|
|
6213
|
+
bodyRotateX: [f + O],
|
|
6214
|
+
bodyRotateY: [k + p],
|
|
6215
|
+
eyesRotateX: [-3 * O + 0.1],
|
|
6216
6216
|
eyesRotateY: [-5 * p],
|
|
6217
6217
|
browInnerUp: [[0, 0.7]],
|
|
6218
6218
|
mouthLeft: [[0, 0.7]],
|
|
@@ -6221,7 +6221,7 @@ class Be {
|
|
|
6221
6221
|
headMove: [0]
|
|
6222
6222
|
}
|
|
6223
6223
|
};
|
|
6224
|
-
this.animQueue.push(this.animFactory(
|
|
6224
|
+
this.animQueue.push(this.animFactory(H));
|
|
6225
6225
|
}
|
|
6226
6226
|
}
|
|
6227
6227
|
/**
|
|
@@ -6232,14 +6232,14 @@ class Be {
|
|
|
6232
6232
|
*/
|
|
6233
6233
|
touchAt(t, e) {
|
|
6234
6234
|
if (!this.camera) return;
|
|
6235
|
-
const n = this.nodeAvatar.getBoundingClientRect(), i = new
|
|
6235
|
+
const n = this.nodeAvatar.getBoundingClientRect(), i = new y.Vector2(
|
|
6236
6236
|
(t - n.left) / n.width * 2 - 1,
|
|
6237
6237
|
-((e - n.top) / n.height) * 2 + 1
|
|
6238
|
-
), s = new
|
|
6238
|
+
), s = new y.Raycaster();
|
|
6239
6239
|
s.setFromCamera(i, this.camera);
|
|
6240
6240
|
const o = s.intersectObject(this.armature);
|
|
6241
6241
|
if (o.length > 0) {
|
|
6242
|
-
const l = o[0].point, h = new
|
|
6242
|
+
const l = o[0].point, h = new y.Vector3(), r = new y.Vector3();
|
|
6243
6243
|
this.objectLeftArm.getWorldPosition(h), this.objectRightArm.getWorldPosition(r);
|
|
6244
6244
|
const u = h.distanceToSquared(l), a = r.distanceToSquared(l);
|
|
6245
6245
|
u < a ? (this.ikSolve({
|
|
@@ -6283,7 +6283,7 @@ class Be {
|
|
|
6283
6283
|
{ link: "LeftForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -0.5, maxz: 3 },
|
|
6284
6284
|
{ link: "LeftArm", minx: -1.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -1, maxz: 3 }
|
|
6285
6285
|
]
|
|
6286
|
-
}, new
|
|
6286
|
+
}, new y.Vector3(
|
|
6287
6287
|
this.gaussianRandom(0, 0.5),
|
|
6288
6288
|
this.gaussianRandom(-0.8, -0.2),
|
|
6289
6289
|
this.gaussianRandom(0, 0.5)
|
|
@@ -6295,15 +6295,15 @@ class Be {
|
|
|
6295
6295
|
{ link: "RightForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -3, maxz: 0.5 },
|
|
6296
6296
|
{ link: "RightArm" }
|
|
6297
6297
|
]
|
|
6298
|
-
}, new
|
|
6298
|
+
}, new y.Vector3(
|
|
6299
6299
|
this.gaussianRandom(-0.5, 0),
|
|
6300
6300
|
this.gaussianRandom(-0.8, -0.2),
|
|
6301
6301
|
this.gaussianRandom(0, 0.5)
|
|
6302
6302
|
), !0);
|
|
6303
6303
|
const n = [], i = [];
|
|
6304
6304
|
n.push(100 + Math.round(Math.random() * 500)), i.push({ duration: 1e3, props: {
|
|
6305
|
-
"LeftHand.quaternion": new
|
|
6306
|
-
"RightHand.quaternion": new
|
|
6305
|
+
"LeftHand.quaternion": new y.Quaternion().setFromEuler(new y.Euler(0, -1 - Math.random(), 0)),
|
|
6306
|
+
"RightHand.quaternion": new y.Quaternion().setFromEuler(new y.Euler(0, 1 + Math.random(), 0))
|
|
6307
6307
|
} }), ["LeftArm", "LeftForeArm", "RightArm", "RightForeArm"].forEach((o) => {
|
|
6308
6308
|
i[0].props[o + ".quaternion"] = this.ikMesh.getObjectByName(o).quaternion.clone();
|
|
6309
6309
|
}), n.push(1e3 + Math.round(Math.random() * 500)), i.push({ duration: 2e3, props: {} }), ["LeftArm", "LeftForeArm", "RightArm", "RightForeArm", "LeftHand", "RightHand"].forEach((o) => {
|
|
@@ -6388,9 +6388,9 @@ class Be {
|
|
|
6388
6388
|
let h = this.animQueue.find((a) => a.template.name === "pose");
|
|
6389
6389
|
h && (h.ts[0] = 1 / 0), Object.entries(l.pose.props).forEach((a) => {
|
|
6390
6390
|
this.poseBase.props[a[0]] = a[1].clone(), this.poseTarget.props[a[0]] = a[1].clone(), this.poseTarget.props[a[0]].t = 0, this.poseTarget.props[a[0]].d = 1e3;
|
|
6391
|
-
}), this.mixer ? console.log("Using existing mixer for FBX animation, preserving morph targets") : (this.mixer = new
|
|
6391
|
+
}), this.mixer ? console.log("Using existing mixer for FBX animation, preserving morph targets") : (this.mixer = new y.AnimationMixer(this.armature), console.log("Created new mixer for FBX animation")), this.mixer.addEventListener("finished", this.stopAnimation.bind(this), { once: !0 });
|
|
6392
6392
|
const r = Math.ceil(n / l.clip.duration), u = this.mixer.clipAction(l.clip);
|
|
6393
|
-
u.setLoop(
|
|
6393
|
+
u.setLoop(y.LoopRepeat, r), u.clampWhenFinished = !0, this.currentFBXAction = u;
|
|
6394
6394
|
try {
|
|
6395
6395
|
u.fadeIn(0.5).play(), console.log("FBX animation started successfully:", t);
|
|
6396
6396
|
} catch (a) {
|
|
@@ -6427,13 +6427,13 @@ class Be {
|
|
|
6427
6427
|
suggestion: "Make sure the file is a valid FBX file and the path is correct"
|
|
6428
6428
|
}), d.message && d.message.includes("version number") && (console.error("FBX Loader Error: Cannot find version number"), console.error("This error usually means:"), console.error("1. The file is not a valid FBX file (might be GLB, corrupted, or wrong format)"), console.error("2. The file might be corrupted"), console.error("3. The file path might be incorrect"), console.error("4. The server returned an HTML error page instead of the FBX file"), console.error("5. The file might not exist at that path"), console.error(""), console.error("Solution: Please verify:"), console.error(` - File exists at: ${t}`), console.error(" - File is a valid FBX binary file"), console.error(" - File path matches your public folder structure"), console.error(" - File is not corrupted"));
|
|
6429
6429
|
try {
|
|
6430
|
-
const c = await fetch(t), g = c.headers.get("content-type"),
|
|
6430
|
+
const c = await fetch(t), g = c.headers.get("content-type"), x = await c.text();
|
|
6431
6431
|
console.error("Response details:", {
|
|
6432
6432
|
status: c.status,
|
|
6433
6433
|
contentType: g,
|
|
6434
|
-
firstBytes:
|
|
6435
|
-
isHTML:
|
|
6436
|
-
}), (
|
|
6434
|
+
firstBytes: x.substring(0, 100),
|
|
6435
|
+
isHTML: x.trim().startsWith("<!DOCTYPE") || x.trim().startsWith("<html")
|
|
6436
|
+
}), (x.trim().startsWith("<!DOCTYPE") || x.trim().startsWith("<html")) && console.error("The server returned an HTML page instead of an FBX file. The file path is likely incorrect.");
|
|
6437
6437
|
} catch (c) {
|
|
6438
6438
|
console.error("Could not fetch file for debugging:", c);
|
|
6439
6439
|
}
|
|
@@ -6442,37 +6442,37 @@ class Be {
|
|
|
6442
6442
|
if (a && a.animations && a.animations[i]) {
|
|
6443
6443
|
let d = a.animations[i];
|
|
6444
6444
|
const c = /* @__PURE__ */ new Set();
|
|
6445
|
-
this.armature && this.armature.traverse((
|
|
6446
|
-
(
|
|
6445
|
+
this.armature && this.armature.traverse((L) => {
|
|
6446
|
+
(L.isBone || L.type === "Bone") && c.add(L.name);
|
|
6447
6447
|
});
|
|
6448
|
-
const g = /* @__PURE__ */ new Map(),
|
|
6448
|
+
const g = /* @__PURE__ */ new Map(), x = (L) => {
|
|
6449
|
+
if (c.has(L))
|
|
6450
|
+
return L;
|
|
6451
|
+
let I = L.replace(/^mixamorig/i, "").replace(/^CC_Base_/i, "").replace(/^RPM_/i, "");
|
|
6449
6452
|
if (c.has(I))
|
|
6450
6453
|
return I;
|
|
6451
|
-
|
|
6452
|
-
if (
|
|
6453
|
-
|
|
6454
|
-
const A = z.toLowerCase();
|
|
6455
|
-
if (A.includes("left") && A.includes("arm")) {
|
|
6456
|
-
if (A.includes("fore") || A.includes("lower")) {
|
|
6454
|
+
const z = I.toLowerCase();
|
|
6455
|
+
if (z.includes("left") && z.includes("arm")) {
|
|
6456
|
+
if (z.includes("fore") || z.includes("lower")) {
|
|
6457
6457
|
if (c.has("LeftForeArm")) return "LeftForeArm";
|
|
6458
6458
|
if (c.has("LeftForearm")) return "LeftForearm";
|
|
6459
|
-
} else if (!
|
|
6459
|
+
} else if (!z.includes("fore") && !z.includes("hand") && c.has("LeftArm"))
|
|
6460
6460
|
return "LeftArm";
|
|
6461
6461
|
}
|
|
6462
|
-
if (
|
|
6463
|
-
if (
|
|
6462
|
+
if (z.includes("right") && z.includes("arm")) {
|
|
6463
|
+
if (z.includes("fore") || z.includes("lower")) {
|
|
6464
6464
|
if (c.has("RightForeArm")) return "RightForeArm";
|
|
6465
6465
|
if (c.has("RightForearm")) return "RightForearm";
|
|
6466
|
-
} else if (!
|
|
6466
|
+
} else if (!z.includes("fore") && !z.includes("hand") && c.has("RightArm"))
|
|
6467
6467
|
return "RightArm";
|
|
6468
6468
|
}
|
|
6469
|
-
if (
|
|
6469
|
+
if (z.includes("left") && z.includes("hand") && !z.includes("index") && !z.includes("thumb") && !z.includes("middle") && !z.includes("ring") && !z.includes("pinky") && c.has("LeftHand"))
|
|
6470
6470
|
return "LeftHand";
|
|
6471
|
-
if (
|
|
6471
|
+
if (z.includes("right") && z.includes("hand") && !z.includes("index") && !z.includes("thumb") && !z.includes("middle") && !z.includes("ring") && !z.includes("pinky") && c.has("RightHand"))
|
|
6472
6472
|
return "RightHand";
|
|
6473
|
-
if (
|
|
6473
|
+
if (z.includes("left") && (z.includes("shoulder") || z.includes("clavicle")) && c.has("LeftShoulder"))
|
|
6474
6474
|
return "LeftShoulder";
|
|
6475
|
-
if (
|
|
6475
|
+
if (z.includes("right") && (z.includes("shoulder") || z.includes("clavicle")) && c.has("RightShoulder"))
|
|
6476
6476
|
return "RightShoulder";
|
|
6477
6477
|
const Y = {
|
|
6478
6478
|
// Arm bones - exact matches
|
|
@@ -6514,65 +6514,65 @@ class Be {
|
|
|
6514
6514
|
Root: "Hips",
|
|
6515
6515
|
root: "Hips"
|
|
6516
6516
|
};
|
|
6517
|
-
if (Y[
|
|
6518
|
-
const
|
|
6519
|
-
if (c.has(
|
|
6520
|
-
return
|
|
6517
|
+
if (Y[I]) {
|
|
6518
|
+
const S = Y[I];
|
|
6519
|
+
if (c.has(S))
|
|
6520
|
+
return S;
|
|
6521
6521
|
}
|
|
6522
|
-
for (const
|
|
6523
|
-
if (
|
|
6524
|
-
return
|
|
6525
|
-
for (const
|
|
6526
|
-
const
|
|
6527
|
-
if ((
|
|
6528
|
-
return
|
|
6522
|
+
for (const S of c)
|
|
6523
|
+
if (S.toLowerCase() === z)
|
|
6524
|
+
return S;
|
|
6525
|
+
for (const S of c) {
|
|
6526
|
+
const F = S.toLowerCase();
|
|
6527
|
+
if ((z.includes("left") && F.includes("left") || z.includes("right") && F.includes("right")) && (z.includes("arm") && F.includes("arm") && !F.includes("fore") || z.includes("forearm") && F.includes("forearm") || z.includes("hand") && F.includes("hand") && !F.includes("index") && !F.includes("thumb") || z.includes("shoulder") && F.includes("shoulder")))
|
|
6528
|
+
return S;
|
|
6529
6529
|
}
|
|
6530
6530
|
return null;
|
|
6531
|
-
},
|
|
6532
|
-
d.tracks.forEach((
|
|
6533
|
-
const
|
|
6534
|
-
|
|
6535
|
-
}), console.log("=== Ready Player Me Animation Bone Analysis ==="), console.log("FBX bone names:", Array.from(
|
|
6536
|
-
const
|
|
6537
|
-
(
|
|
6538
|
-
),
|
|
6539
|
-
(
|
|
6531
|
+
}, f = /* @__PURE__ */ new Set();
|
|
6532
|
+
d.tracks.forEach((L) => {
|
|
6533
|
+
const I = L.name.split(".");
|
|
6534
|
+
f.add(I[0]);
|
|
6535
|
+
}), console.log("=== Ready Player Me Animation Bone Analysis ==="), console.log("FBX bone names:", Array.from(f).sort().join(", ")), console.log("Avatar skeleton bone names:", Array.from(c).sort().join(", "));
|
|
6536
|
+
const k = Array.from(f).filter(
|
|
6537
|
+
(L) => L.toLowerCase().includes("arm") || L.toLowerCase().includes("hand") || L.toLowerCase().includes("shoulder")
|
|
6538
|
+
), O = Array.from(c).filter(
|
|
6539
|
+
(L) => L.includes("Arm") || L.includes("Hand") || L.includes("Shoulder")
|
|
6540
6540
|
);
|
|
6541
|
-
console.log("FBX arm/hand/shoulder bones:",
|
|
6542
|
-
const p = [],
|
|
6543
|
-
if (d.tracks.forEach((
|
|
6544
|
-
const
|
|
6545
|
-
if (
|
|
6546
|
-
const
|
|
6547
|
-
|
|
6541
|
+
console.log("FBX arm/hand/shoulder bones:", k.sort().join(", ")), console.log("Avatar arm/hand/shoulder bones:", O.sort().join(", "));
|
|
6542
|
+
const p = [], B = /* @__PURE__ */ new Set();
|
|
6543
|
+
if (d.tracks.forEach((L) => {
|
|
6544
|
+
const z = L.name.replaceAll("mixamorig", "").split("."), Y = z[0], S = z[1], F = x(Y);
|
|
6545
|
+
if (F && S) {
|
|
6546
|
+
const X = `${F}.${S}`, Z = L.clone();
|
|
6547
|
+
Z.name = X, p.push(Z), Y !== F && g.set(Y, F);
|
|
6548
6548
|
} else
|
|
6549
|
-
|
|
6550
|
-
}),
|
|
6551
|
-
d = new
|
|
6549
|
+
B.add(Y), (Y.toLowerCase().includes("arm") || Y.toLowerCase().includes("hand") || Y.toLowerCase().includes("shoulder")) && console.warn(`⚠️ Arm bone "${Y}" could not be mapped to avatar skeleton`);
|
|
6550
|
+
}), B.size > 0 && console.warn(`⚠️ ${B.size} bone(s) could not be mapped:`, Array.from(B).sort().join(", ")), p.length > 0) {
|
|
6551
|
+
d = new y.AnimationClip(d.name, d.duration, p), console.log(`✓ Created animation with ${p.length} mapped tracks (from ${d.tracks.length} original tracks)`), g.size > 0 && console.log(
|
|
6552
6552
|
`✓ Mapped ${g.size} bone(s):`,
|
|
6553
|
-
Array.from(g.entries()).map(([
|
|
6553
|
+
Array.from(g.entries()).map(([I, z]) => `${I}→${z}`).join(", ")
|
|
6554
6554
|
);
|
|
6555
|
-
const
|
|
6556
|
-
(
|
|
6555
|
+
const L = Array.from(g.values()).filter(
|
|
6556
|
+
(I) => I.includes("Arm") || I.includes("Hand") || I.includes("Shoulder")
|
|
6557
6557
|
);
|
|
6558
|
-
|
|
6558
|
+
L.length > 0 ? console.log(`✓ Arm bones mapped: ${L.join(", ")}`) : console.warn("⚠️ No arm bones were mapped! This may cause arm rigging issues.");
|
|
6559
6559
|
} else
|
|
6560
6560
|
console.error("❌ No tracks could be mapped! Animation may not work correctly.");
|
|
6561
|
-
const
|
|
6562
|
-
d.tracks.forEach((
|
|
6563
|
-
|
|
6564
|
-
const
|
|
6565
|
-
if (
|
|
6566
|
-
for (let
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
} else
|
|
6561
|
+
const H = {};
|
|
6562
|
+
d.tracks.forEach((L) => {
|
|
6563
|
+
L.name = L.name.replaceAll("mixamorig", "");
|
|
6564
|
+
const I = L.name.split(".");
|
|
6565
|
+
if (I[1] === "position") {
|
|
6566
|
+
for (let z = 0; z < L.values.length; z++)
|
|
6567
|
+
L.values[z] = L.values[z] * s;
|
|
6568
|
+
H[L.name] = new y.Vector3(L.values[0], L.values[1], L.values[2]);
|
|
6569
|
+
} else I[1] === "quaternion" ? H[L.name] = new y.Quaternion(L.values[0], L.values[1], L.values[2], L.values[3]) : I[1] === "rotation" && (H[I[0] + ".quaternion"] = new y.Quaternion().setFromEuler(new y.Euler(L.values[0], L.values[1], L.values[2], "XYZ")).normalize());
|
|
6570
6570
|
});
|
|
6571
|
-
const
|
|
6572
|
-
|
|
6571
|
+
const v = { props: H };
|
|
6572
|
+
H["Hips.position"] && (H["Hips.position"].y < 0.5 ? v.lying = !0 : v.standing = !0), this.animClips.push({
|
|
6573
6573
|
url: t + "-" + i,
|
|
6574
6574
|
clip: d,
|
|
6575
|
-
pose:
|
|
6575
|
+
pose: v
|
|
6576
6576
|
}), this.playAnimation(t, e, n, i, s);
|
|
6577
6577
|
} else {
|
|
6578
6578
|
const d = "Animation " + t + " (ndx=" + i + ") not found";
|
|
@@ -6617,7 +6617,7 @@ class Be {
|
|
|
6617
6617
|
r.tracks.forEach((d) => {
|
|
6618
6618
|
d.name = d.name.replaceAll("mixamorig", "");
|
|
6619
6619
|
const c = d.name.split(".");
|
|
6620
|
-
c[1] === "position" ? u[d.name] = new
|
|
6620
|
+
c[1] === "position" ? u[d.name] = new y.Vector3(d.values[0] * s, d.values[1] * s, d.values[2] * s) : c[1] === "quaternion" ? u[d.name] = new y.Quaternion(d.values[0], d.values[1], d.values[2], d.values[3]) : c[1] === "rotation" && (u[c[0] + ".quaternion"] = new y.Quaternion().setFromEuler(new y.Euler(d.values[0], d.values[1], d.values[2], "XYZ")).normalize());
|
|
6621
6621
|
});
|
|
6622
6622
|
const a = { props: u };
|
|
6623
6623
|
u["Hips.position"] && (u["Hips.position"].y < 0.5 ? a.lying = !0 : a.standing = !0), this.animPoses.push({
|
|
@@ -6650,7 +6650,7 @@ class Be {
|
|
|
6650
6650
|
if (s) {
|
|
6651
6651
|
this.gestureTimeout && (clearTimeout(this.gestureTimeout), this.gestureTimeout = null);
|
|
6652
6652
|
let l = this.animQueue.findIndex((h) => h.template.name === "talkinghands");
|
|
6653
|
-
l !== -1 && (this.animQueue[l].ts = this.animQueue[l].ts.map((h) => 0)), this.gesture = this.propsToThreeObjects(s), n && (this.gesture = this.mirrorPose(this.gesture)), t === "namaste" && this.avatar.body === "M" && (this.gesture["RightArm.quaternion"].rotateTowards(new
|
|
6653
|
+
l !== -1 && (this.animQueue[l].ts = this.animQueue[l].ts.map((h) => 0)), this.gesture = this.propsToThreeObjects(s), n && (this.gesture = this.mirrorPose(this.gesture)), t === "namaste" && this.avatar.body === "M" && (this.gesture["RightArm.quaternion"].rotateTowards(new y.Quaternion(0, 1, 0, 0), -0.25), this.gesture["LeftArm.quaternion"].rotateTowards(new y.Quaternion(0, 1, 0, 0), -0.25));
|
|
6654
6654
|
for (let [h, r] of Object.entries(this.gesture))
|
|
6655
6655
|
r.t = this.animClock, r.d = i, this.poseTarget.props.hasOwnProperty(h) && (this.poseTarget.props[h].copy(r), this.poseTarget.props[h].t = this.animClock, this.poseTarget.props[h].d = i);
|
|
6656
6656
|
e && Number.isFinite(e) && (this.gestureTimeout = setTimeout(this.stopGesture.bind(this, i), 1e3 * e));
|
|
@@ -6663,9 +6663,9 @@ class Be {
|
|
|
6663
6663
|
const h = l.ts[0], u = l.ts[l.ts.length - 1] - h;
|
|
6664
6664
|
if (e * 1e3 - u > 0) {
|
|
6665
6665
|
const d = [];
|
|
6666
|
-
for (let
|
|
6667
|
-
const c = o.template?.rescale || d.map((
|
|
6668
|
-
l.ts = l.ts.map((
|
|
6666
|
+
for (let x = 1; x < l.ts.length; x++) d.push(l.ts[x] - l.ts[x - 1]);
|
|
6667
|
+
const c = o.template?.rescale || d.map((x) => x / u), g = e * 1e3 - u;
|
|
6668
|
+
l.ts = l.ts.map((x, f, k) => f === 0 ? h : k[f - 1] + d[f - 1] + c[f - 1] * g);
|
|
6669
6669
|
} else {
|
|
6670
6670
|
const d = e * 1e3 / u;
|
|
6671
6671
|
l.ts = l.ts.map((c) => h + d * (c - h));
|
|
@@ -6698,34 +6698,34 @@ class Be {
|
|
|
6698
6698
|
* @param {numeric} [d=null] If set, apply in d milliseconds
|
|
6699
6699
|
*/
|
|
6700
6700
|
ikSolve(t, e = null, n = !1, i = null) {
|
|
6701
|
-
const s = new
|
|
6701
|
+
const s = new y.Vector3(), o = new y.Vector3(), l = new y.Vector3(), h = new y.Vector3(), r = new y.Quaternion(), u = new y.Vector3(), a = new y.Vector3(), d = new y.Vector3(), c = this.ikMesh.getObjectByName(t.root);
|
|
6702
6702
|
c.position.setFromMatrixPosition(this.armature.getObjectByName(t.root).matrixWorld), c.quaternion.setFromRotationMatrix(this.armature.getObjectByName(t.root).matrixWorld), e && n && e.applyQuaternion(this.armature.quaternion).add(c.position);
|
|
6703
|
-
const g = this.ikMesh.getObjectByName(t.effector),
|
|
6704
|
-
|
|
6705
|
-
|
|
6703
|
+
const g = this.ikMesh.getObjectByName(t.effector), x = t.links;
|
|
6704
|
+
x.forEach((k) => {
|
|
6705
|
+
k.bone = this.ikMesh.getObjectByName(k.link), k.bone.quaternion.copy(this.getPoseTemplateProp(k.link + ".quaternion"));
|
|
6706
6706
|
}), c.updateMatrixWorld(!0);
|
|
6707
|
-
const
|
|
6707
|
+
const f = t.iterations || 10;
|
|
6708
6708
|
if (e)
|
|
6709
|
-
for (let
|
|
6710
|
-
let
|
|
6711
|
-
for (let p = 0,
|
|
6712
|
-
const
|
|
6713
|
-
|
|
6714
|
-
let
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
), new
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
))),
|
|
6709
|
+
for (let k = 0; k < f; k++) {
|
|
6710
|
+
let O = !1;
|
|
6711
|
+
for (let p = 0, B = x.length; p < B; p++) {
|
|
6712
|
+
const H = x[p].bone;
|
|
6713
|
+
H.matrixWorld.decompose(h, r, u), r.invert(), o.setFromMatrixPosition(g.matrixWorld), l.subVectors(o, h), l.applyQuaternion(r), l.normalize(), s.subVectors(e, h), s.applyQuaternion(r), s.normalize();
|
|
6714
|
+
let v = s.dot(l);
|
|
6715
|
+
v > 1 ? v = 1 : v < -1 && (v = -1), v = Math.acos(v), !(v < 1e-5) && (x[p].minAngle !== void 0 && v < x[p].minAngle && (v = x[p].minAngle), x[p].maxAngle !== void 0 && v > x[p].maxAngle && (v = x[p].maxAngle), a.crossVectors(l, s), a.normalize(), J.setFromAxisAngle(a, v), H.quaternion.multiply(J), H.rotation.setFromVector3(d.setFromEuler(H.rotation).clamp(new y.Vector3(
|
|
6716
|
+
x[p].minx !== void 0 ? x[p].minx : -1 / 0,
|
|
6717
|
+
x[p].miny !== void 0 ? x[p].miny : -1 / 0,
|
|
6718
|
+
x[p].minz !== void 0 ? x[p].minz : -1 / 0
|
|
6719
|
+
), new y.Vector3(
|
|
6720
|
+
x[p].maxx !== void 0 ? x[p].maxx : 1 / 0,
|
|
6721
|
+
x[p].maxy !== void 0 ? x[p].maxy : 1 / 0,
|
|
6722
|
+
x[p].maxz !== void 0 ? x[p].maxz : 1 / 0
|
|
6723
|
+
))), H.updateMatrixWorld(!0), O = !0);
|
|
6724
6724
|
}
|
|
6725
|
-
if (!
|
|
6725
|
+
if (!O) break;
|
|
6726
6726
|
}
|
|
6727
|
-
i &&
|
|
6728
|
-
this.poseTarget.props[
|
|
6727
|
+
i && x.forEach((k) => {
|
|
6728
|
+
this.poseTarget.props[k.link + ".quaternion"].copy(k.bone.quaternion), this.poseTarget.props[k.link + ".quaternion"].t = this.animClock, this.poseTarget.props[k.link + ".quaternion"].d = i;
|
|
6729
6729
|
});
|
|
6730
6730
|
}
|
|
6731
6731
|
/**
|
|
@@ -6784,17 +6784,17 @@ function Ee() {
|
|
|
6784
6784
|
voices: Ie.voices
|
|
6785
6785
|
};
|
|
6786
6786
|
}
|
|
6787
|
-
function
|
|
6788
|
-
const
|
|
6789
|
-
return Object.entries(
|
|
6787
|
+
function wt() {
|
|
6788
|
+
const V = Ee(), t = [];
|
|
6789
|
+
return Object.entries(V.voices).forEach(([e, n]) => {
|
|
6790
6790
|
t.push({
|
|
6791
6791
|
value: n,
|
|
6792
|
-
label: `${e.charAt(0).toUpperCase() + e.slice(1)} (${
|
|
6792
|
+
label: `${e.charAt(0).toUpperCase() + e.slice(1)} (${V.service})`
|
|
6793
6793
|
});
|
|
6794
6794
|
}), t;
|
|
6795
6795
|
}
|
|
6796
6796
|
const Ve = Me(({
|
|
6797
|
-
avatarUrl:
|
|
6797
|
+
avatarUrl: V = "/avatars/brunette.glb",
|
|
6798
6798
|
avatarBody: t = "F",
|
|
6799
6799
|
mood: e = "neutral",
|
|
6800
6800
|
ttsLang: n = "en",
|
|
@@ -6812,313 +6812,313 @@ const Ve = Me(({
|
|
|
6812
6812
|
onError: c = () => {
|
|
6813
6813
|
},
|
|
6814
6814
|
className: g = "",
|
|
6815
|
-
style:
|
|
6816
|
-
animations:
|
|
6817
|
-
},
|
|
6818
|
-
const
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
}, [
|
|
6822
|
-
|
|
6815
|
+
style: x = {},
|
|
6816
|
+
animations: f = {}
|
|
6817
|
+
}, k) => {
|
|
6818
|
+
const O = W(null), p = W(null), B = W(r), H = W(null), v = W(null), L = W(!1), I = W({ remainingText: null, originalText: null, options: null }), z = W([]), Y = W(0), [S, F] = pe(!0), [X, Z] = pe(null), [ne, le] = pe(!1), [ge, de] = pe(!1);
|
|
6819
|
+
ce(() => {
|
|
6820
|
+
L.current = ge;
|
|
6821
|
+
}, [ge]), ce(() => {
|
|
6822
|
+
B.current = r;
|
|
6823
6823
|
}, [r]);
|
|
6824
|
-
const
|
|
6825
|
-
let
|
|
6826
|
-
|
|
6824
|
+
const $ = Ee(), be = i || $.service;
|
|
6825
|
+
let j;
|
|
6826
|
+
be === "browser" ? j = {
|
|
6827
6827
|
service: "browser",
|
|
6828
6828
|
endpoint: "",
|
|
6829
6829
|
apiKey: null,
|
|
6830
6830
|
defaultVoice: "Google US English"
|
|
6831
|
-
} :
|
|
6831
|
+
} : be === "elevenlabs" ? j = {
|
|
6832
6832
|
service: "elevenlabs",
|
|
6833
6833
|
endpoint: "https://api.elevenlabs.io/v1/text-to-speech",
|
|
6834
|
-
apiKey: o ||
|
|
6835
|
-
defaultVoice: s ||
|
|
6836
|
-
voices:
|
|
6837
|
-
} :
|
|
6834
|
+
apiKey: o || $.apiKey,
|
|
6835
|
+
defaultVoice: s || $.defaultVoice || Ie.defaultVoice,
|
|
6836
|
+
voices: $.voices || Ie.voices
|
|
6837
|
+
} : be === "deepgram" ? j = {
|
|
6838
6838
|
service: "deepgram",
|
|
6839
6839
|
endpoint: "https://api.deepgram.com/v1/speak",
|
|
6840
|
-
apiKey: o ||
|
|
6841
|
-
defaultVoice: s ||
|
|
6842
|
-
voices:
|
|
6843
|
-
} :
|
|
6844
|
-
|
|
6840
|
+
apiKey: o || $.apiKey,
|
|
6841
|
+
defaultVoice: s || $.defaultVoice || Te.defaultVoice,
|
|
6842
|
+
voices: $.voices || Te.voices
|
|
6843
|
+
} : j = {
|
|
6844
|
+
...$,
|
|
6845
6845
|
// Override API key if provided via props
|
|
6846
|
-
apiKey: o !== null ? o :
|
|
6846
|
+
apiKey: o !== null ? o : $.apiKey
|
|
6847
6847
|
};
|
|
6848
|
-
const
|
|
6849
|
-
url:
|
|
6848
|
+
const b = {
|
|
6849
|
+
url: V,
|
|
6850
6850
|
body: t,
|
|
6851
6851
|
avatarMood: e,
|
|
6852
|
-
ttsLang:
|
|
6853
|
-
ttsVoice: s ||
|
|
6852
|
+
ttsLang: be === "browser" ? "en-US" : n,
|
|
6853
|
+
ttsVoice: s || j.defaultVoice,
|
|
6854
6854
|
lipsyncLang: "en",
|
|
6855
6855
|
showFullAvatar: r,
|
|
6856
6856
|
bodyMovement: l,
|
|
6857
6857
|
movementIntensity: h
|
|
6858
6858
|
}, R = {
|
|
6859
|
-
ttsEndpoint:
|
|
6860
|
-
ttsApikey:
|
|
6861
|
-
ttsService:
|
|
6859
|
+
ttsEndpoint: j.endpoint,
|
|
6860
|
+
ttsApikey: j.apiKey,
|
|
6861
|
+
ttsService: be,
|
|
6862
6862
|
lipsyncModules: ["en"],
|
|
6863
6863
|
cameraView: u
|
|
6864
|
-
},
|
|
6865
|
-
if (!(!
|
|
6864
|
+
}, M = N(async () => {
|
|
6865
|
+
if (!(!O.current || p.current))
|
|
6866
6866
|
try {
|
|
6867
|
-
if (
|
|
6868
|
-
if (
|
|
6869
|
-
const
|
|
6870
|
-
d(
|
|
6867
|
+
if (F(!0), Z(null), p.current = new Be(O.current, R), p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1), f && Object.keys(f).length > 0 && (p.current.customAnimations = f), await p.current.showAvatar(b, (_) => {
|
|
6868
|
+
if (_.lengthComputable) {
|
|
6869
|
+
const te = Math.min(100, Math.round(_.loaded / _.total * 100));
|
|
6870
|
+
d(te);
|
|
6871
6871
|
}
|
|
6872
|
-
}), await new Promise((
|
|
6873
|
-
const
|
|
6874
|
-
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ?
|
|
6872
|
+
}), await new Promise((_) => {
|
|
6873
|
+
const te = () => {
|
|
6874
|
+
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? _() : setTimeout(te, 100);
|
|
6875
6875
|
};
|
|
6876
|
-
|
|
6876
|
+
te();
|
|
6877
6877
|
}), p.current && p.current.setShowFullAvatar)
|
|
6878
6878
|
try {
|
|
6879
6879
|
p.current.setShowFullAvatar(r);
|
|
6880
|
-
} catch (
|
|
6881
|
-
console.warn("Error setting full body mode on initialization:",
|
|
6880
|
+
} catch (_) {
|
|
6881
|
+
console.warn("Error setting full body mode on initialization:", _);
|
|
6882
6882
|
}
|
|
6883
|
-
p.current && p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1, p.current.controls.update()),
|
|
6884
|
-
const
|
|
6883
|
+
p.current && p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1, p.current.controls.update()), F(!1), le(!0), a(p.current);
|
|
6884
|
+
const U = () => {
|
|
6885
6885
|
document.visibilityState === "visible" ? p.current?.start() : p.current?.stop();
|
|
6886
6886
|
};
|
|
6887
|
-
return document.addEventListener("visibilitychange",
|
|
6888
|
-
document.removeEventListener("visibilitychange",
|
|
6887
|
+
return document.addEventListener("visibilitychange", U), () => {
|
|
6888
|
+
document.removeEventListener("visibilitychange", U);
|
|
6889
6889
|
};
|
|
6890
|
-
} catch (
|
|
6891
|
-
console.error("Error initializing TalkingHead:",
|
|
6890
|
+
} catch (w) {
|
|
6891
|
+
console.error("Error initializing TalkingHead:", w), Z(w.message || "Failed to initialize avatar"), F(!1), c(w);
|
|
6892
6892
|
}
|
|
6893
|
-
}, [
|
|
6894
|
-
|
|
6893
|
+
}, [V, t, e, n, i, s, o, r, l, h, u]);
|
|
6894
|
+
ce(() => (M(), () => {
|
|
6895
6895
|
p.current && (p.current.stop(), p.current.dispose(), p.current = null);
|
|
6896
|
-
}), [
|
|
6897
|
-
if (!
|
|
6898
|
-
const
|
|
6899
|
-
for (const
|
|
6896
|
+
}), [M]), ce(() => {
|
|
6897
|
+
if (!O.current || !p.current) return;
|
|
6898
|
+
const w = new ResizeObserver((_) => {
|
|
6899
|
+
for (const te of _)
|
|
6900
6900
|
p.current && p.current.onResize && p.current.onResize();
|
|
6901
6901
|
});
|
|
6902
|
-
|
|
6903
|
-
const
|
|
6902
|
+
w.observe(O.current);
|
|
6903
|
+
const U = () => {
|
|
6904
6904
|
p.current && p.current.onResize && p.current.onResize();
|
|
6905
6905
|
};
|
|
6906
|
-
return window.addEventListener("resize",
|
|
6907
|
-
|
|
6906
|
+
return window.addEventListener("resize", U), () => {
|
|
6907
|
+
w.disconnect(), window.removeEventListener("resize", U);
|
|
6908
6908
|
};
|
|
6909
|
-
}, [
|
|
6910
|
-
const
|
|
6909
|
+
}, [ne]);
|
|
6910
|
+
const E = N(async () => {
|
|
6911
6911
|
if (p.current && p.current.audioCtx)
|
|
6912
6912
|
try {
|
|
6913
6913
|
(p.current.audioCtx.state === "suspended" || p.current.audioCtx.state === "interrupted") && (await p.current.audioCtx.resume(), console.log("Audio context resumed"));
|
|
6914
|
-
} catch (
|
|
6915
|
-
console.warn("Failed to resume audio context:",
|
|
6914
|
+
} catch (w) {
|
|
6915
|
+
console.warn("Failed to resume audio context:", w);
|
|
6916
6916
|
}
|
|
6917
|
-
}, []),
|
|
6918
|
-
if (p.current &&
|
|
6917
|
+
}, []), D = N(async (w, U = {}) => {
|
|
6918
|
+
if (p.current && ne)
|
|
6919
6919
|
try {
|
|
6920
|
-
|
|
6921
|
-
const
|
|
6922
|
-
|
|
6923
|
-
const
|
|
6924
|
-
...
|
|
6925
|
-
lipsyncLang:
|
|
6920
|
+
v.current && (clearInterval(v.current), v.current = null), H.current = { text: w, options: U }, I.current = { remainingText: null, originalText: null, options: null };
|
|
6921
|
+
const _ = /[!\.\?\n\p{Extended_Pictographic}]/ug, te = w.split(_).map((A) => A.trim()).filter((A) => A.length > 0);
|
|
6922
|
+
z.current = te, Y.current = 0, de(!1), L.current = !1, await E();
|
|
6923
|
+
const me = {
|
|
6924
|
+
...U,
|
|
6925
|
+
lipsyncLang: U.lipsyncLang || b.lipsyncLang || "en"
|
|
6926
6926
|
};
|
|
6927
|
-
if (
|
|
6928
|
-
const
|
|
6929
|
-
let
|
|
6930
|
-
const
|
|
6931
|
-
let
|
|
6932
|
-
|
|
6933
|
-
if (
|
|
6927
|
+
if (U.onSpeechEnd && p.current) {
|
|
6928
|
+
const A = p.current;
|
|
6929
|
+
let P = null, K = 0;
|
|
6930
|
+
const ie = 1200;
|
|
6931
|
+
let se = !1;
|
|
6932
|
+
P = setInterval(() => {
|
|
6933
|
+
if (K++, L.current)
|
|
6934
6934
|
return;
|
|
6935
|
-
if (
|
|
6936
|
-
if (
|
|
6937
|
-
|
|
6935
|
+
if (K > ie) {
|
|
6936
|
+
if (P && (clearInterval(P), P = null, v.current = null), !se && !L.current) {
|
|
6937
|
+
se = !0;
|
|
6938
6938
|
try {
|
|
6939
|
-
|
|
6939
|
+
U.onSpeechEnd();
|
|
6940
6940
|
} catch (Ne) {
|
|
6941
6941
|
console.error("Error in onSpeechEnd callback (timeout):", Ne);
|
|
6942
6942
|
}
|
|
6943
6943
|
}
|
|
6944
6944
|
return;
|
|
6945
6945
|
}
|
|
6946
|
-
const
|
|
6947
|
-
|
|
6948
|
-
if (
|
|
6949
|
-
|
|
6946
|
+
const oe = !A.speechQueue || A.speechQueue.length === 0, we = !A.audioPlaylist || A.audioPlaylist.length === 0;
|
|
6947
|
+
A && A.isSpeaking === !1 && oe && we && A.isAudioPlaying === !1 && !se && !L.current && setTimeout(() => {
|
|
6948
|
+
if (A && !L.current && A.isSpeaking === !1 && (!A.speechQueue || A.speechQueue.length === 0) && (!A.audioPlaylist || A.audioPlaylist.length === 0) && A.isAudioPlaying === !1 && !se && !L.current) {
|
|
6949
|
+
se = !0, P && (clearInterval(P), P = null, v.current = null);
|
|
6950
6950
|
try {
|
|
6951
|
-
|
|
6951
|
+
U.onSpeechEnd();
|
|
6952
6952
|
} catch (Ze) {
|
|
6953
6953
|
console.error("Error in onSpeechEnd callback:", Ze);
|
|
6954
6954
|
}
|
|
6955
6955
|
}
|
|
6956
6956
|
}, 100);
|
|
6957
|
-
}, 100),
|
|
6957
|
+
}, 100), v.current = P;
|
|
6958
6958
|
}
|
|
6959
|
-
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(
|
|
6960
|
-
await
|
|
6959
|
+
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(w, me)) : setTimeout(async () => {
|
|
6960
|
+
await E(), p.current && p.current.lipsync && (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(w, me));
|
|
6961
6961
|
}, 100);
|
|
6962
|
-
} catch (
|
|
6963
|
-
console.error("Error speaking text:",
|
|
6962
|
+
} catch (_) {
|
|
6963
|
+
console.error("Error speaking text:", _), Z(_.message || "Failed to speak text");
|
|
6964
6964
|
}
|
|
6965
|
-
}, [
|
|
6966
|
-
p.current && (p.current.stopSpeaking(), p.current.setSlowdownRate && p.current.setSlowdownRate(1),
|
|
6967
|
-
}, []), Q =
|
|
6965
|
+
}, [ne, E, b.lipsyncLang]), ee = N(() => {
|
|
6966
|
+
p.current && (p.current.stopSpeaking(), p.current.setSlowdownRate && p.current.setSlowdownRate(1), H.current = null, de(!1));
|
|
6967
|
+
}, []), Q = N(() => {
|
|
6968
6968
|
if (p.current && p.current.pauseSpeaking) {
|
|
6969
|
-
const
|
|
6970
|
-
if (
|
|
6971
|
-
|
|
6972
|
-
let
|
|
6973
|
-
if (
|
|
6974
|
-
const
|
|
6975
|
-
if (
|
|
6976
|
-
const
|
|
6977
|
-
|
|
6969
|
+
const w = p.current;
|
|
6970
|
+
if (w.isSpeaking || w.audioPlaylist && w.audioPlaylist.length > 0 || w.speechQueue && w.speechQueue.length > 0) {
|
|
6971
|
+
v.current && (clearInterval(v.current), v.current = null);
|
|
6972
|
+
let _ = "";
|
|
6973
|
+
if (H.current && z.current.length > 0) {
|
|
6974
|
+
const te = z.current.length, me = w.speechQueue ? w.speechQueue.filter((ie) => ie && ie.text && Array.isArray(ie.text) && ie.text.length > 0).length : 0, A = w.audioPlaylist && w.audioPlaylist.length > 0, P = me + (A ? 1 : 0), K = te - P;
|
|
6975
|
+
if (P > 0 && K < te && (_ = z.current.slice(K).join(". ").trim(), !_ && me > 0 && w.speechQueue)) {
|
|
6976
|
+
const se = w.speechQueue.filter((oe) => oe && oe.text && Array.isArray(oe.text) && oe.text.length > 0).map((oe) => oe.text.map((we) => we.word || "").filter((we) => we.length > 0).join(" ")).filter((oe) => oe.length > 0).join(" ");
|
|
6977
|
+
se && se.trim() && (_ = se.trim());
|
|
6978
6978
|
}
|
|
6979
6979
|
}
|
|
6980
|
-
|
|
6981
|
-
remainingText:
|
|
6982
|
-
originalText:
|
|
6983
|
-
options:
|
|
6984
|
-
}),
|
|
6980
|
+
H.current && (I.current = {
|
|
6981
|
+
remainingText: _ || null,
|
|
6982
|
+
originalText: H.current.text,
|
|
6983
|
+
options: H.current.options
|
|
6984
|
+
}), w.speechQueue && (w.speechQueue.length = 0), p.current.pauseSpeaking(), L.current = !0, de(!0);
|
|
6985
6985
|
}
|
|
6986
6986
|
}
|
|
6987
|
-
}, []),
|
|
6988
|
-
if (!p.current || !
|
|
6987
|
+
}, []), q = N(async () => {
|
|
6988
|
+
if (!p.current || !ge)
|
|
6989
6989
|
return;
|
|
6990
|
-
let
|
|
6991
|
-
if (
|
|
6992
|
-
|
|
6993
|
-
else if (
|
|
6994
|
-
|
|
6990
|
+
let w = "", U = {};
|
|
6991
|
+
if (I.current && I.current.remainingText)
|
|
6992
|
+
w = I.current.remainingText, U = I.current.options || {}, I.current = { remainingText: null, originalText: null, options: null };
|
|
6993
|
+
else if (H.current && H.current.text)
|
|
6994
|
+
w = H.current.text, U = H.current.options || {};
|
|
6995
6995
|
else {
|
|
6996
|
-
console.warn("Resume called but no paused speech found"),
|
|
6996
|
+
console.warn("Resume called but no paused speech found"), de(!1), L.current = !1;
|
|
6997
6997
|
return;
|
|
6998
6998
|
}
|
|
6999
|
-
|
|
7000
|
-
const
|
|
7001
|
-
...
|
|
7002
|
-
lipsyncLang:
|
|
6999
|
+
de(!1), L.current = !1, await E();
|
|
7000
|
+
const _ = {
|
|
7001
|
+
...U,
|
|
7002
|
+
lipsyncLang: U.lipsyncLang || b.lipsyncLang || "en"
|
|
7003
7003
|
};
|
|
7004
7004
|
try {
|
|
7005
|
-
await
|
|
7006
|
-
} catch (
|
|
7007
|
-
console.error("Error resuming speech:",
|
|
7005
|
+
await D(w, _);
|
|
7006
|
+
} catch (te) {
|
|
7007
|
+
console.error("Error resuming speech:", te), de(!1), L.current = !1;
|
|
7008
7008
|
}
|
|
7009
|
-
}, [
|
|
7010
|
-
p.current && p.current.setMood(
|
|
7011
|
-
}, []),
|
|
7012
|
-
p.current && p.current.setSlowdownRate && p.current.setSlowdownRate(
|
|
7013
|
-
}, []),
|
|
7009
|
+
}, [E, ge, D, b]), Ae = N((w) => {
|
|
7010
|
+
p.current && p.current.setMood(w);
|
|
7011
|
+
}, []), Se = N((w) => {
|
|
7012
|
+
p.current && p.current.setSlowdownRate && p.current.setSlowdownRate(w);
|
|
7013
|
+
}, []), Le = N((w, U = !1) => {
|
|
7014
7014
|
if (p.current && p.current.playAnimation) {
|
|
7015
|
-
if (
|
|
7015
|
+
if (f && f[w] && (w = f[w]), p.current.setShowFullAvatar)
|
|
7016
7016
|
try {
|
|
7017
|
-
p.current.setShowFullAvatar(
|
|
7018
|
-
} catch (
|
|
7019
|
-
console.warn("Error setting full body mode:",
|
|
7017
|
+
p.current.setShowFullAvatar(B.current);
|
|
7018
|
+
} catch (te) {
|
|
7019
|
+
console.warn("Error setting full body mode:", te);
|
|
7020
7020
|
}
|
|
7021
|
-
if (
|
|
7021
|
+
if (w.includes("."))
|
|
7022
7022
|
try {
|
|
7023
|
-
p.current.playAnimation(
|
|
7024
|
-
} catch (
|
|
7025
|
-
console.warn(`Failed to play ${
|
|
7023
|
+
p.current.playAnimation(w, null, 10, 0, 0.01, U);
|
|
7024
|
+
} catch (te) {
|
|
7025
|
+
console.warn(`Failed to play ${w}:`, te);
|
|
7026
7026
|
try {
|
|
7027
7027
|
p.current.setBodyMovement("idle");
|
|
7028
|
-
} catch (
|
|
7029
|
-
console.warn("Fallback animation also failed:",
|
|
7028
|
+
} catch (me) {
|
|
7029
|
+
console.warn("Fallback animation also failed:", me);
|
|
7030
7030
|
}
|
|
7031
7031
|
}
|
|
7032
7032
|
else {
|
|
7033
|
-
const
|
|
7034
|
-
let
|
|
7035
|
-
for (const
|
|
7033
|
+
const te = [".fbx", ".glb", ".gltf"];
|
|
7034
|
+
let me = !1;
|
|
7035
|
+
for (const A of te)
|
|
7036
7036
|
try {
|
|
7037
|
-
p.current.playAnimation(
|
|
7037
|
+
p.current.playAnimation(w + A, null, 10, 0, 0.01, U), me = !0;
|
|
7038
7038
|
break;
|
|
7039
7039
|
} catch {
|
|
7040
7040
|
}
|
|
7041
|
-
if (!
|
|
7042
|
-
console.warn("Animation not found:",
|
|
7041
|
+
if (!me) {
|
|
7042
|
+
console.warn("Animation not found:", w);
|
|
7043
7043
|
try {
|
|
7044
7044
|
p.current.setBodyMovement("idle");
|
|
7045
|
-
} catch (
|
|
7046
|
-
console.warn("Fallback animation also failed:",
|
|
7045
|
+
} catch (A) {
|
|
7046
|
+
console.warn("Fallback animation also failed:", A);
|
|
7047
7047
|
}
|
|
7048
7048
|
}
|
|
7049
7049
|
}
|
|
7050
7050
|
}
|
|
7051
|
-
}, [
|
|
7051
|
+
}, [f]), ke = N(() => {
|
|
7052
7052
|
p.current && p.current.onResize && p.current.onResize();
|
|
7053
7053
|
}, []);
|
|
7054
|
-
return Fe(
|
|
7055
|
-
speakText:
|
|
7056
|
-
stopSpeaking:
|
|
7054
|
+
return Fe(k, () => ({
|
|
7055
|
+
speakText: D,
|
|
7056
|
+
stopSpeaking: ee,
|
|
7057
7057
|
pauseSpeaking: Q,
|
|
7058
|
-
resumeSpeaking:
|
|
7059
|
-
resumeAudioContext:
|
|
7058
|
+
resumeSpeaking: q,
|
|
7059
|
+
resumeAudioContext: E,
|
|
7060
7060
|
setMood: Ae,
|
|
7061
|
-
setTimingAdjustment:
|
|
7062
|
-
playAnimation:
|
|
7063
|
-
isReady:
|
|
7064
|
-
isPaused:
|
|
7061
|
+
setTimingAdjustment: Se,
|
|
7062
|
+
playAnimation: Le,
|
|
7063
|
+
isReady: ne,
|
|
7064
|
+
isPaused: ge,
|
|
7065
7065
|
talkingHead: p.current,
|
|
7066
|
-
handleResize:
|
|
7067
|
-
setBodyMovement: (
|
|
7066
|
+
handleResize: ke,
|
|
7067
|
+
setBodyMovement: (w) => {
|
|
7068
7068
|
if (p.current && p.current.setShowFullAvatar && p.current.setBodyMovement)
|
|
7069
7069
|
try {
|
|
7070
|
-
p.current.setShowFullAvatar(
|
|
7071
|
-
} catch (
|
|
7072
|
-
console.warn("Error setting body movement:",
|
|
7070
|
+
p.current.setShowFullAvatar(B.current), p.current.setBodyMovement(w);
|
|
7071
|
+
} catch (U) {
|
|
7072
|
+
console.warn("Error setting body movement:", U);
|
|
7073
7073
|
}
|
|
7074
7074
|
},
|
|
7075
|
-
setMovementIntensity: (
|
|
7075
|
+
setMovementIntensity: (w) => p.current?.setMovementIntensity(w),
|
|
7076
7076
|
playRandomDance: () => {
|
|
7077
7077
|
if (p.current && p.current.setShowFullAvatar && p.current.playRandomDance)
|
|
7078
7078
|
try {
|
|
7079
|
-
p.current.setShowFullAvatar(
|
|
7080
|
-
} catch (
|
|
7081
|
-
console.warn("Error playing random dance:",
|
|
7079
|
+
p.current.setShowFullAvatar(B.current), p.current.playRandomDance();
|
|
7080
|
+
} catch (w) {
|
|
7081
|
+
console.warn("Error playing random dance:", w);
|
|
7082
7082
|
}
|
|
7083
7083
|
},
|
|
7084
|
-
playReaction: (
|
|
7084
|
+
playReaction: (w) => {
|
|
7085
7085
|
if (p.current && p.current.setShowFullAvatar && p.current.playReaction)
|
|
7086
7086
|
try {
|
|
7087
|
-
p.current.setShowFullAvatar(
|
|
7088
|
-
} catch (
|
|
7089
|
-
console.warn("Error playing reaction:",
|
|
7087
|
+
p.current.setShowFullAvatar(B.current), p.current.playReaction(w);
|
|
7088
|
+
} catch (U) {
|
|
7089
|
+
console.warn("Error playing reaction:", U);
|
|
7090
7090
|
}
|
|
7091
7091
|
},
|
|
7092
7092
|
playCelebration: () => {
|
|
7093
7093
|
if (p.current && p.current.setShowFullAvatar && p.current.playCelebration)
|
|
7094
7094
|
try {
|
|
7095
|
-
p.current.setShowFullAvatar(
|
|
7096
|
-
} catch (
|
|
7097
|
-
console.warn("Error playing celebration:",
|
|
7095
|
+
p.current.setShowFullAvatar(B.current), p.current.playCelebration();
|
|
7096
|
+
} catch (w) {
|
|
7097
|
+
console.warn("Error playing celebration:", w);
|
|
7098
7098
|
}
|
|
7099
7099
|
},
|
|
7100
|
-
setShowFullAvatar: (
|
|
7100
|
+
setShowFullAvatar: (w) => {
|
|
7101
7101
|
if (p.current && p.current.setShowFullAvatar)
|
|
7102
7102
|
try {
|
|
7103
|
-
|
|
7104
|
-
} catch (
|
|
7105
|
-
console.warn("Error setting showFullAvatar:",
|
|
7103
|
+
B.current = w, p.current.setShowFullAvatar(w);
|
|
7104
|
+
} catch (U) {
|
|
7105
|
+
console.warn("Error setting showFullAvatar:", U);
|
|
7106
7106
|
}
|
|
7107
7107
|
},
|
|
7108
7108
|
lockAvatarPosition: () => {
|
|
7109
7109
|
if (p.current && p.current.lockAvatarPosition)
|
|
7110
7110
|
try {
|
|
7111
7111
|
p.current.lockAvatarPosition();
|
|
7112
|
-
} catch (
|
|
7113
|
-
console.warn("Error locking avatar position:",
|
|
7112
|
+
} catch (w) {
|
|
7113
|
+
console.warn("Error locking avatar position:", w);
|
|
7114
7114
|
}
|
|
7115
7115
|
},
|
|
7116
7116
|
unlockAvatarPosition: () => {
|
|
7117
7117
|
if (p.current && p.current.unlockAvatarPosition)
|
|
7118
7118
|
try {
|
|
7119
7119
|
p.current.unlockAvatarPosition();
|
|
7120
|
-
} catch (
|
|
7121
|
-
console.warn("Error unlocking avatar position:",
|
|
7120
|
+
} catch (w) {
|
|
7121
|
+
console.warn("Error unlocking avatar position:", w);
|
|
7122
7122
|
}
|
|
7123
7123
|
}
|
|
7124
7124
|
})), /* @__PURE__ */ Pe(
|
|
@@ -7129,13 +7129,13 @@ const Ve = Me(({
|
|
|
7129
7129
|
width: "100%",
|
|
7130
7130
|
height: "100%",
|
|
7131
7131
|
position: "relative",
|
|
7132
|
-
...
|
|
7132
|
+
...x
|
|
7133
7133
|
},
|
|
7134
7134
|
children: [
|
|
7135
|
-
/* @__PURE__ */
|
|
7135
|
+
/* @__PURE__ */ ye(
|
|
7136
7136
|
"div",
|
|
7137
7137
|
{
|
|
7138
|
-
ref:
|
|
7138
|
+
ref: O,
|
|
7139
7139
|
className: "talking-head-viewer",
|
|
7140
7140
|
style: {
|
|
7141
7141
|
width: "100%",
|
|
@@ -7144,7 +7144,7 @@ const Ve = Me(({
|
|
|
7144
7144
|
}
|
|
7145
7145
|
}
|
|
7146
7146
|
),
|
|
7147
|
-
|
|
7147
|
+
S && /* @__PURE__ */ ye("div", { className: "loading-overlay", style: {
|
|
7148
7148
|
position: "absolute",
|
|
7149
7149
|
top: "50%",
|
|
7150
7150
|
left: "50%",
|
|
@@ -7153,7 +7153,7 @@ const Ve = Me(({
|
|
|
7153
7153
|
fontSize: "18px",
|
|
7154
7154
|
zIndex: 10
|
|
7155
7155
|
}, children: "Loading avatar..." }),
|
|
7156
|
-
|
|
7156
|
+
X && /* @__PURE__ */ ye("div", { className: "error-overlay", style: {
|
|
7157
7157
|
position: "absolute",
|
|
7158
7158
|
top: "50%",
|
|
7159
7159
|
left: "50%",
|
|
@@ -7164,14 +7164,14 @@ const Ve = Me(({
|
|
|
7164
7164
|
zIndex: 10,
|
|
7165
7165
|
padding: "20px",
|
|
7166
7166
|
borderRadius: "8px"
|
|
7167
|
-
}, children:
|
|
7167
|
+
}, children: X })
|
|
7168
7168
|
]
|
|
7169
7169
|
}
|
|
7170
7170
|
);
|
|
7171
7171
|
});
|
|
7172
7172
|
Ve.displayName = "TalkingHeadAvatar";
|
|
7173
7173
|
const pt = Me(({
|
|
7174
|
-
text:
|
|
7174
|
+
text: V = "Hello! I'm a talking avatar. How are you today?",
|
|
7175
7175
|
onLoading: t = () => {
|
|
7176
7176
|
},
|
|
7177
7177
|
onError: e = () => {
|
|
@@ -7182,23 +7182,23 @@ const pt = Me(({
|
|
|
7182
7182
|
style: s = {},
|
|
7183
7183
|
avatarConfig: o = {}
|
|
7184
7184
|
}, l) => {
|
|
7185
|
-
const h =
|
|
7185
|
+
const h = W(null), r = W(null), [u, a] = pe(!0), [d, c] = pe(null), [g, x] = pe(!1), f = Ee(), k = o.ttsService || f.service, O = k === "browser" ? {
|
|
7186
7186
|
endpoint: "",
|
|
7187
7187
|
apiKey: null,
|
|
7188
7188
|
defaultVoice: "Google US English"
|
|
7189
7189
|
} : {
|
|
7190
|
-
...
|
|
7190
|
+
...f,
|
|
7191
7191
|
// Override API key if provided via avatarConfig
|
|
7192
|
-
apiKey: o.ttsApiKey !== void 0 && o.ttsApiKey !== null ? o.ttsApiKey :
|
|
7192
|
+
apiKey: o.ttsApiKey !== void 0 && o.ttsApiKey !== null ? o.ttsApiKey : f.apiKey,
|
|
7193
7193
|
// Override endpoint for ElevenLabs if service is explicitly set
|
|
7194
|
-
endpoint:
|
|
7194
|
+
endpoint: k === "elevenlabs" && o.ttsApiKey ? "https://api.elevenlabs.io/v1/text-to-speech" : f.endpoint
|
|
7195
7195
|
}, p = {
|
|
7196
7196
|
url: "/avatars/brunette.glb",
|
|
7197
7197
|
// Use brunette avatar (working glTF file)
|
|
7198
7198
|
body: "F",
|
|
7199
7199
|
avatarMood: "neutral",
|
|
7200
|
-
ttsLang:
|
|
7201
|
-
ttsVoice: o.ttsVoice ||
|
|
7200
|
+
ttsLang: k === "browser" ? "en-US" : "en",
|
|
7201
|
+
ttsVoice: o.ttsVoice || O.defaultVoice,
|
|
7202
7202
|
lipsyncLang: "en",
|
|
7203
7203
|
// English lip-sync
|
|
7204
7204
|
showFullAvatar: !0,
|
|
@@ -7206,176 +7206,176 @@ const pt = Me(({
|
|
|
7206
7206
|
bodyMovement: "idle",
|
|
7207
7207
|
movementIntensity: 0.5,
|
|
7208
7208
|
...o
|
|
7209
|
-
},
|
|
7210
|
-
ttsEndpoint:
|
|
7211
|
-
ttsApikey:
|
|
7212
|
-
ttsService:
|
|
7209
|
+
}, B = {
|
|
7210
|
+
ttsEndpoint: O.endpoint,
|
|
7211
|
+
ttsApikey: O.apiKey,
|
|
7212
|
+
ttsService: k,
|
|
7213
7213
|
lipsyncModules: ["en"],
|
|
7214
7214
|
cameraView: "upper"
|
|
7215
|
-
},
|
|
7215
|
+
}, H = N(async () => {
|
|
7216
7216
|
if (!(!h.current || r.current))
|
|
7217
7217
|
try {
|
|
7218
|
-
if (a(!0), c(null), r.current = new Be(h.current,
|
|
7219
|
-
if (
|
|
7220
|
-
const
|
|
7221
|
-
t(
|
|
7218
|
+
if (a(!0), c(null), r.current = new Be(h.current, B), await r.current.showAvatar(p, (X) => {
|
|
7219
|
+
if (X.lengthComputable) {
|
|
7220
|
+
const Z = Math.min(100, Math.round(X.loaded / X.total * 100));
|
|
7221
|
+
t(Z);
|
|
7222
7222
|
}
|
|
7223
7223
|
}), r.current.morphs && r.current.morphs.length > 0) {
|
|
7224
|
-
const
|
|
7225
|
-
console.log("Available morph targets:", Object.keys(
|
|
7226
|
-
const
|
|
7227
|
-
console.log("Viseme morph targets found:",
|
|
7224
|
+
const X = r.current.morphs[0].morphTargetDictionary;
|
|
7225
|
+
console.log("Available morph targets:", Object.keys(X));
|
|
7226
|
+
const Z = Object.keys(X).filter((ne) => ne.startsWith("viseme_"));
|
|
7227
|
+
console.log("Viseme morph targets found:", Z), Z.length === 0 && (console.warn("No viseme morph targets found! Lip-sync will not work properly."), console.log("Expected viseme targets: viseme_aa, viseme_E, viseme_I, viseme_O, viseme_U, viseme_PP, viseme_SS, viseme_TH, viseme_DD, viseme_FF, viseme_kk, viseme_nn, viseme_RR, viseme_CH, viseme_sil"));
|
|
7228
7228
|
}
|
|
7229
|
-
if (await new Promise((
|
|
7230
|
-
const
|
|
7231
|
-
r.current.lipsync && Object.keys(r.current.lipsync).length > 0 ? (console.log("Lip-sync modules loaded:", Object.keys(r.current.lipsync)),
|
|
7229
|
+
if (await new Promise((X) => {
|
|
7230
|
+
const Z = () => {
|
|
7231
|
+
r.current.lipsync && Object.keys(r.current.lipsync).length > 0 ? (console.log("Lip-sync modules loaded:", Object.keys(r.current.lipsync)), X()) : (console.log("Waiting for lip-sync modules to load..."), setTimeout(Z, 100));
|
|
7232
7232
|
};
|
|
7233
|
-
|
|
7233
|
+
Z();
|
|
7234
7234
|
}), r.current && r.current.setShowFullAvatar)
|
|
7235
7235
|
try {
|
|
7236
7236
|
r.current.setShowFullAvatar(!0), console.log("Avatar initialized in full body mode");
|
|
7237
|
-
} catch (
|
|
7238
|
-
console.warn("Error setting full body mode on initialization:",
|
|
7237
|
+
} catch (X) {
|
|
7238
|
+
console.warn("Error setting full body mode on initialization:", X);
|
|
7239
7239
|
}
|
|
7240
|
-
a(!1),
|
|
7241
|
-
const
|
|
7240
|
+
a(!1), x(!0), n(r.current);
|
|
7241
|
+
const F = () => {
|
|
7242
7242
|
document.visibilityState === "visible" ? r.current?.start() : r.current?.stop();
|
|
7243
7243
|
};
|
|
7244
|
-
return document.addEventListener("visibilitychange",
|
|
7245
|
-
document.removeEventListener("visibilitychange",
|
|
7244
|
+
return document.addEventListener("visibilitychange", F), () => {
|
|
7245
|
+
document.removeEventListener("visibilitychange", F);
|
|
7246
7246
|
};
|
|
7247
|
-
} catch (
|
|
7248
|
-
console.error("Error initializing TalkingHead:",
|
|
7247
|
+
} catch (S) {
|
|
7248
|
+
console.error("Error initializing TalkingHead:", S), c(S.message || "Failed to initialize avatar"), a(!1), e(S);
|
|
7249
7249
|
}
|
|
7250
7250
|
}, []);
|
|
7251
|
-
|
|
7251
|
+
ce(() => (H(), () => {
|
|
7252
7252
|
r.current && (r.current.stop(), r.current.dispose(), r.current = null);
|
|
7253
|
-
}), [
|
|
7254
|
-
const
|
|
7253
|
+
}), [H]);
|
|
7254
|
+
const v = N((S) => {
|
|
7255
7255
|
if (r.current && g)
|
|
7256
7256
|
try {
|
|
7257
|
-
console.log("Speaking text:",
|
|
7258
|
-
r.current && r.current.lipsync ? (console.log("Lip-sync now ready, speaking..."), r.current.setSlowdownRate && (r.current.setSlowdownRate(1.05), console.log("Applied timing adjustment for better lip-sync")), r.current.speakText(
|
|
7257
|
+
console.log("Speaking text:", S), console.log("Avatar config:", p), console.log("TalkingHead instance:", r.current), r.current.lipsync && Object.keys(r.current.lipsync).length > 0 ? (console.log("Lip-sync modules loaded:", Object.keys(r.current.lipsync)), r.current.setSlowdownRate && (r.current.setSlowdownRate(1.05), console.log("Applied timing adjustment for better lip-sync")), r.current.speakText(S)) : (console.warn("Lip-sync modules not ready, waiting..."), setTimeout(() => {
|
|
7258
|
+
r.current && r.current.lipsync ? (console.log("Lip-sync now ready, speaking..."), r.current.setSlowdownRate && (r.current.setSlowdownRate(1.05), console.log("Applied timing adjustment for better lip-sync")), r.current.speakText(S)) : console.error("Lip-sync still not ready after waiting");
|
|
7259
7259
|
}, 500));
|
|
7260
|
-
} catch (
|
|
7261
|
-
console.error("Error speaking text:",
|
|
7260
|
+
} catch (F) {
|
|
7261
|
+
console.error("Error speaking text:", F), c(F.message || "Failed to speak text");
|
|
7262
7262
|
}
|
|
7263
7263
|
else
|
|
7264
7264
|
console.warn("Avatar not ready for speaking. isReady:", g, "talkingHeadRef:", !!r.current);
|
|
7265
|
-
}, [g, p]),
|
|
7265
|
+
}, [g, p]), L = N(() => {
|
|
7266
7266
|
r.current && (r.current.stopSpeaking(), r.current.setSlowdownRate && (r.current.setSlowdownRate(1), console.log("Reset timing to normal")));
|
|
7267
|
-
}, []),
|
|
7268
|
-
r.current && r.current.setMood(
|
|
7269
|
-
}, []),
|
|
7270
|
-
r.current && r.current.setSlowdownRate && (r.current.setSlowdownRate(
|
|
7271
|
-
}, []), Y =
|
|
7267
|
+
}, []), I = N((S) => {
|
|
7268
|
+
r.current && r.current.setMood(S);
|
|
7269
|
+
}, []), z = N((S) => {
|
|
7270
|
+
r.current && r.current.setSlowdownRate && (r.current.setSlowdownRate(S), console.log("Timing adjustment set to:", S));
|
|
7271
|
+
}, []), Y = N((S, F = !1) => {
|
|
7272
7272
|
if (r.current && r.current.playAnimation) {
|
|
7273
7273
|
if (r.current.setShowFullAvatar)
|
|
7274
7274
|
try {
|
|
7275
7275
|
r.current.setShowFullAvatar(!0);
|
|
7276
|
-
} catch (
|
|
7277
|
-
console.warn("Error setting full body mode:",
|
|
7276
|
+
} catch (Z) {
|
|
7277
|
+
console.warn("Error setting full body mode:", Z);
|
|
7278
7278
|
}
|
|
7279
|
-
if (
|
|
7279
|
+
if (S.includes("."))
|
|
7280
7280
|
try {
|
|
7281
|
-
r.current.playAnimation(
|
|
7282
|
-
} catch (
|
|
7283
|
-
console.log(`Failed to play ${
|
|
7281
|
+
r.current.playAnimation(S, null, 10, 0, 0.01, F), console.log("Playing animation:", S);
|
|
7282
|
+
} catch (Z) {
|
|
7283
|
+
console.log(`Failed to play ${S}:`, Z);
|
|
7284
7284
|
try {
|
|
7285
7285
|
r.current.setBodyMovement("idle"), console.log("Fallback to idle animation");
|
|
7286
|
-
} catch (
|
|
7287
|
-
console.warn("Fallback animation also failed:",
|
|
7286
|
+
} catch (ne) {
|
|
7287
|
+
console.warn("Fallback animation also failed:", ne);
|
|
7288
7288
|
}
|
|
7289
7289
|
}
|
|
7290
7290
|
else {
|
|
7291
|
-
const
|
|
7292
|
-
let
|
|
7293
|
-
for (const
|
|
7291
|
+
const Z = [".fbx", ".glb", ".gltf"];
|
|
7292
|
+
let ne = !1;
|
|
7293
|
+
for (const le of Z)
|
|
7294
7294
|
try {
|
|
7295
|
-
r.current.playAnimation(
|
|
7295
|
+
r.current.playAnimation(S + le, null, 10, 0, 0.01, F), console.log("Playing animation:", S + le), ne = !0;
|
|
7296
7296
|
break;
|
|
7297
7297
|
} catch {
|
|
7298
|
-
console.log(`Failed to play ${
|
|
7298
|
+
console.log(`Failed to play ${S}${le}, trying next format...`);
|
|
7299
7299
|
}
|
|
7300
|
-
if (!
|
|
7301
|
-
console.warn("Animation system not available or animation not found:",
|
|
7300
|
+
if (!ne) {
|
|
7301
|
+
console.warn("Animation system not available or animation not found:", S);
|
|
7302
7302
|
try {
|
|
7303
7303
|
r.current.setBodyMovement("idle"), console.log("Fallback to idle animation");
|
|
7304
|
-
} catch (
|
|
7305
|
-
console.warn("Fallback animation also failed:",
|
|
7304
|
+
} catch (le) {
|
|
7305
|
+
console.warn("Fallback animation also failed:", le);
|
|
7306
7306
|
}
|
|
7307
7307
|
}
|
|
7308
7308
|
}
|
|
7309
7309
|
} else
|
|
7310
|
-
console.warn("Animation system not available or animation not found:",
|
|
7310
|
+
console.warn("Animation system not available or animation not found:", S);
|
|
7311
7311
|
}, []);
|
|
7312
7312
|
return Fe(l, () => ({
|
|
7313
|
-
speakText:
|
|
7314
|
-
stopSpeaking:
|
|
7315
|
-
setMood:
|
|
7316
|
-
setTimingAdjustment:
|
|
7313
|
+
speakText: v,
|
|
7314
|
+
stopSpeaking: L,
|
|
7315
|
+
setMood: I,
|
|
7316
|
+
setTimingAdjustment: z,
|
|
7317
7317
|
playAnimation: Y,
|
|
7318
7318
|
isReady: g,
|
|
7319
7319
|
talkingHead: r.current,
|
|
7320
|
-
setBodyMovement: (
|
|
7320
|
+
setBodyMovement: (S) => {
|
|
7321
7321
|
if (r.current && r.current.setShowFullAvatar && r.current.setBodyMovement)
|
|
7322
7322
|
try {
|
|
7323
|
-
r.current.setShowFullAvatar(!0), r.current.setBodyMovement(
|
|
7324
|
-
} catch (
|
|
7325
|
-
console.warn("Error setting body movement:",
|
|
7323
|
+
r.current.setShowFullAvatar(!0), r.current.setBodyMovement(S), console.log("Body movement set with full body mode:", S);
|
|
7324
|
+
} catch (F) {
|
|
7325
|
+
console.warn("Error setting body movement:", F);
|
|
7326
7326
|
}
|
|
7327
7327
|
},
|
|
7328
|
-
setMovementIntensity: (
|
|
7328
|
+
setMovementIntensity: (S) => r.current?.setMovementIntensity(S),
|
|
7329
7329
|
playRandomDance: () => {
|
|
7330
7330
|
if (r.current && r.current.setShowFullAvatar && r.current.playRandomDance)
|
|
7331
7331
|
try {
|
|
7332
7332
|
r.current.setShowFullAvatar(!0), r.current.playRandomDance(), console.log("Random dance played with full body mode");
|
|
7333
|
-
} catch (
|
|
7334
|
-
console.warn("Error playing random dance:",
|
|
7333
|
+
} catch (S) {
|
|
7334
|
+
console.warn("Error playing random dance:", S);
|
|
7335
7335
|
}
|
|
7336
7336
|
},
|
|
7337
|
-
playReaction: (
|
|
7337
|
+
playReaction: (S) => {
|
|
7338
7338
|
if (r.current && r.current.setShowFullAvatar && r.current.playReaction)
|
|
7339
7339
|
try {
|
|
7340
|
-
r.current.setShowFullAvatar(!0), r.current.playReaction(
|
|
7341
|
-
} catch (
|
|
7342
|
-
console.warn("Error playing reaction:",
|
|
7340
|
+
r.current.setShowFullAvatar(!0), r.current.playReaction(S), console.log("Reaction played with full body mode:", S);
|
|
7341
|
+
} catch (F) {
|
|
7342
|
+
console.warn("Error playing reaction:", F);
|
|
7343
7343
|
}
|
|
7344
7344
|
},
|
|
7345
7345
|
playCelebration: () => {
|
|
7346
7346
|
if (r.current && r.current.setShowFullAvatar && r.current.playCelebration)
|
|
7347
7347
|
try {
|
|
7348
7348
|
r.current.setShowFullAvatar(!0), r.current.playCelebration(), console.log("Celebration played with full body mode");
|
|
7349
|
-
} catch (
|
|
7350
|
-
console.warn("Error playing celebration:",
|
|
7349
|
+
} catch (S) {
|
|
7350
|
+
console.warn("Error playing celebration:", S);
|
|
7351
7351
|
}
|
|
7352
7352
|
},
|
|
7353
|
-
setShowFullAvatar: (
|
|
7353
|
+
setShowFullAvatar: (S) => {
|
|
7354
7354
|
if (r.current && r.current.setShowFullAvatar)
|
|
7355
7355
|
try {
|
|
7356
|
-
r.current.setShowFullAvatar(
|
|
7357
|
-
} catch (
|
|
7358
|
-
console.warn("Error setting showFullAvatar:",
|
|
7356
|
+
r.current.setShowFullAvatar(S), console.log("Show full avatar set to:", S);
|
|
7357
|
+
} catch (F) {
|
|
7358
|
+
console.warn("Error setting showFullAvatar:", F);
|
|
7359
7359
|
}
|
|
7360
7360
|
},
|
|
7361
7361
|
lockAvatarPosition: () => {
|
|
7362
7362
|
if (r.current && r.current.lockAvatarPosition)
|
|
7363
7363
|
try {
|
|
7364
7364
|
r.current.lockAvatarPosition();
|
|
7365
|
-
} catch (
|
|
7366
|
-
console.warn("Error locking avatar position:",
|
|
7365
|
+
} catch (S) {
|
|
7366
|
+
console.warn("Error locking avatar position:", S);
|
|
7367
7367
|
}
|
|
7368
7368
|
},
|
|
7369
7369
|
unlockAvatarPosition: () => {
|
|
7370
7370
|
if (r.current && r.current.unlockAvatarPosition)
|
|
7371
7371
|
try {
|
|
7372
7372
|
r.current.unlockAvatarPosition();
|
|
7373
|
-
} catch (
|
|
7374
|
-
console.warn("Error unlocking avatar position:",
|
|
7373
|
+
} catch (S) {
|
|
7374
|
+
console.warn("Error unlocking avatar position:", S);
|
|
7375
7375
|
}
|
|
7376
7376
|
}
|
|
7377
7377
|
})), /* @__PURE__ */ Pe("div", { className: `talking-head-container ${i}`, style: s, children: [
|
|
7378
|
-
/* @__PURE__ */
|
|
7378
|
+
/* @__PURE__ */ ye(
|
|
7379
7379
|
"div",
|
|
7380
7380
|
{
|
|
7381
7381
|
ref: h,
|
|
@@ -7387,7 +7387,7 @@ const pt = Me(({
|
|
|
7387
7387
|
}
|
|
7388
7388
|
}
|
|
7389
7389
|
),
|
|
7390
|
-
u && /* @__PURE__ */
|
|
7390
|
+
u && /* @__PURE__ */ ye("div", { className: "loading-overlay", style: {
|
|
7391
7391
|
position: "absolute",
|
|
7392
7392
|
top: "50%",
|
|
7393
7393
|
left: "50%",
|
|
@@ -7396,7 +7396,7 @@ const pt = Me(({
|
|
|
7396
7396
|
fontSize: "18px",
|
|
7397
7397
|
zIndex: 10
|
|
7398
7398
|
}, children: "Loading avatar..." }),
|
|
7399
|
-
d && /* @__PURE__ */
|
|
7399
|
+
d && /* @__PURE__ */ ye("div", { className: "error-overlay", style: {
|
|
7400
7400
|
position: "absolute",
|
|
7401
7401
|
top: "50%",
|
|
7402
7402
|
left: "50%",
|
|
@@ -7411,8 +7411,15 @@ const pt = Me(({
|
|
|
7411
7411
|
] });
|
|
7412
7412
|
});
|
|
7413
7413
|
pt.displayName = "TalkingHeadComponent";
|
|
7414
|
-
|
|
7415
|
-
|
|
7414
|
+
async function gt(V) {
|
|
7415
|
+
try {
|
|
7416
|
+
return (await (await fetch(V)).json()).animations || {};
|
|
7417
|
+
} catch (t) {
|
|
7418
|
+
return console.error("Failed to load animation manifest:", t), {};
|
|
7419
|
+
}
|
|
7420
|
+
}
|
|
7421
|
+
const yt = Me(({
|
|
7422
|
+
text: V = null,
|
|
7416
7423
|
avatarUrl: t = "/avatars/brunette.glb",
|
|
7417
7424
|
avatarBody: e = "F",
|
|
7418
7425
|
mood: n = "neutral",
|
|
@@ -7430,173 +7437,223 @@ const gt = Me(({
|
|
|
7430
7437
|
},
|
|
7431
7438
|
onError: g = () => {
|
|
7432
7439
|
},
|
|
7433
|
-
onSpeechEnd:
|
|
7440
|
+
onSpeechEnd: x = () => {
|
|
7434
7441
|
},
|
|
7435
|
-
className:
|
|
7436
|
-
style:
|
|
7437
|
-
animations:
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7442
|
+
className: f = "",
|
|
7443
|
+
style: k = {},
|
|
7444
|
+
animations: O = {},
|
|
7445
|
+
autoAnimationGroup: p = null,
|
|
7446
|
+
// e.g., "talking" - will randomly select from this group when speaking
|
|
7447
|
+
autoIdleGroup: B = null,
|
|
7448
|
+
// e.g., "idle" - will randomly select from this group when idle
|
|
7449
|
+
autoSpeak: H = !1
|
|
7450
|
+
}, v) => {
|
|
7451
|
+
const L = W(null), I = W(null), z = W(u), Y = W(null), S = W(null), F = W(!1), X = W({ remainingText: null, originalText: null, options: null }), Z = W([]), [ne, le] = pe(!0), [ge, de] = pe(null), [$, be] = pe(!1), [j, b] = pe(!1), [R, M] = pe(O), E = W(null);
|
|
7452
|
+
ce(() => {
|
|
7453
|
+
F.current = j;
|
|
7454
|
+
}, [j]), ce(() => {
|
|
7455
|
+
(async () => {
|
|
7456
|
+
if (O.manifest)
|
|
7457
|
+
try {
|
|
7458
|
+
const P = await gt(O.manifest);
|
|
7459
|
+
M(P), console.log("Loaded animations from manifest:", P);
|
|
7460
|
+
} catch (P) {
|
|
7461
|
+
console.error("Failed to load animation manifest:", P), M(O);
|
|
7462
|
+
}
|
|
7463
|
+
else
|
|
7464
|
+
M(O);
|
|
7465
|
+
})();
|
|
7466
|
+
}, [O]), ce(() => {
|
|
7467
|
+
z.current = u;
|
|
7445
7468
|
}, [u]);
|
|
7446
|
-
const
|
|
7447
|
-
let
|
|
7448
|
-
|
|
7469
|
+
const D = Ee(), ee = s || D.service;
|
|
7470
|
+
let Q;
|
|
7471
|
+
ee === "browser" ? Q = {
|
|
7449
7472
|
service: "browser",
|
|
7450
7473
|
endpoint: "",
|
|
7451
7474
|
apiKey: null,
|
|
7452
7475
|
defaultVoice: "Google US English"
|
|
7453
|
-
} :
|
|
7476
|
+
} : ee === "elevenlabs" ? Q = {
|
|
7454
7477
|
service: "elevenlabs",
|
|
7455
7478
|
endpoint: "https://api.elevenlabs.io/v1/text-to-speech",
|
|
7456
|
-
apiKey: l ||
|
|
7457
|
-
defaultVoice: o ||
|
|
7458
|
-
voices:
|
|
7459
|
-
} :
|
|
7479
|
+
apiKey: l || D.apiKey,
|
|
7480
|
+
defaultVoice: o || D.defaultVoice || Ie.defaultVoice,
|
|
7481
|
+
voices: D.voices || Ie.voices
|
|
7482
|
+
} : ee === "deepgram" ? Q = {
|
|
7460
7483
|
service: "deepgram",
|
|
7461
7484
|
endpoint: "https://api.deepgram.com/v1/speak",
|
|
7462
|
-
apiKey: l ||
|
|
7463
|
-
defaultVoice: o ||
|
|
7464
|
-
voices:
|
|
7465
|
-
} :
|
|
7466
|
-
...
|
|
7467
|
-
apiKey: l !== null ? l :
|
|
7485
|
+
apiKey: l || D.apiKey,
|
|
7486
|
+
defaultVoice: o || D.defaultVoice || Te.defaultVoice,
|
|
7487
|
+
voices: D.voices || Te.voices
|
|
7488
|
+
} : Q = {
|
|
7489
|
+
...D,
|
|
7490
|
+
apiKey: l !== null ? l : D.apiKey
|
|
7468
7491
|
};
|
|
7469
|
-
const
|
|
7492
|
+
const q = {
|
|
7470
7493
|
url: t,
|
|
7471
7494
|
body: e,
|
|
7472
7495
|
avatarMood: n,
|
|
7473
|
-
ttsLang:
|
|
7474
|
-
ttsVoice: o ||
|
|
7496
|
+
ttsLang: ee === "browser" ? "en-US" : i,
|
|
7497
|
+
ttsVoice: o || Q.defaultVoice,
|
|
7475
7498
|
lipsyncLang: "en",
|
|
7476
7499
|
showFullAvatar: u,
|
|
7477
7500
|
bodyMovement: h,
|
|
7478
7501
|
movementIntensity: r
|
|
7479
|
-
},
|
|
7480
|
-
ttsEndpoint:
|
|
7481
|
-
ttsApikey:
|
|
7482
|
-
ttsService:
|
|
7502
|
+
}, Ae = {
|
|
7503
|
+
ttsEndpoint: Q.endpoint,
|
|
7504
|
+
ttsApikey: Q.apiKey,
|
|
7505
|
+
ttsService: ee,
|
|
7483
7506
|
lipsyncModules: ["en"],
|
|
7484
7507
|
cameraView: a
|
|
7485
|
-
},
|
|
7486
|
-
if (!(!
|
|
7508
|
+
}, Se = N(async () => {
|
|
7509
|
+
if (!(!L.current || I.current))
|
|
7487
7510
|
try {
|
|
7488
|
-
|
|
7489
|
-
url:
|
|
7490
|
-
body:
|
|
7491
|
-
avatarMood:
|
|
7492
|
-
}), await
|
|
7493
|
-
if (
|
|
7494
|
-
const
|
|
7495
|
-
c(
|
|
7511
|
+
le(!0), de(null), I.current = new Be(L.current, Ae), console.log("Avatar config being passed:", {
|
|
7512
|
+
url: q.url,
|
|
7513
|
+
body: q.body,
|
|
7514
|
+
avatarMood: q.avatarMood
|
|
7515
|
+
}), await I.current.showAvatar(q, (P) => {
|
|
7516
|
+
if (P.lengthComputable) {
|
|
7517
|
+
const K = Math.min(100, Math.round(P.loaded / P.total * 100));
|
|
7518
|
+
c(K);
|
|
7496
7519
|
}
|
|
7497
|
-
}),
|
|
7498
|
-
const
|
|
7499
|
-
document.visibilityState === "visible" ?
|
|
7520
|
+
}), I.current?.avatar && console.log("Avatar body after initialization:", I.current.avatar.body), le(!1), be(!0), d(I.current);
|
|
7521
|
+
const A = () => {
|
|
7522
|
+
document.visibilityState === "visible" ? I.current?.start() : I.current?.stop();
|
|
7500
7523
|
};
|
|
7501
|
-
return document.addEventListener("visibilitychange",
|
|
7502
|
-
document.removeEventListener("visibilitychange",
|
|
7524
|
+
return document.addEventListener("visibilitychange", A), () => {
|
|
7525
|
+
document.removeEventListener("visibilitychange", A);
|
|
7503
7526
|
};
|
|
7504
|
-
} catch (
|
|
7505
|
-
console.error("Error initializing TalkingHead:",
|
|
7527
|
+
} catch (A) {
|
|
7528
|
+
console.error("Error initializing TalkingHead:", A), de(A.message || "Failed to initialize avatar"), le(!1), g(A);
|
|
7506
7529
|
}
|
|
7507
7530
|
}, []);
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
}), [
|
|
7511
|
-
const
|
|
7512
|
-
if (
|
|
7531
|
+
ce(() => (Se(), () => {
|
|
7532
|
+
I.current && (I.current.stop(), I.current.dispose(), I.current = null);
|
|
7533
|
+
}), [Se]);
|
|
7534
|
+
const Le = N(async () => {
|
|
7535
|
+
if (I.current)
|
|
7513
7536
|
try {
|
|
7514
|
-
const
|
|
7515
|
-
|
|
7516
|
-
} catch (
|
|
7517
|
-
console.warn("Failed to resume audio context:",
|
|
7537
|
+
const A = I.current.audioCtx || I.current.audioContext;
|
|
7538
|
+
A && (A.state === "suspended" || A.state === "interrupted") && (await A.resume(), console.log("Audio context resumed"));
|
|
7539
|
+
} catch (A) {
|
|
7540
|
+
console.warn("Failed to resume audio context:", A);
|
|
7518
7541
|
}
|
|
7519
|
-
}, []),
|
|
7520
|
-
if (!
|
|
7542
|
+
}, []), ke = N((A) => {
|
|
7543
|
+
if (!R || !R[A])
|
|
7544
|
+
return null;
|
|
7545
|
+
const P = R[A];
|
|
7546
|
+
if (Array.isArray(P) && P.length > 0) {
|
|
7547
|
+
const K = Math.floor(Math.random() * P.length);
|
|
7548
|
+
return P[K];
|
|
7549
|
+
}
|
|
7550
|
+
return typeof P == "string" ? P : null;
|
|
7551
|
+
}, [R]), w = N((A, P = !1) => {
|
|
7552
|
+
const K = ke(A);
|
|
7553
|
+
if (K && I.current)
|
|
7554
|
+
try {
|
|
7555
|
+
return I.current.playAnimation(K, null, 10, 0, 0.01, P), console.log(`Playing random animation from "${A}" group:`, K), K;
|
|
7556
|
+
} catch (ie) {
|
|
7557
|
+
return console.warn(`Failed to play random animation from "${A}" group:`, ie), null;
|
|
7558
|
+
}
|
|
7559
|
+
return null;
|
|
7560
|
+
}, [ke]), U = N(async (A, P = {}) => {
|
|
7561
|
+
if (!I.current || !$) {
|
|
7521
7562
|
console.warn("Avatar not ready for speaking");
|
|
7522
7563
|
return;
|
|
7523
7564
|
}
|
|
7524
|
-
if (!
|
|
7565
|
+
if (!A || A.trim() === "") {
|
|
7525
7566
|
console.warn("No text provided to speak");
|
|
7526
7567
|
return;
|
|
7527
7568
|
}
|
|
7528
|
-
await
|
|
7529
|
-
const
|
|
7530
|
-
|
|
7531
|
-
const
|
|
7532
|
-
|
|
7569
|
+
await Le();
|
|
7570
|
+
const K = P.animationGroup || p;
|
|
7571
|
+
K && !P.skipAnimation && w(K), X.current = { remainingText: null, originalText: null, options: null }, Z.current = [], Y.current = { text: A, options: P }, S.current && (clearInterval(S.current), S.current = null), b(!1), F.current = !1;
|
|
7572
|
+
const ie = A.split(/[.!?]+/).filter((oe) => oe.trim().length > 0);
|
|
7573
|
+
Z.current = ie;
|
|
7574
|
+
const se = {
|
|
7575
|
+
lipsyncLang: P.lipsyncLang || "en",
|
|
7533
7576
|
onSpeechEnd: () => {
|
|
7534
|
-
|
|
7577
|
+
S.current && (clearInterval(S.current), S.current = null), P.onSpeechEnd && P.onSpeechEnd(), x();
|
|
7535
7578
|
}
|
|
7536
7579
|
};
|
|
7537
7580
|
try {
|
|
7538
|
-
|
|
7539
|
-
} catch (
|
|
7540
|
-
console.error("Error speaking text:",
|
|
7581
|
+
I.current.speakText(A, se);
|
|
7582
|
+
} catch (oe) {
|
|
7583
|
+
console.error("Error speaking text:", oe), de(oe.message || "Failed to speak text");
|
|
7541
7584
|
}
|
|
7542
|
-
}, [
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7585
|
+
}, [$, x, Le, p, w]);
|
|
7586
|
+
ce(() => {
|
|
7587
|
+
if (!$ || !B || !I.current)
|
|
7588
|
+
return;
|
|
7589
|
+
E.current && clearInterval(E.current);
|
|
7590
|
+
const A = () => {
|
|
7591
|
+
I.current && !F.current && w(B);
|
|
7592
|
+
};
|
|
7593
|
+
return A(), E.current = setInterval(() => {
|
|
7594
|
+
A();
|
|
7595
|
+
}, 12e3 + Math.random() * 3e3), () => {
|
|
7596
|
+
E.current && (clearInterval(E.current), E.current = null);
|
|
7597
|
+
};
|
|
7598
|
+
}, [$, B, w]), ce(() => {
|
|
7599
|
+
$ && V && H && I.current && U(V);
|
|
7600
|
+
}, [$, V, H, U]);
|
|
7601
|
+
const _ = N(() => {
|
|
7602
|
+
if (I.current)
|
|
7548
7603
|
try {
|
|
7549
|
-
const
|
|
7550
|
-
if (
|
|
7551
|
-
|
|
7552
|
-
let
|
|
7553
|
-
|
|
7554
|
-
remainingText:
|
|
7555
|
-
originalText:
|
|
7556
|
-
options:
|
|
7557
|
-
},
|
|
7604
|
+
const A = I.current.isSpeaking || !1, P = I.current.audioPlaylist || [], K = I.current.speechQueue || [];
|
|
7605
|
+
if (A || P.length > 0 || K.length > 0) {
|
|
7606
|
+
S.current && (clearInterval(S.current), S.current = null);
|
|
7607
|
+
let ie = "";
|
|
7608
|
+
K.length > 0 && (ie = K.map((se) => se.text && Array.isArray(se.text) ? se.text.map((oe) => oe.word).join(" ") : se.text || "").join(" ")), X.current = {
|
|
7609
|
+
remainingText: ie || null,
|
|
7610
|
+
originalText: Y.current?.text || null,
|
|
7611
|
+
options: Y.current?.options || null
|
|
7612
|
+
}, I.current.speechQueue.length = 0, I.current.pauseSpeaking(), b(!0), F.current = !0;
|
|
7558
7613
|
}
|
|
7559
|
-
} catch (
|
|
7560
|
-
console.warn("Error pausing speech:",
|
|
7614
|
+
} catch (A) {
|
|
7615
|
+
console.warn("Error pausing speech:", A);
|
|
7561
7616
|
}
|
|
7562
|
-
}, []),
|
|
7563
|
-
if (!(!
|
|
7617
|
+
}, []), te = N(async () => {
|
|
7618
|
+
if (!(!I.current || !j))
|
|
7564
7619
|
try {
|
|
7565
|
-
await
|
|
7566
|
-
const
|
|
7567
|
-
|
|
7568
|
-
} catch (
|
|
7569
|
-
console.warn("Error resuming speech:",
|
|
7620
|
+
await Le(), b(!1), F.current = !1;
|
|
7621
|
+
const A = X.current?.remainingText, P = X.current?.originalText || Y.current?.text, K = X.current?.options || Y.current?.options || {}, ie = A || P;
|
|
7622
|
+
ie && U(ie, K);
|
|
7623
|
+
} catch (A) {
|
|
7624
|
+
console.warn("Error resuming speech:", A), b(!1), F.current = !1;
|
|
7570
7625
|
}
|
|
7571
|
-
}, [
|
|
7572
|
-
|
|
7626
|
+
}, [j, U, Le]), me = N(() => {
|
|
7627
|
+
I.current && (I.current.stopSpeaking(), S.current && (clearInterval(S.current), S.current = null), b(!1), F.current = !1);
|
|
7573
7628
|
}, []);
|
|
7574
|
-
return Fe(
|
|
7575
|
-
speakText:
|
|
7576
|
-
pauseSpeaking:
|
|
7577
|
-
resumeSpeaking:
|
|
7578
|
-
stopSpeaking:
|
|
7579
|
-
resumeAudioContext:
|
|
7580
|
-
isPaused: () =>
|
|
7581
|
-
setMood: (
|
|
7582
|
-
setBodyMovement: (
|
|
7583
|
-
|
|
7629
|
+
return Fe(v, () => ({
|
|
7630
|
+
speakText: U,
|
|
7631
|
+
pauseSpeaking: _,
|
|
7632
|
+
resumeSpeaking: te,
|
|
7633
|
+
stopSpeaking: me,
|
|
7634
|
+
resumeAudioContext: Le,
|
|
7635
|
+
isPaused: () => j,
|
|
7636
|
+
setMood: (A) => I.current?.setMood(A),
|
|
7637
|
+
setBodyMovement: (A) => {
|
|
7638
|
+
I.current && I.current.setBodyMovement(A);
|
|
7584
7639
|
},
|
|
7585
|
-
playAnimation: (
|
|
7586
|
-
|
|
7640
|
+
playAnimation: (A, P = !1) => {
|
|
7641
|
+
I.current && I.current.playAnimation && I.current.playAnimation(A, null, 10, 0, 0.01, P);
|
|
7587
7642
|
},
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7643
|
+
playRandomAnimation: (A, P = !1) => w(A, P),
|
|
7644
|
+
getRandomAnimation: (A) => ke(A),
|
|
7645
|
+
playReaction: (A) => I.current?.playReaction(A),
|
|
7646
|
+
playCelebration: () => I.current?.playCelebration(),
|
|
7647
|
+
setShowFullAvatar: (A) => {
|
|
7648
|
+
I.current && (z.current = A, I.current.setShowFullAvatar(A));
|
|
7592
7649
|
},
|
|
7593
|
-
isReady:
|
|
7594
|
-
talkingHead:
|
|
7595
|
-
})), /* @__PURE__ */ Pe("div", { className: `simple-talking-avatar-container ${
|
|
7596
|
-
/* @__PURE__ */
|
|
7650
|
+
isReady: $,
|
|
7651
|
+
talkingHead: I.current
|
|
7652
|
+
})), /* @__PURE__ */ Pe("div", { className: `simple-talking-avatar-container ${f}`, style: k, children: [
|
|
7653
|
+
/* @__PURE__ */ ye(
|
|
7597
7654
|
"div",
|
|
7598
7655
|
{
|
|
7599
|
-
ref:
|
|
7656
|
+
ref: L,
|
|
7600
7657
|
className: "talking-head-viewer",
|
|
7601
7658
|
style: {
|
|
7602
7659
|
width: "100%",
|
|
@@ -7605,7 +7662,7 @@ const gt = Me(({
|
|
|
7605
7662
|
}
|
|
7606
7663
|
}
|
|
7607
7664
|
),
|
|
7608
|
-
|
|
7665
|
+
ne && /* @__PURE__ */ ye("div", { className: "loading-overlay", style: {
|
|
7609
7666
|
position: "absolute",
|
|
7610
7667
|
top: "50%",
|
|
7611
7668
|
left: "50%",
|
|
@@ -7614,7 +7671,7 @@ const gt = Me(({
|
|
|
7614
7671
|
fontSize: "18px",
|
|
7615
7672
|
zIndex: 10
|
|
7616
7673
|
}, children: "Loading avatar..." }),
|
|
7617
|
-
|
|
7674
|
+
ge && /* @__PURE__ */ ye("div", { className: "error-overlay", style: {
|
|
7618
7675
|
position: "absolute",
|
|
7619
7676
|
top: "50%",
|
|
7620
7677
|
left: "50%",
|
|
@@ -7625,12 +7682,12 @@ const gt = Me(({
|
|
|
7625
7682
|
zIndex: 10,
|
|
7626
7683
|
padding: "20px",
|
|
7627
7684
|
borderRadius: "8px"
|
|
7628
|
-
}, children:
|
|
7685
|
+
}, children: ge })
|
|
7629
7686
|
] });
|
|
7630
7687
|
});
|
|
7631
|
-
|
|
7632
|
-
const
|
|
7633
|
-
curriculumData:
|
|
7688
|
+
yt.displayName = "SimpleTalkingAvatar";
|
|
7689
|
+
const ft = Me(({
|
|
7690
|
+
curriculumData: V = null,
|
|
7634
7691
|
avatarConfig: t = {},
|
|
7635
7692
|
animations: e = {},
|
|
7636
7693
|
onLessonStart: n = () => {
|
|
@@ -7645,7 +7702,7 @@ const yt = Me(({
|
|
|
7645
7702
|
},
|
|
7646
7703
|
autoStart: h = !1
|
|
7647
7704
|
}, r) => {
|
|
7648
|
-
const u =
|
|
7705
|
+
const u = W(null), a = W({
|
|
7649
7706
|
currentModuleIndex: 0,
|
|
7650
7707
|
currentLessonIndex: 0,
|
|
7651
7708
|
currentQuestionIndex: 0,
|
|
@@ -7655,18 +7712,18 @@ const yt = Me(({
|
|
|
7655
7712
|
curriculumCompleted: !1,
|
|
7656
7713
|
score: 0,
|
|
7657
7714
|
totalQuestions: 0
|
|
7658
|
-
}), d =
|
|
7715
|
+
}), d = W({
|
|
7659
7716
|
onLessonStart: n,
|
|
7660
7717
|
onLessonComplete: i,
|
|
7661
7718
|
onQuestionAnswer: s,
|
|
7662
7719
|
onCurriculumComplete: o,
|
|
7663
7720
|
onCustomAction: l
|
|
7664
|
-
}), c =
|
|
7721
|
+
}), c = W(null), g = W(null), x = W(null), f = W(null), k = W(null), O = W(null), p = W(null), B = W(V?.curriculum || {
|
|
7665
7722
|
title: "Default Curriculum",
|
|
7666
7723
|
description: "No curriculum data provided",
|
|
7667
7724
|
language: "en",
|
|
7668
7725
|
modules: []
|
|
7669
|
-
}),
|
|
7726
|
+
}), H = W({
|
|
7670
7727
|
avatarUrl: t.avatarUrl || "/avatars/brunette.glb",
|
|
7671
7728
|
avatarBody: t.avatarBody || "F",
|
|
7672
7729
|
mood: t.mood || "happy",
|
|
@@ -7680,7 +7737,7 @@ const yt = Me(({
|
|
|
7680
7737
|
animations: e,
|
|
7681
7738
|
lipsyncLang: "en"
|
|
7682
7739
|
});
|
|
7683
|
-
|
|
7740
|
+
ce(() => {
|
|
7684
7741
|
d.current = {
|
|
7685
7742
|
onLessonStart: n,
|
|
7686
7743
|
onLessonComplete: i,
|
|
@@ -7688,13 +7745,13 @@ const yt = Me(({
|
|
|
7688
7745
|
onCurriculumComplete: o,
|
|
7689
7746
|
onCustomAction: l
|
|
7690
7747
|
};
|
|
7691
|
-
}, [n, i, s, o, l]),
|
|
7692
|
-
|
|
7748
|
+
}, [n, i, s, o, l]), ce(() => {
|
|
7749
|
+
B.current = V?.curriculum || {
|
|
7693
7750
|
title: "Default Curriculum",
|
|
7694
7751
|
description: "No curriculum data provided",
|
|
7695
7752
|
language: "en",
|
|
7696
7753
|
modules: []
|
|
7697
|
-
},
|
|
7754
|
+
}, H.current = {
|
|
7698
7755
|
avatarUrl: t.avatarUrl || "/avatars/brunette.glb",
|
|
7699
7756
|
avatarBody: t.avatarBody || "F",
|
|
7700
7757
|
mood: t.mood || "happy",
|
|
@@ -7708,24 +7765,24 @@ const yt = Me(({
|
|
|
7708
7765
|
animations: e,
|
|
7709
7766
|
lipsyncLang: "en"
|
|
7710
7767
|
};
|
|
7711
|
-
}, [
|
|
7712
|
-
const
|
|
7768
|
+
}, [V, t, e]);
|
|
7769
|
+
const v = N(() => (B.current || { modules: [] }).modules[a.current.currentModuleIndex]?.lessons[a.current.currentLessonIndex], []), L = N(() => v()?.questions[a.current.currentQuestionIndex], [v]), I = N((b, R) => R.type === "multiple_choice" || R.type === "true_false" ? b === R.answer : R.type === "code_test" && typeof b == "object" && b !== null ? b.passed === !0 : !1, []), z = N(() => {
|
|
7713
7770
|
a.current.lessonCompleted = !0, a.current.isQuestionMode = !1;
|
|
7714
|
-
const
|
|
7771
|
+
const b = a.current.totalQuestions > 0 ? Math.round(a.current.score / a.current.totalQuestions * 100) : 100;
|
|
7715
7772
|
let R = "Congratulations! You've completed this lesson";
|
|
7716
|
-
if (a.current.totalQuestions > 0 ? R += ` You got ${a.current.score} correct out of ${a.current.totalQuestions} question${a.current.totalQuestions === 1 ? "" : "s"}, achieving a score of ${
|
|
7773
|
+
if (a.current.totalQuestions > 0 ? R += ` You got ${a.current.score} correct out of ${a.current.totalQuestions} question${a.current.totalQuestions === 1 ? "" : "s"}, achieving a score of ${b} percent. ` : R += "! ", b >= 80 ? R += "Excellent work! You have a great understanding of this topic." : b >= 60 ? R += "Good job! You understand most of the concepts." : R += "Keep practicing! You're making progress.", d.current.onLessonComplete({
|
|
7717
7774
|
moduleIndex: a.current.currentModuleIndex,
|
|
7718
7775
|
lessonIndex: a.current.currentLessonIndex,
|
|
7719
7776
|
score: a.current.score,
|
|
7720
7777
|
totalQuestions: a.current.totalQuestions,
|
|
7721
|
-
percentage:
|
|
7778
|
+
percentage: b
|
|
7722
7779
|
}), d.current.onCustomAction({
|
|
7723
7780
|
type: "lessonComplete",
|
|
7724
7781
|
moduleIndex: a.current.currentModuleIndex,
|
|
7725
7782
|
lessonIndex: a.current.currentLessonIndex,
|
|
7726
7783
|
score: a.current.score,
|
|
7727
7784
|
totalQuestions: a.current.totalQuestions,
|
|
7728
|
-
percentage:
|
|
7785
|
+
percentage: b
|
|
7729
7786
|
}), u.current) {
|
|
7730
7787
|
if (u.current.setMood("happy"), e.lessonComplete)
|
|
7731
7788
|
try {
|
|
@@ -7733,9 +7790,9 @@ const yt = Me(({
|
|
|
7733
7790
|
} catch {
|
|
7734
7791
|
u.current.playCelebration();
|
|
7735
7792
|
}
|
|
7736
|
-
const
|
|
7793
|
+
const M = B.current || { modules: [] }, E = M.modules[a.current.currentModuleIndex], D = a.current.currentLessonIndex < (E?.lessons?.length || 0) - 1, ee = a.current.currentModuleIndex < (M.modules?.length || 0) - 1, Q = D || ee, q = H.current || { lipsyncLang: "en" };
|
|
7737
7794
|
u.current.speakText(R, {
|
|
7738
|
-
lipsyncLang:
|
|
7795
|
+
lipsyncLang: q.lipsyncLang,
|
|
7739
7796
|
onSpeechEnd: () => {
|
|
7740
7797
|
d.current.onCustomAction({
|
|
7741
7798
|
type: "lessonCompleteFeedbackDone",
|
|
@@ -7743,18 +7800,18 @@ const yt = Me(({
|
|
|
7743
7800
|
lessonIndex: a.current.currentLessonIndex,
|
|
7744
7801
|
score: a.current.score,
|
|
7745
7802
|
totalQuestions: a.current.totalQuestions,
|
|
7746
|
-
percentage:
|
|
7803
|
+
percentage: b,
|
|
7747
7804
|
hasNextLesson: Q
|
|
7748
7805
|
});
|
|
7749
7806
|
}
|
|
7750
7807
|
});
|
|
7751
7808
|
}
|
|
7752
|
-
}, [e.lessonComplete]), Y =
|
|
7809
|
+
}, [e.lessonComplete]), Y = N(() => {
|
|
7753
7810
|
a.current.curriculumCompleted = !0;
|
|
7754
|
-
const
|
|
7811
|
+
const b = B.current || { modules: [] };
|
|
7755
7812
|
if (d.current.onCurriculumComplete({
|
|
7756
|
-
modules:
|
|
7757
|
-
totalLessons:
|
|
7813
|
+
modules: b.modules.length,
|
|
7814
|
+
totalLessons: b.modules.reduce((R, M) => R + M.lessons.length, 0)
|
|
7758
7815
|
}), u.current) {
|
|
7759
7816
|
if (u.current.setMood("celebrating"), e.curriculumComplete)
|
|
7760
7817
|
try {
|
|
@@ -7762,13 +7819,13 @@ const yt = Me(({
|
|
|
7762
7819
|
} catch {
|
|
7763
7820
|
u.current.playCelebration();
|
|
7764
7821
|
}
|
|
7765
|
-
const R =
|
|
7822
|
+
const R = H.current || { lipsyncLang: "en" };
|
|
7766
7823
|
u.current.speakText("Amazing! You've completed the entire curriculum! You're now ready to move on to more advanced topics. Well done!", { lipsyncLang: R.lipsyncLang });
|
|
7767
7824
|
}
|
|
7768
|
-
}, [e.curriculumComplete]),
|
|
7769
|
-
const
|
|
7770
|
-
a.current.isQuestionMode = !0, a.current.currentQuestionIndex = 0, a.current.totalQuestions =
|
|
7771
|
-
const R =
|
|
7825
|
+
}, [e.curriculumComplete]), S = N(() => {
|
|
7826
|
+
const b = v();
|
|
7827
|
+
a.current.isQuestionMode = !0, a.current.currentQuestionIndex = 0, a.current.totalQuestions = b?.questions?.length || 0, a.current.score = 0;
|
|
7828
|
+
const R = L();
|
|
7772
7829
|
R && d.current.onCustomAction({
|
|
7773
7830
|
type: "questionStart",
|
|
7774
7831
|
moduleIndex: a.current.currentModuleIndex,
|
|
@@ -7778,35 +7835,35 @@ const yt = Me(({
|
|
|
7778
7835
|
question: R,
|
|
7779
7836
|
score: a.current.score
|
|
7780
7837
|
});
|
|
7781
|
-
const
|
|
7838
|
+
const M = () => {
|
|
7782
7839
|
if (!u.current || !R) return;
|
|
7783
7840
|
if (u.current.setMood("happy"), e.questionStart)
|
|
7784
7841
|
try {
|
|
7785
7842
|
u.current.playAnimation(e.questionStart, !0);
|
|
7786
|
-
} catch (
|
|
7787
|
-
console.warn("Failed to play questionStart animation:",
|
|
7843
|
+
} catch (D) {
|
|
7844
|
+
console.warn("Failed to play questionStart animation:", D);
|
|
7788
7845
|
}
|
|
7789
|
-
const
|
|
7790
|
-
R.type === "code_test" ? u.current.speakText(`Let's test your coding skills! Here's your first challenge: ${R.question}`, { lipsyncLang:
|
|
7846
|
+
const E = H.current || { lipsyncLang: "en" };
|
|
7847
|
+
R.type === "code_test" ? u.current.speakText(`Let's test your coding skills! Here's your first challenge: ${R.question}`, { lipsyncLang: E.lipsyncLang }) : R.type === "multiple_choice" ? u.current.speakText(`Now let me ask you some questions. Here's the first one: ${R.question}`, { lipsyncLang: E.lipsyncLang }) : R.type === "true_false" ? u.current.speakText(`Let's start with some true or false questions. First question: ${R.question}`, { lipsyncLang: E.lipsyncLang }) : u.current.speakText(`Now let me ask you some questions. Here's the first one: ${R.question}`, { lipsyncLang: E.lipsyncLang });
|
|
7791
7848
|
};
|
|
7792
7849
|
if (u.current && u.current.isReady && R)
|
|
7793
|
-
|
|
7850
|
+
M();
|
|
7794
7851
|
else if (u.current && u.current.isReady) {
|
|
7795
|
-
const
|
|
7796
|
-
u.current.speakText("Now let me ask you some questions to test your understanding.", { lipsyncLang:
|
|
7852
|
+
const E = H.current || { lipsyncLang: "en" };
|
|
7853
|
+
u.current.speakText("Now let me ask you some questions to test your understanding.", { lipsyncLang: E.lipsyncLang });
|
|
7797
7854
|
} else {
|
|
7798
|
-
const
|
|
7799
|
-
u.current && u.current.isReady && (clearInterval(
|
|
7855
|
+
const E = setInterval(() => {
|
|
7856
|
+
u.current && u.current.isReady && (clearInterval(E), R && M());
|
|
7800
7857
|
}, 100);
|
|
7801
7858
|
setTimeout(() => {
|
|
7802
|
-
clearInterval(
|
|
7859
|
+
clearInterval(E);
|
|
7803
7860
|
}, 5e3);
|
|
7804
7861
|
}
|
|
7805
|
-
}, [e.questionStart,
|
|
7806
|
-
const
|
|
7807
|
-
if (a.current.currentQuestionIndex < (
|
|
7862
|
+
}, [e.questionStart, v, L]), F = N(() => {
|
|
7863
|
+
const b = v();
|
|
7864
|
+
if (a.current.currentQuestionIndex < (b?.questions?.length || 0) - 1) {
|
|
7808
7865
|
u.current && u.current.stopSpeaking && u.current.stopSpeaking(), a.current.currentQuestionIndex += 1;
|
|
7809
|
-
const R =
|
|
7866
|
+
const R = L();
|
|
7810
7867
|
R && d.current.onCustomAction({
|
|
7811
7868
|
type: "nextQuestion",
|
|
7812
7869
|
moduleIndex: a.current.currentModuleIndex,
|
|
@@ -7816,45 +7873,45 @@ const yt = Me(({
|
|
|
7816
7873
|
question: R,
|
|
7817
7874
|
score: a.current.score
|
|
7818
7875
|
});
|
|
7819
|
-
const
|
|
7876
|
+
const M = () => {
|
|
7820
7877
|
if (!u.current || !R) return;
|
|
7821
7878
|
if (u.current.setMood("happy"), u.current.setBodyMovement("idle"), e.nextQuestion)
|
|
7822
7879
|
try {
|
|
7823
7880
|
u.current.playAnimation(e.nextQuestion, !0);
|
|
7824
|
-
} catch (
|
|
7825
|
-
console.warn("Failed to play nextQuestion animation:",
|
|
7881
|
+
} catch (q) {
|
|
7882
|
+
console.warn("Failed to play nextQuestion animation:", q);
|
|
7826
7883
|
}
|
|
7827
|
-
const
|
|
7884
|
+
const E = H.current || { lipsyncLang: "en" }, ee = v()?.questions?.length || 0, Q = a.current.currentQuestionIndex >= ee - 1;
|
|
7828
7885
|
if (R.type === "code_test") {
|
|
7829
|
-
const
|
|
7830
|
-
u.current.speakText(
|
|
7831
|
-
lipsyncLang:
|
|
7886
|
+
const q = Q ? `Great! Here's your final coding challenge: ${R.question}` : `Great! Now let's move on to your next coding challenge: ${R.question}`;
|
|
7887
|
+
u.current.speakText(q, {
|
|
7888
|
+
lipsyncLang: E.lipsyncLang
|
|
7832
7889
|
});
|
|
7833
7890
|
} else if (R.type === "multiple_choice") {
|
|
7834
|
-
const
|
|
7835
|
-
u.current.speakText(
|
|
7836
|
-
lipsyncLang:
|
|
7891
|
+
const q = Q ? `Alright! Here's your final question: ${R.question}` : `Alright! Here's your next question: ${R.question}`;
|
|
7892
|
+
u.current.speakText(q, {
|
|
7893
|
+
lipsyncLang: E.lipsyncLang
|
|
7837
7894
|
});
|
|
7838
7895
|
} else if (R.type === "true_false") {
|
|
7839
|
-
const
|
|
7840
|
-
u.current.speakText(
|
|
7841
|
-
lipsyncLang:
|
|
7896
|
+
const q = Q ? `Now let's try this final one: ${R.question}` : `Now let's try this one: ${R.question}`;
|
|
7897
|
+
u.current.speakText(q, {
|
|
7898
|
+
lipsyncLang: E.lipsyncLang
|
|
7842
7899
|
});
|
|
7843
7900
|
} else {
|
|
7844
|
-
const
|
|
7845
|
-
u.current.speakText(
|
|
7846
|
-
lipsyncLang:
|
|
7901
|
+
const q = Q ? `Here's your final question: ${R.question}` : `Here's the next question: ${R.question}`;
|
|
7902
|
+
u.current.speakText(q, {
|
|
7903
|
+
lipsyncLang: E.lipsyncLang
|
|
7847
7904
|
});
|
|
7848
7905
|
}
|
|
7849
7906
|
};
|
|
7850
7907
|
if (u.current && u.current.isReady && R)
|
|
7851
|
-
|
|
7908
|
+
M();
|
|
7852
7909
|
else if (R) {
|
|
7853
|
-
const
|
|
7854
|
-
u.current && u.current.isReady && (clearInterval(
|
|
7910
|
+
const E = setInterval(() => {
|
|
7911
|
+
u.current && u.current.isReady && (clearInterval(E), M());
|
|
7855
7912
|
}, 100);
|
|
7856
7913
|
setTimeout(() => {
|
|
7857
|
-
clearInterval(
|
|
7914
|
+
clearInterval(E);
|
|
7858
7915
|
}, 5e3);
|
|
7859
7916
|
}
|
|
7860
7917
|
} else
|
|
@@ -7865,11 +7922,11 @@ const yt = Me(({
|
|
|
7865
7922
|
totalQuestions: a.current.totalQuestions,
|
|
7866
7923
|
score: a.current.score
|
|
7867
7924
|
});
|
|
7868
|
-
}, [e.nextQuestion,
|
|
7869
|
-
const
|
|
7925
|
+
}, [e.nextQuestion, v, L]), X = N(() => {
|
|
7926
|
+
const b = B.current || { modules: [] }, R = b.modules[a.current.currentModuleIndex];
|
|
7870
7927
|
if (a.current.currentLessonIndex < (R?.lessons?.length || 0) - 1) {
|
|
7871
7928
|
a.current.currentLessonIndex += 1, a.current.currentQuestionIndex = 0, a.current.lessonCompleted = !1, a.current.isQuestionMode = !1, a.current.isTeaching = !1, a.current.score = 0, a.current.totalQuestions = 0;
|
|
7872
|
-
const
|
|
7929
|
+
const E = b.modules[a.current.currentModuleIndex], D = a.current.currentLessonIndex < (E?.lessons?.length || 0) - 1, ee = a.current.currentModuleIndex < (b.modules?.length || 0) - 1, Q = D || ee;
|
|
7873
7930
|
d.current.onCustomAction({
|
|
7874
7931
|
type: "lessonStart",
|
|
7875
7932
|
moduleIndex: a.current.currentModuleIndex,
|
|
@@ -7878,81 +7935,81 @@ const yt = Me(({
|
|
|
7878
7935
|
}), d.current.onLessonStart({
|
|
7879
7936
|
moduleIndex: a.current.currentModuleIndex,
|
|
7880
7937
|
lessonIndex: a.current.currentLessonIndex,
|
|
7881
|
-
lesson:
|
|
7938
|
+
lesson: v()
|
|
7882
7939
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7883
|
-
} else if (a.current.currentModuleIndex < (
|
|
7940
|
+
} else if (a.current.currentModuleIndex < (b.modules?.length || 0) - 1) {
|
|
7884
7941
|
a.current.currentModuleIndex += 1, a.current.currentLessonIndex = 0, a.current.currentQuestionIndex = 0, a.current.lessonCompleted = !1, a.current.isQuestionMode = !1, a.current.isTeaching = !1, a.current.score = 0, a.current.totalQuestions = 0;
|
|
7885
|
-
const
|
|
7942
|
+
const D = b.modules[a.current.currentModuleIndex], ee = a.current.currentLessonIndex < (D?.lessons?.length || 0) - 1, Q = a.current.currentModuleIndex < (b.modules?.length || 0) - 1, q = ee || Q;
|
|
7886
7943
|
d.current.onCustomAction({
|
|
7887
7944
|
type: "lessonStart",
|
|
7888
7945
|
moduleIndex: a.current.currentModuleIndex,
|
|
7889
7946
|
lessonIndex: a.current.currentLessonIndex,
|
|
7890
|
-
hasNextLesson:
|
|
7947
|
+
hasNextLesson: q
|
|
7891
7948
|
}), d.current.onLessonStart({
|
|
7892
7949
|
moduleIndex: a.current.currentModuleIndex,
|
|
7893
7950
|
lessonIndex: a.current.currentLessonIndex,
|
|
7894
|
-
lesson:
|
|
7951
|
+
lesson: v()
|
|
7895
7952
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7896
7953
|
} else
|
|
7897
|
-
|
|
7898
|
-
}, []),
|
|
7899
|
-
const
|
|
7954
|
+
k.current && k.current();
|
|
7955
|
+
}, []), Z = N(() => {
|
|
7956
|
+
const b = v();
|
|
7900
7957
|
let R = null;
|
|
7901
|
-
if (
|
|
7902
|
-
const
|
|
7903
|
-
R = `${
|
|
7958
|
+
if (b?.avatar_script && b?.body) {
|
|
7959
|
+
const M = b.avatar_script.trim(), E = b.body.trim(), D = M.match(/[.!?]$/) ? " " : ". ";
|
|
7960
|
+
R = `${M}${D}${E}`;
|
|
7904
7961
|
} else
|
|
7905
|
-
R =
|
|
7962
|
+
R = b?.avatar_script || b?.body || null;
|
|
7906
7963
|
if (u.current && u.current.isReady && R) {
|
|
7907
7964
|
a.current.isTeaching = !0, a.current.isQuestionMode = !1, a.current.score = 0, a.current.totalQuestions = 0, u.current.setMood("happy");
|
|
7908
|
-
let
|
|
7965
|
+
let M = !1;
|
|
7909
7966
|
if (e.teaching)
|
|
7910
7967
|
try {
|
|
7911
|
-
u.current.playAnimation(e.teaching, !0),
|
|
7912
|
-
} catch (
|
|
7913
|
-
console.warn("Failed to play teaching animation:",
|
|
7968
|
+
u.current.playAnimation(e.teaching, !0), M = !0;
|
|
7969
|
+
} catch (D) {
|
|
7970
|
+
console.warn("Failed to play teaching animation:", D);
|
|
7914
7971
|
}
|
|
7915
|
-
|
|
7916
|
-
const
|
|
7972
|
+
M || u.current.setBodyMovement("gesturing");
|
|
7973
|
+
const E = H.current || { lipsyncLang: "en" };
|
|
7917
7974
|
d.current.onLessonStart({
|
|
7918
7975
|
moduleIndex: a.current.currentModuleIndex,
|
|
7919
7976
|
lessonIndex: a.current.currentLessonIndex,
|
|
7920
|
-
lesson:
|
|
7977
|
+
lesson: b
|
|
7921
7978
|
}), d.current.onCustomAction({
|
|
7922
7979
|
type: "teachingStart",
|
|
7923
7980
|
moduleIndex: a.current.currentModuleIndex,
|
|
7924
7981
|
lessonIndex: a.current.currentLessonIndex,
|
|
7925
|
-
lesson:
|
|
7982
|
+
lesson: b
|
|
7926
7983
|
}), u.current.speakText(R, {
|
|
7927
|
-
lipsyncLang:
|
|
7984
|
+
lipsyncLang: E.lipsyncLang,
|
|
7928
7985
|
onSpeechEnd: () => {
|
|
7929
7986
|
a.current.isTeaching = !1, d.current.onCustomAction({
|
|
7930
7987
|
type: "teachingComplete",
|
|
7931
7988
|
moduleIndex: a.current.currentModuleIndex,
|
|
7932
7989
|
lessonIndex: a.current.currentLessonIndex,
|
|
7933
|
-
lesson:
|
|
7934
|
-
hasQuestions:
|
|
7935
|
-
}),
|
|
7990
|
+
lesson: b,
|
|
7991
|
+
hasQuestions: b.questions && b.questions.length > 0
|
|
7992
|
+
}), b?.code_example && d.current.onCustomAction({
|
|
7936
7993
|
type: "codeExampleReady",
|
|
7937
7994
|
moduleIndex: a.current.currentModuleIndex,
|
|
7938
7995
|
lessonIndex: a.current.currentLessonIndex,
|
|
7939
|
-
lesson:
|
|
7940
|
-
codeExample:
|
|
7996
|
+
lesson: b,
|
|
7997
|
+
codeExample: b.code_example
|
|
7941
7998
|
});
|
|
7942
7999
|
}
|
|
7943
8000
|
});
|
|
7944
8001
|
}
|
|
7945
|
-
}, [e.teaching,
|
|
7946
|
-
const R =
|
|
7947
|
-
if (
|
|
8002
|
+
}, [e.teaching, v]), ne = N((b) => {
|
|
8003
|
+
const R = L(), M = I(b, R);
|
|
8004
|
+
if (M && (a.current.score += 1), d.current.onQuestionAnswer({
|
|
7948
8005
|
moduleIndex: a.current.currentModuleIndex,
|
|
7949
8006
|
lessonIndex: a.current.currentLessonIndex,
|
|
7950
8007
|
questionIndex: a.current.currentQuestionIndex,
|
|
7951
|
-
answer:
|
|
7952
|
-
isCorrect:
|
|
8008
|
+
answer: b,
|
|
8009
|
+
isCorrect: M,
|
|
7953
8010
|
question: R
|
|
7954
8011
|
}), u.current)
|
|
7955
|
-
if (
|
|
8012
|
+
if (M) {
|
|
7956
8013
|
if (u.current.setMood("happy"), e.correct)
|
|
7957
8014
|
try {
|
|
7958
8015
|
u.current.playReaction("happy");
|
|
@@ -7960,13 +8017,13 @@ const yt = Me(({
|
|
|
7960
8017
|
u.current.setBodyMovement("happy");
|
|
7961
8018
|
}
|
|
7962
8019
|
u.current.setBodyMovement("gesturing");
|
|
7963
|
-
const
|
|
7964
|
-
a.current.currentQuestionIndex >=
|
|
7965
|
-
const
|
|
7966
|
-
console.log("[CurriculumLearning] Answer feedback - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:",
|
|
7967
|
-
const Q = R.type === "code_test" ? `Great job! Your code passed all the tests! ${R.explanation || ""}` : `Excellent! That's correct! ${R.explanation || ""}`,
|
|
8020
|
+
const D = v()?.questions?.length || 0;
|
|
8021
|
+
a.current.currentQuestionIndex >= D - 1;
|
|
8022
|
+
const ee = a.current.currentQuestionIndex < D - 1;
|
|
8023
|
+
console.log("[CurriculumLearning] Answer feedback - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:", D, "hasNextQuestion:", ee);
|
|
8024
|
+
const Q = R.type === "code_test" ? `Great job! Your code passed all the tests! ${R.explanation || ""}` : `Excellent! That's correct! ${R.explanation || ""}`, q = H.current || { lipsyncLang: "en" };
|
|
7968
8025
|
u.current.speakText(Q, {
|
|
7969
|
-
lipsyncLang:
|
|
8026
|
+
lipsyncLang: q.lipsyncLang,
|
|
7970
8027
|
onSpeechEnd: () => {
|
|
7971
8028
|
d.current.onCustomAction({
|
|
7972
8029
|
type: "answerFeedbackComplete",
|
|
@@ -7974,7 +8031,7 @@ const yt = Me(({
|
|
|
7974
8031
|
lessonIndex: a.current.currentLessonIndex,
|
|
7975
8032
|
questionIndex: a.current.currentQuestionIndex,
|
|
7976
8033
|
isCorrect: !0,
|
|
7977
|
-
hasNextQuestion:
|
|
8034
|
+
hasNextQuestion: ee,
|
|
7978
8035
|
score: a.current.score,
|
|
7979
8036
|
totalQuestions: a.current.totalQuestions
|
|
7980
8037
|
});
|
|
@@ -7988,10 +8045,10 @@ const yt = Me(({
|
|
|
7988
8045
|
u.current.setBodyMovement("idle");
|
|
7989
8046
|
}
|
|
7990
8047
|
u.current.setBodyMovement("gesturing");
|
|
7991
|
-
const
|
|
7992
|
-
console.log("[CurriculumLearning] Answer feedback (incorrect) - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:",
|
|
7993
|
-
const
|
|
7994
|
-
u.current.speakText(
|
|
8048
|
+
const D = v()?.questions?.length || 0, ee = a.current.currentQuestionIndex >= D - 1, Q = a.current.currentQuestionIndex < D - 1;
|
|
8049
|
+
console.log("[CurriculumLearning] Answer feedback (incorrect) - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:", D, "hasNextQuestion:", Q);
|
|
8050
|
+
const q = R.type === "code_test" ? `Your code didn't pass all the tests. ${R.explanation || "Try again!"}` : `Not quite right, but don't worry! ${R.explanation || ""}${ee ? "" : " Let's move on to the next question."}`, Ae = H.current || { lipsyncLang: "en" };
|
|
8051
|
+
u.current.speakText(q, {
|
|
7995
8052
|
lipsyncLang: Ae.lipsyncLang,
|
|
7996
8053
|
onSpeechEnd: () => {
|
|
7997
8054
|
d.current.onCustomAction({
|
|
@@ -8008,22 +8065,22 @@ const yt = Me(({
|
|
|
8008
8065
|
});
|
|
8009
8066
|
}
|
|
8010
8067
|
else {
|
|
8011
|
-
const
|
|
8068
|
+
const D = v()?.questions?.length || 0;
|
|
8012
8069
|
d.current.onCustomAction({
|
|
8013
8070
|
type: "answerFeedbackComplete",
|
|
8014
8071
|
moduleIndex: a.current.currentModuleIndex,
|
|
8015
8072
|
lessonIndex: a.current.currentLessonIndex,
|
|
8016
8073
|
questionIndex: a.current.currentQuestionIndex,
|
|
8017
|
-
isCorrect:
|
|
8018
|
-
hasNextQuestion: a.current.currentQuestionIndex <
|
|
8074
|
+
isCorrect: M,
|
|
8075
|
+
hasNextQuestion: a.current.currentQuestionIndex < D - 1,
|
|
8019
8076
|
score: a.current.score,
|
|
8020
8077
|
totalQuestions: a.current.totalQuestions,
|
|
8021
8078
|
avatarNotReady: !0
|
|
8022
8079
|
});
|
|
8023
8080
|
}
|
|
8024
|
-
}, [e.correct, e.incorrect,
|
|
8025
|
-
const R =
|
|
8026
|
-
if (!
|
|
8081
|
+
}, [e.correct, e.incorrect, L, v, I]), le = N((b) => {
|
|
8082
|
+
const R = L();
|
|
8083
|
+
if (!b || typeof b != "object") {
|
|
8027
8084
|
console.error("Invalid code test result format. Expected object with {passed: boolean, ...}");
|
|
8028
8085
|
return;
|
|
8029
8086
|
}
|
|
@@ -8031,61 +8088,61 @@ const yt = Me(({
|
|
|
8031
8088
|
console.warn("Current question is not a code test. Use handleAnswerSelect for other question types.");
|
|
8032
8089
|
return;
|
|
8033
8090
|
}
|
|
8034
|
-
const
|
|
8035
|
-
passed:
|
|
8036
|
-
results:
|
|
8037
|
-
output:
|
|
8038
|
-
error:
|
|
8039
|
-
executionTime:
|
|
8040
|
-
testCount:
|
|
8041
|
-
passedCount:
|
|
8042
|
-
failedCount:
|
|
8091
|
+
const M = {
|
|
8092
|
+
passed: b.passed === !0,
|
|
8093
|
+
results: b.results || [],
|
|
8094
|
+
output: b.output || "",
|
|
8095
|
+
error: b.error || null,
|
|
8096
|
+
executionTime: b.executionTime || null,
|
|
8097
|
+
testCount: b.testCount || 0,
|
|
8098
|
+
passedCount: b.passedCount || 0,
|
|
8099
|
+
failedCount: b.failedCount || 0
|
|
8043
8100
|
};
|
|
8044
8101
|
d.current.onCustomAction({
|
|
8045
8102
|
type: "codeTestSubmitted",
|
|
8046
8103
|
moduleIndex: a.current.currentModuleIndex,
|
|
8047
8104
|
lessonIndex: a.current.currentLessonIndex,
|
|
8048
8105
|
questionIndex: a.current.currentQuestionIndex,
|
|
8049
|
-
testResult:
|
|
8106
|
+
testResult: M,
|
|
8050
8107
|
question: R
|
|
8051
|
-
}), p.current && p.current(
|
|
8052
|
-
}, [
|
|
8108
|
+
}), p.current && p.current(M);
|
|
8109
|
+
}, [L, I]), ge = N(() => {
|
|
8053
8110
|
if (a.current.currentQuestionIndex > 0) {
|
|
8054
8111
|
a.current.currentQuestionIndex -= 1;
|
|
8055
|
-
const
|
|
8056
|
-
|
|
8112
|
+
const b = L();
|
|
8113
|
+
b && d.current.onCustomAction({
|
|
8057
8114
|
type: "questionStart",
|
|
8058
8115
|
moduleIndex: a.current.currentModuleIndex,
|
|
8059
8116
|
lessonIndex: a.current.currentLessonIndex,
|
|
8060
8117
|
questionIndex: a.current.currentQuestionIndex,
|
|
8061
8118
|
totalQuestions: a.current.totalQuestions,
|
|
8062
|
-
question:
|
|
8119
|
+
question: b,
|
|
8063
8120
|
score: a.current.score
|
|
8064
8121
|
});
|
|
8065
8122
|
const R = () => {
|
|
8066
|
-
if (!u.current || !
|
|
8123
|
+
if (!u.current || !b) return;
|
|
8067
8124
|
u.current.setMood("happy"), u.current.setBodyMovement("idle");
|
|
8068
|
-
const
|
|
8069
|
-
|
|
8070
|
-
lipsyncLang:
|
|
8071
|
-
}) : u.current.speakText(`Going back to: ${
|
|
8072
|
-
lipsyncLang:
|
|
8125
|
+
const M = H.current || { lipsyncLang: "en" };
|
|
8126
|
+
b.type === "code_test" ? u.current.speakText(`Let's go back to this coding challenge: ${b.question}`, {
|
|
8127
|
+
lipsyncLang: M.lipsyncLang
|
|
8128
|
+
}) : u.current.speakText(`Going back to: ${b.question}`, {
|
|
8129
|
+
lipsyncLang: M.lipsyncLang
|
|
8073
8130
|
});
|
|
8074
8131
|
};
|
|
8075
|
-
if (u.current && u.current.isReady &&
|
|
8132
|
+
if (u.current && u.current.isReady && b)
|
|
8076
8133
|
R();
|
|
8077
|
-
else if (
|
|
8078
|
-
const
|
|
8079
|
-
u.current && u.current.isReady && (clearInterval(
|
|
8134
|
+
else if (b) {
|
|
8135
|
+
const M = setInterval(() => {
|
|
8136
|
+
u.current && u.current.isReady && (clearInterval(M), R());
|
|
8080
8137
|
}, 100);
|
|
8081
8138
|
setTimeout(() => {
|
|
8082
|
-
clearInterval(
|
|
8139
|
+
clearInterval(M);
|
|
8083
8140
|
}, 5e3);
|
|
8084
8141
|
}
|
|
8085
8142
|
}
|
|
8086
|
-
}, [
|
|
8087
|
-
const
|
|
8088
|
-
if (
|
|
8143
|
+
}, [L]), de = N(() => {
|
|
8144
|
+
const b = B.current || { modules: [] };
|
|
8145
|
+
if (b.modules[a.current.currentModuleIndex], a.current.currentLessonIndex > 0)
|
|
8089
8146
|
a.current.currentLessonIndex -= 1, a.current.currentQuestionIndex = 0, a.current.lessonCompleted = !1, a.current.isQuestionMode = !1, a.current.isTeaching = !1, a.current.score = 0, a.current.totalQuestions = 0, d.current.onCustomAction({
|
|
8090
8147
|
type: "lessonStart",
|
|
8091
8148
|
moduleIndex: a.current.currentModuleIndex,
|
|
@@ -8093,66 +8150,66 @@ const yt = Me(({
|
|
|
8093
8150
|
}), d.current.onLessonStart({
|
|
8094
8151
|
moduleIndex: a.current.currentModuleIndex,
|
|
8095
8152
|
lessonIndex: a.current.currentLessonIndex,
|
|
8096
|
-
lesson:
|
|
8153
|
+
lesson: v()
|
|
8097
8154
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
8098
8155
|
else if (a.current.currentModuleIndex > 0) {
|
|
8099
|
-
const
|
|
8100
|
-
a.current.currentModuleIndex -= 1, a.current.currentLessonIndex = (
|
|
8156
|
+
const E = b.modules[a.current.currentModuleIndex - 1];
|
|
8157
|
+
a.current.currentModuleIndex -= 1, a.current.currentLessonIndex = (E?.lessons?.length || 1) - 1, a.current.currentQuestionIndex = 0, a.current.lessonCompleted = !1, a.current.isQuestionMode = !1, a.current.isTeaching = !1, a.current.score = 0, a.current.totalQuestions = 0, d.current.onCustomAction({
|
|
8101
8158
|
type: "lessonStart",
|
|
8102
8159
|
moduleIndex: a.current.currentModuleIndex,
|
|
8103
8160
|
lessonIndex: a.current.currentLessonIndex
|
|
8104
8161
|
}), d.current.onLessonStart({
|
|
8105
8162
|
moduleIndex: a.current.currentModuleIndex,
|
|
8106
8163
|
lessonIndex: a.current.currentLessonIndex,
|
|
8107
|
-
lesson:
|
|
8164
|
+
lesson: v()
|
|
8108
8165
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
8109
8166
|
}
|
|
8110
|
-
}, [
|
|
8167
|
+
}, [v]), $ = N(() => {
|
|
8111
8168
|
a.current.currentModuleIndex = 0, a.current.currentLessonIndex = 0, a.current.currentQuestionIndex = 0, a.current.isTeaching = !1, a.current.isQuestionMode = !1, a.current.lessonCompleted = !1, a.current.curriculumCompleted = !1, a.current.score = 0, a.current.totalQuestions = 0;
|
|
8112
|
-
}, []),
|
|
8113
|
-
console.log("Avatar is ready!",
|
|
8114
|
-
const R =
|
|
8115
|
-
h &&
|
|
8169
|
+
}, []), be = N((b) => {
|
|
8170
|
+
console.log("Avatar is ready!", b);
|
|
8171
|
+
const R = v(), M = R?.avatar_script || R?.body;
|
|
8172
|
+
h && M && setTimeout(() => {
|
|
8116
8173
|
c.current && c.current();
|
|
8117
8174
|
}, 10);
|
|
8118
|
-
}, [h,
|
|
8175
|
+
}, [h, v]);
|
|
8119
8176
|
Xe(() => {
|
|
8120
|
-
c.current =
|
|
8177
|
+
c.current = Z, g.current = X, x.current = z, f.current = F, k.current = Y, O.current = S, p.current = ne;
|
|
8121
8178
|
}), Fe(r, () => ({
|
|
8122
8179
|
// Curriculum control methods
|
|
8123
|
-
startTeaching:
|
|
8124
|
-
startQuestions:
|
|
8125
|
-
handleAnswerSelect:
|
|
8126
|
-
handleCodeTestResult:
|
|
8127
|
-
nextQuestion:
|
|
8128
|
-
previousQuestion:
|
|
8129
|
-
nextLesson:
|
|
8130
|
-
previousLesson:
|
|
8131
|
-
completeLesson:
|
|
8180
|
+
startTeaching: Z,
|
|
8181
|
+
startQuestions: S,
|
|
8182
|
+
handleAnswerSelect: ne,
|
|
8183
|
+
handleCodeTestResult: le,
|
|
8184
|
+
nextQuestion: F,
|
|
8185
|
+
previousQuestion: ge,
|
|
8186
|
+
nextLesson: X,
|
|
8187
|
+
previousLesson: de,
|
|
8188
|
+
completeLesson: z,
|
|
8132
8189
|
completeCurriculum: Y,
|
|
8133
|
-
resetCurriculum:
|
|
8190
|
+
resetCurriculum: $,
|
|
8134
8191
|
getState: () => ({ ...a.current }),
|
|
8135
|
-
getCurrentQuestion: () =>
|
|
8136
|
-
getCurrentLesson: () =>
|
|
8192
|
+
getCurrentQuestion: () => L(),
|
|
8193
|
+
getCurrentLesson: () => v(),
|
|
8137
8194
|
// Direct access to avatar ref (always returns current value)
|
|
8138
8195
|
getAvatarRef: () => u.current,
|
|
8139
8196
|
// Convenience methods that delegate to avatar (always check current ref)
|
|
8140
|
-
speakText: async (
|
|
8197
|
+
speakText: async (b, R = {}) => {
|
|
8141
8198
|
await u.current?.resumeAudioContext?.();
|
|
8142
|
-
const
|
|
8143
|
-
u.current?.speakText(
|
|
8199
|
+
const M = H.current || { lipsyncLang: "en" };
|
|
8200
|
+
u.current?.speakText(b, { ...R, lipsyncLang: R.lipsyncLang || M.lipsyncLang });
|
|
8144
8201
|
},
|
|
8145
8202
|
resumeAudioContext: async () => {
|
|
8146
8203
|
if (u.current?.resumeAudioContext)
|
|
8147
8204
|
return await u.current.resumeAudioContext();
|
|
8148
|
-
const
|
|
8149
|
-
if (
|
|
8150
|
-
const R =
|
|
8205
|
+
const b = u.current?.talkingHead;
|
|
8206
|
+
if (b?.audioCtx) {
|
|
8207
|
+
const R = b.audioCtx;
|
|
8151
8208
|
if (R.state === "suspended" || R.state === "interrupted")
|
|
8152
8209
|
try {
|
|
8153
8210
|
await R.resume(), console.log("Audio context resumed via talkingHead");
|
|
8154
|
-
} catch (
|
|
8155
|
-
console.warn("Failed to resume audio context:",
|
|
8211
|
+
} catch (M) {
|
|
8212
|
+
console.warn("Failed to resume audio context:", M);
|
|
8156
8213
|
}
|
|
8157
8214
|
} else
|
|
8158
8215
|
console.warn("Audio context not available yet");
|
|
@@ -8161,21 +8218,21 @@ const yt = Me(({
|
|
|
8161
8218
|
pauseSpeaking: () => u.current?.pauseSpeaking(),
|
|
8162
8219
|
resumeSpeaking: async () => await u.current?.resumeSpeaking(),
|
|
8163
8220
|
isPaused: () => u.current && typeof u.current.isPaused < "u" ? u.current.isPaused : !1,
|
|
8164
|
-
setMood: (
|
|
8165
|
-
playAnimation: (
|
|
8166
|
-
setBodyMovement: (
|
|
8167
|
-
setMovementIntensity: (
|
|
8221
|
+
setMood: (b) => u.current?.setMood(b),
|
|
8222
|
+
playAnimation: (b, R) => u.current?.playAnimation(b, R),
|
|
8223
|
+
setBodyMovement: (b) => u.current?.setBodyMovement(b),
|
|
8224
|
+
setMovementIntensity: (b) => u.current?.setMovementIntensity(b),
|
|
8168
8225
|
playRandomDance: () => u.current?.playRandomDance(),
|
|
8169
|
-
playReaction: (
|
|
8226
|
+
playReaction: (b) => u.current?.playReaction(b),
|
|
8170
8227
|
playCelebration: () => u.current?.playCelebration(),
|
|
8171
|
-
setShowFullAvatar: (
|
|
8172
|
-
setTimingAdjustment: (
|
|
8228
|
+
setShowFullAvatar: (b) => u.current?.setShowFullAvatar(b),
|
|
8229
|
+
setTimingAdjustment: (b) => u.current?.setTimingAdjustment(b),
|
|
8173
8230
|
lockAvatarPosition: () => u.current?.lockAvatarPosition(),
|
|
8174
8231
|
unlockAvatarPosition: () => u.current?.unlockAvatarPosition(),
|
|
8175
8232
|
// Custom action trigger
|
|
8176
|
-
triggerCustomAction: (
|
|
8233
|
+
triggerCustomAction: (b, R) => {
|
|
8177
8234
|
d.current.onCustomAction({
|
|
8178
|
-
type:
|
|
8235
|
+
type: b,
|
|
8179
8236
|
...R,
|
|
8180
8237
|
state: { ...a.current }
|
|
8181
8238
|
});
|
|
@@ -8184,8 +8241,8 @@ const yt = Me(({
|
|
|
8184
8241
|
handleResize: () => u.current?.handleResize(),
|
|
8185
8242
|
// Avatar readiness check (always returns current value)
|
|
8186
8243
|
isAvatarReady: () => u.current?.isReady || !1
|
|
8187
|
-
}), [
|
|
8188
|
-
const
|
|
8244
|
+
}), [Z, S, ne, le, F, X, z, Y, $, L, v]);
|
|
8245
|
+
const j = H.current || {
|
|
8189
8246
|
avatarUrl: "/avatars/brunette.glb",
|
|
8190
8247
|
avatarBody: "F",
|
|
8191
8248
|
mood: "happy",
|
|
@@ -8198,32 +8255,32 @@ const yt = Me(({
|
|
|
8198
8255
|
showFullAvatar: !1,
|
|
8199
8256
|
animations: e
|
|
8200
8257
|
};
|
|
8201
|
-
return /* @__PURE__ */
|
|
8258
|
+
return /* @__PURE__ */ ye("div", { style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ ye(
|
|
8202
8259
|
Ve,
|
|
8203
8260
|
{
|
|
8204
8261
|
ref: u,
|
|
8205
|
-
avatarUrl:
|
|
8206
|
-
avatarBody:
|
|
8207
|
-
mood:
|
|
8208
|
-
ttsLang:
|
|
8209
|
-
ttsService:
|
|
8210
|
-
ttsVoice:
|
|
8211
|
-
ttsApiKey:
|
|
8212
|
-
bodyMovement:
|
|
8213
|
-
movementIntensity:
|
|
8214
|
-
showFullAvatar:
|
|
8262
|
+
avatarUrl: j.avatarUrl,
|
|
8263
|
+
avatarBody: j.avatarBody,
|
|
8264
|
+
mood: j.mood,
|
|
8265
|
+
ttsLang: j.ttsLang,
|
|
8266
|
+
ttsService: j.ttsService,
|
|
8267
|
+
ttsVoice: j.ttsVoice,
|
|
8268
|
+
ttsApiKey: j.ttsApiKey,
|
|
8269
|
+
bodyMovement: j.bodyMovement,
|
|
8270
|
+
movementIntensity: j.movementIntensity,
|
|
8271
|
+
showFullAvatar: j.showFullAvatar,
|
|
8215
8272
|
cameraView: "upper",
|
|
8216
|
-
animations:
|
|
8217
|
-
onReady:
|
|
8273
|
+
animations: j.animations,
|
|
8274
|
+
onReady: be,
|
|
8218
8275
|
onLoading: () => {
|
|
8219
8276
|
},
|
|
8220
|
-
onError: (
|
|
8221
|
-
console.error("Avatar error:",
|
|
8277
|
+
onError: (b) => {
|
|
8278
|
+
console.error("Avatar error:", b);
|
|
8222
8279
|
}
|
|
8223
8280
|
}
|
|
8224
8281
|
) });
|
|
8225
8282
|
});
|
|
8226
|
-
|
|
8283
|
+
ft.displayName = "CurriculumLearning";
|
|
8227
8284
|
const Ge = {
|
|
8228
8285
|
// Code-based dance animations (no FBX required)
|
|
8229
8286
|
dance: {
|
|
@@ -8327,15 +8384,15 @@ const Ge = {
|
|
|
8327
8384
|
duration: 5e3,
|
|
8328
8385
|
description: "Excited, energetic movement"
|
|
8329
8386
|
}
|
|
8330
|
-
},
|
|
8387
|
+
}, zt = (V) => Ge[V] || null, Ct = (V) => Ge.hasOwnProperty(V);
|
|
8331
8388
|
export {
|
|
8332
|
-
|
|
8333
|
-
|
|
8389
|
+
ft as CurriculumLearning,
|
|
8390
|
+
yt as SimpleTalkingAvatar,
|
|
8334
8391
|
Ve as TalkingHeadAvatar,
|
|
8335
8392
|
pt as TalkingHeadComponent,
|
|
8336
8393
|
Ge as animations,
|
|
8337
8394
|
Ee as getActiveTTSConfig,
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8395
|
+
zt as getAnimation,
|
|
8396
|
+
wt as getVoiceOptions,
|
|
8397
|
+
Ct as hasAnimation
|
|
8341
8398
|
};
|