@sage-rsc/talking-head-react 1.0.84 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2 -2
- package/dist/index.js +641 -624
- package/package.json +1 -1
- package/src/lib/talkinghead.mjs +93 -45
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxs as Pe, jsx as me } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef as Me, useRef as
|
|
3
|
-
import * as
|
|
2
|
+
import { forwardRef as Me, useRef as D, useState as ce, useEffect as de, useCallback as T, useImperativeHandle as Ee, useLayoutEffect as Xe } from "react";
|
|
3
|
+
import * as f 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";
|
|
@@ -8,13 +8,13 @@ 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 Ke from "three/addons/libs/stats.module.js";
|
|
10
10
|
let m, re, ue;
|
|
11
|
-
const A = [0, 0, 0, 0], w = new
|
|
12
|
-
new
|
|
13
|
-
new
|
|
14
|
-
new
|
|
15
|
-
const ie = new
|
|
16
|
-
new
|
|
17
|
-
const He = new
|
|
11
|
+
const A = [0, 0, 0, 0], w = new f.Vector3(), ze = new f.Vector3(), ne = new f.Vector3(), Ce = new f.Vector3();
|
|
12
|
+
new f.Plane();
|
|
13
|
+
new f.Ray();
|
|
14
|
+
new f.Euler();
|
|
15
|
+
const ie = new f.Quaternion(), Oe = new f.Quaternion(), fe = new f.Matrix4(), xe = new f.Matrix4();
|
|
16
|
+
new f.Vector3();
|
|
17
|
+
const He = new f.Vector3(0, 0, 1), _e = new f.Vector3(1, 0, 0), Je = new f.Vector3(0, 1, 0), $e = new f.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(w, ie, ne), w.copy(He).applyQuaternion(ie).setY(0).normalize(), ie.premultiply(
|
|
341
|
+
u.boneParent.matrixWorld.decompose(w, ie, ne), w.copy(He).applyQuaternion(ie).setY(0).normalize(), ie.premultiply(Oe.setFromUnitVectors(He, w).invert()).normalize(), u.qWorldInverseYaw = ie.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) {
|
|
@@ -369,7 +369,7 @@ class et {
|
|
|
369
369
|
o.vBasis.y + A[1],
|
|
370
370
|
o.vBasis.z - A[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(w, ie, ne), w.copy(He).applyQuaternion(ie).setY(0).normalize(), ie.premultiply(
|
|
372
|
+
else if (o.boneParent.quaternion.copy(o.qBasis), o.pivot && this.opt.isPivots && (o.boneParent.updateWorldMatrix(!1, !1), o.boneParent.matrixWorld.decompose(w, ie, ne), w.copy(He).applyQuaternion(ie).setY(0).normalize(), ie.premultiply(Oe.setFromUnitVectors(He, w).invert()).normalize(), o.boneParent.quaternion.multiply(ie.invert()), o.boneParent.quaternion.multiply(o.qWorldInverseYaw)), o.isZ && (m = Math.atan(A[0] / o.l), ie.setFromAxisAngle($e, -m), o.boneParent.quaternion.multiply(ie)), o.isY && (m = o.l / 3, m = m * Math.tanh(A[1] / m), o.bone.position.setLength(o.l + m)), o.isX && (m = Math.atan(A[2] / o.l), ie.setFromAxisAngle(_e, -m), o.boneParent.quaternion.multiply(ie)), o.isT && (m = 1.5 * Math.tanh(A[3] * 1.5), ie.setFromAxisAngle(Je, -m), o.boneParent.quaternion.multiply(ie)), o.boneParent.updateWorldMatrix(!1, !0), o.excludes && this.opt.isExcludes)
|
|
373
373
|
for (n = 0, s = o.excludes.length; n < s; n++)
|
|
374
374
|
m = o.excludes[n], ne.set(0, 0, 0), m.deltaLocal && (ne.x += m.deltaLocal[0], ne.y += m.deltaLocal[1], ne.z += m.deltaLocal[2]), ne.applyMatrix4(m.bone.matrixWorld), xe.copy(o.boneParent.matrixWorld).invert(), ne.applyMatrix4(xe), w.copy(o.bone.position), !(w.distanceToSquared(ne) >= m.radiusSq) && (ue = w.length(), re = ne.length(), !(re > m.radius + ue) && (re < Math.abs(m.radius - ue) || (re = (re * re + ue * ue - m.radiusSq) / (2 * re), ne.normalize(), Ce.copy(ne).multiplyScalar(re), re = Math.sqrt(ue * ue - re * re), w.subVectors(w, Ce).projectOnPlane(ne).normalize().multiplyScalar(re), ze.subVectors(o.vBasis, Ce).projectOnPlane(ne).normalize(), ue = ze.dot(w), ue < 0 && (ue = Math.sqrt(re * re - ue * ue), ze.multiplyScalar(ue), w.add(ze)), w.add(Ce).normalize(), ne.copy(o.bone.position).normalize(), ie.setFromUnitVectors(ne, w), o.boneParent.quaternion.premultiply(ie), o.boneParent.updateWorldMatrix(!1, !0))));
|
|
375
375
|
}
|
|
@@ -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 f.SphereGeometry(m.radii[n], 6, 6), s = new f.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 f.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 f.BufferGeometry(), n = m.bones.map((h) => [0, 0, 0]).flat();
|
|
412
|
+
e.setAttribute("position", new f.Float32BufferAttribute(n, 3));
|
|
413
|
+
const i = new f.Color(this.opt.helperBoneColor1), s = new f.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 f.Float32BufferAttribute(o, 3));
|
|
415
|
+
const l = new f.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 f.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 f.BufferGeometry(), n = m.bones.map((h) => [0, 0, 0, 0, 0, 0]).flat();
|
|
427
|
+
e.setAttribute("position", new f.Float32BufferAttribute(n, 3));
|
|
428
|
+
const i = new f.Color(this.opt.helperLinkColor1), s = new f.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 f.Float32BufferAttribute(o, 3));
|
|
430
|
+
const l = new f.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 f.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
|
/**
|
|
@@ -521,10 +521,10 @@ class tt {
|
|
|
521
521
|
for (let l = 0; l < o; l++) {
|
|
522
522
|
const h = l * s, r = Math.min(h + i, t.length), u = t.slice(h, r), a = this.calculateEnergy(u);
|
|
523
523
|
n.energy.push(a);
|
|
524
|
-
const
|
|
525
|
-
n.spectralCentroid.push(
|
|
526
|
-
const
|
|
527
|
-
n.zeroCrossingRate.push(
|
|
524
|
+
const c = this.calculateSpectralCentroid(u);
|
|
525
|
+
n.spectralCentroid.push(c);
|
|
526
|
+
const d = this.calculateZeroCrossingRate(u);
|
|
527
|
+
n.zeroCrossingRate.push(d);
|
|
528
528
|
const g = this.calculateMFCC(u);
|
|
529
529
|
n.mfcc.push(g);
|
|
530
530
|
}
|
|
@@ -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
|
|
610
|
-
n[(h + a) * 2] =
|
|
611
|
-
const b = r * o - u * l,
|
|
612
|
-
r = b, u =
|
|
609
|
+
const c = n[(h + a) * 2], d = 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] = c + g, n[(h + a) * 2 + 1] = d + x, n[(h + a + i / 2) * 2] = c - g, n[(h + a + i / 2) * 2 + 1] = d - x;
|
|
611
|
+
const b = r * o - u * l, R = r * l + u * o;
|
|
612
|
+
r = b, u = R;
|
|
613
613
|
}
|
|
614
614
|
}
|
|
615
615
|
}
|
|
@@ -703,15 +703,15 @@ class tt {
|
|
|
703
703
|
const o = this.textToVisemes(e);
|
|
704
704
|
let l = 0, h = 0;
|
|
705
705
|
for (let r = 0; r < s.length && l < o.length; r++) {
|
|
706
|
-
const u = s[r], a = o[l],
|
|
706
|
+
const u = s[r], a = o[l], c = t.energy[Math.floor(u / 0.023)] || 0, d = this.calculateVisemeDuration(a, c);
|
|
707
707
|
i.push({
|
|
708
708
|
viseme: a,
|
|
709
709
|
startTime: h,
|
|
710
|
-
endTime: h +
|
|
711
|
-
duration:
|
|
712
|
-
intensity: Math.min(1,
|
|
710
|
+
endTime: h + d,
|
|
711
|
+
duration: d,
|
|
712
|
+
intensity: Math.min(1, c * 2)
|
|
713
713
|
// Map energy to viseme intensity
|
|
714
|
-
}), h +=
|
|
714
|
+
}), h += d, l++;
|
|
715
715
|
}
|
|
716
716
|
for (; l < o.length; ) {
|
|
717
717
|
const r = o[l], u = this.calculateVisemeDuration(r, 0.5);
|
|
@@ -1207,10 +1207,10 @@ class nt {
|
|
|
1207
1207
|
Object.keys(this.rules).forEach((e) => {
|
|
1208
1208
|
this.rules[e] = this.rules[e].map((n) => {
|
|
1209
1209
|
const i = n.indexOf("["), s = n.indexOf("]"), o = n.indexOf("="), l = n.substring(0, i), h = n.substring(i + 1, s), r = n.substring(s + 1, o), u = n.substring(o + 1), a = { regex: "", move: 0, visemes: [] };
|
|
1210
|
-
let
|
|
1211
|
-
|
|
1212
|
-
const
|
|
1213
|
-
return
|
|
1210
|
+
let c = "";
|
|
1211
|
+
c += [...l].map((g) => t[g] || g).join("");
|
|
1212
|
+
const d = [...h];
|
|
1213
|
+
return d[0] = d[0].toLowerCase(), c += d.join(""), a.move = d.length, c += [...r].map((g) => t[g] || g).join(""), a.regex = new RegExp(c), u.length && u.split(" ").forEach((g) => {
|
|
1214
1214
|
a.visemes.push(g);
|
|
1215
1215
|
}), a;
|
|
1216
1216
|
});
|
|
@@ -1380,11 +1380,11 @@ class nt {
|
|
|
1380
1380
|
if ((e.words.substring(0, e.i) + s.toLowerCase() + e.words.substring(e.i + 1)).match(h.regex)) {
|
|
1381
1381
|
h.visemes.forEach((a) => {
|
|
1382
1382
|
if (e.visemes.length && e.visemes[e.visemes.length - 1] === a) {
|
|
1383
|
-
const
|
|
1384
|
-
e.durations[e.durations.length - 1] +=
|
|
1383
|
+
const c = 0.7 * (this.visemeDurations[a] || 1);
|
|
1384
|
+
e.durations[e.durations.length - 1] += c, n += c;
|
|
1385
1385
|
} else {
|
|
1386
|
-
const
|
|
1387
|
-
e.visemes.push(a), e.times.push(n), e.durations.push(
|
|
1386
|
+
const c = this.visemeDurations[a] || 1;
|
|
1387
|
+
e.visemes.push(a), e.times.push(n), e.durations.push(c), n += c;
|
|
1388
1388
|
}
|
|
1389
1389
|
}), e.i += h.move;
|
|
1390
1390
|
break;
|
|
@@ -1617,10 +1617,10 @@ class ot {
|
|
|
1617
1617
|
Object.keys(this.rules).forEach((e) => {
|
|
1618
1618
|
this.rules[e] = this.rules[e].map((n) => {
|
|
1619
1619
|
const i = n.indexOf("["), s = n.indexOf("]"), o = n.indexOf("="), l = n.substring(0, i), h = n.substring(i + 1, s), r = n.substring(s + 1, o), u = n.substring(o + 1), a = { regex: "", move: 0, visemes: [] };
|
|
1620
|
-
let
|
|
1621
|
-
|
|
1622
|
-
const
|
|
1623
|
-
return
|
|
1620
|
+
let c = "";
|
|
1621
|
+
c += [...l].map((g) => t[g] || g).join("");
|
|
1622
|
+
const d = [...h];
|
|
1623
|
+
return d[0] = d[0].toLowerCase(), c += d.join(""), a.move = d.length, c += [...r].map((g) => t[g] || g).join(""), a.regex = new RegExp(c), u.length && u.split(" ").forEach((g) => {
|
|
1624
1624
|
a.visemes.push(g);
|
|
1625
1625
|
}), a;
|
|
1626
1626
|
});
|
|
@@ -1735,13 +1735,13 @@ class ot {
|
|
|
1735
1735
|
for (let h = 0; h < o.length; h++) {
|
|
1736
1736
|
const r = o[h];
|
|
1737
1737
|
if ((e.words.substring(0, e.i) + s.toLowerCase() + e.words.substring(e.i + 1)).match(r.regex)) {
|
|
1738
|
-
r.visemes.forEach((
|
|
1739
|
-
if (e.visemes.length && e.visemes[e.visemes.length - 1] ===
|
|
1740
|
-
const
|
|
1741
|
-
e.durations[e.durations.length - 1] +=
|
|
1738
|
+
r.visemes.forEach((c) => {
|
|
1739
|
+
if (e.visemes.length && e.visemes[e.visemes.length - 1] === c) {
|
|
1740
|
+
const d = 0.7 * (this.visemeDurations[c] || 1);
|
|
1741
|
+
e.durations[e.durations.length - 1] += d, n += d;
|
|
1742
1742
|
} else {
|
|
1743
|
-
const
|
|
1744
|
-
e.visemes.push(
|
|
1743
|
+
const d = this.visemeDurations[c] || 1;
|
|
1744
|
+
e.visemes.push(c), e.times.push(n), e.durations.push(d), n += d;
|
|
1745
1745
|
}
|
|
1746
1746
|
}), e.i += r.move, l = !0;
|
|
1747
1747
|
break;
|
|
@@ -2132,10 +2132,10 @@ class at {
|
|
|
2132
2132
|
Object.keys(this.rules).forEach((e) => {
|
|
2133
2133
|
this.rules[e] = this.rules[e].map((n) => {
|
|
2134
2134
|
const i = n.indexOf("["), s = n.indexOf("]"), o = n.indexOf("="), l = n.substring(0, i), h = n.substring(i + 1, s), r = n.substring(s + 1, o), u = n.substring(o + 1), a = { regex: "", move: 0, visemes: [] };
|
|
2135
|
-
let
|
|
2136
|
-
|
|
2137
|
-
const
|
|
2138
|
-
return
|
|
2135
|
+
let c = "";
|
|
2136
|
+
c += [...l].map((g) => t[g] || g).join("");
|
|
2137
|
+
const d = [...h];
|
|
2138
|
+
return d[0] = d[0].toLowerCase(), c += d.join(""), a.move = d.length, c += [...r].map((g) => t[g] || g).join(""), a.regex = new RegExp(c, "i"), u.length && u.split(" ").forEach((g) => {
|
|
2139
2139
|
g && a.visemes.push(g);
|
|
2140
2140
|
}), a;
|
|
2141
2141
|
});
|
|
@@ -2270,13 +2270,13 @@ class at {
|
|
|
2270
2270
|
for (let h = 0; h < o.length; h++) {
|
|
2271
2271
|
const r = o[h];
|
|
2272
2272
|
if ((e.words.substring(0, e.i) + s.toLowerCase() + e.words.substring(e.i + 1)).match(r.regex)) {
|
|
2273
|
-
r.visemes.forEach((
|
|
2274
|
-
if (e.visemes.length && e.visemes[e.visemes.length - 1] ===
|
|
2275
|
-
const
|
|
2276
|
-
e.durations[e.durations.length - 1] +=
|
|
2273
|
+
r.visemes.forEach((c) => {
|
|
2274
|
+
if (e.visemes.length && e.visemes[e.visemes.length - 1] === c) {
|
|
2275
|
+
const d = 0.7 * (this.visemeDurations[c] || 1);
|
|
2276
|
+
e.durations[e.durations.length - 1] += d, n += d;
|
|
2277
2277
|
} else {
|
|
2278
|
-
const
|
|
2279
|
-
e.visemes.push(
|
|
2278
|
+
const d = this.visemeDurations[c] || 1;
|
|
2279
|
+
e.visemes.push(c), e.times.push(n), e.durations.push(d), n += d;
|
|
2280
2280
|
}
|
|
2281
2281
|
}), e.i += r.move, l = !0;
|
|
2282
2282
|
break;
|
|
@@ -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
|
-
}, Q = new
|
|
2633
|
-
new
|
|
2634
|
-
new
|
|
2635
|
-
new
|
|
2636
|
-
new
|
|
2637
|
-
const mt = new
|
|
2638
|
-
new
|
|
2639
|
-
new
|
|
2632
|
+
}, Q = new f.Quaternion(), V = new f.Euler(), ve = new f.Vector3(), Ie = new f.Vector3(), We = new f.Box3();
|
|
2633
|
+
new f.Matrix4();
|
|
2634
|
+
new f.Matrix4();
|
|
2635
|
+
new f.Vector3();
|
|
2636
|
+
new f.Vector3(0, 0, 1);
|
|
2637
|
+
const mt = new f.Vector3(1, 0, 0);
|
|
2638
|
+
new f.Vector3(0, 1, 0);
|
|
2639
|
+
new f.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 f.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 = f.SRGBColorSpace, this.renderer.toneMapping = f.ACESFilmicToneMapping, this.renderer.shadowMap.enabled = !1, this.nodeAvatar.appendChild(this.renderer.domElement), this.camera = new f.PerspectiveCamera(10, this.nodeAvatar.clientWidth / this.nodeAvatar.clientHeight, 0.1, 2e3), this.scene = new f.Scene(), this.lightAmbient = new f.AmbientLight(
|
|
4077
|
+
new f.Color(this.opt.lightAmbientColor),
|
|
4078
4078
|
this.opt.lightAmbientIntensity
|
|
4079
|
-
), this.lightDirect = new
|
|
4080
|
-
new
|
|
4079
|
+
), this.lightDirect = new f.DirectionalLight(
|
|
4080
|
+
new f.Color(this.opt.lightDirectColor),
|
|
4081
4081
|
this.opt.lightDirectIntensity
|
|
4082
|
-
), this.lightSpot = new
|
|
4083
|
-
new
|
|
4082
|
+
), this.lightSpot = new f.SpotLight(
|
|
4083
|
+
new f.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 f.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 f.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 f.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 f.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 f.Vector3(o, l, h) : s[1] === "rotation" ? (n = s[0] + ".quaternion", e[n] = new f.Quaternion().setFromEuler(new f.Euler(o, l, h, "XYZ")).normalize()) : s[1] === "quaternion" && (e[n] = new f.Quaternion(o, l, h, i.w).normalize());
|
|
4198
4198
|
}
|
|
4199
4199
|
return e;
|
|
4200
4200
|
}
|
|
@@ -4225,16 +4225,16 @@ class Be {
|
|
|
4225
4225
|
let l = null, h = null;
|
|
4226
4226
|
for (const [r, u] of Object.entries(n))
|
|
4227
4227
|
if (s.morphTargetDictionary.hasOwnProperty(r)) {
|
|
4228
|
-
const a = s.morphTargetDictionary[r],
|
|
4229
|
-
l || (l = new
|
|
4230
|
-
for (let g = 0; g <
|
|
4231
|
-
const
|
|
4232
|
-
l.setXYZ(g,
|
|
4228
|
+
const a = s.morphTargetDictionary[r], c = o.morphAttributes.position[a], d = o.morphAttributes.normal?.[a];
|
|
4229
|
+
l || (l = new f.Float32BufferAttribute(c.count * 3, 3), d && (h = new f.Float32BufferAttribute(c.count * 3, 3)));
|
|
4230
|
+
for (let g = 0; g < c.count; g++) {
|
|
4231
|
+
const x = l.getX(g) + c.getX(g) * u, b = l.getY(g) + c.getY(g) * u, R = l.getZ(g) + c.getZ(g) * u;
|
|
4232
|
+
l.setXYZ(g, x, b, R);
|
|
4233
4233
|
}
|
|
4234
|
-
if (
|
|
4235
|
-
for (let g = 0; g <
|
|
4236
|
-
const
|
|
4237
|
-
h.setXYZ(g,
|
|
4234
|
+
if (d)
|
|
4235
|
+
for (let g = 0; g < c.count; g++) {
|
|
4236
|
+
const x = h.getX(g) + d.getX(g) * u, b = h.getY(g) + d.getY(g) * u, R = h.getZ(g) + d.getZ(g) * u;
|
|
4237
|
+
h.setXYZ(g, x, b, R);
|
|
4238
4238
|
}
|
|
4239
4239
|
}
|
|
4240
4240
|
if (l) {
|
|
@@ -4299,8 +4299,8 @@ class Be {
|
|
|
4299
4299
|
u && ["fixed", "system", "systemd", "realtime", "base", "v", "value", "applied"].forEach((a) => {
|
|
4300
4300
|
l[r][a] = u[a];
|
|
4301
4301
|
}), this.morphs.forEach((a) => {
|
|
4302
|
-
const
|
|
4303
|
-
|
|
4302
|
+
const c = a.morphTargetDictionary[r];
|
|
4303
|
+
c !== void 0 && (l[r].ms.push(a.morphTargetInfluences), l[r].is.push(c), a.morphTargetInfluences[c] = l[r].applied);
|
|
4304
4304
|
});
|
|
4305
4305
|
}), this.mtAvatar = l, this.poseAvatar = { props: {} }, this.posePropNames.forEach((r) => {
|
|
4306
4306
|
const u = r.split("."), a = this.armature.getObjectByName(u[0]);
|
|
@@ -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 f.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 f.Vector3(r, u, 0), this.cameraEnd = new f.Vector3(r, u, a).applyEuler(new f.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 f.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 f.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 f.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 f.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
|
+
V.set(e.x, e.y, e.z);
|
|
4402
4402
|
const n = this.poseAvatar.props[t];
|
|
4403
|
-
n.isQuaternion ? (Q.setFromEuler(
|
|
4403
|
+
n.isQuaternion ? (Q.setFromEuler(V), n.multiply(Q)) : n.isVector3 && n.add(V);
|
|
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 f.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;
|
|
@@ -4666,43 +4666,31 @@ class Be {
|
|
|
4666
4666
|
x: this.armature.position.x,
|
|
4667
4667
|
y: this.armature.position.y,
|
|
4668
4668
|
z: this.armature.position.z
|
|
4669
|
-
}, console.log("Original position stored:", this.originalPosition))
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
y: t,
|
|
4675
|
-
// Set to the upward offset directly
|
|
4676
|
-
z: 0
|
|
4677
|
-
// Keep centered horizontally
|
|
4678
|
-
}, this.armature.position.set(
|
|
4679
|
-
this.lockedPosition.x,
|
|
4680
|
-
this.lockedPosition.y,
|
|
4681
|
-
this.lockedPosition.z
|
|
4682
|
-
), console.log("BEFORE: Avatar position was:", this.armature.position.x, this.armature.position.y, this.armature.position.z), console.log("AFTER: Avatar position moved up and locked at:", this.lockedPosition), console.log("Current view:", this.viewName);
|
|
4669
|
+
}, console.log("Original position stored:", this.originalPosition)), this.lockedPosition = {
|
|
4670
|
+
x: this.armature.position.x,
|
|
4671
|
+
y: this.armature.position.y,
|
|
4672
|
+
z: this.armature.position.z
|
|
4673
|
+
}, console.log("Avatar position locked at current position:", this.lockedPosition);
|
|
4683
4674
|
}
|
|
4684
4675
|
/**
|
|
4685
|
-
* Unlock avatar position and
|
|
4676
|
+
* Unlock avatar position and restore original position.
|
|
4686
4677
|
*/
|
|
4687
4678
|
unlockAvatarPosition() {
|
|
4688
|
-
this.armature && (this.armature.position.set(
|
|
4679
|
+
this.armature && this.originalPosition ? (this.armature.position.set(
|
|
4680
|
+
this.originalPosition.x,
|
|
4681
|
+
this.originalPosition.y,
|
|
4682
|
+
this.originalPosition.z
|
|
4683
|
+
), console.log("Avatar position restored to original:", this.originalPosition)) : this.armature && (this.armature.position.set(0, 0, 0), console.log("Avatar position reset to center (0,0,0)")), this.lockedPosition = null, this.originalPosition = null, console.log("Avatar position unlocked");
|
|
4689
4684
|
}
|
|
4690
4685
|
/**
|
|
4691
4686
|
* Ensure avatar stays at locked position.
|
|
4692
4687
|
*/
|
|
4693
4688
|
maintainLockedPosition() {
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
this.lockedPosition.z
|
|
4700
|
-
) : t > n && this.armature.position.set(
|
|
4701
|
-
this.lockedPosition.x,
|
|
4702
|
-
n,
|
|
4703
|
-
this.lockedPosition.z
|
|
4704
|
-
), this.armature.position.x = this.lockedPosition.x, this.armature.position.z = this.lockedPosition.z;
|
|
4705
|
-
}
|
|
4689
|
+
this.lockedPosition && this.armature && this.armature.position.set(
|
|
4690
|
+
this.lockedPosition.x,
|
|
4691
|
+
this.lockedPosition.y,
|
|
4692
|
+
this.lockedPosition.z
|
|
4693
|
+
);
|
|
4706
4694
|
}
|
|
4707
4695
|
/**
|
|
4708
4696
|
* Create body movement animation.
|
|
@@ -4999,10 +4987,10 @@ class Be {
|
|
|
4999
4987
|
if (l.alt.length > 1) {
|
|
5000
4988
|
const u = Math.random();
|
|
5001
4989
|
let a = 0;
|
|
5002
|
-
for (let
|
|
5003
|
-
let
|
|
5004
|
-
if (a +=
|
|
5005
|
-
r = l.alt[
|
|
4990
|
+
for (let c = 0; c < l.alt.length; c++) {
|
|
4991
|
+
let d = this.valueFn(l.alt[c].p);
|
|
4992
|
+
if (a += d === void 0 ? (1 - a) / (l.alt.length - 1 - c) : d, u < a) {
|
|
4993
|
+
r = l.alt[c];
|
|
5006
4994
|
break;
|
|
5007
4995
|
}
|
|
5008
4996
|
}
|
|
@@ -5023,8 +5011,8 @@ class Be {
|
|
|
5023
5011
|
}
|
|
5024
5012
|
s ? o.ts = o.ts.map((r) => h + r * n) : o.ts = o.ts.map((r) => this.animClock + h + r * n), l.vs && l.vs.pose && console.log("Pose being selected from vs.pose:", l.vs.pose, "for avatar body:", this.avatar?.body);
|
|
5025
5013
|
for (let [r, u] of Object.entries(l.vs)) {
|
|
5026
|
-
const a = this.getBaselineValue(r),
|
|
5027
|
-
r === "eyesRotateY" ? (o.vs.eyeLookOutLeft = [null, ...
|
|
5014
|
+
const a = this.getBaselineValue(r), c = u.map((d) => (d = this.valueFn(d), d === null ? null : typeof d == "function" ? d : typeof d == "string" || d instanceof String ? r === "pose" && this.avatar && this.avatar.body === "M" && (d === "hip" || d === "side") ? (console.log("Intercepting pose", d, "in animation factory, overriding to wide for male avatar"), "wide") : d.slice() : Array.isArray(d) ? r === "gesture" ? d.slice() : (a === void 0 ? 0 : a) + i * this.gaussianRandom(...d) : typeof d == "boolean" ? d : d instanceof Object && d.constructor === Object ? Object.assign({}, d) : (a === void 0 ? 0 : a) + i * d));
|
|
5015
|
+
r === "eyesRotateY" ? (o.vs.eyeLookOutLeft = [null, ...c.map((d) => d > 0 ? d : 0)], o.vs.eyeLookInLeft = [null, ...c.map((d) => d > 0 ? 0 : -d)], o.vs.eyeLookOutRight = [null, ...c.map((d) => d > 0 ? 0 : -d)], o.vs.eyeLookInRight = [null, ...c.map((d) => d > 0 ? d : 0)]) : r === "eyesRotateX" ? (o.vs.eyesLookDown = [null, ...c.map((d) => d > 0 ? d : 0)], o.vs.eyesLookUp = [null, ...c.map((d) => d > 0 ? 0 : -d)]) : o.vs[r] = [null, ...c];
|
|
5028
5016
|
}
|
|
5029
5017
|
for (let r of Object.keys(o.vs))
|
|
5030
5018
|
for (; o.vs[r].length <= o.ts.length; ) o.vs[r].push(o.vs[r][o.vs[r].length - 1]);
|
|
@@ -5111,20 +5099,20 @@ class Be {
|
|
|
5111
5099
|
const a = this.animQueue[n];
|
|
5112
5100
|
if (!(!a || !a.ts || !a.ts.length || this.animClock < a.ts[0])) {
|
|
5113
5101
|
for (i = a.ndx || 0, o = a.ts.length; i < o && !(this.animClock < a.ts[i]); i++)
|
|
5114
|
-
for (let [
|
|
5115
|
-
if (this.mtAvatar.hasOwnProperty(
|
|
5116
|
-
if (
|
|
5117
|
-
const g = this.mtAvatar[
|
|
5118
|
-
if (
|
|
5119
|
-
g.newvalue =
|
|
5102
|
+
for (let [c, d] of Object.entries(a.vs))
|
|
5103
|
+
if (this.mtAvatar.hasOwnProperty(c)) {
|
|
5104
|
+
if (d[i + 1] === null) continue;
|
|
5105
|
+
const g = this.mtAvatar[c];
|
|
5106
|
+
if (d[i] === null && (d[i] = g.value), i === o - 1)
|
|
5107
|
+
g.newvalue = d[i];
|
|
5120
5108
|
else {
|
|
5121
|
-
g.newvalue =
|
|
5122
|
-
const
|
|
5109
|
+
g.newvalue = d[i + 1];
|
|
5110
|
+
const x = a.ts[i + 1] - a.ts[i];
|
|
5123
5111
|
let b = 1;
|
|
5124
|
-
|
|
5112
|
+
x > 1e-4 && (b = (this.animClock - a.ts[i]) / x), b < 1 && (g.easing && (b = g.easing(b)), g.newvalue = (1 - b) * d[i] + b * g.newvalue), g.ref && g.ref !== a.vs && g.ref.hasOwnProperty(c) && delete g.ref[c], g.ref = a.vs;
|
|
5125
5113
|
}
|
|
5126
5114
|
if (l)
|
|
5127
|
-
switch (
|
|
5115
|
+
switch (c) {
|
|
5128
5116
|
case "viseme_aa":
|
|
5129
5117
|
case "viseme_E":
|
|
5130
5118
|
case "viseme_I":
|
|
@@ -5133,11 +5121,11 @@ class Be {
|
|
|
5133
5121
|
g.newvalue *= 1 + l / 255 - 0.5;
|
|
5134
5122
|
}
|
|
5135
5123
|
g.needsUpdate = !0;
|
|
5136
|
-
} else
|
|
5124
|
+
} else c === "eyeContact" && d[i] !== null && h !== !1 ? h = !!d[i] : c === "headMove" && d[i] !== null && r !== !1 ? d[i] === 0 ? r = !1 : (Math.random() < d[i] && (r = !0), d[i] = null) : d[i] !== null && (u.push({ mt: c, val: d[i] }), d[i] = null);
|
|
5137
5125
|
i === o ? (a.hasOwnProperty("mood") && this.setMood(a.mood), a.loop ? (o = this.isSpeaking && (a.template.name === "head" || a.template.name === "eyes") ? 4 : 1, this.animQueue[n] = this.animFactory(a.template, a.loop > 0 ? a.loop - 1 : a.loop, 1, 1 / o)) : (this.animQueue.splice(n--, 1), s--)) : a.ndx = i - 1;
|
|
5138
5126
|
}
|
|
5139
5127
|
}
|
|
5140
|
-
for (let a = 0,
|
|
5128
|
+
for (let a = 0, c = u.length; a < c; a++)
|
|
5141
5129
|
switch (i = u[a].val, u[a].mt) {
|
|
5142
5130
|
case "speak":
|
|
5143
5131
|
this.speakText(i);
|
|
@@ -5155,8 +5143,8 @@ class Be {
|
|
|
5155
5143
|
i && typeof i == "function" && i();
|
|
5156
5144
|
break;
|
|
5157
5145
|
case "moveto":
|
|
5158
|
-
Object.entries(i.props).forEach((
|
|
5159
|
-
|
|
5146
|
+
Object.entries(i.props).forEach((d) => {
|
|
5147
|
+
d[1] ? this.poseTarget.props[d[0]].copy(d[1]) : this.poseTarget.props[d[0]].copy(this.getPoseTemplateProp(d[0])), this.poseTarget.props[d[0]].t = this.animClock, this.poseTarget.props[d[0]].d = d[1] && d[1].d ? d[1].d : d.duration || 2e3;
|
|
5160
5148
|
});
|
|
5161
5149
|
break;
|
|
5162
5150
|
case "handLeft":
|
|
@@ -5169,7 +5157,7 @@ class Be {
|
|
|
5169
5157
|
{ link: "LeftForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -0.5, maxz: 3 },
|
|
5170
5158
|
{ link: "LeftArm", minx: -1.5, maxx: 1.5, miny: 0, maxy: 0, minz: -1, maxz: 3 }
|
|
5171
5159
|
]
|
|
5172
|
-
}, i.x ? new
|
|
5160
|
+
}, i.x ? new f.Vector3(i.x, i.y, i.z) : null, !0, i.d);
|
|
5173
5161
|
break;
|
|
5174
5162
|
case "handRight":
|
|
5175
5163
|
this.ikSolve({
|
|
@@ -5181,10 +5169,10 @@ class Be {
|
|
|
5181
5169
|
{ link: "RightForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -3, maxz: 0.5, maxAngle: 0.2 },
|
|
5182
5170
|
{ link: "RightArm", minx: -1.5, maxx: 1.5, miny: 0, maxy: 0, minz: -1, maxz: 3 }
|
|
5183
5171
|
]
|
|
5184
|
-
}, i.x ? new
|
|
5172
|
+
}, i.x ? new f.Vector3(i.x, i.y, i.z) : null, !0, i.d);
|
|
5185
5173
|
break;
|
|
5186
5174
|
}
|
|
5187
|
-
if ((h || r) && (
|
|
5175
|
+
if ((h || r) && (V.setFromQuaternion(this.poseAvatar.props["Head.quaternion"]), V.x = Math.max(-0.9, Math.min(0.9, 2 * V.x - 0.5)), V.y = Math.max(-0.9, Math.min(0.9, -2.5 * V.y)), h ? (Object.assign(this.mtAvatar.eyesLookDown, { system: V.x < 0 ? -V.x : 0, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyesLookUp, { system: V.x < 0 ? 0 : V.x, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookInLeft, { system: V.y < 0 ? -V.y : 0, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookOutLeft, { system: V.y < 0 ? 0 : V.y, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookInRight, { system: V.y < 0 ? 0 : V.y, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookOutRight, { system: V.y < 0 ? -V.y : 0, needsUpdate: !0 }), r && (n = -this.mtAvatar.bodyRotateY.value, i = this.gaussianRandom(-0.2, 0.2), this.animQueue.push(this.animFactory({
|
|
5188
5176
|
name: "headmove",
|
|
5189
5177
|
dt: [[1e3, 2e3], [1e3, 2e3, 1, 2], [1e3, 2e3], [1e3, 2e3, 1, 2]],
|
|
5190
5178
|
vs: {
|
|
@@ -5205,13 +5193,13 @@ class Be {
|
|
|
5205
5193
|
eyeLookOutRight: [null, 0],
|
|
5206
5194
|
eyeContact: [0]
|
|
5207
5195
|
}
|
|
5208
|
-
})))), 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 && (Q.setFromAxisAngle(mt, this.volumeHeadCurrent), this.objectNeck.quaternion.multiply(Q)), We.setFromObject(this.armature), this.objectLeftToeBase.getWorldPosition(ve), ve.sub(this.armature.position), this.objectRightToeBase.getWorldPosition(
|
|
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 && (Q.setFromAxisAngle(mt, this.volumeHeadCurrent), this.objectNeck.quaternion.multiply(Q)), We.setFromObject(this.armature), this.objectLeftToeBase.getWorldPosition(ve), ve.sub(this.armature.position), this.objectRightToeBase.getWorldPosition(Ie), Ie.sub(this.armature.position), this.objectHips.position.y -= We.min.y / 2, this.objectHips.position.x -= (ve.x + Ie.x) / 4, this.objectHips.position.z -= (ve.z + Ie.z) / 2, this.dynamicbones.update(e), this.fbxAnimationLoader && this.fbxAnimationLoader.update(), this.opt.update && this.opt.update(e), this.updateMorphTargets(e), this.isAvatarOnly)
|
|
5209
5197
|
this.stats && this.stats.end();
|
|
5210
5198
|
else {
|
|
5211
5199
|
if (this.cameraClock !== null && this.cameraClock < 1e3) {
|
|
5212
5200
|
this.cameraClock += e, this.cameraClock > 1e3 && (this.cameraClock = 1e3);
|
|
5213
|
-
let a = new
|
|
5214
|
-
a.phi += this.easing(this.cameraClock / 1e3) * (
|
|
5201
|
+
let a = new f.Spherical().setFromVector3(this.cameraStart), c = new f.Spherical().setFromVector3(this.cameraEnd);
|
|
5202
|
+
a.phi += this.easing(this.cameraClock / 1e3) * (c.phi - a.phi), a.theta += this.easing(this.cameraClock / 1e3) * (c.theta - a.theta), a.radius += this.easing(this.cameraClock / 1e3) * (c.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), c.setFromVector3(this.controlsEnd), a.phi += this.easing(this.cameraClock / 1e3) * (c.phi - a.phi), a.theta += this.easing(this.cameraClock / 1e3) * (c.theta - a.theta), a.radius += this.easing(this.cameraClock / 1e3) * (c.radius - a.radius), a.makeSafe(), this.controls.target.setFromSpherical(a)), this.controls.update();
|
|
5215
5203
|
}
|
|
5216
5204
|
this.controls.autoRotate && this.controls.update(), this.stats && this.stats.end(), this.render();
|
|
5217
5205
|
}
|
|
@@ -5273,48 +5261,48 @@ class Be {
|
|
|
5273
5261
|
speakText(t, e = null, n = null, i = null) {
|
|
5274
5262
|
e = e || {};
|
|
5275
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;
|
|
5276
|
-
let u = "", a = "",
|
|
5277
|
-
const
|
|
5278
|
-
for (let b = 0; b <
|
|
5279
|
-
const
|
|
5280
|
-
let p =
|
|
5281
|
-
const M =
|
|
5282
|
-
if (p && !
|
|
5283
|
-
mark:
|
|
5264
|
+
let u = "", a = "", c = 0, d = [], g = [];
|
|
5265
|
+
const x = Array.from(this.segmenter.segment(t), (b) => b.segment);
|
|
5266
|
+
for (let b = 0; b < x.length; b++) {
|
|
5267
|
+
const R = b === x.length - 1, B = x[b].match(l);
|
|
5268
|
+
let p = x[b].match(s);
|
|
5269
|
+
const M = x[b].match(h), z = x[b].match(o);
|
|
5270
|
+
if (p && !R && !M && x[b + 1].match(s) && (p = !1), n && (u += x[b]), B && (!i || i.every((y) => b < y[0] || b > y[1])) && (a += x[b]), (z || p || R) && (a.length && (a = this.lipsyncPreProcessText(a, r), a.length && d.push({
|
|
5271
|
+
mark: c,
|
|
5284
5272
|
word: a
|
|
5285
5273
|
})), u.length && (g.push({
|
|
5286
|
-
mark:
|
|
5274
|
+
mark: c,
|
|
5287
5275
|
template: { name: "subtitles" },
|
|
5288
5276
|
ts: [0],
|
|
5289
5277
|
vs: {
|
|
5290
5278
|
subtitles: [u]
|
|
5291
5279
|
}
|
|
5292
5280
|
}), u = ""), a.length)) {
|
|
5293
|
-
const
|
|
5294
|
-
if (
|
|
5295
|
-
const E =
|
|
5296
|
-
for (let P = 0; P <
|
|
5281
|
+
const y = this.lipsyncWordsToVisemes(a, r);
|
|
5282
|
+
if (y && y.visemes && y.visemes.length) {
|
|
5283
|
+
const E = y.times[y.visemes.length - 1] + y.durations[y.visemes.length - 1];
|
|
5284
|
+
for (let P = 0; P < y.visemes.length; P++)
|
|
5297
5285
|
g.push({
|
|
5298
|
-
mark:
|
|
5286
|
+
mark: c,
|
|
5299
5287
|
template: { name: "viseme" },
|
|
5300
|
-
ts: [(
|
|
5288
|
+
ts: [(y.times[P] - 0.6) / E, (y.times[P] + 0.5) / E, (y.times[P] + y.durations[P] + 0.5) / E],
|
|
5301
5289
|
vs: {
|
|
5302
|
-
["viseme_" +
|
|
5290
|
+
["viseme_" + y.visemes[P]]: [null, y.visemes[P] === "PP" || y.visemes[P] === "FF" ? 0.9 : 0.6, 0]
|
|
5303
5291
|
}
|
|
5304
5292
|
});
|
|
5305
5293
|
}
|
|
5306
|
-
a = "",
|
|
5294
|
+
a = "", c++;
|
|
5307
5295
|
}
|
|
5308
|
-
if (p ||
|
|
5309
|
-
if (
|
|
5310
|
-
const
|
|
5296
|
+
if (p || R) {
|
|
5297
|
+
if (d.length || R && g.length) {
|
|
5298
|
+
const y = {
|
|
5311
5299
|
anim: g
|
|
5312
5300
|
};
|
|
5313
|
-
n && (
|
|
5301
|
+
n && (y.onSubtitles = n), d.length && !e.avatarMute && (y.text = d, e.avatarMood && (y.mood = e.avatarMood), e.ttsLang && (y.lang = e.ttsLang), e.ttsVoice && (y.voice = e.ttsVoice), e.ttsRate && (y.rate = e.ttsRate), e.ttsVoice && (y.pitch = e.ttsPitch), e.ttsVolume && (y.volume = e.ttsVolume)), this.speechQueue.push(y), d = [], a = "", c = 0, g = [];
|
|
5314
5302
|
}
|
|
5315
5303
|
if (M) {
|
|
5316
|
-
let
|
|
5317
|
-
|
|
5304
|
+
let y = this.animEmojis[x[b]];
|
|
5305
|
+
y && y.link && (y = this.animEmojis[y.link]), y && this.speechQueue.push({ emoji: y });
|
|
5318
5306
|
}
|
|
5319
5307
|
this.speechQueue.push({ break: 100 });
|
|
5320
5308
|
}
|
|
@@ -5404,18 +5392,18 @@ class Be {
|
|
|
5404
5392
|
subtitles: [" " + h]
|
|
5405
5393
|
}
|
|
5406
5394
|
}), !t.visemes)) {
|
|
5407
|
-
const a = this.lipsyncPreProcessText(h, i),
|
|
5408
|
-
if (
|
|
5409
|
-
const
|
|
5410
|
-
let
|
|
5411
|
-
if (u = Math.min(u,
|
|
5412
|
-
for (let b = 0; b <
|
|
5413
|
-
const
|
|
5395
|
+
const a = this.lipsyncPreProcessText(h, i), c = this.lipsyncWordsToVisemes(a, i);
|
|
5396
|
+
if (c && c.visemes && c.visemes.length) {
|
|
5397
|
+
const d = c.times[c.visemes.length - 1] + c.durations[c.visemes.length - 1], g = Math.min(u, Math.max(0, u - c.visemes.length * 150));
|
|
5398
|
+
let x = 0.6 + this.convertRange(g, [0, u], [0, 0.4]);
|
|
5399
|
+
if (u = Math.min(u, c.visemes.length * 200), d > 0)
|
|
5400
|
+
for (let b = 0; b < c.visemes.length; b++) {
|
|
5401
|
+
const R = r + c.times[b] / d * u, B = c.durations[b] / d * u;
|
|
5414
5402
|
o.push({
|
|
5415
5403
|
template: { name: "viseme" },
|
|
5416
|
-
ts: [
|
|
5404
|
+
ts: [R - Math.min(60, 2 * B / 3), R + Math.min(25, B / 2), R + B + Math.min(60, B / 2)],
|
|
5417
5405
|
vs: {
|
|
5418
|
-
["viseme_" +
|
|
5406
|
+
["viseme_" + c.visemes[b]]: [null, c.visemes[b] === "PP" || c.visemes[b] === "FF" ? 0.9 : x, 0]
|
|
5419
5407
|
}
|
|
5420
5408
|
});
|
|
5421
5409
|
}
|
|
@@ -5498,31 +5486,31 @@ class Be {
|
|
|
5498
5486
|
const p = u.find((M) => M.name.includes(a) || M.lang === o);
|
|
5499
5487
|
p && (s.voice = p);
|
|
5500
5488
|
}
|
|
5501
|
-
const
|
|
5489
|
+
const c = i.length * 100 / s.rate, d = this.audioCtx.createBuffer(1, this.audioCtx.sampleRate * (c / 1e3), this.audioCtx.sampleRate), g = this.avatar.lipsyncLang || this.opt.lipsyncLang || "en", x = this.lipsyncPreProcessText(i, g), b = this.lipsyncWordsToVisemes(x, g);
|
|
5502
5490
|
console.log("Browser TTS Lip-sync Debug:", {
|
|
5503
5491
|
text: i,
|
|
5504
5492
|
lipsyncLang: g,
|
|
5505
|
-
processedText:
|
|
5493
|
+
processedText: x,
|
|
5506
5494
|
lipsyncData: b,
|
|
5507
5495
|
hasVisemes: b && b.visemes && b.visemes.length > 0,
|
|
5508
|
-
estimatedDuration:
|
|
5496
|
+
estimatedDuration: c
|
|
5509
5497
|
});
|
|
5510
|
-
const
|
|
5498
|
+
const R = [];
|
|
5511
5499
|
if (b && b.visemes && b.visemes.length > 0) {
|
|
5512
5500
|
const p = b.times[b.visemes.length - 1] + b.durations[b.visemes.length - 1];
|
|
5513
5501
|
for (let M = 0; M < b.visemes.length; M++) {
|
|
5514
|
-
const z = b.visemes[M],
|
|
5515
|
-
|
|
5502
|
+
const z = b.visemes[M], y = b.times[M] / p, E = b.durations[M] / p, P = y * c, W = E * c;
|
|
5503
|
+
R.push({
|
|
5516
5504
|
template: { name: "viseme" },
|
|
5517
|
-
ts: [P - Math.min(60, 2 *
|
|
5505
|
+
ts: [P - Math.min(60, 2 * W / 3), P + Math.min(25, W / 2), P + W + Math.min(60, W / 2)],
|
|
5518
5506
|
vs: {
|
|
5519
5507
|
["viseme_" + z]: [null, z === "PP" || z === "FF" ? 0.9 : 0.6, 0]
|
|
5520
5508
|
}
|
|
5521
5509
|
});
|
|
5522
5510
|
}
|
|
5523
5511
|
}
|
|
5524
|
-
const
|
|
5525
|
-
this.audioPlaylist.push({ anim:
|
|
5512
|
+
const B = [...t.anim, ...R];
|
|
5513
|
+
this.audioPlaylist.push({ anim: B, audio: d }), this.onSubtitles = t.onSubtitles || null, this.resetLips(), t.mood && this.setMood(t.mood), this.playAudio(), s.onend = () => {
|
|
5526
5514
|
e();
|
|
5527
5515
|
}, s.onerror = (p) => {
|
|
5528
5516
|
console.error("Speech synthesis error:", p.error), n(p.error);
|
|
@@ -5534,7 +5522,7 @@ class Be {
|
|
|
5534
5522
|
* @param {Object} line Speech line object
|
|
5535
5523
|
*/
|
|
5536
5524
|
async synthesizeWithElevenLabsTTS(t) {
|
|
5537
|
-
const e = t.text.map((
|
|
5525
|
+
const e = t.text.map((c) => c.word).join(" "), n = t.voice || this.avatar.ttsVoice || this.opt.ttsVoice || "21m00Tcm4TlvDq8ikWAM", i = {
|
|
5538
5526
|
text: e,
|
|
5539
5527
|
model_id: "eleven_monolingual_v1",
|
|
5540
5528
|
voice_settings: {
|
|
@@ -5564,18 +5552,18 @@ class Be {
|
|
|
5564
5552
|
lipsyncKeys: this.lipsync ? Object.keys(this.lipsync) : [],
|
|
5565
5553
|
lipsyncLang: h
|
|
5566
5554
|
});
|
|
5567
|
-
const
|
|
5555
|
+
const c = this.lipsyncPreProcessText(e, h), d = this.lipsyncWordsToVisemes(c, h);
|
|
5568
5556
|
if (console.log("Lip-sync data:", {
|
|
5569
|
-
processedText:
|
|
5570
|
-
lipsyncData:
|
|
5571
|
-
hasVisemes:
|
|
5572
|
-
}),
|
|
5557
|
+
processedText: c,
|
|
5558
|
+
lipsyncData: d,
|
|
5559
|
+
hasVisemes: d && d.visemes && d.visemes.length > 0
|
|
5560
|
+
}), d && d.visemes && d.visemes.length > 0)
|
|
5573
5561
|
r = {
|
|
5574
|
-
visemes:
|
|
5562
|
+
visemes: d.visemes.map((g, x) => ({
|
|
5575
5563
|
viseme: g,
|
|
5576
|
-
startTime:
|
|
5577
|
-
endTime: (
|
|
5578
|
-
duration: l.duration /
|
|
5564
|
+
startTime: x * l.duration / d.visemes.length,
|
|
5565
|
+
endTime: (x + 1) * l.duration / d.visemes.length,
|
|
5566
|
+
duration: l.duration / d.visemes.length,
|
|
5579
5567
|
intensity: 0.7
|
|
5580
5568
|
})),
|
|
5581
5569
|
words: [],
|
|
@@ -5584,17 +5572,17 @@ class Be {
|
|
|
5584
5572
|
};
|
|
5585
5573
|
else
|
|
5586
5574
|
throw new Error("No visemes generated from text");
|
|
5587
|
-
} catch (
|
|
5588
|
-
console.error("Text-based lip-sync failed, using fallback:",
|
|
5589
|
-
const
|
|
5590
|
-
for (const
|
|
5591
|
-
for (const b of
|
|
5592
|
-
let
|
|
5593
|
-
"aeiou".includes(b) ?
|
|
5575
|
+
} catch (c) {
|
|
5576
|
+
console.error("Text-based lip-sync failed, using fallback:", c);
|
|
5577
|
+
const d = e.toLowerCase().split(/\s+/), g = [];
|
|
5578
|
+
for (const x of d)
|
|
5579
|
+
for (const b of x) {
|
|
5580
|
+
let R = "aa";
|
|
5581
|
+
"aeiou".includes(b) ? R = "aa" : "bp".includes(b) ? R = "PP" : "fv".includes(b) ? R = "FF" : "st".includes(b) ? R = "SS" : "dln".includes(b) ? R = "DD" : "kg".includes(b) ? R = "kk" : "rw".includes(b) && (R = "RR"), g.push(R);
|
|
5594
5582
|
}
|
|
5595
5583
|
r = {
|
|
5596
|
-
visemes: g.map((
|
|
5597
|
-
viseme:
|
|
5584
|
+
visemes: g.map((x, b) => ({
|
|
5585
|
+
viseme: x,
|
|
5598
5586
|
startTime: b * l.duration / g.length,
|
|
5599
5587
|
endTime: (b + 1) * l.duration / g.length,
|
|
5600
5588
|
duration: l.duration / g.length,
|
|
@@ -5620,13 +5608,13 @@ class Be {
|
|
|
5620
5608
|
const u = [];
|
|
5621
5609
|
if (r.visemes && r.visemes.length > 0) {
|
|
5622
5610
|
console.log("ElevenLabs: Generating lip-sync animation from", r.visemes.length, "visemes");
|
|
5623
|
-
for (let
|
|
5624
|
-
const
|
|
5611
|
+
for (let c = 0; c < r.visemes.length; c++) {
|
|
5612
|
+
const d = r.visemes[c], g = d.startTime * 1e3, x = d.duration * 1e3, b = d.intensity;
|
|
5625
5613
|
u.push({
|
|
5626
5614
|
template: { name: "viseme" },
|
|
5627
|
-
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)],
|
|
5628
5616
|
vs: {
|
|
5629
|
-
["viseme_" +
|
|
5617
|
+
["viseme_" + d.viseme]: [null, b, 0]
|
|
5630
5618
|
}
|
|
5631
5619
|
});
|
|
5632
5620
|
}
|
|
@@ -5641,7 +5629,7 @@ class Be {
|
|
|
5641
5629
|
* @param {Object} line Speech line object
|
|
5642
5630
|
*/
|
|
5643
5631
|
async synthesizeWithDeepgramTTS(t) {
|
|
5644
|
-
const e = t.text.map((
|
|
5632
|
+
const e = t.text.map((c) => c.word).join(" "), n = t.voice || this.avatar.ttsVoice || this.opt.ttsVoice || "aura-2-thalia-en", i = `${this.opt.ttsEndpoint}?model=${n}`, s = await fetch(i, {
|
|
5645
5633
|
method: "POST",
|
|
5646
5634
|
headers: {
|
|
5647
5635
|
Authorization: `Token ${this.opt.ttsApikey}`,
|
|
@@ -5662,18 +5650,18 @@ class Be {
|
|
|
5662
5650
|
lipsyncKeys: this.lipsync ? Object.keys(this.lipsync) : [],
|
|
5663
5651
|
lipsyncLang: h
|
|
5664
5652
|
});
|
|
5665
|
-
const
|
|
5653
|
+
const c = this.lipsyncPreProcessText(e, h), d = this.lipsyncWordsToVisemes(c, h);
|
|
5666
5654
|
if (console.log("Lip-sync data:", {
|
|
5667
|
-
processedText:
|
|
5668
|
-
lipsyncData:
|
|
5669
|
-
hasVisemes:
|
|
5670
|
-
}),
|
|
5655
|
+
processedText: c,
|
|
5656
|
+
lipsyncData: d,
|
|
5657
|
+
hasVisemes: d && d.visemes && d.visemes.length > 0
|
|
5658
|
+
}), d && d.visemes && d.visemes.length > 0)
|
|
5671
5659
|
r = {
|
|
5672
|
-
visemes:
|
|
5660
|
+
visemes: d.visemes.map((g, x) => ({
|
|
5673
5661
|
viseme: g,
|
|
5674
|
-
startTime:
|
|
5675
|
-
endTime: (
|
|
5676
|
-
duration: l.duration /
|
|
5662
|
+
startTime: x * l.duration / d.visemes.length,
|
|
5663
|
+
endTime: (x + 1) * l.duration / d.visemes.length,
|
|
5664
|
+
duration: l.duration / d.visemes.length,
|
|
5677
5665
|
intensity: 0.7
|
|
5678
5666
|
})),
|
|
5679
5667
|
words: [],
|
|
@@ -5682,17 +5670,17 @@ class Be {
|
|
|
5682
5670
|
};
|
|
5683
5671
|
else
|
|
5684
5672
|
throw new Error("No visemes generated from text");
|
|
5685
|
-
} catch (
|
|
5686
|
-
console.error("Text-based lip-sync failed, using fallback:",
|
|
5687
|
-
const
|
|
5688
|
-
for (const
|
|
5689
|
-
for (const b of
|
|
5690
|
-
let
|
|
5691
|
-
"aeiou".includes(b) ?
|
|
5673
|
+
} catch (c) {
|
|
5674
|
+
console.error("Text-based lip-sync failed, using fallback:", c);
|
|
5675
|
+
const d = e.toLowerCase().split(/\s+/), g = [];
|
|
5676
|
+
for (const x of d)
|
|
5677
|
+
for (const b of x) {
|
|
5678
|
+
let R = "aa";
|
|
5679
|
+
"aeiou".includes(b) ? R = "aa" : "bp".includes(b) ? R = "PP" : "fv".includes(b) ? R = "FF" : "st".includes(b) ? R = "SS" : "dln".includes(b) ? R = "DD" : "kg".includes(b) ? R = "kk" : "rw".includes(b) && (R = "RR"), g.push(R);
|
|
5692
5680
|
}
|
|
5693
5681
|
r = {
|
|
5694
|
-
visemes: g.map((
|
|
5695
|
-
viseme:
|
|
5682
|
+
visemes: g.map((x, b) => ({
|
|
5683
|
+
viseme: x,
|
|
5696
5684
|
startTime: b * l.duration / g.length,
|
|
5697
5685
|
endTime: (b + 1) * l.duration / g.length,
|
|
5698
5686
|
duration: l.duration / g.length,
|
|
@@ -5718,13 +5706,13 @@ class Be {
|
|
|
5718
5706
|
const u = [];
|
|
5719
5707
|
if (r.visemes && r.visemes.length > 0) {
|
|
5720
5708
|
console.log("Deepgram: Generating lip-sync animation from", r.visemes.length, "visemes");
|
|
5721
|
-
for (let
|
|
5722
|
-
const
|
|
5709
|
+
for (let c = 0; c < r.visemes.length; c++) {
|
|
5710
|
+
const d = r.visemes[c], g = d.startTime * 1e3, x = d.duration * 1e3, b = d.intensity;
|
|
5723
5711
|
u.push({
|
|
5724
5712
|
template: { name: "viseme" },
|
|
5725
|
-
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)],
|
|
5726
5714
|
vs: {
|
|
5727
|
-
["viseme_" +
|
|
5715
|
+
["viseme_" + d.viseme]: [null, b, 0]
|
|
5728
5716
|
}
|
|
5729
5717
|
});
|
|
5730
5718
|
}
|
|
@@ -5771,12 +5759,12 @@ class Be {
|
|
|
5771
5759
|
});
|
|
5772
5760
|
const r = [];
|
|
5773
5761
|
for (let a = 0; a < h.visemes.length; a++) {
|
|
5774
|
-
const
|
|
5762
|
+
const c = h.visemes[a], d = c.startTime * 1e3, g = c.duration * 1e3, x = c.intensity;
|
|
5775
5763
|
r.push({
|
|
5776
5764
|
template: { name: "viseme" },
|
|
5777
|
-
ts: [
|
|
5765
|
+
ts: [d - Math.min(60, 2 * g / 3), d + Math.min(25, g / 2), d + g + Math.min(60, g / 2)],
|
|
5778
5766
|
vs: {
|
|
5779
|
-
["viseme_" +
|
|
5767
|
+
["viseme_" + c.viseme]: [null, x, 0]
|
|
5780
5768
|
}
|
|
5781
5769
|
});
|
|
5782
5770
|
}
|
|
@@ -5822,25 +5810,25 @@ class Be {
|
|
|
5822
5810
|
this.speakWithHands();
|
|
5823
5811
|
const h = [0];
|
|
5824
5812
|
let r = 0;
|
|
5825
|
-
t.text.forEach((
|
|
5826
|
-
if (
|
|
5813
|
+
t.text.forEach((c, d) => {
|
|
5814
|
+
if (d > 0) {
|
|
5827
5815
|
let g = h[h.length - 1];
|
|
5828
|
-
s.timepoints[r] && (g = s.timepoints[r].timeSeconds * 1e3, s.timepoints[r].markName === "" +
|
|
5816
|
+
s.timepoints[r] && (g = s.timepoints[r].timeSeconds * 1e3, s.timepoints[r].markName === "" + c.mark && r++), h.push(g);
|
|
5829
5817
|
}
|
|
5830
5818
|
});
|
|
5831
5819
|
const u = [{ mark: 0, time: 0 }];
|
|
5832
|
-
h.forEach((
|
|
5833
|
-
if (
|
|
5834
|
-
let g =
|
|
5835
|
-
u[
|
|
5820
|
+
h.forEach((c, d) => {
|
|
5821
|
+
if (d > 0) {
|
|
5822
|
+
let g = c - h[d - 1];
|
|
5823
|
+
u[d - 1].duration = g, u.push({ mark: d, time: c });
|
|
5836
5824
|
}
|
|
5837
5825
|
});
|
|
5838
5826
|
let a = 1e3 * l.duration;
|
|
5839
|
-
a > this.opt.ttsTrimEnd && (a = a - this.opt.ttsTrimEnd), u[u.length - 1].duration = a - u[u.length - 1].time, t.anim.forEach((
|
|
5840
|
-
const
|
|
5841
|
-
if (
|
|
5842
|
-
for (let g = 0; g <
|
|
5843
|
-
|
|
5827
|
+
a > this.opt.ttsTrimEnd && (a = a - this.opt.ttsTrimEnd), u[u.length - 1].duration = a - u[u.length - 1].time, t.anim.forEach((c) => {
|
|
5828
|
+
const d = u[c.mark];
|
|
5829
|
+
if (d)
|
|
5830
|
+
for (let g = 0; g < c.ts.length; g++)
|
|
5831
|
+
c.ts[g] = d.time + c.ts[g] * d.duration + this.opt.ttsTrimStart;
|
|
5844
5832
|
}), this.audioPlaylist.push({ anim: t.anim, audio: l }), this.onSubtitles = t.onSubtitles || null, this.resetLips(), t.mood && this.setMood(t.mood), this.playAudio();
|
|
5845
5833
|
} else
|
|
5846
5834
|
this.startSpeaking(!0);
|
|
@@ -6059,15 +6047,15 @@ class Be {
|
|
|
6059
6047
|
const l = this.streamLipsyncLang || this.avatar.lipsyncLang || this.opt.lipsyncLang, h = this.lipsyncPreProcessText(i, l), r = this.lipsyncWordsToVisemes(h, l);
|
|
6060
6048
|
if (r && r.visemes && r.visemes.length) {
|
|
6061
6049
|
const u = r.times[r.visemes.length - 1] + r.durations[r.visemes.length - 1], a = Math.min(o, Math.max(0, o - r.visemes.length * 150));
|
|
6062
|
-
let
|
|
6050
|
+
let c = 0.6 + this.convertRange(a, [0, o], [0, 0.4]);
|
|
6063
6051
|
if (o = Math.min(o, r.visemes.length * 200), u > 0)
|
|
6064
|
-
for (let
|
|
6065
|
-
const g = e + s + r.times[
|
|
6052
|
+
for (let d = 0; d < r.visemes.length; d++) {
|
|
6053
|
+
const g = e + s + r.times[d] / u * o, x = r.durations[d] / u * o;
|
|
6066
6054
|
this.animQueue.push({
|
|
6067
6055
|
template: { name: "viseme" },
|
|
6068
|
-
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)],
|
|
6069
6057
|
vs: {
|
|
6070
|
-
["viseme_" + r.visemes[
|
|
6058
|
+
["viseme_" + r.visemes[d]]: [null, r.visemes[d] === "PP" || r.visemes[d] === "FF" ? 0.9 : c, 0]
|
|
6071
6059
|
}
|
|
6072
6060
|
});
|
|
6073
6061
|
}
|
|
@@ -6158,7 +6146,7 @@ class Be {
|
|
|
6158
6146
|
*/
|
|
6159
6147
|
lookAtCamera(t) {
|
|
6160
6148
|
let e;
|
|
6161
|
-
if (this.speakTo && (e = new
|
|
6149
|
+
if (this.speakTo && (e = new f.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), Ie.setFromMatrixPosition(this.speakTo.objectRightEye.matrixWorld), e.addVectors(ve, Ie).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) {
|
|
6162
6150
|
if (this.avatar.hasOwnProperty("avatarIgnoreCamera")) {
|
|
6163
6151
|
if (this.avatar.avatarIgnoreCamera) {
|
|
6164
6152
|
this.lookAhead(t);
|
|
@@ -6171,22 +6159,22 @@ class Be {
|
|
|
6171
6159
|
this.lookAt(null, null, t);
|
|
6172
6160
|
return;
|
|
6173
6161
|
}
|
|
6174
|
-
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0), ve.setFromMatrixPosition(this.objectLeftEye.matrixWorld),
|
|
6175
|
-
const n = new
|
|
6176
|
-
|
|
6177
|
-
const l = new
|
|
6178
|
-
|
|
6179
|
-
let r =
|
|
6162
|
+
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0), ve.setFromMatrixPosition(this.objectLeftEye.matrixWorld), Ie.setFromMatrixPosition(this.objectRightEye.matrixWorld), ve.add(Ie).divideScalar(2), Q.copy(this.armature.quaternion), Q.multiply(this.poseTarget.props["Hips.quaternion"]), Q.multiply(this.poseTarget.props["Spine.quaternion"]), Q.multiply(this.poseTarget.props["Spine1.quaternion"]), Q.multiply(this.poseTarget.props["Spine2.quaternion"]), Q.multiply(this.poseTarget.props["Neck.quaternion"]), Q.multiply(this.poseTarget.props["Head.quaternion"]);
|
|
6163
|
+
const n = new f.Vector3().subVectors(e, ve).normalize(), i = Math.atan2(n.x, n.z), s = Math.asin(-n.y);
|
|
6164
|
+
V.set(s, i, 0, "YXZ");
|
|
6165
|
+
const l = new f.Quaternion().setFromEuler(V), h = new f.Quaternion().copy(l).multiply(Q.clone().invert());
|
|
6166
|
+
V.setFromQuaternion(h, "YXZ");
|
|
6167
|
+
let r = V.x / (40 / 24) + 0.2, u = V.y / (9 / 4), a = Math.min(0.6, Math.max(-0.3, r)), c = Math.min(0.8, Math.max(-0.8, u)), d = (Math.random() - 0.5) / 4, g = (Math.random() - 0.5) / 4;
|
|
6180
6168
|
if (t) {
|
|
6181
|
-
let
|
|
6182
|
-
|
|
6169
|
+
let x = this.animQueue.findIndex((R) => R.template.name === "lookat");
|
|
6170
|
+
x !== -1 && this.animQueue.splice(x, 1);
|
|
6183
6171
|
const b = {
|
|
6184
6172
|
name: "lookat",
|
|
6185
6173
|
dt: [750, t],
|
|
6186
6174
|
vs: {
|
|
6187
|
-
bodyRotateX: [a +
|
|
6188
|
-
bodyRotateY: [
|
|
6189
|
-
eyesRotateX: [-3 *
|
|
6175
|
+
bodyRotateX: [a + d],
|
|
6176
|
+
bodyRotateY: [c + g],
|
|
6177
|
+
eyesRotateX: [-3 * d + 0.1],
|
|
6190
6178
|
eyesRotateY: [-5 * g],
|
|
6191
6179
|
browInnerUp: [[0, 0.7]],
|
|
6192
6180
|
mouthLeft: [[0, 0.7]],
|
|
@@ -6208,23 +6196,23 @@ class Be {
|
|
|
6208
6196
|
if (!this.camera) return;
|
|
6209
6197
|
const i = this.nodeAvatar.getBoundingClientRect();
|
|
6210
6198
|
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0);
|
|
6211
|
-
const s = new
|
|
6199
|
+
const s = new f.Vector3().setFromMatrixPosition(this.objectLeftEye.matrixWorld), o = new f.Vector3().setFromMatrixPosition(this.objectRightEye.matrixWorld), l = new f.Vector3().addVectors(s, o).divideScalar(2);
|
|
6212
6200
|
l.project(this.camera);
|
|
6213
6201
|
let h = (l.x + 1) / 2 * i.width + i.left, r = -(l.y - 1) / 2 * i.height + i.top;
|
|
6214
|
-
t === null && (t = h), e === null && (e = r), Q.copy(this.armature.quaternion), Q.multiply(this.poseTarget.props["Hips.quaternion"]), Q.multiply(this.poseTarget.props["Spine.quaternion"]), Q.multiply(this.poseTarget.props["Spine1.quaternion"]), Q.multiply(this.poseTarget.props["Spine2.quaternion"]), Q.multiply(this.poseTarget.props["Neck.quaternion"]), Q.multiply(this.poseTarget.props["Head.quaternion"]),
|
|
6215
|
-
let u =
|
|
6216
|
-
b = Math.min(0.6, Math.max(-0.3, b)),
|
|
6217
|
-
let
|
|
6202
|
+
t === null && (t = h), e === null && (e = r), Q.copy(this.armature.quaternion), Q.multiply(this.poseTarget.props["Hips.quaternion"]), Q.multiply(this.poseTarget.props["Spine.quaternion"]), Q.multiply(this.poseTarget.props["Spine1.quaternion"]), Q.multiply(this.poseTarget.props["Spine2.quaternion"]), Q.multiply(this.poseTarget.props["Neck.quaternion"]), Q.multiply(this.poseTarget.props["Head.quaternion"]), V.setFromQuaternion(Q);
|
|
6203
|
+
let u = V.x / (40 / 24), a = V.y / (9 / 4), c = Math.min(0.4, Math.max(-0.4, this.camera.rotation.x)), d = 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), b = this.convertRange(e, [r - x, r + x], [-0.3, 0.6]) - u + c, R = this.convertRange(t, [h - g, h + g], [-0.8, 0.8]) - a + d;
|
|
6204
|
+
b = Math.min(0.6, Math.max(-0.3, b)), R = Math.min(0.8, Math.max(-0.8, R));
|
|
6205
|
+
let B = (Math.random() - 0.5) / 4, p = (Math.random() - 0.5) / 4;
|
|
6218
6206
|
if (n) {
|
|
6219
|
-
let M = this.animQueue.findIndex((
|
|
6207
|
+
let M = this.animQueue.findIndex((y) => y.template.name === "lookat");
|
|
6220
6208
|
M !== -1 && this.animQueue.splice(M, 1);
|
|
6221
6209
|
const z = {
|
|
6222
6210
|
name: "lookat",
|
|
6223
6211
|
dt: [750, n],
|
|
6224
6212
|
vs: {
|
|
6225
|
-
bodyRotateX: [b +
|
|
6226
|
-
bodyRotateY: [
|
|
6227
|
-
eyesRotateX: [-3 *
|
|
6213
|
+
bodyRotateX: [b + B],
|
|
6214
|
+
bodyRotateY: [R + p],
|
|
6215
|
+
eyesRotateX: [-3 * B + 0.1],
|
|
6228
6216
|
eyesRotateY: [-5 * p],
|
|
6229
6217
|
browInnerUp: [[0, 0.7]],
|
|
6230
6218
|
mouthLeft: [[0, 0.7]],
|
|
@@ -6244,14 +6232,14 @@ class Be {
|
|
|
6244
6232
|
*/
|
|
6245
6233
|
touchAt(t, e) {
|
|
6246
6234
|
if (!this.camera) return;
|
|
6247
|
-
const n = this.nodeAvatar.getBoundingClientRect(), i = new
|
|
6235
|
+
const n = this.nodeAvatar.getBoundingClientRect(), i = new f.Vector2(
|
|
6248
6236
|
(t - n.left) / n.width * 2 - 1,
|
|
6249
6237
|
-((e - n.top) / n.height) * 2 + 1
|
|
6250
|
-
), s = new
|
|
6238
|
+
), s = new f.Raycaster();
|
|
6251
6239
|
s.setFromCamera(i, this.camera);
|
|
6252
6240
|
const o = s.intersectObject(this.armature);
|
|
6253
6241
|
if (o.length > 0) {
|
|
6254
|
-
const l = o[0].point, h = new
|
|
6242
|
+
const l = o[0].point, h = new f.Vector3(), r = new f.Vector3();
|
|
6255
6243
|
this.objectLeftArm.getWorldPosition(h), this.objectRightArm.getWorldPosition(r);
|
|
6256
6244
|
const u = h.distanceToSquared(l), a = r.distanceToSquared(l);
|
|
6257
6245
|
u < a ? (this.ikSolve({
|
|
@@ -6295,7 +6283,7 @@ class Be {
|
|
|
6295
6283
|
{ link: "LeftForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -0.5, maxz: 3 },
|
|
6296
6284
|
{ link: "LeftArm", minx: -1.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -1, maxz: 3 }
|
|
6297
6285
|
]
|
|
6298
|
-
}, new
|
|
6286
|
+
}, new f.Vector3(
|
|
6299
6287
|
this.gaussianRandom(0, 0.5),
|
|
6300
6288
|
this.gaussianRandom(-0.8, -0.2),
|
|
6301
6289
|
this.gaussianRandom(0, 0.5)
|
|
@@ -6307,15 +6295,15 @@ class Be {
|
|
|
6307
6295
|
{ link: "RightForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -3, maxz: 0.5 },
|
|
6308
6296
|
{ link: "RightArm" }
|
|
6309
6297
|
]
|
|
6310
|
-
}, new
|
|
6298
|
+
}, new f.Vector3(
|
|
6311
6299
|
this.gaussianRandom(-0.5, 0),
|
|
6312
6300
|
this.gaussianRandom(-0.8, -0.2),
|
|
6313
6301
|
this.gaussianRandom(0, 0.5)
|
|
6314
6302
|
), !0);
|
|
6315
6303
|
const n = [], i = [];
|
|
6316
6304
|
n.push(100 + Math.round(Math.random() * 500)), i.push({ duration: 1e3, props: {
|
|
6317
|
-
"LeftHand.quaternion": new
|
|
6318
|
-
"RightHand.quaternion": new
|
|
6305
|
+
"LeftHand.quaternion": new f.Quaternion().setFromEuler(new f.Euler(0, -1 - Math.random(), 0)),
|
|
6306
|
+
"RightHand.quaternion": new f.Quaternion().setFromEuler(new f.Euler(0, 1 + Math.random(), 0))
|
|
6319
6307
|
} }), ["LeftArm", "LeftForeArm", "RightArm", "RightForeArm"].forEach((o) => {
|
|
6320
6308
|
i[0].props[o + ".quaternion"] = this.ikMesh.getObjectByName(o).quaternion.clone();
|
|
6321
6309
|
}), n.push(1e3 + Math.round(Math.random() * 500)), i.push({ duration: 2e3, props: {} }), ["LeftArm", "LeftForeArm", "RightArm", "RightForeArm", "LeftHand", "RightHand"].forEach((o) => {
|
|
@@ -6392,6 +6380,29 @@ class Be {
|
|
|
6392
6380
|
* @param {number} [ndx=0] Index of the clip
|
|
6393
6381
|
* @param {number} [scale=0.01] Position scale factor
|
|
6394
6382
|
*/
|
|
6383
|
+
/**
|
|
6384
|
+
* Get all bone names from the avatar's armature
|
|
6385
|
+
* @returns {Set<string>} Set of bone names
|
|
6386
|
+
*/
|
|
6387
|
+
getAvailableBoneNames() {
|
|
6388
|
+
const t = /* @__PURE__ */ new Set();
|
|
6389
|
+
return this.armature && this.armature.traverse((e) => {
|
|
6390
|
+
(e.isBone || e.type === "Bone") && t.add(e.name);
|
|
6391
|
+
}), t;
|
|
6392
|
+
}
|
|
6393
|
+
/**
|
|
6394
|
+
* Filter animation tracks to only include bones that exist in the avatar
|
|
6395
|
+
* @param {THREE.AnimationClip} clip - Animation clip to filter
|
|
6396
|
+
* @param {Set<string>} availableBones - Set of available bone names
|
|
6397
|
+
* @returns {THREE.AnimationClip} Filtered animation clip
|
|
6398
|
+
*/
|
|
6399
|
+
filterAnimationTracks(t, e) {
|
|
6400
|
+
const n = [], i = /* @__PURE__ */ new Set();
|
|
6401
|
+
return t.tracks.forEach((s) => {
|
|
6402
|
+
const l = s.name.split(".")[0];
|
|
6403
|
+
e.has(l) ? n.push(s) : i.add(l);
|
|
6404
|
+
}), i.size > 0 ? (console.warn(`FBX animation "${t.name}" contains tracks for ${i.size} bone(s) not found in avatar skeleton:`, Array.from(i).slice(0, 10).join(", "), i.size > 10 ? "..." : ""), console.info(`Filtered ${t.tracks.length} tracks down to ${n.length} valid tracks`)) : n.length > 0 && console.info(`FBX animation "${t.name}" is fully compatible: all ${n.length} tracks match avatar skeleton`), n.length === 0 ? (console.error(`No valid tracks found for animation "${t.name}". All bones are missing from avatar skeleton.`), null) : new f.AnimationClip(t.name, t.duration, n);
|
|
6405
|
+
}
|
|
6395
6406
|
async playAnimation(t, e = null, n = 10, i = 0, s = 0.01, o = !1) {
|
|
6396
6407
|
if (!this.armature) return;
|
|
6397
6408
|
this.positionWasLocked = !o, o ? console.log("Position locking disabled for FBX animation:", t) : (this.lockAvatarPosition(), console.log("Position locked immediately before FBX animation:", t));
|
|
@@ -6400,9 +6411,9 @@ class Be {
|
|
|
6400
6411
|
let h = this.animQueue.find((a) => a.template.name === "pose");
|
|
6401
6412
|
h && (h.ts[0] = 1 / 0), Object.entries(l.pose.props).forEach((a) => {
|
|
6402
6413
|
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;
|
|
6403
|
-
}), this.mixer ? console.log("Using existing mixer for FBX animation, preserving morph targets") : (this.mixer = new
|
|
6414
|
+
}), this.mixer ? console.log("Using existing mixer for FBX animation, preserving morph targets") : (this.mixer = new f.AnimationMixer(this.armature), console.log("Created new mixer for FBX animation")), this.mixer.addEventListener("finished", this.stopAnimation.bind(this), { once: !0 });
|
|
6404
6415
|
const r = Math.ceil(n / l.clip.duration), u = this.mixer.clipAction(l.clip);
|
|
6405
|
-
u.setLoop(
|
|
6416
|
+
u.setLoop(f.LoopRepeat, r), u.clampWhenFinished = !0, this.currentFBXAction = u;
|
|
6406
6417
|
try {
|
|
6407
6418
|
u.fadeIn(0.5).play(), console.log("FBX animation started successfully:", t);
|
|
6408
6419
|
} catch (a) {
|
|
@@ -6420,58 +6431,64 @@ class Be {
|
|
|
6420
6431
|
}
|
|
6421
6432
|
let r = !1;
|
|
6422
6433
|
try {
|
|
6423
|
-
const
|
|
6424
|
-
if (r =
|
|
6425
|
-
console.error(`FBX file not found at ${t}. Status: ${
|
|
6434
|
+
const c = await fetch(t, { method: "HEAD" });
|
|
6435
|
+
if (r = c.ok, !r) {
|
|
6436
|
+
console.error(`FBX file not found at ${t}. Status: ${c.status}`), console.error("Please check:"), console.error("1. File path is correct (note: path is case-sensitive)"), console.error("2. File exists in your public folder"), console.error("3. File is accessible (not blocked by server)");
|
|
6426
6437
|
return;
|
|
6427
6438
|
}
|
|
6428
|
-
} catch (
|
|
6429
|
-
console.warn(`Could not verify file existence for ${t}, attempting to load anyway:`,
|
|
6439
|
+
} catch (c) {
|
|
6440
|
+
console.warn(`Could not verify file existence for ${t}, attempting to load anyway:`, c);
|
|
6430
6441
|
}
|
|
6431
6442
|
const u = new De();
|
|
6432
6443
|
let a;
|
|
6433
6444
|
try {
|
|
6434
6445
|
a = await u.loadAsync(t, e);
|
|
6435
|
-
} catch (
|
|
6436
|
-
console.error(`Failed to load FBX animation from ${t}:`,
|
|
6437
|
-
message:
|
|
6446
|
+
} catch (c) {
|
|
6447
|
+
console.error(`Failed to load FBX animation from ${t}:`, c), console.error("Error details:", {
|
|
6448
|
+
message: c.message,
|
|
6438
6449
|
url: t,
|
|
6439
6450
|
suggestion: "Make sure the file is a valid FBX file and the path is correct"
|
|
6440
|
-
}),
|
|
6451
|
+
}), c.message && c.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"));
|
|
6441
6452
|
try {
|
|
6442
|
-
const
|
|
6453
|
+
const d = await fetch(t), g = d.headers.get("content-type"), x = await d.text();
|
|
6443
6454
|
console.error("Response details:", {
|
|
6444
|
-
status:
|
|
6455
|
+
status: d.status,
|
|
6445
6456
|
contentType: g,
|
|
6446
|
-
firstBytes:
|
|
6447
|
-
isHTML:
|
|
6448
|
-
}), (
|
|
6449
|
-
} catch (
|
|
6450
|
-
console.error("Could not fetch file for debugging:",
|
|
6457
|
+
firstBytes: x.substring(0, 100),
|
|
6458
|
+
isHTML: x.trim().startsWith("<!DOCTYPE") || x.trim().startsWith("<html")
|
|
6459
|
+
}), (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.");
|
|
6460
|
+
} catch (d) {
|
|
6461
|
+
console.error("Could not fetch file for debugging:", d);
|
|
6451
6462
|
}
|
|
6452
6463
|
return;
|
|
6453
6464
|
}
|
|
6454
6465
|
if (a && a.animations && a.animations[i]) {
|
|
6455
|
-
let
|
|
6456
|
-
const
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6466
|
+
let c = a.animations[i];
|
|
6467
|
+
const d = this.getAvailableBoneNames(), g = this.filterAnimationTracks(c, d);
|
|
6468
|
+
if (!g) {
|
|
6469
|
+
console.error(`Cannot play FBX animation "${t}": No compatible bones found.`);
|
|
6470
|
+
return;
|
|
6471
|
+
}
|
|
6472
|
+
c = g;
|
|
6473
|
+
const x = {};
|
|
6474
|
+
c.tracks.forEach((R) => {
|
|
6475
|
+
R.name = R.name.replaceAll("mixamorig", "");
|
|
6476
|
+
const B = R.name.split(".");
|
|
6477
|
+
if (B[1] === "position") {
|
|
6478
|
+
for (let p = 0; p < R.values.length; p++)
|
|
6479
|
+
R.values[p] = R.values[p] * s;
|
|
6480
|
+
x[R.name] = new f.Vector3(R.values[0], R.values[1], R.values[2]);
|
|
6481
|
+
} else B[1] === "quaternion" ? x[R.name] = new f.Quaternion(R.values[0], R.values[1], R.values[2], R.values[3]) : B[1] === "rotation" && (x[B[0] + ".quaternion"] = new f.Quaternion().setFromEuler(new f.Euler(R.values[0], R.values[1], R.values[2], "XYZ")).normalize());
|
|
6465
6482
|
});
|
|
6466
|
-
const
|
|
6467
|
-
|
|
6483
|
+
const b = { props: x };
|
|
6484
|
+
x["Hips.position"] && (x["Hips.position"].y < 0.5 ? b.lying = !0 : b.standing = !0), this.animClips.push({
|
|
6468
6485
|
url: t + "-" + i,
|
|
6469
|
-
clip:
|
|
6470
|
-
pose:
|
|
6486
|
+
clip: c,
|
|
6487
|
+
pose: b
|
|
6471
6488
|
}), this.playAnimation(t, e, n, i, s);
|
|
6472
6489
|
} else {
|
|
6473
|
-
const
|
|
6474
|
-
console.error(
|
|
6490
|
+
const c = "Animation " + t + " (ndx=" + i + ") not found";
|
|
6491
|
+
console.error(c), a && a.animations ? console.error(`FBX file loaded but has ${a.animations.length} animation(s), requested index ${i}`) : console.error(a ? "FBX file loaded but contains no animations" : "FBX file failed to load or is invalid");
|
|
6475
6492
|
}
|
|
6476
6493
|
}
|
|
6477
6494
|
}
|
|
@@ -6509,10 +6526,10 @@ class Be {
|
|
|
6509
6526
|
if (h && h.animations && h.animations[i]) {
|
|
6510
6527
|
let r = h.animations[i];
|
|
6511
6528
|
const u = {};
|
|
6512
|
-
r.tracks.forEach((
|
|
6513
|
-
|
|
6514
|
-
const
|
|
6515
|
-
|
|
6529
|
+
r.tracks.forEach((c) => {
|
|
6530
|
+
c.name = c.name.replaceAll("mixamorig", "");
|
|
6531
|
+
const d = c.name.split(".");
|
|
6532
|
+
d[1] === "position" ? u[c.name] = new f.Vector3(c.values[0] * s, c.values[1] * s, c.values[2] * s) : d[1] === "quaternion" ? u[c.name] = new f.Quaternion(c.values[0], c.values[1], c.values[2], c.values[3]) : d[1] === "rotation" && (u[d[0] + ".quaternion"] = new f.Quaternion().setFromEuler(new f.Euler(c.values[0], c.values[1], c.values[2], "XYZ")).normalize());
|
|
6516
6533
|
});
|
|
6517
6534
|
const a = { props: u };
|
|
6518
6535
|
u["Hips.position"] && (u["Hips.position"].y < 0.5 ? a.lying = !0 : a.standing = !0), this.animPoses.push({
|
|
@@ -6545,7 +6562,7 @@ class Be {
|
|
|
6545
6562
|
if (s) {
|
|
6546
6563
|
this.gestureTimeout && (clearTimeout(this.gestureTimeout), this.gestureTimeout = null);
|
|
6547
6564
|
let l = this.animQueue.findIndex((h) => h.template.name === "talkinghands");
|
|
6548
|
-
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
|
|
6565
|
+
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 f.Quaternion(0, 1, 0, 0), -0.25), this.gesture["LeftArm.quaternion"].rotateTowards(new f.Quaternion(0, 1, 0, 0), -0.25));
|
|
6549
6566
|
for (let [h, r] of Object.entries(this.gesture))
|
|
6550
6567
|
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);
|
|
6551
6568
|
e && Number.isFinite(e) && (this.gestureTimeout = setTimeout(this.stopGesture.bind(this, i), 1e3 * e));
|
|
@@ -6557,13 +6574,13 @@ class Be {
|
|
|
6557
6574
|
if (l.gesture = !0, e && Number.isFinite(e)) {
|
|
6558
6575
|
const h = l.ts[0], u = l.ts[l.ts.length - 1] - h;
|
|
6559
6576
|
if (e * 1e3 - u > 0) {
|
|
6560
|
-
const
|
|
6561
|
-
for (let
|
|
6562
|
-
const
|
|
6563
|
-
l.ts = l.ts.map((
|
|
6577
|
+
const c = [];
|
|
6578
|
+
for (let x = 1; x < l.ts.length; x++) c.push(l.ts[x] - l.ts[x - 1]);
|
|
6579
|
+
const d = o.template?.rescale || c.map((x) => x / u), g = e * 1e3 - u;
|
|
6580
|
+
l.ts = l.ts.map((x, b, R) => b === 0 ? h : R[b - 1] + c[b - 1] + d[b - 1] * g);
|
|
6564
6581
|
} else {
|
|
6565
|
-
const
|
|
6566
|
-
l.ts = l.ts.map((
|
|
6582
|
+
const c = e * 1e3 / u;
|
|
6583
|
+
l.ts = l.ts.map((d) => h + c * (d - h));
|
|
6567
6584
|
}
|
|
6568
6585
|
}
|
|
6569
6586
|
this.animQueue.push(l);
|
|
@@ -6593,34 +6610,34 @@ class Be {
|
|
|
6593
6610
|
* @param {numeric} [d=null] If set, apply in d milliseconds
|
|
6594
6611
|
*/
|
|
6595
6612
|
ikSolve(t, e = null, n = !1, i = null) {
|
|
6596
|
-
const s = new
|
|
6597
|
-
|
|
6598
|
-
const g = this.ikMesh.getObjectByName(t.effector),
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
}),
|
|
6613
|
+
const s = new f.Vector3(), o = new f.Vector3(), l = new f.Vector3(), h = new f.Vector3(), r = new f.Quaternion(), u = new f.Vector3(), a = new f.Vector3(), c = new f.Vector3(), d = this.ikMesh.getObjectByName(t.root);
|
|
6614
|
+
d.position.setFromMatrixPosition(this.armature.getObjectByName(t.root).matrixWorld), d.quaternion.setFromRotationMatrix(this.armature.getObjectByName(t.root).matrixWorld), e && n && e.applyQuaternion(this.armature.quaternion).add(d.position);
|
|
6615
|
+
const g = this.ikMesh.getObjectByName(t.effector), x = t.links;
|
|
6616
|
+
x.forEach((R) => {
|
|
6617
|
+
R.bone = this.ikMesh.getObjectByName(R.link), R.bone.quaternion.copy(this.getPoseTemplateProp(R.link + ".quaternion"));
|
|
6618
|
+
}), d.updateMatrixWorld(!0);
|
|
6602
6619
|
const b = t.iterations || 10;
|
|
6603
6620
|
if (e)
|
|
6604
|
-
for (let
|
|
6605
|
-
let
|
|
6606
|
-
for (let p = 0, M =
|
|
6607
|
-
const z =
|
|
6621
|
+
for (let R = 0; R < b; R++) {
|
|
6622
|
+
let B = !1;
|
|
6623
|
+
for (let p = 0, M = x.length; p < M; p++) {
|
|
6624
|
+
const z = x[p].bone;
|
|
6608
6625
|
z.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();
|
|
6609
|
-
let
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
), new
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
))), z.updateMatrixWorld(!0),
|
|
6626
|
+
let y = s.dot(l);
|
|
6627
|
+
y > 1 ? y = 1 : y < -1 && (y = -1), y = Math.acos(y), !(y < 1e-5) && (x[p].minAngle !== void 0 && y < x[p].minAngle && (y = x[p].minAngle), x[p].maxAngle !== void 0 && y > x[p].maxAngle && (y = x[p].maxAngle), a.crossVectors(l, s), a.normalize(), Q.setFromAxisAngle(a, y), z.quaternion.multiply(Q), z.rotation.setFromVector3(c.setFromEuler(z.rotation).clamp(new f.Vector3(
|
|
6628
|
+
x[p].minx !== void 0 ? x[p].minx : -1 / 0,
|
|
6629
|
+
x[p].miny !== void 0 ? x[p].miny : -1 / 0,
|
|
6630
|
+
x[p].minz !== void 0 ? x[p].minz : -1 / 0
|
|
6631
|
+
), new f.Vector3(
|
|
6632
|
+
x[p].maxx !== void 0 ? x[p].maxx : 1 / 0,
|
|
6633
|
+
x[p].maxy !== void 0 ? x[p].maxy : 1 / 0,
|
|
6634
|
+
x[p].maxz !== void 0 ? x[p].maxz : 1 / 0
|
|
6635
|
+
))), z.updateMatrixWorld(!0), B = !0);
|
|
6619
6636
|
}
|
|
6620
|
-
if (!
|
|
6637
|
+
if (!B) break;
|
|
6621
6638
|
}
|
|
6622
|
-
i &&
|
|
6623
|
-
this.poseTarget.props[
|
|
6639
|
+
i && x.forEach((R) => {
|
|
6640
|
+
this.poseTarget.props[R.link + ".quaternion"].copy(R.bone.quaternion), this.poseTarget.props[R.link + ".quaternion"].t = this.animClock, this.poseTarget.props[R.link + ".quaternion"].d = i;
|
|
6624
6641
|
});
|
|
6625
6642
|
}
|
|
6626
6643
|
/**
|
|
@@ -6630,7 +6647,7 @@ class Be {
|
|
|
6630
6647
|
this.isRunning = !1, this.stop(), this.stopSpeaking(), this.streamStop(), this.isAvatarOnly ? this.armature && (this.armature.parent && this.armature.parent.remove(this.armature), this.clearThree(this.armature)) : (this.clearThree(this.scene), this.resizeobserver.disconnect(), this.renderer && (this.renderer.dispose(), this.renderer.domElement && this.renderer.domElement.parentNode && this.renderer.domElement.parentNode.removeChild(this.renderer.domElement), this.renderer = null)), this.clearThree(this.ikMesh), this.dynamicbones.dispose();
|
|
6631
6648
|
}
|
|
6632
6649
|
}
|
|
6633
|
-
const
|
|
6650
|
+
const Re = {
|
|
6634
6651
|
apiKey: "sk_ace57ef3ef65a92b9d3bee2a00183b78ca790bc3e10964f2",
|
|
6635
6652
|
// Replace with your actual API key (should start with sk_)
|
|
6636
6653
|
endpoint: "https://api.elevenlabs.io/v1/text-to-speech",
|
|
@@ -6673,10 +6690,10 @@ const Ie = {
|
|
|
6673
6690
|
function Fe() {
|
|
6674
6691
|
return {
|
|
6675
6692
|
service: "elevenlabs",
|
|
6676
|
-
endpoint:
|
|
6677
|
-
apiKey:
|
|
6678
|
-
defaultVoice:
|
|
6679
|
-
voices:
|
|
6693
|
+
endpoint: Re.endpoint,
|
|
6694
|
+
apiKey: Re.apiKey,
|
|
6695
|
+
defaultVoice: Re.defaultVoice,
|
|
6696
|
+
voices: Re.voices
|
|
6680
6697
|
};
|
|
6681
6698
|
}
|
|
6682
6699
|
function kt() {
|
|
@@ -6702,40 +6719,40 @@ const Ve = Me(({
|
|
|
6702
6719
|
cameraView: u = "upper",
|
|
6703
6720
|
onReady: a = () => {
|
|
6704
6721
|
},
|
|
6705
|
-
onLoading:
|
|
6722
|
+
onLoading: c = () => {
|
|
6706
6723
|
},
|
|
6707
|
-
onError:
|
|
6724
|
+
onError: d = () => {
|
|
6708
6725
|
},
|
|
6709
6726
|
className: g = "",
|
|
6710
|
-
style:
|
|
6727
|
+
style: x = {},
|
|
6711
6728
|
animations: b = {}
|
|
6712
|
-
},
|
|
6713
|
-
const
|
|
6729
|
+
}, R) => {
|
|
6730
|
+
const B = D(null), p = D(null), M = D(r), z = D(null), y = D(null), E = D(!1), P = D({ remainingText: null, originalText: null, options: null }), W = D([]), oe = D(0), [S, Z] = ce(!0), [K, X] = ce(null), [$, se] = ce(!1), [ae, pe] = ce(!1);
|
|
6714
6731
|
de(() => {
|
|
6715
6732
|
E.current = ae;
|
|
6716
6733
|
}, [ae]), de(() => {
|
|
6717
6734
|
M.current = r;
|
|
6718
6735
|
}, [r]);
|
|
6719
6736
|
const ee = Fe(), le = i || ee.service;
|
|
6720
|
-
let
|
|
6721
|
-
le === "browser" ?
|
|
6737
|
+
let O;
|
|
6738
|
+
le === "browser" ? O = {
|
|
6722
6739
|
service: "browser",
|
|
6723
6740
|
endpoint: "",
|
|
6724
6741
|
apiKey: null,
|
|
6725
6742
|
defaultVoice: "Google US English"
|
|
6726
|
-
} : le === "elevenlabs" ?
|
|
6743
|
+
} : le === "elevenlabs" ? O = {
|
|
6727
6744
|
service: "elevenlabs",
|
|
6728
6745
|
endpoint: "https://api.elevenlabs.io/v1/text-to-speech",
|
|
6729
6746
|
apiKey: o || ee.apiKey,
|
|
6730
|
-
defaultVoice: s || ee.defaultVoice ||
|
|
6731
|
-
voices: ee.voices ||
|
|
6732
|
-
} : le === "deepgram" ?
|
|
6747
|
+
defaultVoice: s || ee.defaultVoice || Re.defaultVoice,
|
|
6748
|
+
voices: ee.voices || Re.voices
|
|
6749
|
+
} : le === "deepgram" ? O = {
|
|
6733
6750
|
service: "deepgram",
|
|
6734
6751
|
endpoint: "https://api.deepgram.com/v1/speak",
|
|
6735
6752
|
apiKey: o || ee.apiKey,
|
|
6736
6753
|
defaultVoice: s || ee.defaultVoice || Te.defaultVoice,
|
|
6737
6754
|
voices: ee.voices || Te.voices
|
|
6738
|
-
} :
|
|
6755
|
+
} : O = {
|
|
6739
6756
|
...ee,
|
|
6740
6757
|
// Override API key if provided via props
|
|
6741
6758
|
apiKey: o !== null ? o : ee.apiKey
|
|
@@ -6745,35 +6762,35 @@ const Ve = Me(({
|
|
|
6745
6762
|
body: t,
|
|
6746
6763
|
avatarMood: e,
|
|
6747
6764
|
ttsLang: le === "browser" ? "en-US" : n,
|
|
6748
|
-
ttsVoice: s ||
|
|
6765
|
+
ttsVoice: s || O.defaultVoice,
|
|
6749
6766
|
lipsyncLang: "en",
|
|
6750
6767
|
showFullAvatar: r,
|
|
6751
6768
|
bodyMovement: l,
|
|
6752
6769
|
movementIntensity: h
|
|
6753
|
-
},
|
|
6754
|
-
ttsEndpoint:
|
|
6755
|
-
ttsApikey:
|
|
6770
|
+
}, I = {
|
|
6771
|
+
ttsEndpoint: O.endpoint,
|
|
6772
|
+
ttsApikey: O.apiKey,
|
|
6756
6773
|
ttsService: le,
|
|
6757
6774
|
lipsyncModules: ["en"],
|
|
6758
6775
|
cameraView: u
|
|
6759
6776
|
}, k = T(async () => {
|
|
6760
|
-
if (!(!
|
|
6777
|
+
if (!(!B.current || p.current))
|
|
6761
6778
|
try {
|
|
6762
|
-
if (Z(!0), X(null), p.current = new Be(
|
|
6763
|
-
if (
|
|
6764
|
-
const J = Math.min(100, Math.round(
|
|
6765
|
-
|
|
6779
|
+
if (Z(!0), X(null), p.current = new Be(B.current, I), p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1), b && Object.keys(b).length > 0 && (p.current.customAnimations = b), await p.current.showAvatar(v, (N) => {
|
|
6780
|
+
if (N.lengthComputable) {
|
|
6781
|
+
const J = Math.min(100, Math.round(N.loaded / N.total * 100));
|
|
6782
|
+
c(J);
|
|
6766
6783
|
}
|
|
6767
|
-
}), await new Promise((
|
|
6784
|
+
}), await new Promise((N) => {
|
|
6768
6785
|
const J = () => {
|
|
6769
|
-
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ?
|
|
6786
|
+
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? N() : setTimeout(J, 100);
|
|
6770
6787
|
};
|
|
6771
6788
|
J();
|
|
6772
6789
|
}), p.current && p.current.setShowFullAvatar)
|
|
6773
6790
|
try {
|
|
6774
6791
|
p.current.setShowFullAvatar(r);
|
|
6775
|
-
} catch (
|
|
6776
|
-
console.warn("Error setting full body mode on initialization:",
|
|
6792
|
+
} catch (N) {
|
|
6793
|
+
console.warn("Error setting full body mode on initialization:", N);
|
|
6777
6794
|
}
|
|
6778
6795
|
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()), Z(!1), se(!0), a(p.current);
|
|
6779
6796
|
const F = () => {
|
|
@@ -6783,18 +6800,18 @@ const Ve = Me(({
|
|
|
6783
6800
|
document.removeEventListener("visibilitychange", F);
|
|
6784
6801
|
};
|
|
6785
6802
|
} catch (L) {
|
|
6786
|
-
console.error("Error initializing TalkingHead:", L), X(L.message || "Failed to initialize avatar"), Z(!1),
|
|
6803
|
+
console.error("Error initializing TalkingHead:", L), X(L.message || "Failed to initialize avatar"), Z(!1), d(L);
|
|
6787
6804
|
}
|
|
6788
6805
|
}, [G, t, e, n, i, s, o, r, l, h, u]);
|
|
6789
6806
|
de(() => (k(), () => {
|
|
6790
6807
|
p.current && (p.current.stop(), p.current.dispose(), p.current = null);
|
|
6791
6808
|
}), [k]), de(() => {
|
|
6792
|
-
if (!
|
|
6793
|
-
const L = new ResizeObserver((
|
|
6794
|
-
for (const J of
|
|
6809
|
+
if (!B.current || !p.current) return;
|
|
6810
|
+
const L = new ResizeObserver((N) => {
|
|
6811
|
+
for (const J of N)
|
|
6795
6812
|
p.current && p.current.onResize && p.current.onResize();
|
|
6796
6813
|
});
|
|
6797
|
-
L.observe(
|
|
6814
|
+
L.observe(B.current);
|
|
6798
6815
|
const F = () => {
|
|
6799
6816
|
p.current && p.current.onResize && p.current.onResize();
|
|
6800
6817
|
};
|
|
@@ -6809,12 +6826,12 @@ const Ve = Me(({
|
|
|
6809
6826
|
} catch (L) {
|
|
6810
6827
|
console.warn("Failed to resume audio context:", L);
|
|
6811
6828
|
}
|
|
6812
|
-
}, []),
|
|
6829
|
+
}, []), U = T(async (L, F = {}) => {
|
|
6813
6830
|
if (p.current && $)
|
|
6814
6831
|
try {
|
|
6815
|
-
|
|
6816
|
-
const
|
|
6817
|
-
|
|
6832
|
+
y.current && (clearInterval(y.current), y.current = null), z.current = { text: L, options: F }, P.current = { remainingText: null, originalText: null, options: null };
|
|
6833
|
+
const N = /[!\.\?\n\p{Extended_Pictographic}]/ug, J = L.split(N).map((Y) => Y.trim()).filter((Y) => Y.length > 0);
|
|
6834
|
+
W.current = J, oe.current = 0, pe(!1), E.current = !1, await H();
|
|
6818
6835
|
const ge = {
|
|
6819
6836
|
...F,
|
|
6820
6837
|
lipsyncLang: F.lipsyncLang || v.lipsyncLang || "en"
|
|
@@ -6828,12 +6845,12 @@ const Ve = Me(({
|
|
|
6828
6845
|
if (Se++, E.current)
|
|
6829
6846
|
return;
|
|
6830
6847
|
if (Se > Ae) {
|
|
6831
|
-
if (he && (clearInterval(he), he = null,
|
|
6848
|
+
if (he && (clearInterval(he), he = null, y.current = null), !be && !E.current) {
|
|
6832
6849
|
be = !0;
|
|
6833
6850
|
try {
|
|
6834
6851
|
F.onSpeechEnd();
|
|
6835
|
-
} catch (
|
|
6836
|
-
console.error("Error in onSpeechEnd callback (timeout):",
|
|
6852
|
+
} catch (Ne) {
|
|
6853
|
+
console.error("Error in onSpeechEnd callback (timeout):", Ne);
|
|
6837
6854
|
}
|
|
6838
6855
|
}
|
|
6839
6856
|
return;
|
|
@@ -6841,7 +6858,7 @@ const Ve = Me(({
|
|
|
6841
6858
|
const ye = !Y.speechQueue || Y.speechQueue.length === 0, ke = !Y.audioPlaylist || Y.audioPlaylist.length === 0;
|
|
6842
6859
|
Y && Y.isSpeaking === !1 && ye && ke && Y.isAudioPlaying === !1 && !be && !E.current && setTimeout(() => {
|
|
6843
6860
|
if (Y && !E.current && Y.isSpeaking === !1 && (!Y.speechQueue || Y.speechQueue.length === 0) && (!Y.audioPlaylist || Y.audioPlaylist.length === 0) && Y.isAudioPlaying === !1 && !be && !E.current) {
|
|
6844
|
-
be = !0, he && (clearInterval(he), he = null,
|
|
6861
|
+
be = !0, he && (clearInterval(he), he = null, y.current = null);
|
|
6845
6862
|
try {
|
|
6846
6863
|
F.onSpeechEnd();
|
|
6847
6864
|
} catch (Ze) {
|
|
@@ -6849,13 +6866,13 @@ const Ve = Me(({
|
|
|
6849
6866
|
}
|
|
6850
6867
|
}
|
|
6851
6868
|
}, 100);
|
|
6852
|
-
}, 100),
|
|
6869
|
+
}, 100), y.current = he;
|
|
6853
6870
|
}
|
|
6854
6871
|
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(L, ge)) : setTimeout(async () => {
|
|
6855
6872
|
await H(), p.current && p.current.lipsync && (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(L, ge));
|
|
6856
6873
|
}, 100);
|
|
6857
|
-
} catch (
|
|
6858
|
-
console.error("Error speaking text:",
|
|
6874
|
+
} catch (N) {
|
|
6875
|
+
console.error("Error speaking text:", N), X(N.message || "Failed to speak text");
|
|
6859
6876
|
}
|
|
6860
6877
|
}, [$, H, v.lipsyncLang]), _ = T(() => {
|
|
6861
6878
|
p.current && (p.current.stopSpeaking(), p.current.setSlowdownRate && p.current.setSlowdownRate(1), z.current = null, pe(!1));
|
|
@@ -6863,17 +6880,17 @@ const Ve = Me(({
|
|
|
6863
6880
|
if (p.current && p.current.pauseSpeaking) {
|
|
6864
6881
|
const L = p.current;
|
|
6865
6882
|
if (L.isSpeaking || L.audioPlaylist && L.audioPlaylist.length > 0 || L.speechQueue && L.speechQueue.length > 0) {
|
|
6866
|
-
|
|
6867
|
-
let
|
|
6868
|
-
if (z.current &&
|
|
6869
|
-
const J =
|
|
6870
|
-
if (he > 0 && Se < J && (
|
|
6883
|
+
y.current && (clearInterval(y.current), y.current = null);
|
|
6884
|
+
let N = "";
|
|
6885
|
+
if (z.current && W.current.length > 0) {
|
|
6886
|
+
const J = W.current.length, ge = L.speechQueue ? L.speechQueue.filter((Ae) => Ae && Ae.text && Array.isArray(Ae.text) && Ae.text.length > 0).length : 0, Y = L.audioPlaylist && L.audioPlaylist.length > 0, he = ge + (Y ? 1 : 0), Se = J - he;
|
|
6887
|
+
if (he > 0 && Se < J && (N = W.current.slice(Se).join(". ").trim(), !N && ge > 0 && L.speechQueue)) {
|
|
6871
6888
|
const be = L.speechQueue.filter((ye) => ye && ye.text && Array.isArray(ye.text) && ye.text.length > 0).map((ye) => ye.text.map((ke) => ke.word || "").filter((ke) => ke.length > 0).join(" ")).filter((ye) => ye.length > 0).join(" ");
|
|
6872
|
-
be && be.trim() && (
|
|
6889
|
+
be && be.trim() && (N = be.trim());
|
|
6873
6890
|
}
|
|
6874
6891
|
}
|
|
6875
6892
|
z.current && (P.current = {
|
|
6876
|
-
remainingText:
|
|
6893
|
+
remainingText: N || null,
|
|
6877
6894
|
originalText: z.current.text,
|
|
6878
6895
|
options: z.current.options
|
|
6879
6896
|
}), L.speechQueue && (L.speechQueue.length = 0), p.current.pauseSpeaking(), E.current = !0, pe(!0);
|
|
@@ -6892,16 +6909,16 @@ const Ve = Me(({
|
|
|
6892
6909
|
return;
|
|
6893
6910
|
}
|
|
6894
6911
|
pe(!1), E.current = !1, await H();
|
|
6895
|
-
const
|
|
6912
|
+
const N = {
|
|
6896
6913
|
...F,
|
|
6897
6914
|
lipsyncLang: F.lipsyncLang || v.lipsyncLang || "en"
|
|
6898
6915
|
};
|
|
6899
6916
|
try {
|
|
6900
|
-
await
|
|
6917
|
+
await U(L, N);
|
|
6901
6918
|
} catch (J) {
|
|
6902
6919
|
console.error("Error resuming speech:", J), pe(!1), E.current = !1;
|
|
6903
6920
|
}
|
|
6904
|
-
}, [H, ae,
|
|
6921
|
+
}, [H, ae, U, v]), Le = T((L) => {
|
|
6905
6922
|
p.current && p.current.setMood(L);
|
|
6906
6923
|
}, []), we = T((L) => {
|
|
6907
6924
|
p.current && p.current.setSlowdownRate && p.current.setSlowdownRate(L);
|
|
@@ -6946,8 +6963,8 @@ const Ve = Me(({
|
|
|
6946
6963
|
}, [b]), te = T(() => {
|
|
6947
6964
|
p.current && p.current.onResize && p.current.onResize();
|
|
6948
6965
|
}, []);
|
|
6949
|
-
return Ee(
|
|
6950
|
-
speakText:
|
|
6966
|
+
return Ee(R, () => ({
|
|
6967
|
+
speakText: U,
|
|
6951
6968
|
stopSpeaking: _,
|
|
6952
6969
|
pauseSpeaking: j,
|
|
6953
6970
|
resumeSpeaking: q,
|
|
@@ -7024,13 +7041,13 @@ const Ve = Me(({
|
|
|
7024
7041
|
width: "100%",
|
|
7025
7042
|
height: "100%",
|
|
7026
7043
|
position: "relative",
|
|
7027
|
-
...
|
|
7044
|
+
...x
|
|
7028
7045
|
},
|
|
7029
7046
|
children: [
|
|
7030
7047
|
/* @__PURE__ */ me(
|
|
7031
7048
|
"div",
|
|
7032
7049
|
{
|
|
7033
|
-
ref:
|
|
7050
|
+
ref: B,
|
|
7034
7051
|
className: "talking-head-viewer",
|
|
7035
7052
|
style: {
|
|
7036
7053
|
width: "100%",
|
|
@@ -7077,7 +7094,7 @@ const pt = Me(({
|
|
|
7077
7094
|
style: s = {},
|
|
7078
7095
|
avatarConfig: o = {}
|
|
7079
7096
|
}, l) => {
|
|
7080
|
-
const h =
|
|
7097
|
+
const h = D(null), r = D(null), [u, a] = ce(!0), [c, d] = ce(null), [g, x] = ce(!1), b = Fe(), R = o.ttsService || b.service, B = R === "browser" ? {
|
|
7081
7098
|
endpoint: "",
|
|
7082
7099
|
apiKey: null,
|
|
7083
7100
|
defaultVoice: "Google US English"
|
|
@@ -7086,14 +7103,14 @@ const pt = Me(({
|
|
|
7086
7103
|
// Override API key if provided via avatarConfig
|
|
7087
7104
|
apiKey: o.ttsApiKey !== void 0 && o.ttsApiKey !== null ? o.ttsApiKey : b.apiKey,
|
|
7088
7105
|
// Override endpoint for ElevenLabs if service is explicitly set
|
|
7089
|
-
endpoint:
|
|
7106
|
+
endpoint: R === "elevenlabs" && o.ttsApiKey ? "https://api.elevenlabs.io/v1/text-to-speech" : b.endpoint
|
|
7090
7107
|
}, p = {
|
|
7091
7108
|
url: "/avatars/brunette.glb",
|
|
7092
7109
|
// Use brunette avatar (working glTF file)
|
|
7093
7110
|
body: "F",
|
|
7094
7111
|
avatarMood: "neutral",
|
|
7095
|
-
ttsLang:
|
|
7096
|
-
ttsVoice: o.ttsVoice ||
|
|
7112
|
+
ttsLang: R === "browser" ? "en-US" : "en",
|
|
7113
|
+
ttsVoice: o.ttsVoice || B.defaultVoice,
|
|
7097
7114
|
lipsyncLang: "en",
|
|
7098
7115
|
// English lip-sync
|
|
7099
7116
|
showFullAvatar: !0,
|
|
@@ -7102,15 +7119,15 @@ const pt = Me(({
|
|
|
7102
7119
|
movementIntensity: 0.5,
|
|
7103
7120
|
...o
|
|
7104
7121
|
}, M = {
|
|
7105
|
-
ttsEndpoint:
|
|
7106
|
-
ttsApikey:
|
|
7107
|
-
ttsService:
|
|
7122
|
+
ttsEndpoint: B.endpoint,
|
|
7123
|
+
ttsApikey: B.apiKey,
|
|
7124
|
+
ttsService: R,
|
|
7108
7125
|
lipsyncModules: ["en"],
|
|
7109
7126
|
cameraView: "upper"
|
|
7110
7127
|
}, z = T(async () => {
|
|
7111
7128
|
if (!(!h.current || r.current))
|
|
7112
7129
|
try {
|
|
7113
|
-
if (a(!0),
|
|
7130
|
+
if (a(!0), d(null), r.current = new Be(h.current, M), await r.current.showAvatar(p, (K) => {
|
|
7114
7131
|
if (K.lengthComputable) {
|
|
7115
7132
|
const X = Math.min(100, Math.round(K.loaded / K.total * 100));
|
|
7116
7133
|
t(X);
|
|
@@ -7132,7 +7149,7 @@ const pt = Me(({
|
|
|
7132
7149
|
} catch (K) {
|
|
7133
7150
|
console.warn("Error setting full body mode on initialization:", K);
|
|
7134
7151
|
}
|
|
7135
|
-
a(!1),
|
|
7152
|
+
a(!1), x(!0), n(r.current);
|
|
7136
7153
|
const Z = () => {
|
|
7137
7154
|
document.visibilityState === "visible" ? r.current?.start() : r.current?.stop();
|
|
7138
7155
|
};
|
|
@@ -7140,20 +7157,20 @@ const pt = Me(({
|
|
|
7140
7157
|
document.removeEventListener("visibilitychange", Z);
|
|
7141
7158
|
};
|
|
7142
7159
|
} catch (S) {
|
|
7143
|
-
console.error("Error initializing TalkingHead:", S),
|
|
7160
|
+
console.error("Error initializing TalkingHead:", S), d(S.message || "Failed to initialize avatar"), a(!1), e(S);
|
|
7144
7161
|
}
|
|
7145
7162
|
}, []);
|
|
7146
7163
|
de(() => (z(), () => {
|
|
7147
7164
|
r.current && (r.current.stop(), r.current.dispose(), r.current = null);
|
|
7148
7165
|
}), [z]);
|
|
7149
|
-
const
|
|
7166
|
+
const y = T((S) => {
|
|
7150
7167
|
if (r.current && g)
|
|
7151
7168
|
try {
|
|
7152
7169
|
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(() => {
|
|
7153
7170
|
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");
|
|
7154
7171
|
}, 500));
|
|
7155
7172
|
} catch (Z) {
|
|
7156
|
-
console.error("Error speaking text:", Z),
|
|
7173
|
+
console.error("Error speaking text:", Z), d(Z.message || "Failed to speak text");
|
|
7157
7174
|
}
|
|
7158
7175
|
else
|
|
7159
7176
|
console.warn("Avatar not ready for speaking. isReady:", g, "talkingHeadRef:", !!r.current);
|
|
@@ -7161,7 +7178,7 @@ const pt = Me(({
|
|
|
7161
7178
|
r.current && (r.current.stopSpeaking(), r.current.setSlowdownRate && (r.current.setSlowdownRate(1), console.log("Reset timing to normal")));
|
|
7162
7179
|
}, []), P = T((S) => {
|
|
7163
7180
|
r.current && r.current.setMood(S);
|
|
7164
|
-
}, []),
|
|
7181
|
+
}, []), W = T((S) => {
|
|
7165
7182
|
r.current && r.current.setSlowdownRate && (r.current.setSlowdownRate(S), console.log("Timing adjustment set to:", S));
|
|
7166
7183
|
}, []), oe = T((S, Z = !1) => {
|
|
7167
7184
|
if (r.current && r.current.playAnimation) {
|
|
@@ -7205,10 +7222,10 @@ const pt = Me(({
|
|
|
7205
7222
|
console.warn("Animation system not available or animation not found:", S);
|
|
7206
7223
|
}, []);
|
|
7207
7224
|
return Ee(l, () => ({
|
|
7208
|
-
speakText:
|
|
7225
|
+
speakText: y,
|
|
7209
7226
|
stopSpeaking: E,
|
|
7210
7227
|
setMood: P,
|
|
7211
|
-
setTimingAdjustment:
|
|
7228
|
+
setTimingAdjustment: W,
|
|
7212
7229
|
playAnimation: oe,
|
|
7213
7230
|
isReady: g,
|
|
7214
7231
|
talkingHead: r.current,
|
|
@@ -7291,7 +7308,7 @@ const pt = Me(({
|
|
|
7291
7308
|
fontSize: "18px",
|
|
7292
7309
|
zIndex: 10
|
|
7293
7310
|
}, children: "Loading avatar..." }),
|
|
7294
|
-
|
|
7311
|
+
c && /* @__PURE__ */ me("div", { className: "error-overlay", style: {
|
|
7295
7312
|
position: "absolute",
|
|
7296
7313
|
top: "50%",
|
|
7297
7314
|
left: "50%",
|
|
@@ -7302,7 +7319,7 @@ const pt = Me(({
|
|
|
7302
7319
|
zIndex: 10,
|
|
7303
7320
|
padding: "20px",
|
|
7304
7321
|
borderRadius: "8px"
|
|
7305
|
-
}, children:
|
|
7322
|
+
}, children: c })
|
|
7306
7323
|
] });
|
|
7307
7324
|
});
|
|
7308
7325
|
pt.displayName = "TalkingHeadComponent";
|
|
@@ -7319,79 +7336,79 @@ const gt = Me(({
|
|
|
7319
7336
|
movementIntensity: r = 0.5,
|
|
7320
7337
|
showFullAvatar: u = !1,
|
|
7321
7338
|
cameraView: a = "upper",
|
|
7322
|
-
onReady:
|
|
7339
|
+
onReady: c = () => {
|
|
7323
7340
|
},
|
|
7324
|
-
onLoading:
|
|
7341
|
+
onLoading: d = () => {
|
|
7325
7342
|
},
|
|
7326
7343
|
onError: g = () => {
|
|
7327
7344
|
},
|
|
7328
|
-
onSpeechEnd:
|
|
7345
|
+
onSpeechEnd: x = () => {
|
|
7329
7346
|
},
|
|
7330
7347
|
className: b = "",
|
|
7331
|
-
style:
|
|
7332
|
-
animations:
|
|
7348
|
+
style: R = {},
|
|
7349
|
+
animations: B = {},
|
|
7333
7350
|
autoSpeak: p = !1
|
|
7334
7351
|
}, M) => {
|
|
7335
|
-
const z =
|
|
7352
|
+
const z = D(null), y = D(null), E = D(u), P = D(null), W = D(null), oe = D(!1), S = D({ remainingText: null, originalText: null, options: null }), Z = D([]), [K, X] = ce(!0), [$, se] = ce(null), [ae, pe] = ce(!1), [ee, le] = ce(!1);
|
|
7336
7353
|
de(() => {
|
|
7337
7354
|
oe.current = ee;
|
|
7338
7355
|
}, [ee]), de(() => {
|
|
7339
7356
|
E.current = u;
|
|
7340
7357
|
}, [u]);
|
|
7341
|
-
const
|
|
7342
|
-
let
|
|
7343
|
-
v === "browser" ?
|
|
7358
|
+
const O = Fe(), v = s || O.service;
|
|
7359
|
+
let I;
|
|
7360
|
+
v === "browser" ? I = {
|
|
7344
7361
|
service: "browser",
|
|
7345
7362
|
endpoint: "",
|
|
7346
7363
|
apiKey: null,
|
|
7347
7364
|
defaultVoice: "Google US English"
|
|
7348
|
-
} : v === "elevenlabs" ?
|
|
7365
|
+
} : v === "elevenlabs" ? I = {
|
|
7349
7366
|
service: "elevenlabs",
|
|
7350
7367
|
endpoint: "https://api.elevenlabs.io/v1/text-to-speech",
|
|
7351
|
-
apiKey: l ||
|
|
7352
|
-
defaultVoice: o ||
|
|
7353
|
-
voices:
|
|
7354
|
-
} : v === "deepgram" ?
|
|
7368
|
+
apiKey: l || O.apiKey,
|
|
7369
|
+
defaultVoice: o || O.defaultVoice || Re.defaultVoice,
|
|
7370
|
+
voices: O.voices || Re.voices
|
|
7371
|
+
} : v === "deepgram" ? I = {
|
|
7355
7372
|
service: "deepgram",
|
|
7356
7373
|
endpoint: "https://api.deepgram.com/v1/speak",
|
|
7357
|
-
apiKey: l ||
|
|
7358
|
-
defaultVoice: o ||
|
|
7359
|
-
voices:
|
|
7360
|
-
} :
|
|
7361
|
-
...
|
|
7362
|
-
apiKey: l !== null ? l :
|
|
7374
|
+
apiKey: l || O.apiKey,
|
|
7375
|
+
defaultVoice: o || O.defaultVoice || Te.defaultVoice,
|
|
7376
|
+
voices: O.voices || Te.voices
|
|
7377
|
+
} : I = {
|
|
7378
|
+
...O,
|
|
7379
|
+
apiKey: l !== null ? l : O.apiKey
|
|
7363
7380
|
};
|
|
7364
7381
|
const k = {
|
|
7365
7382
|
url: t,
|
|
7366
7383
|
body: e,
|
|
7367
7384
|
avatarMood: n,
|
|
7368
7385
|
ttsLang: v === "browser" ? "en-US" : i,
|
|
7369
|
-
ttsVoice: o ||
|
|
7386
|
+
ttsVoice: o || I.defaultVoice,
|
|
7370
7387
|
lipsyncLang: "en",
|
|
7371
7388
|
showFullAvatar: u,
|
|
7372
7389
|
bodyMovement: h,
|
|
7373
7390
|
movementIntensity: r
|
|
7374
7391
|
}, H = {
|
|
7375
|
-
ttsEndpoint:
|
|
7376
|
-
ttsApikey:
|
|
7392
|
+
ttsEndpoint: I.endpoint,
|
|
7393
|
+
ttsApikey: I.apiKey,
|
|
7377
7394
|
ttsService: v,
|
|
7378
7395
|
lipsyncModules: ["en"],
|
|
7379
7396
|
cameraView: a
|
|
7380
|
-
},
|
|
7381
|
-
if (!(!z.current ||
|
|
7397
|
+
}, U = T(async () => {
|
|
7398
|
+
if (!(!z.current || y.current))
|
|
7382
7399
|
try {
|
|
7383
|
-
X(!0), se(null),
|
|
7400
|
+
X(!0), se(null), y.current = new Be(z.current, H), console.log("Avatar config being passed:", {
|
|
7384
7401
|
url: k.url,
|
|
7385
7402
|
body: k.body,
|
|
7386
7403
|
avatarMood: k.avatarMood
|
|
7387
|
-
}), await
|
|
7404
|
+
}), await y.current.showAvatar(k, (te) => {
|
|
7388
7405
|
if (te.lengthComputable) {
|
|
7389
7406
|
const L = Math.min(100, Math.round(te.loaded / te.total * 100));
|
|
7390
|
-
|
|
7407
|
+
d(L);
|
|
7391
7408
|
}
|
|
7392
|
-
}),
|
|
7409
|
+
}), y.current?.avatar && console.log("Avatar body after initialization:", y.current.avatar.body), X(!1), pe(!0), c(y.current);
|
|
7393
7410
|
const C = () => {
|
|
7394
|
-
document.visibilityState === "visible" ?
|
|
7411
|
+
document.visibilityState === "visible" ? y.current?.start() : y.current?.stop();
|
|
7395
7412
|
};
|
|
7396
7413
|
return document.addEventListener("visibilitychange", C), () => {
|
|
7397
7414
|
document.removeEventListener("visibilitychange", C);
|
|
@@ -7400,19 +7417,19 @@ const gt = Me(({
|
|
|
7400
7417
|
console.error("Error initializing TalkingHead:", C), se(C.message || "Failed to initialize avatar"), X(!1), g(C);
|
|
7401
7418
|
}
|
|
7402
7419
|
}, []);
|
|
7403
|
-
de(() => (
|
|
7404
|
-
|
|
7405
|
-
}), [
|
|
7420
|
+
de(() => (U(), () => {
|
|
7421
|
+
y.current && (y.current.stop(), y.current.dispose(), y.current = null);
|
|
7422
|
+
}), [U]);
|
|
7406
7423
|
const _ = T(async () => {
|
|
7407
|
-
if (
|
|
7424
|
+
if (y.current)
|
|
7408
7425
|
try {
|
|
7409
|
-
const C =
|
|
7426
|
+
const C = y.current.audioCtx || y.current.audioContext;
|
|
7410
7427
|
C && (C.state === "suspended" || C.state === "interrupted") && (await C.resume(), console.log("Audio context resumed"));
|
|
7411
7428
|
} catch (C) {
|
|
7412
7429
|
console.warn("Failed to resume audio context:", C);
|
|
7413
7430
|
}
|
|
7414
7431
|
}, []), j = T(async (C, te = {}) => {
|
|
7415
|
-
if (!
|
|
7432
|
+
if (!y.current || !ae) {
|
|
7416
7433
|
console.warn("Avatar not ready for speaking");
|
|
7417
7434
|
return;
|
|
7418
7435
|
}
|
|
@@ -7420,42 +7437,42 @@ const gt = Me(({
|
|
|
7420
7437
|
console.warn("No text provided to speak");
|
|
7421
7438
|
return;
|
|
7422
7439
|
}
|
|
7423
|
-
await _(), S.current = { remainingText: null, originalText: null, options: null }, Z.current = [], P.current = { text: C, options: te },
|
|
7424
|
-
const L = C.split(/[.!?]+/).filter((
|
|
7440
|
+
await _(), S.current = { remainingText: null, originalText: null, options: null }, Z.current = [], P.current = { text: C, options: te }, W.current && (clearInterval(W.current), W.current = null), le(!1), oe.current = !1;
|
|
7441
|
+
const L = C.split(/[.!?]+/).filter((N) => N.trim().length > 0);
|
|
7425
7442
|
Z.current = L;
|
|
7426
7443
|
const F = {
|
|
7427
7444
|
lipsyncLang: te.lipsyncLang || "en",
|
|
7428
7445
|
onSpeechEnd: () => {
|
|
7429
|
-
|
|
7446
|
+
W.current && (clearInterval(W.current), W.current = null), te.onSpeechEnd && te.onSpeechEnd(), x();
|
|
7430
7447
|
}
|
|
7431
7448
|
};
|
|
7432
7449
|
try {
|
|
7433
|
-
|
|
7434
|
-
} catch (
|
|
7435
|
-
console.error("Error speaking text:",
|
|
7450
|
+
y.current.speakText(C, F);
|
|
7451
|
+
} catch (N) {
|
|
7452
|
+
console.error("Error speaking text:", N), se(N.message || "Failed to speak text");
|
|
7436
7453
|
}
|
|
7437
|
-
}, [ae,
|
|
7454
|
+
}, [ae, x, _]);
|
|
7438
7455
|
de(() => {
|
|
7439
|
-
ae && G && p &&
|
|
7456
|
+
ae && G && p && y.current && j(G);
|
|
7440
7457
|
}, [ae, G, p, j]);
|
|
7441
7458
|
const q = T(() => {
|
|
7442
|
-
if (
|
|
7459
|
+
if (y.current)
|
|
7443
7460
|
try {
|
|
7444
|
-
const C =
|
|
7461
|
+
const C = y.current.isSpeaking || !1, te = y.current.audioPlaylist || [], L = y.current.speechQueue || [];
|
|
7445
7462
|
if (C || te.length > 0 || L.length > 0) {
|
|
7446
|
-
|
|
7463
|
+
W.current && (clearInterval(W.current), W.current = null);
|
|
7447
7464
|
let F = "";
|
|
7448
|
-
L.length > 0 && (F = L.map((
|
|
7465
|
+
L.length > 0 && (F = L.map((N) => N.text && Array.isArray(N.text) ? N.text.map((J) => J.word).join(" ") : N.text || "").join(" ")), S.current = {
|
|
7449
7466
|
remainingText: F || null,
|
|
7450
7467
|
originalText: P.current?.text || null,
|
|
7451
7468
|
options: P.current?.options || null
|
|
7452
|
-
},
|
|
7469
|
+
}, y.current.speechQueue.length = 0, y.current.pauseSpeaking(), le(!0), oe.current = !0;
|
|
7453
7470
|
}
|
|
7454
7471
|
} catch (C) {
|
|
7455
7472
|
console.warn("Error pausing speech:", C);
|
|
7456
7473
|
}
|
|
7457
7474
|
}, []), Le = T(async () => {
|
|
7458
|
-
if (!(!
|
|
7475
|
+
if (!(!y.current || !ee))
|
|
7459
7476
|
try {
|
|
7460
7477
|
await _(), le(!1), oe.current = !1;
|
|
7461
7478
|
const C = S.current?.remainingText, te = S.current?.originalText || P.current?.text, L = S.current?.options || P.current?.options || {}, F = C || te;
|
|
@@ -7464,7 +7481,7 @@ const gt = Me(({
|
|
|
7464
7481
|
console.warn("Error resuming speech:", C), le(!1), oe.current = !1;
|
|
7465
7482
|
}
|
|
7466
7483
|
}, [ee, j, _]), we = T(() => {
|
|
7467
|
-
|
|
7484
|
+
y.current && (y.current.stopSpeaking(), W.current && (clearInterval(W.current), W.current = null), le(!1), oe.current = !1);
|
|
7468
7485
|
}, []);
|
|
7469
7486
|
return Ee(M, () => ({
|
|
7470
7487
|
speakText: j,
|
|
@@ -7473,21 +7490,21 @@ const gt = Me(({
|
|
|
7473
7490
|
stopSpeaking: we,
|
|
7474
7491
|
resumeAudioContext: _,
|
|
7475
7492
|
isPaused: () => ee,
|
|
7476
|
-
setMood: (C) =>
|
|
7493
|
+
setMood: (C) => y.current?.setMood(C),
|
|
7477
7494
|
setBodyMovement: (C) => {
|
|
7478
|
-
|
|
7495
|
+
y.current && y.current.setBodyMovement(C);
|
|
7479
7496
|
},
|
|
7480
7497
|
playAnimation: (C, te = !1) => {
|
|
7481
|
-
|
|
7498
|
+
y.current && y.current.playAnimation && y.current.playAnimation(C, null, 10, 0, 0.01, te);
|
|
7482
7499
|
},
|
|
7483
|
-
playReaction: (C) =>
|
|
7484
|
-
playCelebration: () =>
|
|
7500
|
+
playReaction: (C) => y.current?.playReaction(C),
|
|
7501
|
+
playCelebration: () => y.current?.playCelebration(),
|
|
7485
7502
|
setShowFullAvatar: (C) => {
|
|
7486
|
-
|
|
7503
|
+
y.current && (E.current = C, y.current.setShowFullAvatar(C));
|
|
7487
7504
|
},
|
|
7488
7505
|
isReady: ae,
|
|
7489
|
-
talkingHead:
|
|
7490
|
-
})), /* @__PURE__ */ Pe("div", { className: `simple-talking-avatar-container ${b}`, style:
|
|
7506
|
+
talkingHead: y.current
|
|
7507
|
+
})), /* @__PURE__ */ Pe("div", { className: `simple-talking-avatar-container ${b}`, style: R, children: [
|
|
7491
7508
|
/* @__PURE__ */ me(
|
|
7492
7509
|
"div",
|
|
7493
7510
|
{
|
|
@@ -7540,7 +7557,7 @@ const yt = Me(({
|
|
|
7540
7557
|
},
|
|
7541
7558
|
autoStart: h = !1
|
|
7542
7559
|
}, r) => {
|
|
7543
|
-
const u =
|
|
7560
|
+
const u = D(null), a = D({
|
|
7544
7561
|
currentModuleIndex: 0,
|
|
7545
7562
|
currentLessonIndex: 0,
|
|
7546
7563
|
currentQuestionIndex: 0,
|
|
@@ -7550,18 +7567,18 @@ const yt = Me(({
|
|
|
7550
7567
|
curriculumCompleted: !1,
|
|
7551
7568
|
score: 0,
|
|
7552
7569
|
totalQuestions: 0
|
|
7553
|
-
}),
|
|
7570
|
+
}), c = D({
|
|
7554
7571
|
onLessonStart: n,
|
|
7555
7572
|
onLessonComplete: i,
|
|
7556
7573
|
onQuestionAnswer: s,
|
|
7557
7574
|
onCurriculumComplete: o,
|
|
7558
7575
|
onCustomAction: l
|
|
7559
|
-
}),
|
|
7576
|
+
}), d = D(null), g = D(null), x = D(null), b = D(null), R = D(null), B = D(null), p = D(null), M = D(G?.curriculum || {
|
|
7560
7577
|
title: "Default Curriculum",
|
|
7561
7578
|
description: "No curriculum data provided",
|
|
7562
7579
|
language: "en",
|
|
7563
7580
|
modules: []
|
|
7564
|
-
}), z =
|
|
7581
|
+
}), z = D({
|
|
7565
7582
|
avatarUrl: t.avatarUrl || "/avatars/brunette.glb",
|
|
7566
7583
|
avatarBody: t.avatarBody || "F",
|
|
7567
7584
|
mood: t.mood || "happy",
|
|
@@ -7576,7 +7593,7 @@ const yt = Me(({
|
|
|
7576
7593
|
lipsyncLang: "en"
|
|
7577
7594
|
});
|
|
7578
7595
|
de(() => {
|
|
7579
|
-
|
|
7596
|
+
c.current = {
|
|
7580
7597
|
onLessonStart: n,
|
|
7581
7598
|
onLessonComplete: i,
|
|
7582
7599
|
onQuestionAnswer: s,
|
|
@@ -7604,17 +7621,17 @@ const yt = Me(({
|
|
|
7604
7621
|
lipsyncLang: "en"
|
|
7605
7622
|
};
|
|
7606
7623
|
}, [G, t, e]);
|
|
7607
|
-
const
|
|
7624
|
+
const y = T(() => (M.current || { modules: [] }).modules[a.current.currentModuleIndex]?.lessons[a.current.currentLessonIndex], []), E = T(() => y()?.questions[a.current.currentQuestionIndex], [y]), P = T((v, I) => I.type === "multiple_choice" || I.type === "true_false" ? v === I.answer : I.type === "code_test" && typeof v == "object" && v !== null ? v.passed === !0 : !1, []), W = T(() => {
|
|
7608
7625
|
a.current.lessonCompleted = !0, a.current.isQuestionMode = !1;
|
|
7609
7626
|
const v = a.current.totalQuestions > 0 ? Math.round(a.current.score / a.current.totalQuestions * 100) : 100;
|
|
7610
|
-
let
|
|
7611
|
-
if (a.current.totalQuestions > 0 ?
|
|
7627
|
+
let I = "Congratulations! You've completed this lesson";
|
|
7628
|
+
if (a.current.totalQuestions > 0 ? I += ` You got ${a.current.score} correct out of ${a.current.totalQuestions} question${a.current.totalQuestions === 1 ? "" : "s"}, achieving a score of ${v} percent. ` : I += "! ", v >= 80 ? I += "Excellent work! You have a great understanding of this topic." : v >= 60 ? I += "Good job! You understand most of the concepts." : I += "Keep practicing! You're making progress.", c.current.onLessonComplete({
|
|
7612
7629
|
moduleIndex: a.current.currentModuleIndex,
|
|
7613
7630
|
lessonIndex: a.current.currentLessonIndex,
|
|
7614
7631
|
score: a.current.score,
|
|
7615
7632
|
totalQuestions: a.current.totalQuestions,
|
|
7616
7633
|
percentage: v
|
|
7617
|
-
}),
|
|
7634
|
+
}), c.current.onCustomAction({
|
|
7618
7635
|
type: "lessonComplete",
|
|
7619
7636
|
moduleIndex: a.current.currentModuleIndex,
|
|
7620
7637
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7628,11 +7645,11 @@ const yt = Me(({
|
|
|
7628
7645
|
} catch {
|
|
7629
7646
|
u.current.playCelebration();
|
|
7630
7647
|
}
|
|
7631
|
-
const k = M.current || { modules: [] }, H = k.modules[a.current.currentModuleIndex],
|
|
7632
|
-
u.current.speakText(
|
|
7648
|
+
const k = M.current || { modules: [] }, H = k.modules[a.current.currentModuleIndex], U = a.current.currentLessonIndex < (H?.lessons?.length || 0) - 1, _ = a.current.currentModuleIndex < (k.modules?.length || 0) - 1, j = U || _, q = z.current || { lipsyncLang: "en" };
|
|
7649
|
+
u.current.speakText(I, {
|
|
7633
7650
|
lipsyncLang: q.lipsyncLang,
|
|
7634
7651
|
onSpeechEnd: () => {
|
|
7635
|
-
|
|
7652
|
+
c.current.onCustomAction({
|
|
7636
7653
|
type: "lessonCompleteFeedbackDone",
|
|
7637
7654
|
moduleIndex: a.current.currentModuleIndex,
|
|
7638
7655
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7647,9 +7664,9 @@ const yt = Me(({
|
|
|
7647
7664
|
}, [e.lessonComplete]), oe = T(() => {
|
|
7648
7665
|
a.current.curriculumCompleted = !0;
|
|
7649
7666
|
const v = M.current || { modules: [] };
|
|
7650
|
-
if (
|
|
7667
|
+
if (c.current.onCurriculumComplete({
|
|
7651
7668
|
modules: v.modules.length,
|
|
7652
|
-
totalLessons: v.modules.reduce((
|
|
7669
|
+
totalLessons: v.modules.reduce((I, k) => I + k.lessons.length, 0)
|
|
7653
7670
|
}), u.current) {
|
|
7654
7671
|
if (u.current.setMood("celebrating"), e.curriculumComplete)
|
|
7655
7672
|
try {
|
|
@@ -7657,94 +7674,94 @@ const yt = Me(({
|
|
|
7657
7674
|
} catch {
|
|
7658
7675
|
u.current.playCelebration();
|
|
7659
7676
|
}
|
|
7660
|
-
const
|
|
7661
|
-
u.current.speakText("Amazing! You've completed the entire curriculum! You're now ready to move on to more advanced topics. Well done!", { lipsyncLang:
|
|
7677
|
+
const I = z.current || { lipsyncLang: "en" };
|
|
7678
|
+
u.current.speakText("Amazing! You've completed the entire curriculum! You're now ready to move on to more advanced topics. Well done!", { lipsyncLang: I.lipsyncLang });
|
|
7662
7679
|
}
|
|
7663
7680
|
}, [e.curriculumComplete]), S = T(() => {
|
|
7664
|
-
const v =
|
|
7681
|
+
const v = y();
|
|
7665
7682
|
a.current.isQuestionMode = !0, a.current.currentQuestionIndex = 0, a.current.totalQuestions = v?.questions?.length || 0, a.current.score = 0;
|
|
7666
|
-
const
|
|
7667
|
-
|
|
7683
|
+
const I = E();
|
|
7684
|
+
I && c.current.onCustomAction({
|
|
7668
7685
|
type: "questionStart",
|
|
7669
7686
|
moduleIndex: a.current.currentModuleIndex,
|
|
7670
7687
|
lessonIndex: a.current.currentLessonIndex,
|
|
7671
7688
|
questionIndex: a.current.currentQuestionIndex,
|
|
7672
7689
|
totalQuestions: a.current.totalQuestions,
|
|
7673
|
-
question:
|
|
7690
|
+
question: I,
|
|
7674
7691
|
score: a.current.score
|
|
7675
7692
|
});
|
|
7676
7693
|
const k = () => {
|
|
7677
|
-
if (!u.current || !
|
|
7694
|
+
if (!u.current || !I) return;
|
|
7678
7695
|
if (u.current.setMood("happy"), e.questionStart)
|
|
7679
7696
|
try {
|
|
7680
7697
|
u.current.playAnimation(e.questionStart, !0);
|
|
7681
|
-
} catch (
|
|
7682
|
-
console.warn("Failed to play questionStart animation:",
|
|
7698
|
+
} catch (U) {
|
|
7699
|
+
console.warn("Failed to play questionStart animation:", U);
|
|
7683
7700
|
}
|
|
7684
7701
|
const H = z.current || { lipsyncLang: "en" };
|
|
7685
|
-
|
|
7702
|
+
I.type === "code_test" ? u.current.speakText(`Let's test your coding skills! Here's your first challenge: ${I.question}`, { lipsyncLang: H.lipsyncLang }) : I.type === "multiple_choice" ? u.current.speakText(`Now let me ask you some questions. Here's the first one: ${I.question}`, { lipsyncLang: H.lipsyncLang }) : I.type === "true_false" ? u.current.speakText(`Let's start with some true or false questions. First question: ${I.question}`, { lipsyncLang: H.lipsyncLang }) : u.current.speakText(`Now let me ask you some questions. Here's the first one: ${I.question}`, { lipsyncLang: H.lipsyncLang });
|
|
7686
7703
|
};
|
|
7687
|
-
if (u.current && u.current.isReady &&
|
|
7704
|
+
if (u.current && u.current.isReady && I)
|
|
7688
7705
|
k();
|
|
7689
7706
|
else if (u.current && u.current.isReady) {
|
|
7690
7707
|
const H = z.current || { lipsyncLang: "en" };
|
|
7691
7708
|
u.current.speakText("Now let me ask you some questions to test your understanding.", { lipsyncLang: H.lipsyncLang });
|
|
7692
7709
|
} else {
|
|
7693
7710
|
const H = setInterval(() => {
|
|
7694
|
-
u.current && u.current.isReady && (clearInterval(H),
|
|
7711
|
+
u.current && u.current.isReady && (clearInterval(H), I && k());
|
|
7695
7712
|
}, 100);
|
|
7696
7713
|
setTimeout(() => {
|
|
7697
7714
|
clearInterval(H);
|
|
7698
7715
|
}, 5e3);
|
|
7699
7716
|
}
|
|
7700
|
-
}, [e.questionStart,
|
|
7701
|
-
const v =
|
|
7717
|
+
}, [e.questionStart, y, E]), Z = T(() => {
|
|
7718
|
+
const v = y();
|
|
7702
7719
|
if (a.current.currentQuestionIndex < (v?.questions?.length || 0) - 1) {
|
|
7703
7720
|
u.current && u.current.stopSpeaking && u.current.stopSpeaking(), a.current.currentQuestionIndex += 1;
|
|
7704
|
-
const
|
|
7705
|
-
|
|
7721
|
+
const I = E();
|
|
7722
|
+
I && c.current.onCustomAction({
|
|
7706
7723
|
type: "nextQuestion",
|
|
7707
7724
|
moduleIndex: a.current.currentModuleIndex,
|
|
7708
7725
|
lessonIndex: a.current.currentLessonIndex,
|
|
7709
7726
|
questionIndex: a.current.currentQuestionIndex,
|
|
7710
7727
|
totalQuestions: a.current.totalQuestions,
|
|
7711
|
-
question:
|
|
7728
|
+
question: I,
|
|
7712
7729
|
score: a.current.score
|
|
7713
7730
|
});
|
|
7714
7731
|
const k = () => {
|
|
7715
|
-
if (!u.current || !
|
|
7732
|
+
if (!u.current || !I) return;
|
|
7716
7733
|
if (u.current.setMood("happy"), u.current.setBodyMovement("idle"), e.nextQuestion)
|
|
7717
7734
|
try {
|
|
7718
7735
|
u.current.playAnimation(e.nextQuestion, !0);
|
|
7719
7736
|
} catch (q) {
|
|
7720
7737
|
console.warn("Failed to play nextQuestion animation:", q);
|
|
7721
7738
|
}
|
|
7722
|
-
const H = z.current || { lipsyncLang: "en" }, _ =
|
|
7723
|
-
if (
|
|
7724
|
-
const q = j ? `Great! Here's your final coding challenge: ${
|
|
7739
|
+
const H = z.current || { lipsyncLang: "en" }, _ = y()?.questions?.length || 0, j = a.current.currentQuestionIndex >= _ - 1;
|
|
7740
|
+
if (I.type === "code_test") {
|
|
7741
|
+
const q = j ? `Great! Here's your final coding challenge: ${I.question}` : `Great! Now let's move on to your next coding challenge: ${I.question}`;
|
|
7725
7742
|
u.current.speakText(q, {
|
|
7726
7743
|
lipsyncLang: H.lipsyncLang
|
|
7727
7744
|
});
|
|
7728
|
-
} else if (
|
|
7729
|
-
const q = j ? `Alright! Here's your final question: ${
|
|
7745
|
+
} else if (I.type === "multiple_choice") {
|
|
7746
|
+
const q = j ? `Alright! Here's your final question: ${I.question}` : `Alright! Here's your next question: ${I.question}`;
|
|
7730
7747
|
u.current.speakText(q, {
|
|
7731
7748
|
lipsyncLang: H.lipsyncLang
|
|
7732
7749
|
});
|
|
7733
|
-
} else if (
|
|
7734
|
-
const q = j ? `Now let's try this final one: ${
|
|
7750
|
+
} else if (I.type === "true_false") {
|
|
7751
|
+
const q = j ? `Now let's try this final one: ${I.question}` : `Now let's try this one: ${I.question}`;
|
|
7735
7752
|
u.current.speakText(q, {
|
|
7736
7753
|
lipsyncLang: H.lipsyncLang
|
|
7737
7754
|
});
|
|
7738
7755
|
} else {
|
|
7739
|
-
const q = j ? `Here's your final question: ${
|
|
7756
|
+
const q = j ? `Here's your final question: ${I.question}` : `Here's the next question: ${I.question}`;
|
|
7740
7757
|
u.current.speakText(q, {
|
|
7741
7758
|
lipsyncLang: H.lipsyncLang
|
|
7742
7759
|
});
|
|
7743
7760
|
}
|
|
7744
7761
|
};
|
|
7745
|
-
if (u.current && u.current.isReady &&
|
|
7762
|
+
if (u.current && u.current.isReady && I)
|
|
7746
7763
|
k();
|
|
7747
|
-
else if (
|
|
7764
|
+
else if (I) {
|
|
7748
7765
|
const H = setInterval(() => {
|
|
7749
7766
|
u.current && u.current.isReady && (clearInterval(H), k());
|
|
7750
7767
|
}, 100);
|
|
@@ -7753,81 +7770,81 @@ const yt = Me(({
|
|
|
7753
7770
|
}, 5e3);
|
|
7754
7771
|
}
|
|
7755
7772
|
} else
|
|
7756
|
-
|
|
7773
|
+
c.current.onCustomAction({
|
|
7757
7774
|
type: "allQuestionsComplete",
|
|
7758
7775
|
moduleIndex: a.current.currentModuleIndex,
|
|
7759
7776
|
lessonIndex: a.current.currentLessonIndex,
|
|
7760
7777
|
totalQuestions: a.current.totalQuestions,
|
|
7761
7778
|
score: a.current.score
|
|
7762
7779
|
});
|
|
7763
|
-
}, [e.nextQuestion,
|
|
7764
|
-
const v = M.current || { modules: [] },
|
|
7765
|
-
if (a.current.currentLessonIndex < (
|
|
7780
|
+
}, [e.nextQuestion, y, E]), K = T(() => {
|
|
7781
|
+
const v = M.current || { modules: [] }, I = v.modules[a.current.currentModuleIndex];
|
|
7782
|
+
if (a.current.currentLessonIndex < (I?.lessons?.length || 0) - 1) {
|
|
7766
7783
|
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;
|
|
7767
|
-
const H = v.modules[a.current.currentModuleIndex],
|
|
7768
|
-
|
|
7784
|
+
const H = v.modules[a.current.currentModuleIndex], U = a.current.currentLessonIndex < (H?.lessons?.length || 0) - 1, _ = a.current.currentModuleIndex < (v.modules?.length || 0) - 1, j = U || _;
|
|
7785
|
+
c.current.onCustomAction({
|
|
7769
7786
|
type: "lessonStart",
|
|
7770
7787
|
moduleIndex: a.current.currentModuleIndex,
|
|
7771
7788
|
lessonIndex: a.current.currentLessonIndex,
|
|
7772
7789
|
hasNextLesson: j
|
|
7773
|
-
}),
|
|
7790
|
+
}), c.current.onLessonStart({
|
|
7774
7791
|
moduleIndex: a.current.currentModuleIndex,
|
|
7775
7792
|
lessonIndex: a.current.currentLessonIndex,
|
|
7776
|
-
lesson:
|
|
7793
|
+
lesson: y()
|
|
7777
7794
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7778
7795
|
} else if (a.current.currentModuleIndex < (v.modules?.length || 0) - 1) {
|
|
7779
7796
|
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;
|
|
7780
|
-
const
|
|
7781
|
-
|
|
7797
|
+
const U = v.modules[a.current.currentModuleIndex], _ = a.current.currentLessonIndex < (U?.lessons?.length || 0) - 1, j = a.current.currentModuleIndex < (v.modules?.length || 0) - 1, q = _ || j;
|
|
7798
|
+
c.current.onCustomAction({
|
|
7782
7799
|
type: "lessonStart",
|
|
7783
7800
|
moduleIndex: a.current.currentModuleIndex,
|
|
7784
7801
|
lessonIndex: a.current.currentLessonIndex,
|
|
7785
7802
|
hasNextLesson: q
|
|
7786
|
-
}),
|
|
7803
|
+
}), c.current.onLessonStart({
|
|
7787
7804
|
moduleIndex: a.current.currentModuleIndex,
|
|
7788
7805
|
lessonIndex: a.current.currentLessonIndex,
|
|
7789
|
-
lesson:
|
|
7806
|
+
lesson: y()
|
|
7790
7807
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7791
7808
|
} else
|
|
7792
|
-
|
|
7809
|
+
R.current && R.current();
|
|
7793
7810
|
}, []), X = T(() => {
|
|
7794
|
-
const v =
|
|
7795
|
-
let
|
|
7811
|
+
const v = y();
|
|
7812
|
+
let I = null;
|
|
7796
7813
|
if (v?.avatar_script && v?.body) {
|
|
7797
|
-
const k = v.avatar_script.trim(), H = v.body.trim(),
|
|
7798
|
-
|
|
7814
|
+
const k = v.avatar_script.trim(), H = v.body.trim(), U = k.match(/[.!?]$/) ? " " : ". ";
|
|
7815
|
+
I = `${k}${U}${H}`;
|
|
7799
7816
|
} else
|
|
7800
|
-
|
|
7801
|
-
if (u.current && u.current.isReady &&
|
|
7817
|
+
I = v?.avatar_script || v?.body || null;
|
|
7818
|
+
if (u.current && u.current.isReady && I) {
|
|
7802
7819
|
a.current.isTeaching = !0, a.current.isQuestionMode = !1, a.current.score = 0, a.current.totalQuestions = 0, u.current.setMood("happy");
|
|
7803
7820
|
let k = !1;
|
|
7804
7821
|
if (e.teaching)
|
|
7805
7822
|
try {
|
|
7806
7823
|
u.current.playAnimation(e.teaching, !0), k = !0;
|
|
7807
|
-
} catch (
|
|
7808
|
-
console.warn("Failed to play teaching animation:",
|
|
7824
|
+
} catch (U) {
|
|
7825
|
+
console.warn("Failed to play teaching animation:", U);
|
|
7809
7826
|
}
|
|
7810
7827
|
k || u.current.setBodyMovement("gesturing");
|
|
7811
7828
|
const H = z.current || { lipsyncLang: "en" };
|
|
7812
|
-
|
|
7829
|
+
c.current.onLessonStart({
|
|
7813
7830
|
moduleIndex: a.current.currentModuleIndex,
|
|
7814
7831
|
lessonIndex: a.current.currentLessonIndex,
|
|
7815
7832
|
lesson: v
|
|
7816
|
-
}),
|
|
7833
|
+
}), c.current.onCustomAction({
|
|
7817
7834
|
type: "teachingStart",
|
|
7818
7835
|
moduleIndex: a.current.currentModuleIndex,
|
|
7819
7836
|
lessonIndex: a.current.currentLessonIndex,
|
|
7820
7837
|
lesson: v
|
|
7821
|
-
}), u.current.speakText(
|
|
7838
|
+
}), u.current.speakText(I, {
|
|
7822
7839
|
lipsyncLang: H.lipsyncLang,
|
|
7823
7840
|
onSpeechEnd: () => {
|
|
7824
|
-
a.current.isTeaching = !1,
|
|
7841
|
+
a.current.isTeaching = !1, c.current.onCustomAction({
|
|
7825
7842
|
type: "teachingComplete",
|
|
7826
7843
|
moduleIndex: a.current.currentModuleIndex,
|
|
7827
7844
|
lessonIndex: a.current.currentLessonIndex,
|
|
7828
7845
|
lesson: v,
|
|
7829
7846
|
hasQuestions: v.questions && v.questions.length > 0
|
|
7830
|
-
}), v?.code_example &&
|
|
7847
|
+
}), v?.code_example && c.current.onCustomAction({
|
|
7831
7848
|
type: "codeExampleReady",
|
|
7832
7849
|
moduleIndex: a.current.currentModuleIndex,
|
|
7833
7850
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7837,15 +7854,15 @@ const yt = Me(({
|
|
|
7837
7854
|
}
|
|
7838
7855
|
});
|
|
7839
7856
|
}
|
|
7840
|
-
}, [e.teaching,
|
|
7841
|
-
const
|
|
7842
|
-
if (k && (a.current.score += 1),
|
|
7857
|
+
}, [e.teaching, y]), $ = T((v) => {
|
|
7858
|
+
const I = E(), k = P(v, I);
|
|
7859
|
+
if (k && (a.current.score += 1), c.current.onQuestionAnswer({
|
|
7843
7860
|
moduleIndex: a.current.currentModuleIndex,
|
|
7844
7861
|
lessonIndex: a.current.currentLessonIndex,
|
|
7845
7862
|
questionIndex: a.current.currentQuestionIndex,
|
|
7846
7863
|
answer: v,
|
|
7847
7864
|
isCorrect: k,
|
|
7848
|
-
question:
|
|
7865
|
+
question: I
|
|
7849
7866
|
}), u.current)
|
|
7850
7867
|
if (k) {
|
|
7851
7868
|
if (u.current.setMood("happy"), e.correct)
|
|
@@ -7855,15 +7872,15 @@ const yt = Me(({
|
|
|
7855
7872
|
u.current.setBodyMovement("happy");
|
|
7856
7873
|
}
|
|
7857
7874
|
u.current.setBodyMovement("gesturing");
|
|
7858
|
-
const
|
|
7859
|
-
a.current.currentQuestionIndex >=
|
|
7860
|
-
const _ = a.current.currentQuestionIndex <
|
|
7861
|
-
console.log("[CurriculumLearning] Answer feedback - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:",
|
|
7862
|
-
const j =
|
|
7875
|
+
const U = y()?.questions?.length || 0;
|
|
7876
|
+
a.current.currentQuestionIndex >= U - 1;
|
|
7877
|
+
const _ = a.current.currentQuestionIndex < U - 1;
|
|
7878
|
+
console.log("[CurriculumLearning] Answer feedback - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:", U, "hasNextQuestion:", _);
|
|
7879
|
+
const j = I.type === "code_test" ? `Great job! Your code passed all the tests! ${I.explanation || ""}` : `Excellent! That's correct! ${I.explanation || ""}`, q = z.current || { lipsyncLang: "en" };
|
|
7863
7880
|
u.current.speakText(j, {
|
|
7864
7881
|
lipsyncLang: q.lipsyncLang,
|
|
7865
7882
|
onSpeechEnd: () => {
|
|
7866
|
-
|
|
7883
|
+
c.current.onCustomAction({
|
|
7867
7884
|
type: "answerFeedbackComplete",
|
|
7868
7885
|
moduleIndex: a.current.currentModuleIndex,
|
|
7869
7886
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7883,13 +7900,13 @@ const yt = Me(({
|
|
|
7883
7900
|
u.current.setBodyMovement("idle");
|
|
7884
7901
|
}
|
|
7885
7902
|
u.current.setBodyMovement("gesturing");
|
|
7886
|
-
const
|
|
7887
|
-
console.log("[CurriculumLearning] Answer feedback (incorrect) - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:",
|
|
7888
|
-
const q =
|
|
7903
|
+
const U = y()?.questions?.length || 0, _ = a.current.currentQuestionIndex >= U - 1, j = a.current.currentQuestionIndex < U - 1;
|
|
7904
|
+
console.log("[CurriculumLearning] Answer feedback (incorrect) - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:", U, "hasNextQuestion:", j);
|
|
7905
|
+
const q = I.type === "code_test" ? `Your code didn't pass all the tests. ${I.explanation || "Try again!"}` : `Not quite right, but don't worry! ${I.explanation || ""}${_ ? "" : " Let's move on to the next question."}`, Le = z.current || { lipsyncLang: "en" };
|
|
7889
7906
|
u.current.speakText(q, {
|
|
7890
7907
|
lipsyncLang: Le.lipsyncLang,
|
|
7891
7908
|
onSpeechEnd: () => {
|
|
7892
|
-
|
|
7909
|
+
c.current.onCustomAction({
|
|
7893
7910
|
type: "answerFeedbackComplete",
|
|
7894
7911
|
moduleIndex: a.current.currentModuleIndex,
|
|
7895
7912
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7903,26 +7920,26 @@ const yt = Me(({
|
|
|
7903
7920
|
});
|
|
7904
7921
|
}
|
|
7905
7922
|
else {
|
|
7906
|
-
const
|
|
7907
|
-
|
|
7923
|
+
const U = y()?.questions?.length || 0;
|
|
7924
|
+
c.current.onCustomAction({
|
|
7908
7925
|
type: "answerFeedbackComplete",
|
|
7909
7926
|
moduleIndex: a.current.currentModuleIndex,
|
|
7910
7927
|
lessonIndex: a.current.currentLessonIndex,
|
|
7911
7928
|
questionIndex: a.current.currentQuestionIndex,
|
|
7912
7929
|
isCorrect: k,
|
|
7913
|
-
hasNextQuestion: a.current.currentQuestionIndex <
|
|
7930
|
+
hasNextQuestion: a.current.currentQuestionIndex < U - 1,
|
|
7914
7931
|
score: a.current.score,
|
|
7915
7932
|
totalQuestions: a.current.totalQuestions,
|
|
7916
7933
|
avatarNotReady: !0
|
|
7917
7934
|
});
|
|
7918
7935
|
}
|
|
7919
|
-
}, [e.correct, e.incorrect, E,
|
|
7920
|
-
const
|
|
7936
|
+
}, [e.correct, e.incorrect, E, y, P]), se = T((v) => {
|
|
7937
|
+
const I = E();
|
|
7921
7938
|
if (!v || typeof v != "object") {
|
|
7922
7939
|
console.error("Invalid code test result format. Expected object with {passed: boolean, ...}");
|
|
7923
7940
|
return;
|
|
7924
7941
|
}
|
|
7925
|
-
if (
|
|
7942
|
+
if (I?.type !== "code_test") {
|
|
7926
7943
|
console.warn("Current question is not a code test. Use handleAnswerSelect for other question types.");
|
|
7927
7944
|
return;
|
|
7928
7945
|
}
|
|
@@ -7936,19 +7953,19 @@ const yt = Me(({
|
|
|
7936
7953
|
passedCount: v.passedCount || 0,
|
|
7937
7954
|
failedCount: v.failedCount || 0
|
|
7938
7955
|
};
|
|
7939
|
-
|
|
7956
|
+
c.current.onCustomAction({
|
|
7940
7957
|
type: "codeTestSubmitted",
|
|
7941
7958
|
moduleIndex: a.current.currentModuleIndex,
|
|
7942
7959
|
lessonIndex: a.current.currentLessonIndex,
|
|
7943
7960
|
questionIndex: a.current.currentQuestionIndex,
|
|
7944
7961
|
testResult: k,
|
|
7945
|
-
question:
|
|
7962
|
+
question: I
|
|
7946
7963
|
}), p.current && p.current(k);
|
|
7947
7964
|
}, [E, P]), ae = T(() => {
|
|
7948
7965
|
if (a.current.currentQuestionIndex > 0) {
|
|
7949
7966
|
a.current.currentQuestionIndex -= 1;
|
|
7950
7967
|
const v = E();
|
|
7951
|
-
v &&
|
|
7968
|
+
v && c.current.onCustomAction({
|
|
7952
7969
|
type: "questionStart",
|
|
7953
7970
|
moduleIndex: a.current.currentModuleIndex,
|
|
7954
7971
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7957,7 +7974,7 @@ const yt = Me(({
|
|
|
7957
7974
|
question: v,
|
|
7958
7975
|
score: a.current.score
|
|
7959
7976
|
});
|
|
7960
|
-
const
|
|
7977
|
+
const I = () => {
|
|
7961
7978
|
if (!u.current || !v) return;
|
|
7962
7979
|
u.current.setMood("happy"), u.current.setBodyMovement("idle");
|
|
7963
7980
|
const k = z.current || { lipsyncLang: "en" };
|
|
@@ -7968,10 +7985,10 @@ const yt = Me(({
|
|
|
7968
7985
|
});
|
|
7969
7986
|
};
|
|
7970
7987
|
if (u.current && u.current.isReady && v)
|
|
7971
|
-
|
|
7988
|
+
I();
|
|
7972
7989
|
else if (v) {
|
|
7973
7990
|
const k = setInterval(() => {
|
|
7974
|
-
u.current && u.current.isReady && (clearInterval(k),
|
|
7991
|
+
u.current && u.current.isReady && (clearInterval(k), I());
|
|
7975
7992
|
}, 100);
|
|
7976
7993
|
setTimeout(() => {
|
|
7977
7994
|
clearInterval(k);
|
|
@@ -7981,38 +7998,38 @@ const yt = Me(({
|
|
|
7981
7998
|
}, [E]), pe = T(() => {
|
|
7982
7999
|
const v = M.current || { modules: [] };
|
|
7983
8000
|
if (v.modules[a.current.currentModuleIndex], a.current.currentLessonIndex > 0)
|
|
7984
|
-
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,
|
|
8001
|
+
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, c.current.onCustomAction({
|
|
7985
8002
|
type: "lessonStart",
|
|
7986
8003
|
moduleIndex: a.current.currentModuleIndex,
|
|
7987
8004
|
lessonIndex: a.current.currentLessonIndex
|
|
7988
|
-
}),
|
|
8005
|
+
}), c.current.onLessonStart({
|
|
7989
8006
|
moduleIndex: a.current.currentModuleIndex,
|
|
7990
8007
|
lessonIndex: a.current.currentLessonIndex,
|
|
7991
|
-
lesson:
|
|
8008
|
+
lesson: y()
|
|
7992
8009
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7993
8010
|
else if (a.current.currentModuleIndex > 0) {
|
|
7994
8011
|
const H = v.modules[a.current.currentModuleIndex - 1];
|
|
7995
|
-
a.current.currentModuleIndex -= 1, a.current.currentLessonIndex = (H?.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,
|
|
8012
|
+
a.current.currentModuleIndex -= 1, a.current.currentLessonIndex = (H?.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, c.current.onCustomAction({
|
|
7996
8013
|
type: "lessonStart",
|
|
7997
8014
|
moduleIndex: a.current.currentModuleIndex,
|
|
7998
8015
|
lessonIndex: a.current.currentLessonIndex
|
|
7999
|
-
}),
|
|
8016
|
+
}), c.current.onLessonStart({
|
|
8000
8017
|
moduleIndex: a.current.currentModuleIndex,
|
|
8001
8018
|
lessonIndex: a.current.currentLessonIndex,
|
|
8002
|
-
lesson:
|
|
8019
|
+
lesson: y()
|
|
8003
8020
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
8004
8021
|
}
|
|
8005
|
-
}, [
|
|
8022
|
+
}, [y]), ee = T(() => {
|
|
8006
8023
|
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;
|
|
8007
8024
|
}, []), le = T((v) => {
|
|
8008
8025
|
console.log("Avatar is ready!", v);
|
|
8009
|
-
const
|
|
8026
|
+
const I = y(), k = I?.avatar_script || I?.body;
|
|
8010
8027
|
h && k && setTimeout(() => {
|
|
8011
|
-
|
|
8028
|
+
d.current && d.current();
|
|
8012
8029
|
}, 10);
|
|
8013
|
-
}, [h,
|
|
8030
|
+
}, [h, y]);
|
|
8014
8031
|
Xe(() => {
|
|
8015
|
-
|
|
8032
|
+
d.current = X, g.current = K, x.current = W, b.current = Z, R.current = oe, B.current = S, p.current = $;
|
|
8016
8033
|
}), Ee(r, () => ({
|
|
8017
8034
|
// Curriculum control methods
|
|
8018
8035
|
startTeaching: X,
|
|
@@ -8023,29 +8040,29 @@ const yt = Me(({
|
|
|
8023
8040
|
previousQuestion: ae,
|
|
8024
8041
|
nextLesson: K,
|
|
8025
8042
|
previousLesson: pe,
|
|
8026
|
-
completeLesson:
|
|
8043
|
+
completeLesson: W,
|
|
8027
8044
|
completeCurriculum: oe,
|
|
8028
8045
|
resetCurriculum: ee,
|
|
8029
8046
|
getState: () => ({ ...a.current }),
|
|
8030
8047
|
getCurrentQuestion: () => E(),
|
|
8031
|
-
getCurrentLesson: () =>
|
|
8048
|
+
getCurrentLesson: () => y(),
|
|
8032
8049
|
// Direct access to avatar ref (always returns current value)
|
|
8033
8050
|
getAvatarRef: () => u.current,
|
|
8034
8051
|
// Convenience methods that delegate to avatar (always check current ref)
|
|
8035
|
-
speakText: async (v,
|
|
8052
|
+
speakText: async (v, I = {}) => {
|
|
8036
8053
|
await u.current?.resumeAudioContext?.();
|
|
8037
8054
|
const k = z.current || { lipsyncLang: "en" };
|
|
8038
|
-
u.current?.speakText(v, { ...
|
|
8055
|
+
u.current?.speakText(v, { ...I, lipsyncLang: I.lipsyncLang || k.lipsyncLang });
|
|
8039
8056
|
},
|
|
8040
8057
|
resumeAudioContext: async () => {
|
|
8041
8058
|
if (u.current?.resumeAudioContext)
|
|
8042
8059
|
return await u.current.resumeAudioContext();
|
|
8043
8060
|
const v = u.current?.talkingHead;
|
|
8044
8061
|
if (v?.audioCtx) {
|
|
8045
|
-
const
|
|
8046
|
-
if (
|
|
8062
|
+
const I = v.audioCtx;
|
|
8063
|
+
if (I.state === "suspended" || I.state === "interrupted")
|
|
8047
8064
|
try {
|
|
8048
|
-
await
|
|
8065
|
+
await I.resume(), console.log("Audio context resumed via talkingHead");
|
|
8049
8066
|
} catch (k) {
|
|
8050
8067
|
console.warn("Failed to resume audio context:", k);
|
|
8051
8068
|
}
|
|
@@ -8057,7 +8074,7 @@ const yt = Me(({
|
|
|
8057
8074
|
resumeSpeaking: async () => await u.current?.resumeSpeaking(),
|
|
8058
8075
|
isPaused: () => u.current && typeof u.current.isPaused < "u" ? u.current.isPaused : !1,
|
|
8059
8076
|
setMood: (v) => u.current?.setMood(v),
|
|
8060
|
-
playAnimation: (v,
|
|
8077
|
+
playAnimation: (v, I) => u.current?.playAnimation(v, I),
|
|
8061
8078
|
setBodyMovement: (v) => u.current?.setBodyMovement(v),
|
|
8062
8079
|
setMovementIntensity: (v) => u.current?.setMovementIntensity(v),
|
|
8063
8080
|
playRandomDance: () => u.current?.playRandomDance(),
|
|
@@ -8068,10 +8085,10 @@ const yt = Me(({
|
|
|
8068
8085
|
lockAvatarPosition: () => u.current?.lockAvatarPosition(),
|
|
8069
8086
|
unlockAvatarPosition: () => u.current?.unlockAvatarPosition(),
|
|
8070
8087
|
// Custom action trigger
|
|
8071
|
-
triggerCustomAction: (v,
|
|
8072
|
-
|
|
8088
|
+
triggerCustomAction: (v, I) => {
|
|
8089
|
+
c.current.onCustomAction({
|
|
8073
8090
|
type: v,
|
|
8074
|
-
...
|
|
8091
|
+
...I,
|
|
8075
8092
|
state: { ...a.current }
|
|
8076
8093
|
});
|
|
8077
8094
|
},
|
|
@@ -8079,8 +8096,8 @@ const yt = Me(({
|
|
|
8079
8096
|
handleResize: () => u.current?.handleResize(),
|
|
8080
8097
|
// Avatar readiness check (always returns current value)
|
|
8081
8098
|
isAvatarReady: () => u.current?.isReady || !1
|
|
8082
|
-
}), [X, S, $, se, Z, K,
|
|
8083
|
-
const
|
|
8099
|
+
}), [X, S, $, se, Z, K, W, oe, ee, E, y]);
|
|
8100
|
+
const O = z.current || {
|
|
8084
8101
|
avatarUrl: "/avatars/brunette.glb",
|
|
8085
8102
|
avatarBody: "F",
|
|
8086
8103
|
mood: "happy",
|
|
@@ -8097,18 +8114,18 @@ const yt = Me(({
|
|
|
8097
8114
|
Ve,
|
|
8098
8115
|
{
|
|
8099
8116
|
ref: u,
|
|
8100
|
-
avatarUrl:
|
|
8101
|
-
avatarBody:
|
|
8102
|
-
mood:
|
|
8103
|
-
ttsLang:
|
|
8104
|
-
ttsService:
|
|
8105
|
-
ttsVoice:
|
|
8106
|
-
ttsApiKey:
|
|
8107
|
-
bodyMovement:
|
|
8108
|
-
movementIntensity:
|
|
8109
|
-
showFullAvatar:
|
|
8117
|
+
avatarUrl: O.avatarUrl,
|
|
8118
|
+
avatarBody: O.avatarBody,
|
|
8119
|
+
mood: O.mood,
|
|
8120
|
+
ttsLang: O.ttsLang,
|
|
8121
|
+
ttsService: O.ttsService,
|
|
8122
|
+
ttsVoice: O.ttsVoice,
|
|
8123
|
+
ttsApiKey: O.ttsApiKey,
|
|
8124
|
+
bodyMovement: O.bodyMovement,
|
|
8125
|
+
movementIntensity: O.movementIntensity,
|
|
8126
|
+
showFullAvatar: O.showFullAvatar,
|
|
8110
8127
|
cameraView: "upper",
|
|
8111
|
-
animations:
|
|
8128
|
+
animations: O.animations,
|
|
8112
8129
|
onReady: le,
|
|
8113
8130
|
onLoading: () => {
|
|
8114
8131
|
},
|