@sage-rsc/talking-head-react 1.0.84 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2 -2
- package/dist/index.js +585 -556
- package/package.json +1 -1
- package/src/lib/talkinghead.mjs +69 -0
package/dist/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { jsxs as Pe, jsx as me } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as Me, useRef as O, useState as ce, useEffect as de, useCallback as T, useImperativeHandle as Ee, useLayoutEffect as Xe } from "react";
|
|
3
|
-
import * as
|
|
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";
|
|
7
|
-
import { FBXLoader as
|
|
7
|
+
import { FBXLoader as Oe } 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(), De = 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(De.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(De.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,8 +606,8 @@ 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] =
|
|
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
611
|
const b = r * o - u * l, I = r * l + u * o;
|
|
612
612
|
r = b, u = I;
|
|
613
613
|
}
|
|
@@ -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(), Re = 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, I = l.getZ(g) + c.getZ(g) * u;
|
|
4232
|
+
l.setXYZ(g, x, b, I);
|
|
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, I = h.getZ(g) + d.getZ(g) * u;
|
|
4237
|
+
h.setXYZ(g, x, b, I);
|
|
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;
|
|
@@ -4999,10 +4999,10 @@ class Be {
|
|
|
4999
4999
|
if (l.alt.length > 1) {
|
|
5000
5000
|
const u = Math.random();
|
|
5001
5001
|
let a = 0;
|
|
5002
|
-
for (let
|
|
5003
|
-
let
|
|
5004
|
-
if (a +=
|
|
5005
|
-
r = l.alt[
|
|
5002
|
+
for (let c = 0; c < l.alt.length; c++) {
|
|
5003
|
+
let d = this.valueFn(l.alt[c].p);
|
|
5004
|
+
if (a += d === void 0 ? (1 - a) / (l.alt.length - 1 - c) : d, u < a) {
|
|
5005
|
+
r = l.alt[c];
|
|
5006
5006
|
break;
|
|
5007
5007
|
}
|
|
5008
5008
|
}
|
|
@@ -5023,8 +5023,8 @@ class Be {
|
|
|
5023
5023
|
}
|
|
5024
5024
|
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
5025
|
for (let [r, u] of Object.entries(l.vs)) {
|
|
5026
|
-
const a = this.getBaselineValue(r),
|
|
5027
|
-
r === "eyesRotateY" ? (o.vs.eyeLookOutLeft = [null, ...
|
|
5026
|
+
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));
|
|
5027
|
+
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
5028
|
}
|
|
5029
5029
|
for (let r of Object.keys(o.vs))
|
|
5030
5030
|
for (; o.vs[r].length <= o.ts.length; ) o.vs[r].push(o.vs[r][o.vs[r].length - 1]);
|
|
@@ -5111,20 +5111,20 @@ class Be {
|
|
|
5111
5111
|
const a = this.animQueue[n];
|
|
5112
5112
|
if (!(!a || !a.ts || !a.ts.length || this.animClock < a.ts[0])) {
|
|
5113
5113
|
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 =
|
|
5114
|
+
for (let [c, d] of Object.entries(a.vs))
|
|
5115
|
+
if (this.mtAvatar.hasOwnProperty(c)) {
|
|
5116
|
+
if (d[i + 1] === null) continue;
|
|
5117
|
+
const g = this.mtAvatar[c];
|
|
5118
|
+
if (d[i] === null && (d[i] = g.value), i === o - 1)
|
|
5119
|
+
g.newvalue = d[i];
|
|
5120
5120
|
else {
|
|
5121
|
-
g.newvalue =
|
|
5122
|
-
const
|
|
5121
|
+
g.newvalue = d[i + 1];
|
|
5122
|
+
const x = a.ts[i + 1] - a.ts[i];
|
|
5123
5123
|
let b = 1;
|
|
5124
|
-
|
|
5124
|
+
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
5125
|
}
|
|
5126
5126
|
if (l)
|
|
5127
|
-
switch (
|
|
5127
|
+
switch (c) {
|
|
5128
5128
|
case "viseme_aa":
|
|
5129
5129
|
case "viseme_E":
|
|
5130
5130
|
case "viseme_I":
|
|
@@ -5133,11 +5133,11 @@ class Be {
|
|
|
5133
5133
|
g.newvalue *= 1 + l / 255 - 0.5;
|
|
5134
5134
|
}
|
|
5135
5135
|
g.needsUpdate = !0;
|
|
5136
|
-
} else
|
|
5136
|
+
} 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
5137
|
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
5138
|
}
|
|
5139
5139
|
}
|
|
5140
|
-
for (let a = 0,
|
|
5140
|
+
for (let a = 0, c = u.length; a < c; a++)
|
|
5141
5141
|
switch (i = u[a].val, u[a].mt) {
|
|
5142
5142
|
case "speak":
|
|
5143
5143
|
this.speakText(i);
|
|
@@ -5155,8 +5155,8 @@ class Be {
|
|
|
5155
5155
|
i && typeof i == "function" && i();
|
|
5156
5156
|
break;
|
|
5157
5157
|
case "moveto":
|
|
5158
|
-
Object.entries(i.props).forEach((
|
|
5159
|
-
|
|
5158
|
+
Object.entries(i.props).forEach((d) => {
|
|
5159
|
+
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
5160
|
});
|
|
5161
5161
|
break;
|
|
5162
5162
|
case "handLeft":
|
|
@@ -5169,7 +5169,7 @@ class Be {
|
|
|
5169
5169
|
{ link: "LeftForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -0.5, maxz: 3 },
|
|
5170
5170
|
{ link: "LeftArm", minx: -1.5, maxx: 1.5, miny: 0, maxy: 0, minz: -1, maxz: 3 }
|
|
5171
5171
|
]
|
|
5172
|
-
}, i.x ? new
|
|
5172
|
+
}, i.x ? new f.Vector3(i.x, i.y, i.z) : null, !0, i.d);
|
|
5173
5173
|
break;
|
|
5174
5174
|
case "handRight":
|
|
5175
5175
|
this.ikSolve({
|
|
@@ -5181,10 +5181,10 @@ class Be {
|
|
|
5181
5181
|
{ link: "RightForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -3, maxz: 0.5, maxAngle: 0.2 },
|
|
5182
5182
|
{ link: "RightArm", minx: -1.5, maxx: 1.5, miny: 0, maxy: 0, minz: -1, maxz: 3 }
|
|
5183
5183
|
]
|
|
5184
|
-
}, i.x ? new
|
|
5184
|
+
}, i.x ? new f.Vector3(i.x, i.y, i.z) : null, !0, i.d);
|
|
5185
5185
|
break;
|
|
5186
5186
|
}
|
|
5187
|
-
if ((h || r) && (
|
|
5187
|
+
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
5188
|
name: "headmove",
|
|
5189
5189
|
dt: [[1e3, 2e3], [1e3, 2e3, 1, 2], [1e3, 2e3], [1e3, 2e3, 1, 2]],
|
|
5190
5190
|
vs: {
|
|
@@ -5210,8 +5210,8 @@ class Be {
|
|
|
5210
5210
|
else {
|
|
5211
5211
|
if (this.cameraClock !== null && this.cameraClock < 1e3) {
|
|
5212
5212
|
this.cameraClock += e, this.cameraClock > 1e3 && (this.cameraClock = 1e3);
|
|
5213
|
-
let a = new
|
|
5214
|
-
a.phi += this.easing(this.cameraClock / 1e3) * (
|
|
5213
|
+
let a = new f.Spherical().setFromVector3(this.cameraStart), c = new f.Spherical().setFromVector3(this.cameraEnd);
|
|
5214
|
+
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
5215
|
}
|
|
5216
5216
|
this.controls.autoRotate && this.controls.update(), this.stats && this.stats.end(), this.render();
|
|
5217
5217
|
}
|
|
@@ -5273,48 +5273,48 @@ class Be {
|
|
|
5273
5273
|
speakText(t, e = null, n = null, i = null) {
|
|
5274
5274
|
e = e || {};
|
|
5275
5275
|
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 I = b ===
|
|
5280
|
-
let p =
|
|
5281
|
-
const M =
|
|
5282
|
-
if (p && !I && !M &&
|
|
5283
|
-
mark:
|
|
5276
|
+
let u = "", a = "", c = 0, d = [], g = [];
|
|
5277
|
+
const x = Array.from(this.segmenter.segment(t), (b) => b.segment);
|
|
5278
|
+
for (let b = 0; b < x.length; b++) {
|
|
5279
|
+
const I = b === x.length - 1, B = x[b].match(l);
|
|
5280
|
+
let p = x[b].match(s);
|
|
5281
|
+
const M = x[b].match(h), z = x[b].match(o);
|
|
5282
|
+
if (p && !I && !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 || I) && (a.length && (a = this.lipsyncPreProcessText(a, r), a.length && d.push({
|
|
5283
|
+
mark: c,
|
|
5284
5284
|
word: a
|
|
5285
5285
|
})), u.length && (g.push({
|
|
5286
|
-
mark:
|
|
5286
|
+
mark: c,
|
|
5287
5287
|
template: { name: "subtitles" },
|
|
5288
5288
|
ts: [0],
|
|
5289
5289
|
vs: {
|
|
5290
5290
|
subtitles: [u]
|
|
5291
5291
|
}
|
|
5292
5292
|
}), u = ""), a.length)) {
|
|
5293
|
-
const
|
|
5294
|
-
if (
|
|
5295
|
-
const E =
|
|
5296
|
-
for (let P = 0; P <
|
|
5293
|
+
const y = this.lipsyncWordsToVisemes(a, r);
|
|
5294
|
+
if (y && y.visemes && y.visemes.length) {
|
|
5295
|
+
const E = y.times[y.visemes.length - 1] + y.durations[y.visemes.length - 1];
|
|
5296
|
+
for (let P = 0; P < y.visemes.length; P++)
|
|
5297
5297
|
g.push({
|
|
5298
|
-
mark:
|
|
5298
|
+
mark: c,
|
|
5299
5299
|
template: { name: "viseme" },
|
|
5300
|
-
ts: [(
|
|
5300
|
+
ts: [(y.times[P] - 0.6) / E, (y.times[P] + 0.5) / E, (y.times[P] + y.durations[P] + 0.5) / E],
|
|
5301
5301
|
vs: {
|
|
5302
|
-
["viseme_" +
|
|
5302
|
+
["viseme_" + y.visemes[P]]: [null, y.visemes[P] === "PP" || y.visemes[P] === "FF" ? 0.9 : 0.6, 0]
|
|
5303
5303
|
}
|
|
5304
5304
|
});
|
|
5305
5305
|
}
|
|
5306
|
-
a = "",
|
|
5306
|
+
a = "", c++;
|
|
5307
5307
|
}
|
|
5308
5308
|
if (p || I) {
|
|
5309
|
-
if (
|
|
5310
|
-
const
|
|
5309
|
+
if (d.length || I && g.length) {
|
|
5310
|
+
const y = {
|
|
5311
5311
|
anim: g
|
|
5312
5312
|
};
|
|
5313
|
-
n && (
|
|
5313
|
+
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
5314
|
}
|
|
5315
5315
|
if (M) {
|
|
5316
|
-
let
|
|
5317
|
-
|
|
5316
|
+
let y = this.animEmojis[x[b]];
|
|
5317
|
+
y && y.link && (y = this.animEmojis[y.link]), y && this.speechQueue.push({ emoji: y });
|
|
5318
5318
|
}
|
|
5319
5319
|
this.speechQueue.push({ break: 100 });
|
|
5320
5320
|
}
|
|
@@ -5404,18 +5404,18 @@ class Be {
|
|
|
5404
5404
|
subtitles: [" " + h]
|
|
5405
5405
|
}
|
|
5406
5406
|
}), !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 I = r +
|
|
5407
|
+
const a = this.lipsyncPreProcessText(h, i), c = this.lipsyncWordsToVisemes(a, i);
|
|
5408
|
+
if (c && c.visemes && c.visemes.length) {
|
|
5409
|
+
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));
|
|
5410
|
+
let x = 0.6 + this.convertRange(g, [0, u], [0, 0.4]);
|
|
5411
|
+
if (u = Math.min(u, c.visemes.length * 200), d > 0)
|
|
5412
|
+
for (let b = 0; b < c.visemes.length; b++) {
|
|
5413
|
+
const I = r + c.times[b] / d * u, B = c.durations[b] / d * u;
|
|
5414
5414
|
o.push({
|
|
5415
5415
|
template: { name: "viseme" },
|
|
5416
|
-
ts: [I - Math.min(60, 2 *
|
|
5416
|
+
ts: [I - Math.min(60, 2 * B / 3), I + Math.min(25, B / 2), I + B + Math.min(60, B / 2)],
|
|
5417
5417
|
vs: {
|
|
5418
|
-
["viseme_" +
|
|
5418
|
+
["viseme_" + c.visemes[b]]: [null, c.visemes[b] === "PP" || c.visemes[b] === "FF" ? 0.9 : x, 0]
|
|
5419
5419
|
}
|
|
5420
5420
|
});
|
|
5421
5421
|
}
|
|
@@ -5498,31 +5498,31 @@ class Be {
|
|
|
5498
5498
|
const p = u.find((M) => M.name.includes(a) || M.lang === o);
|
|
5499
5499
|
p && (s.voice = p);
|
|
5500
5500
|
}
|
|
5501
|
-
const
|
|
5501
|
+
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
5502
|
console.log("Browser TTS Lip-sync Debug:", {
|
|
5503
5503
|
text: i,
|
|
5504
5504
|
lipsyncLang: g,
|
|
5505
|
-
processedText:
|
|
5505
|
+
processedText: x,
|
|
5506
5506
|
lipsyncData: b,
|
|
5507
5507
|
hasVisemes: b && b.visemes && b.visemes.length > 0,
|
|
5508
|
-
estimatedDuration:
|
|
5508
|
+
estimatedDuration: c
|
|
5509
5509
|
});
|
|
5510
5510
|
const I = [];
|
|
5511
5511
|
if (b && b.visemes && b.visemes.length > 0) {
|
|
5512
5512
|
const p = b.times[b.visemes.length - 1] + b.durations[b.visemes.length - 1];
|
|
5513
5513
|
for (let M = 0; M < b.visemes.length; M++) {
|
|
5514
|
-
const z = b.visemes[M],
|
|
5514
|
+
const z = b.visemes[M], y = b.times[M] / p, E = b.durations[M] / p, P = y * c, W = E * c;
|
|
5515
5515
|
I.push({
|
|
5516
5516
|
template: { name: "viseme" },
|
|
5517
|
-
ts: [P - Math.min(60, 2 *
|
|
5517
|
+
ts: [P - Math.min(60, 2 * W / 3), P + Math.min(25, W / 2), P + W + Math.min(60, W / 2)],
|
|
5518
5518
|
vs: {
|
|
5519
5519
|
["viseme_" + z]: [null, z === "PP" || z === "FF" ? 0.9 : 0.6, 0]
|
|
5520
5520
|
}
|
|
5521
5521
|
});
|
|
5522
5522
|
}
|
|
5523
5523
|
}
|
|
5524
|
-
const
|
|
5525
|
-
this.audioPlaylist.push({ anim:
|
|
5524
|
+
const B = [...t.anim, ...I];
|
|
5525
|
+
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
5526
|
e();
|
|
5527
5527
|
}, s.onerror = (p) => {
|
|
5528
5528
|
console.error("Speech synthesis error:", p.error), n(p.error);
|
|
@@ -5534,7 +5534,7 @@ class Be {
|
|
|
5534
5534
|
* @param {Object} line Speech line object
|
|
5535
5535
|
*/
|
|
5536
5536
|
async synthesizeWithElevenLabsTTS(t) {
|
|
5537
|
-
const e = t.text.map((
|
|
5537
|
+
const e = t.text.map((c) => c.word).join(" "), n = t.voice || this.avatar.ttsVoice || this.opt.ttsVoice || "21m00Tcm4TlvDq8ikWAM", i = {
|
|
5538
5538
|
text: e,
|
|
5539
5539
|
model_id: "eleven_monolingual_v1",
|
|
5540
5540
|
voice_settings: {
|
|
@@ -5564,18 +5564,18 @@ class Be {
|
|
|
5564
5564
|
lipsyncKeys: this.lipsync ? Object.keys(this.lipsync) : [],
|
|
5565
5565
|
lipsyncLang: h
|
|
5566
5566
|
});
|
|
5567
|
-
const
|
|
5567
|
+
const c = this.lipsyncPreProcessText(e, h), d = this.lipsyncWordsToVisemes(c, h);
|
|
5568
5568
|
if (console.log("Lip-sync data:", {
|
|
5569
|
-
processedText:
|
|
5570
|
-
lipsyncData:
|
|
5571
|
-
hasVisemes:
|
|
5572
|
-
}),
|
|
5569
|
+
processedText: c,
|
|
5570
|
+
lipsyncData: d,
|
|
5571
|
+
hasVisemes: d && d.visemes && d.visemes.length > 0
|
|
5572
|
+
}), d && d.visemes && d.visemes.length > 0)
|
|
5573
5573
|
r = {
|
|
5574
|
-
visemes:
|
|
5574
|
+
visemes: d.visemes.map((g, x) => ({
|
|
5575
5575
|
viseme: g,
|
|
5576
|
-
startTime:
|
|
5577
|
-
endTime: (
|
|
5578
|
-
duration: l.duration /
|
|
5576
|
+
startTime: x * l.duration / d.visemes.length,
|
|
5577
|
+
endTime: (x + 1) * l.duration / d.visemes.length,
|
|
5578
|
+
duration: l.duration / d.visemes.length,
|
|
5579
5579
|
intensity: 0.7
|
|
5580
5580
|
})),
|
|
5581
5581
|
words: [],
|
|
@@ -5584,17 +5584,17 @@ class Be {
|
|
|
5584
5584
|
};
|
|
5585
5585
|
else
|
|
5586
5586
|
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
|
|
5587
|
+
} catch (c) {
|
|
5588
|
+
console.error("Text-based lip-sync failed, using fallback:", c);
|
|
5589
|
+
const d = e.toLowerCase().split(/\s+/), g = [];
|
|
5590
|
+
for (const x of d)
|
|
5591
|
+
for (const b of x) {
|
|
5592
5592
|
let I = "aa";
|
|
5593
5593
|
"aeiou".includes(b) ? I = "aa" : "bp".includes(b) ? I = "PP" : "fv".includes(b) ? I = "FF" : "st".includes(b) ? I = "SS" : "dln".includes(b) ? I = "DD" : "kg".includes(b) ? I = "kk" : "rw".includes(b) && (I = "RR"), g.push(I);
|
|
5594
5594
|
}
|
|
5595
5595
|
r = {
|
|
5596
|
-
visemes: g.map((
|
|
5597
|
-
viseme:
|
|
5596
|
+
visemes: g.map((x, b) => ({
|
|
5597
|
+
viseme: x,
|
|
5598
5598
|
startTime: b * l.duration / g.length,
|
|
5599
5599
|
endTime: (b + 1) * l.duration / g.length,
|
|
5600
5600
|
duration: l.duration / g.length,
|
|
@@ -5620,13 +5620,13 @@ class Be {
|
|
|
5620
5620
|
const u = [];
|
|
5621
5621
|
if (r.visemes && r.visemes.length > 0) {
|
|
5622
5622
|
console.log("ElevenLabs: Generating lip-sync animation from", r.visemes.length, "visemes");
|
|
5623
|
-
for (let
|
|
5624
|
-
const
|
|
5623
|
+
for (let c = 0; c < r.visemes.length; c++) {
|
|
5624
|
+
const d = r.visemes[c], g = d.startTime * 1e3, x = d.duration * 1e3, b = d.intensity;
|
|
5625
5625
|
u.push({
|
|
5626
5626
|
template: { name: "viseme" },
|
|
5627
|
-
ts: [g - Math.min(60, 2 *
|
|
5627
|
+
ts: [g - Math.min(60, 2 * x / 3), g + Math.min(25, x / 2), g + x + Math.min(60, x / 2)],
|
|
5628
5628
|
vs: {
|
|
5629
|
-
["viseme_" +
|
|
5629
|
+
["viseme_" + d.viseme]: [null, b, 0]
|
|
5630
5630
|
}
|
|
5631
5631
|
});
|
|
5632
5632
|
}
|
|
@@ -5641,7 +5641,7 @@ class Be {
|
|
|
5641
5641
|
* @param {Object} line Speech line object
|
|
5642
5642
|
*/
|
|
5643
5643
|
async synthesizeWithDeepgramTTS(t) {
|
|
5644
|
-
const e = t.text.map((
|
|
5644
|
+
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
5645
|
method: "POST",
|
|
5646
5646
|
headers: {
|
|
5647
5647
|
Authorization: `Token ${this.opt.ttsApikey}`,
|
|
@@ -5662,18 +5662,18 @@ class Be {
|
|
|
5662
5662
|
lipsyncKeys: this.lipsync ? Object.keys(this.lipsync) : [],
|
|
5663
5663
|
lipsyncLang: h
|
|
5664
5664
|
});
|
|
5665
|
-
const
|
|
5665
|
+
const c = this.lipsyncPreProcessText(e, h), d = this.lipsyncWordsToVisemes(c, h);
|
|
5666
5666
|
if (console.log("Lip-sync data:", {
|
|
5667
|
-
processedText:
|
|
5668
|
-
lipsyncData:
|
|
5669
|
-
hasVisemes:
|
|
5670
|
-
}),
|
|
5667
|
+
processedText: c,
|
|
5668
|
+
lipsyncData: d,
|
|
5669
|
+
hasVisemes: d && d.visemes && d.visemes.length > 0
|
|
5670
|
+
}), d && d.visemes && d.visemes.length > 0)
|
|
5671
5671
|
r = {
|
|
5672
|
-
visemes:
|
|
5672
|
+
visemes: d.visemes.map((g, x) => ({
|
|
5673
5673
|
viseme: g,
|
|
5674
|
-
startTime:
|
|
5675
|
-
endTime: (
|
|
5676
|
-
duration: l.duration /
|
|
5674
|
+
startTime: x * l.duration / d.visemes.length,
|
|
5675
|
+
endTime: (x + 1) * l.duration / d.visemes.length,
|
|
5676
|
+
duration: l.duration / d.visemes.length,
|
|
5677
5677
|
intensity: 0.7
|
|
5678
5678
|
})),
|
|
5679
5679
|
words: [],
|
|
@@ -5682,17 +5682,17 @@ class Be {
|
|
|
5682
5682
|
};
|
|
5683
5683
|
else
|
|
5684
5684
|
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
|
|
5685
|
+
} catch (c) {
|
|
5686
|
+
console.error("Text-based lip-sync failed, using fallback:", c);
|
|
5687
|
+
const d = e.toLowerCase().split(/\s+/), g = [];
|
|
5688
|
+
for (const x of d)
|
|
5689
|
+
for (const b of x) {
|
|
5690
5690
|
let I = "aa";
|
|
5691
5691
|
"aeiou".includes(b) ? I = "aa" : "bp".includes(b) ? I = "PP" : "fv".includes(b) ? I = "FF" : "st".includes(b) ? I = "SS" : "dln".includes(b) ? I = "DD" : "kg".includes(b) ? I = "kk" : "rw".includes(b) && (I = "RR"), g.push(I);
|
|
5692
5692
|
}
|
|
5693
5693
|
r = {
|
|
5694
|
-
visemes: g.map((
|
|
5695
|
-
viseme:
|
|
5694
|
+
visemes: g.map((x, b) => ({
|
|
5695
|
+
viseme: x,
|
|
5696
5696
|
startTime: b * l.duration / g.length,
|
|
5697
5697
|
endTime: (b + 1) * l.duration / g.length,
|
|
5698
5698
|
duration: l.duration / g.length,
|
|
@@ -5718,13 +5718,13 @@ class Be {
|
|
|
5718
5718
|
const u = [];
|
|
5719
5719
|
if (r.visemes && r.visemes.length > 0) {
|
|
5720
5720
|
console.log("Deepgram: Generating lip-sync animation from", r.visemes.length, "visemes");
|
|
5721
|
-
for (let
|
|
5722
|
-
const
|
|
5721
|
+
for (let c = 0; c < r.visemes.length; c++) {
|
|
5722
|
+
const d = r.visemes[c], g = d.startTime * 1e3, x = d.duration * 1e3, b = d.intensity;
|
|
5723
5723
|
u.push({
|
|
5724
5724
|
template: { name: "viseme" },
|
|
5725
|
-
ts: [g - Math.min(60, 2 *
|
|
5725
|
+
ts: [g - Math.min(60, 2 * x / 3), g + Math.min(25, x / 2), g + x + Math.min(60, x / 2)],
|
|
5726
5726
|
vs: {
|
|
5727
|
-
["viseme_" +
|
|
5727
|
+
["viseme_" + d.viseme]: [null, b, 0]
|
|
5728
5728
|
}
|
|
5729
5729
|
});
|
|
5730
5730
|
}
|
|
@@ -5771,12 +5771,12 @@ class Be {
|
|
|
5771
5771
|
});
|
|
5772
5772
|
const r = [];
|
|
5773
5773
|
for (let a = 0; a < h.visemes.length; a++) {
|
|
5774
|
-
const
|
|
5774
|
+
const c = h.visemes[a], d = c.startTime * 1e3, g = c.duration * 1e3, x = c.intensity;
|
|
5775
5775
|
r.push({
|
|
5776
5776
|
template: { name: "viseme" },
|
|
5777
|
-
ts: [
|
|
5777
|
+
ts: [d - Math.min(60, 2 * g / 3), d + Math.min(25, g / 2), d + g + Math.min(60, g / 2)],
|
|
5778
5778
|
vs: {
|
|
5779
|
-
["viseme_" +
|
|
5779
|
+
["viseme_" + c.viseme]: [null, x, 0]
|
|
5780
5780
|
}
|
|
5781
5781
|
});
|
|
5782
5782
|
}
|
|
@@ -5822,25 +5822,25 @@ class Be {
|
|
|
5822
5822
|
this.speakWithHands();
|
|
5823
5823
|
const h = [0];
|
|
5824
5824
|
let r = 0;
|
|
5825
|
-
t.text.forEach((
|
|
5826
|
-
if (
|
|
5825
|
+
t.text.forEach((c, d) => {
|
|
5826
|
+
if (d > 0) {
|
|
5827
5827
|
let g = h[h.length - 1];
|
|
5828
|
-
s.timepoints[r] && (g = s.timepoints[r].timeSeconds * 1e3, s.timepoints[r].markName === "" +
|
|
5828
|
+
s.timepoints[r] && (g = s.timepoints[r].timeSeconds * 1e3, s.timepoints[r].markName === "" + c.mark && r++), h.push(g);
|
|
5829
5829
|
}
|
|
5830
5830
|
});
|
|
5831
5831
|
const u = [{ mark: 0, time: 0 }];
|
|
5832
|
-
h.forEach((
|
|
5833
|
-
if (
|
|
5834
|
-
let g =
|
|
5835
|
-
u[
|
|
5832
|
+
h.forEach((c, d) => {
|
|
5833
|
+
if (d > 0) {
|
|
5834
|
+
let g = c - h[d - 1];
|
|
5835
|
+
u[d - 1].duration = g, u.push({ mark: d, time: c });
|
|
5836
5836
|
}
|
|
5837
5837
|
});
|
|
5838
5838
|
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
|
-
|
|
5839
|
+
a > this.opt.ttsTrimEnd && (a = a - this.opt.ttsTrimEnd), u[u.length - 1].duration = a - u[u.length - 1].time, t.anim.forEach((c) => {
|
|
5840
|
+
const d = u[c.mark];
|
|
5841
|
+
if (d)
|
|
5842
|
+
for (let g = 0; g < c.ts.length; g++)
|
|
5843
|
+
c.ts[g] = d.time + c.ts[g] * d.duration + this.opt.ttsTrimStart;
|
|
5844
5844
|
}), this.audioPlaylist.push({ anim: t.anim, audio: l }), this.onSubtitles = t.onSubtitles || null, this.resetLips(), t.mood && this.setMood(t.mood), this.playAudio();
|
|
5845
5845
|
} else
|
|
5846
5846
|
this.startSpeaking(!0);
|
|
@@ -6059,15 +6059,15 @@ class Be {
|
|
|
6059
6059
|
const l = this.streamLipsyncLang || this.avatar.lipsyncLang || this.opt.lipsyncLang, h = this.lipsyncPreProcessText(i, l), r = this.lipsyncWordsToVisemes(h, l);
|
|
6060
6060
|
if (r && r.visemes && r.visemes.length) {
|
|
6061
6061
|
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
|
|
6062
|
+
let c = 0.6 + this.convertRange(a, [0, o], [0, 0.4]);
|
|
6063
6063
|
if (o = Math.min(o, r.visemes.length * 200), u > 0)
|
|
6064
|
-
for (let
|
|
6065
|
-
const g = e + s + r.times[
|
|
6064
|
+
for (let d = 0; d < r.visemes.length; d++) {
|
|
6065
|
+
const g = e + s + r.times[d] / u * o, x = r.durations[d] / u * o;
|
|
6066
6066
|
this.animQueue.push({
|
|
6067
6067
|
template: { name: "viseme" },
|
|
6068
|
-
ts: [g - Math.min(60, 2 *
|
|
6068
|
+
ts: [g - Math.min(60, 2 * x / 3), g + Math.min(25, x / 2), g + x + Math.min(60, x / 2)],
|
|
6069
6069
|
vs: {
|
|
6070
|
-
["viseme_" + r.visemes[
|
|
6070
|
+
["viseme_" + r.visemes[d]]: [null, r.visemes[d] === "PP" || r.visemes[d] === "FF" ? 0.9 : c, 0]
|
|
6071
6071
|
}
|
|
6072
6072
|
});
|
|
6073
6073
|
}
|
|
@@ -6158,7 +6158,7 @@ class Be {
|
|
|
6158
6158
|
*/
|
|
6159
6159
|
lookAtCamera(t) {
|
|
6160
6160
|
let e;
|
|
6161
|
-
if (this.speakTo && (e = new
|
|
6161
|
+
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), Re.setFromMatrixPosition(this.speakTo.objectRightEye.matrixWorld), e.addVectors(ve, Re).divideScalar(2)) : this.speakTo.isObject3D ? this.speakTo.getWorldPosition(e) : this.speakTo.isVector3 ? e.set(this.speakTo) : this.speakTo.x && this.speakTo.y && this.speakTo.z && e.set(this.speakTo.x, this.speakTo.y, this.speakTo.z)), !e) {
|
|
6162
6162
|
if (this.avatar.hasOwnProperty("avatarIgnoreCamera")) {
|
|
6163
6163
|
if (this.avatar.avatarIgnoreCamera) {
|
|
6164
6164
|
this.lookAhead(t);
|
|
@@ -6172,21 +6172,21 @@ class Be {
|
|
|
6172
6172
|
return;
|
|
6173
6173
|
}
|
|
6174
6174
|
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0), ve.setFromMatrixPosition(this.objectLeftEye.matrixWorld), Re.setFromMatrixPosition(this.objectRightEye.matrixWorld), ve.add(Re).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"]);
|
|
6175
|
-
const n = new
|
|
6176
|
-
|
|
6177
|
-
const l = new
|
|
6178
|
-
|
|
6179
|
-
let r =
|
|
6175
|
+
const n = new f.Vector3().subVectors(e, ve).normalize(), i = Math.atan2(n.x, n.z), s = Math.asin(-n.y);
|
|
6176
|
+
V.set(s, i, 0, "YXZ");
|
|
6177
|
+
const l = new f.Quaternion().setFromEuler(V), h = new f.Quaternion().copy(l).multiply(Q.clone().invert());
|
|
6178
|
+
V.setFromQuaternion(h, "YXZ");
|
|
6179
|
+
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
6180
|
if (t) {
|
|
6181
|
-
let
|
|
6182
|
-
|
|
6181
|
+
let x = this.animQueue.findIndex((I) => I.template.name === "lookat");
|
|
6182
|
+
x !== -1 && this.animQueue.splice(x, 1);
|
|
6183
6183
|
const b = {
|
|
6184
6184
|
name: "lookat",
|
|
6185
6185
|
dt: [750, t],
|
|
6186
6186
|
vs: {
|
|
6187
|
-
bodyRotateX: [a +
|
|
6188
|
-
bodyRotateY: [
|
|
6189
|
-
eyesRotateX: [-3 *
|
|
6187
|
+
bodyRotateX: [a + d],
|
|
6188
|
+
bodyRotateY: [c + g],
|
|
6189
|
+
eyesRotateX: [-3 * d + 0.1],
|
|
6190
6190
|
eyesRotateY: [-5 * g],
|
|
6191
6191
|
browInnerUp: [[0, 0.7]],
|
|
6192
6192
|
mouthLeft: [[0, 0.7]],
|
|
@@ -6208,23 +6208,23 @@ class Be {
|
|
|
6208
6208
|
if (!this.camera) return;
|
|
6209
6209
|
const i = this.nodeAvatar.getBoundingClientRect();
|
|
6210
6210
|
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0);
|
|
6211
|
-
const s = new
|
|
6211
|
+
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
6212
|
l.project(this.camera);
|
|
6213
6213
|
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 =
|
|
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"]), V.setFromQuaternion(Q);
|
|
6215
|
+
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, I = this.convertRange(t, [h - g, h + g], [-0.8, 0.8]) - a + d;
|
|
6216
6216
|
b = Math.min(0.6, Math.max(-0.3, b)), I = Math.min(0.8, Math.max(-0.8, I));
|
|
6217
|
-
let
|
|
6217
|
+
let B = (Math.random() - 0.5) / 4, p = (Math.random() - 0.5) / 4;
|
|
6218
6218
|
if (n) {
|
|
6219
|
-
let M = this.animQueue.findIndex((
|
|
6219
|
+
let M = this.animQueue.findIndex((y) => y.template.name === "lookat");
|
|
6220
6220
|
M !== -1 && this.animQueue.splice(M, 1);
|
|
6221
6221
|
const z = {
|
|
6222
6222
|
name: "lookat",
|
|
6223
6223
|
dt: [750, n],
|
|
6224
6224
|
vs: {
|
|
6225
|
-
bodyRotateX: [b +
|
|
6225
|
+
bodyRotateX: [b + B],
|
|
6226
6226
|
bodyRotateY: [I + p],
|
|
6227
|
-
eyesRotateX: [-3 *
|
|
6227
|
+
eyesRotateX: [-3 * B + 0.1],
|
|
6228
6228
|
eyesRotateY: [-5 * p],
|
|
6229
6229
|
browInnerUp: [[0, 0.7]],
|
|
6230
6230
|
mouthLeft: [[0, 0.7]],
|
|
@@ -6244,14 +6244,14 @@ class Be {
|
|
|
6244
6244
|
*/
|
|
6245
6245
|
touchAt(t, e) {
|
|
6246
6246
|
if (!this.camera) return;
|
|
6247
|
-
const n = this.nodeAvatar.getBoundingClientRect(), i = new
|
|
6247
|
+
const n = this.nodeAvatar.getBoundingClientRect(), i = new f.Vector2(
|
|
6248
6248
|
(t - n.left) / n.width * 2 - 1,
|
|
6249
6249
|
-((e - n.top) / n.height) * 2 + 1
|
|
6250
|
-
), s = new
|
|
6250
|
+
), s = new f.Raycaster();
|
|
6251
6251
|
s.setFromCamera(i, this.camera);
|
|
6252
6252
|
const o = s.intersectObject(this.armature);
|
|
6253
6253
|
if (o.length > 0) {
|
|
6254
|
-
const l = o[0].point, h = new
|
|
6254
|
+
const l = o[0].point, h = new f.Vector3(), r = new f.Vector3();
|
|
6255
6255
|
this.objectLeftArm.getWorldPosition(h), this.objectRightArm.getWorldPosition(r);
|
|
6256
6256
|
const u = h.distanceToSquared(l), a = r.distanceToSquared(l);
|
|
6257
6257
|
u < a ? (this.ikSolve({
|
|
@@ -6295,7 +6295,7 @@ class Be {
|
|
|
6295
6295
|
{ link: "LeftForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -0.5, maxz: 3 },
|
|
6296
6296
|
{ link: "LeftArm", minx: -1.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -1, maxz: 3 }
|
|
6297
6297
|
]
|
|
6298
|
-
}, new
|
|
6298
|
+
}, new f.Vector3(
|
|
6299
6299
|
this.gaussianRandom(0, 0.5),
|
|
6300
6300
|
this.gaussianRandom(-0.8, -0.2),
|
|
6301
6301
|
this.gaussianRandom(0, 0.5)
|
|
@@ -6307,15 +6307,15 @@ class Be {
|
|
|
6307
6307
|
{ link: "RightForeArm", minx: -0.5, maxx: 1.5, miny: -1.5, maxy: 1.5, minz: -3, maxz: 0.5 },
|
|
6308
6308
|
{ link: "RightArm" }
|
|
6309
6309
|
]
|
|
6310
|
-
}, new
|
|
6310
|
+
}, new f.Vector3(
|
|
6311
6311
|
this.gaussianRandom(-0.5, 0),
|
|
6312
6312
|
this.gaussianRandom(-0.8, -0.2),
|
|
6313
6313
|
this.gaussianRandom(0, 0.5)
|
|
6314
6314
|
), !0);
|
|
6315
6315
|
const n = [], i = [];
|
|
6316
6316
|
n.push(100 + Math.round(Math.random() * 500)), i.push({ duration: 1e3, props: {
|
|
6317
|
-
"LeftHand.quaternion": new
|
|
6318
|
-
"RightHand.quaternion": new
|
|
6317
|
+
"LeftHand.quaternion": new f.Quaternion().setFromEuler(new f.Euler(0, -1 - Math.random(), 0)),
|
|
6318
|
+
"RightHand.quaternion": new f.Quaternion().setFromEuler(new f.Euler(0, 1 + Math.random(), 0))
|
|
6319
6319
|
} }), ["LeftArm", "LeftForeArm", "RightArm", "RightForeArm"].forEach((o) => {
|
|
6320
6320
|
i[0].props[o + ".quaternion"] = this.ikMesh.getObjectByName(o).quaternion.clone();
|
|
6321
6321
|
}), n.push(1e3 + Math.round(Math.random() * 500)), i.push({ duration: 2e3, props: {} }), ["LeftArm", "LeftForeArm", "RightArm", "RightForeArm", "LeftHand", "RightHand"].forEach((o) => {
|
|
@@ -6392,6 +6392,29 @@ class Be {
|
|
|
6392
6392
|
* @param {number} [ndx=0] Index of the clip
|
|
6393
6393
|
* @param {number} [scale=0.01] Position scale factor
|
|
6394
6394
|
*/
|
|
6395
|
+
/**
|
|
6396
|
+
* Get all bone names from the avatar's armature
|
|
6397
|
+
* @returns {Set<string>} Set of bone names
|
|
6398
|
+
*/
|
|
6399
|
+
getAvailableBoneNames() {
|
|
6400
|
+
const t = /* @__PURE__ */ new Set();
|
|
6401
|
+
return this.armature && this.armature.traverse((e) => {
|
|
6402
|
+
(e.isBone || e.type === "Bone") && t.add(e.name);
|
|
6403
|
+
}), t;
|
|
6404
|
+
}
|
|
6405
|
+
/**
|
|
6406
|
+
* Filter animation tracks to only include bones that exist in the avatar
|
|
6407
|
+
* @param {THREE.AnimationClip} clip - Animation clip to filter
|
|
6408
|
+
* @param {Set<string>} availableBones - Set of available bone names
|
|
6409
|
+
* @returns {THREE.AnimationClip} Filtered animation clip
|
|
6410
|
+
*/
|
|
6411
|
+
filterAnimationTracks(t, e) {
|
|
6412
|
+
const n = [], i = /* @__PURE__ */ new Set();
|
|
6413
|
+
return t.tracks.forEach((s) => {
|
|
6414
|
+
const l = s.name.split(".")[0];
|
|
6415
|
+
e.has(l) ? n.push(s) : i.add(l);
|
|
6416
|
+
}), 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);
|
|
6417
|
+
}
|
|
6395
6418
|
async playAnimation(t, e = null, n = 10, i = 0, s = 0.01, o = !1) {
|
|
6396
6419
|
if (!this.armature) return;
|
|
6397
6420
|
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 +6423,9 @@ class Be {
|
|
|
6400
6423
|
let h = this.animQueue.find((a) => a.template.name === "pose");
|
|
6401
6424
|
h && (h.ts[0] = 1 / 0), Object.entries(l.pose.props).forEach((a) => {
|
|
6402
6425
|
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
|
|
6426
|
+
}), 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
6427
|
const r = Math.ceil(n / l.clip.duration), u = this.mixer.clipAction(l.clip);
|
|
6405
|
-
u.setLoop(
|
|
6428
|
+
u.setLoop(f.LoopRepeat, r), u.clampWhenFinished = !0, this.currentFBXAction = u;
|
|
6406
6429
|
try {
|
|
6407
6430
|
u.fadeIn(0.5).play(), console.log("FBX animation started successfully:", t);
|
|
6408
6431
|
} catch (a) {
|
|
@@ -6420,58 +6443,64 @@ class Be {
|
|
|
6420
6443
|
}
|
|
6421
6444
|
let r = !1;
|
|
6422
6445
|
try {
|
|
6423
|
-
const
|
|
6424
|
-
if (r =
|
|
6425
|
-
console.error(`FBX file not found at ${t}. Status: ${
|
|
6446
|
+
const c = await fetch(t, { method: "HEAD" });
|
|
6447
|
+
if (r = c.ok, !r) {
|
|
6448
|
+
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
6449
|
return;
|
|
6427
6450
|
}
|
|
6428
|
-
} catch (
|
|
6429
|
-
console.warn(`Could not verify file existence for ${t}, attempting to load anyway:`,
|
|
6451
|
+
} catch (c) {
|
|
6452
|
+
console.warn(`Could not verify file existence for ${t}, attempting to load anyway:`, c);
|
|
6430
6453
|
}
|
|
6431
|
-
const u = new
|
|
6454
|
+
const u = new Oe();
|
|
6432
6455
|
let a;
|
|
6433
6456
|
try {
|
|
6434
6457
|
a = await u.loadAsync(t, e);
|
|
6435
|
-
} catch (
|
|
6436
|
-
console.error(`Failed to load FBX animation from ${t}:`,
|
|
6437
|
-
message:
|
|
6458
|
+
} catch (c) {
|
|
6459
|
+
console.error(`Failed to load FBX animation from ${t}:`, c), console.error("Error details:", {
|
|
6460
|
+
message: c.message,
|
|
6438
6461
|
url: t,
|
|
6439
6462
|
suggestion: "Make sure the file is a valid FBX file and the path is correct"
|
|
6440
|
-
}),
|
|
6463
|
+
}), 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
6464
|
try {
|
|
6442
|
-
const
|
|
6465
|
+
const d = await fetch(t), g = d.headers.get("content-type"), x = await d.text();
|
|
6443
6466
|
console.error("Response details:", {
|
|
6444
|
-
status:
|
|
6467
|
+
status: d.status,
|
|
6445
6468
|
contentType: g,
|
|
6446
|
-
firstBytes:
|
|
6447
|
-
isHTML:
|
|
6448
|
-
}), (
|
|
6449
|
-
} catch (
|
|
6450
|
-
console.error("Could not fetch file for debugging:",
|
|
6469
|
+
firstBytes: x.substring(0, 100),
|
|
6470
|
+
isHTML: x.trim().startsWith("<!DOCTYPE") || x.trim().startsWith("<html")
|
|
6471
|
+
}), (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.");
|
|
6472
|
+
} catch (d) {
|
|
6473
|
+
console.error("Could not fetch file for debugging:", d);
|
|
6451
6474
|
}
|
|
6452
6475
|
return;
|
|
6453
6476
|
}
|
|
6454
6477
|
if (a && a.animations && a.animations[i]) {
|
|
6455
|
-
let
|
|
6456
|
-
const
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6478
|
+
let c = a.animations[i];
|
|
6479
|
+
const d = this.getAvailableBoneNames(), g = this.filterAnimationTracks(c, d);
|
|
6480
|
+
if (!g) {
|
|
6481
|
+
console.error(`Cannot play FBX animation "${t}": No compatible bones found.`);
|
|
6482
|
+
return;
|
|
6483
|
+
}
|
|
6484
|
+
c = g;
|
|
6485
|
+
const x = {};
|
|
6486
|
+
c.tracks.forEach((I) => {
|
|
6487
|
+
I.name = I.name.replaceAll("mixamorig", "");
|
|
6488
|
+
const B = I.name.split(".");
|
|
6489
|
+
if (B[1] === "position") {
|
|
6490
|
+
for (let p = 0; p < I.values.length; p++)
|
|
6491
|
+
I.values[p] = I.values[p] * s;
|
|
6492
|
+
x[I.name] = new f.Vector3(I.values[0], I.values[1], I.values[2]);
|
|
6493
|
+
} else B[1] === "quaternion" ? x[I.name] = new f.Quaternion(I.values[0], I.values[1], I.values[2], I.values[3]) : B[1] === "rotation" && (x[B[0] + ".quaternion"] = new f.Quaternion().setFromEuler(new f.Euler(I.values[0], I.values[1], I.values[2], "XYZ")).normalize());
|
|
6465
6494
|
});
|
|
6466
|
-
const
|
|
6467
|
-
|
|
6495
|
+
const b = { props: x };
|
|
6496
|
+
x["Hips.position"] && (x["Hips.position"].y < 0.5 ? b.lying = !0 : b.standing = !0), this.animClips.push({
|
|
6468
6497
|
url: t + "-" + i,
|
|
6469
|
-
clip:
|
|
6470
|
-
pose:
|
|
6498
|
+
clip: c,
|
|
6499
|
+
pose: b
|
|
6471
6500
|
}), this.playAnimation(t, e, n, i, s);
|
|
6472
6501
|
} else {
|
|
6473
|
-
const
|
|
6474
|
-
console.error(
|
|
6502
|
+
const c = "Animation " + t + " (ndx=" + i + ") not found";
|
|
6503
|
+
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
6504
|
}
|
|
6476
6505
|
}
|
|
6477
6506
|
}
|
|
@@ -6505,14 +6534,14 @@ class Be {
|
|
|
6505
6534
|
let l = this.animQueue.find((h) => h.template.name === "pose");
|
|
6506
6535
|
l && (l.ts[0] = this.animClock + n * 1e3 + 2e3), this.setPoseFromTemplate(o);
|
|
6507
6536
|
} else {
|
|
6508
|
-
let h = await new
|
|
6537
|
+
let h = await new Oe().loadAsync(t, e);
|
|
6509
6538
|
if (h && h.animations && h.animations[i]) {
|
|
6510
6539
|
let r = h.animations[i];
|
|
6511
6540
|
const u = {};
|
|
6512
|
-
r.tracks.forEach((
|
|
6513
|
-
|
|
6514
|
-
const
|
|
6515
|
-
|
|
6541
|
+
r.tracks.forEach((c) => {
|
|
6542
|
+
c.name = c.name.replaceAll("mixamorig", "");
|
|
6543
|
+
const d = c.name.split(".");
|
|
6544
|
+
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
6545
|
});
|
|
6517
6546
|
const a = { props: u };
|
|
6518
6547
|
u["Hips.position"] && (u["Hips.position"].y < 0.5 ? a.lying = !0 : a.standing = !0), this.animPoses.push({
|
|
@@ -6545,7 +6574,7 @@ class Be {
|
|
|
6545
6574
|
if (s) {
|
|
6546
6575
|
this.gestureTimeout && (clearTimeout(this.gestureTimeout), this.gestureTimeout = null);
|
|
6547
6576
|
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
|
|
6577
|
+
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
6578
|
for (let [h, r] of Object.entries(this.gesture))
|
|
6550
6579
|
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
6580
|
e && Number.isFinite(e) && (this.gestureTimeout = setTimeout(this.stopGesture.bind(this, i), 1e3 * e));
|
|
@@ -6557,13 +6586,13 @@ class Be {
|
|
|
6557
6586
|
if (l.gesture = !0, e && Number.isFinite(e)) {
|
|
6558
6587
|
const h = l.ts[0], u = l.ts[l.ts.length - 1] - h;
|
|
6559
6588
|
if (e * 1e3 - u > 0) {
|
|
6560
|
-
const
|
|
6561
|
-
for (let
|
|
6562
|
-
const
|
|
6563
|
-
l.ts = l.ts.map((
|
|
6589
|
+
const c = [];
|
|
6590
|
+
for (let x = 1; x < l.ts.length; x++) c.push(l.ts[x] - l.ts[x - 1]);
|
|
6591
|
+
const d = o.template?.rescale || c.map((x) => x / u), g = e * 1e3 - u;
|
|
6592
|
+
l.ts = l.ts.map((x, b, I) => b === 0 ? h : I[b - 1] + c[b - 1] + d[b - 1] * g);
|
|
6564
6593
|
} else {
|
|
6565
|
-
const
|
|
6566
|
-
l.ts = l.ts.map((
|
|
6594
|
+
const c = e * 1e3 / u;
|
|
6595
|
+
l.ts = l.ts.map((d) => h + c * (d - h));
|
|
6567
6596
|
}
|
|
6568
6597
|
}
|
|
6569
6598
|
this.animQueue.push(l);
|
|
@@ -6593,33 +6622,33 @@ class Be {
|
|
|
6593
6622
|
* @param {numeric} [d=null] If set, apply in d milliseconds
|
|
6594
6623
|
*/
|
|
6595
6624
|
ikSolve(t, e = null, n = !1, i = null) {
|
|
6596
|
-
const s = new
|
|
6597
|
-
|
|
6598
|
-
const g = this.ikMesh.getObjectByName(t.effector),
|
|
6599
|
-
|
|
6625
|
+
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);
|
|
6626
|
+
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);
|
|
6627
|
+
const g = this.ikMesh.getObjectByName(t.effector), x = t.links;
|
|
6628
|
+
x.forEach((I) => {
|
|
6600
6629
|
I.bone = this.ikMesh.getObjectByName(I.link), I.bone.quaternion.copy(this.getPoseTemplateProp(I.link + ".quaternion"));
|
|
6601
|
-
}),
|
|
6630
|
+
}), d.updateMatrixWorld(!0);
|
|
6602
6631
|
const b = t.iterations || 10;
|
|
6603
6632
|
if (e)
|
|
6604
6633
|
for (let I = 0; I < b; I++) {
|
|
6605
|
-
let
|
|
6606
|
-
for (let p = 0, M =
|
|
6607
|
-
const z =
|
|
6634
|
+
let B = !1;
|
|
6635
|
+
for (let p = 0, M = x.length; p < M; p++) {
|
|
6636
|
+
const z = x[p].bone;
|
|
6608
6637
|
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),
|
|
6638
|
+
let y = s.dot(l);
|
|
6639
|
+
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(
|
|
6640
|
+
x[p].minx !== void 0 ? x[p].minx : -1 / 0,
|
|
6641
|
+
x[p].miny !== void 0 ? x[p].miny : -1 / 0,
|
|
6642
|
+
x[p].minz !== void 0 ? x[p].minz : -1 / 0
|
|
6643
|
+
), new f.Vector3(
|
|
6644
|
+
x[p].maxx !== void 0 ? x[p].maxx : 1 / 0,
|
|
6645
|
+
x[p].maxy !== void 0 ? x[p].maxy : 1 / 0,
|
|
6646
|
+
x[p].maxz !== void 0 ? x[p].maxz : 1 / 0
|
|
6647
|
+
))), z.updateMatrixWorld(!0), B = !0);
|
|
6619
6648
|
}
|
|
6620
|
-
if (!
|
|
6649
|
+
if (!B) break;
|
|
6621
6650
|
}
|
|
6622
|
-
i &&
|
|
6651
|
+
i && x.forEach((I) => {
|
|
6623
6652
|
this.poseTarget.props[I.link + ".quaternion"].copy(I.bone.quaternion), this.poseTarget.props[I.link + ".quaternion"].t = this.animClock, this.poseTarget.props[I.link + ".quaternion"].d = i;
|
|
6624
6653
|
});
|
|
6625
6654
|
}
|
|
@@ -6679,7 +6708,7 @@ function Fe() {
|
|
|
6679
6708
|
voices: Ie.voices
|
|
6680
6709
|
};
|
|
6681
6710
|
}
|
|
6682
|
-
function
|
|
6711
|
+
function St() {
|
|
6683
6712
|
const G = Fe(), t = [];
|
|
6684
6713
|
return Object.entries(G.voices).forEach(([e, n]) => {
|
|
6685
6714
|
t.push({
|
|
@@ -6702,15 +6731,15 @@ const Ve = Me(({
|
|
|
6702
6731
|
cameraView: u = "upper",
|
|
6703
6732
|
onReady: a = () => {
|
|
6704
6733
|
},
|
|
6705
|
-
onLoading:
|
|
6734
|
+
onLoading: c = () => {
|
|
6706
6735
|
},
|
|
6707
|
-
onError:
|
|
6736
|
+
onError: d = () => {
|
|
6708
6737
|
},
|
|
6709
6738
|
className: g = "",
|
|
6710
|
-
style:
|
|
6739
|
+
style: x = {},
|
|
6711
6740
|
animations: b = {}
|
|
6712
6741
|
}, I) => {
|
|
6713
|
-
const
|
|
6742
|
+
const B = O(null), p = O(null), M = O(r), z = O(null), y = O(null), E = O(!1), P = O({ remainingText: null, originalText: null, options: null }), W = O([]), oe = O(0), [k, Z] = ce(!0), [K, X] = ce(null), [$, se] = ce(!1), [ae, pe] = ce(!1);
|
|
6714
6743
|
de(() => {
|
|
6715
6744
|
E.current = ae;
|
|
6716
6745
|
}, [ae]), de(() => {
|
|
@@ -6756,24 +6785,24 @@ const Ve = Me(({
|
|
|
6756
6785
|
ttsService: le,
|
|
6757
6786
|
lipsyncModules: ["en"],
|
|
6758
6787
|
cameraView: u
|
|
6759
|
-
},
|
|
6760
|
-
if (!(!
|
|
6788
|
+
}, S = T(async () => {
|
|
6789
|
+
if (!(!B.current || p.current))
|
|
6761
6790
|
try {
|
|
6762
|
-
if (Z(!0), X(null), p.current = new Be(
|
|
6763
|
-
if (
|
|
6764
|
-
const J = Math.min(100, Math.round(
|
|
6765
|
-
|
|
6791
|
+
if (Z(!0), X(null), p.current = new Be(B.current, R), p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1), b && Object.keys(b).length > 0 && (p.current.customAnimations = b), await p.current.showAvatar(v, (N) => {
|
|
6792
|
+
if (N.lengthComputable) {
|
|
6793
|
+
const J = Math.min(100, Math.round(N.loaded / N.total * 100));
|
|
6794
|
+
c(J);
|
|
6766
6795
|
}
|
|
6767
|
-
}), await new Promise((
|
|
6796
|
+
}), await new Promise((N) => {
|
|
6768
6797
|
const J = () => {
|
|
6769
|
-
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ?
|
|
6798
|
+
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? N() : setTimeout(J, 100);
|
|
6770
6799
|
};
|
|
6771
6800
|
J();
|
|
6772
6801
|
}), p.current && p.current.setShowFullAvatar)
|
|
6773
6802
|
try {
|
|
6774
6803
|
p.current.setShowFullAvatar(r);
|
|
6775
|
-
} catch (
|
|
6776
|
-
console.warn("Error setting full body mode on initialization:",
|
|
6804
|
+
} catch (N) {
|
|
6805
|
+
console.warn("Error setting full body mode on initialization:", N);
|
|
6777
6806
|
}
|
|
6778
6807
|
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
6808
|
const F = () => {
|
|
@@ -6783,18 +6812,18 @@ const Ve = Me(({
|
|
|
6783
6812
|
document.removeEventListener("visibilitychange", F);
|
|
6784
6813
|
};
|
|
6785
6814
|
} catch (L) {
|
|
6786
|
-
console.error("Error initializing TalkingHead:", L), X(L.message || "Failed to initialize avatar"), Z(!1),
|
|
6815
|
+
console.error("Error initializing TalkingHead:", L), X(L.message || "Failed to initialize avatar"), Z(!1), d(L);
|
|
6787
6816
|
}
|
|
6788
6817
|
}, [G, t, e, n, i, s, o, r, l, h, u]);
|
|
6789
|
-
de(() => (
|
|
6818
|
+
de(() => (S(), () => {
|
|
6790
6819
|
p.current && (p.current.stop(), p.current.dispose(), p.current = null);
|
|
6791
|
-
}), [
|
|
6792
|
-
if (!
|
|
6793
|
-
const L = new ResizeObserver((
|
|
6794
|
-
for (const J of
|
|
6820
|
+
}), [S]), de(() => {
|
|
6821
|
+
if (!B.current || !p.current) return;
|
|
6822
|
+
const L = new ResizeObserver((N) => {
|
|
6823
|
+
for (const J of N)
|
|
6795
6824
|
p.current && p.current.onResize && p.current.onResize();
|
|
6796
6825
|
});
|
|
6797
|
-
L.observe(
|
|
6826
|
+
L.observe(B.current);
|
|
6798
6827
|
const F = () => {
|
|
6799
6828
|
p.current && p.current.onResize && p.current.onResize();
|
|
6800
6829
|
};
|
|
@@ -6809,39 +6838,39 @@ const Ve = Me(({
|
|
|
6809
6838
|
} catch (L) {
|
|
6810
6839
|
console.warn("Failed to resume audio context:", L);
|
|
6811
6840
|
}
|
|
6812
|
-
}, []),
|
|
6841
|
+
}, []), U = T(async (L, F = {}) => {
|
|
6813
6842
|
if (p.current && $)
|
|
6814
6843
|
try {
|
|
6815
|
-
|
|
6816
|
-
const
|
|
6817
|
-
|
|
6844
|
+
y.current && (clearInterval(y.current), y.current = null), z.current = { text: L, options: F }, P.current = { remainingText: null, originalText: null, options: null };
|
|
6845
|
+
const N = /[!\.\?\n\p{Extended_Pictographic}]/ug, J = L.split(N).map((Y) => Y.trim()).filter((Y) => Y.length > 0);
|
|
6846
|
+
W.current = J, oe.current = 0, pe(!1), E.current = !1, await H();
|
|
6818
6847
|
const ge = {
|
|
6819
6848
|
...F,
|
|
6820
6849
|
lipsyncLang: F.lipsyncLang || v.lipsyncLang || "en"
|
|
6821
6850
|
};
|
|
6822
6851
|
if (F.onSpeechEnd && p.current) {
|
|
6823
6852
|
const Y = p.current;
|
|
6824
|
-
let he = null,
|
|
6853
|
+
let he = null, ke = 0;
|
|
6825
6854
|
const Ae = 1200;
|
|
6826
6855
|
let be = !1;
|
|
6827
6856
|
he = setInterval(() => {
|
|
6828
|
-
if (
|
|
6857
|
+
if (ke++, E.current)
|
|
6829
6858
|
return;
|
|
6830
|
-
if (
|
|
6831
|
-
if (he && (clearInterval(he), he = null,
|
|
6859
|
+
if (ke > Ae) {
|
|
6860
|
+
if (he && (clearInterval(he), he = null, y.current = null), !be && !E.current) {
|
|
6832
6861
|
be = !0;
|
|
6833
6862
|
try {
|
|
6834
6863
|
F.onSpeechEnd();
|
|
6835
|
-
} catch (
|
|
6836
|
-
console.error("Error in onSpeechEnd callback (timeout):",
|
|
6864
|
+
} catch (Ne) {
|
|
6865
|
+
console.error("Error in onSpeechEnd callback (timeout):", Ne);
|
|
6837
6866
|
}
|
|
6838
6867
|
}
|
|
6839
6868
|
return;
|
|
6840
6869
|
}
|
|
6841
|
-
const ye = !Y.speechQueue || Y.speechQueue.length === 0,
|
|
6842
|
-
Y && Y.isSpeaking === !1 && ye &&
|
|
6870
|
+
const ye = !Y.speechQueue || Y.speechQueue.length === 0, Se = !Y.audioPlaylist || Y.audioPlaylist.length === 0;
|
|
6871
|
+
Y && Y.isSpeaking === !1 && ye && Se && Y.isAudioPlaying === !1 && !be && !E.current && setTimeout(() => {
|
|
6843
6872
|
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,
|
|
6873
|
+
be = !0, he && (clearInterval(he), he = null, y.current = null);
|
|
6845
6874
|
try {
|
|
6846
6875
|
F.onSpeechEnd();
|
|
6847
6876
|
} catch (Ze) {
|
|
@@ -6849,13 +6878,13 @@ const Ve = Me(({
|
|
|
6849
6878
|
}
|
|
6850
6879
|
}
|
|
6851
6880
|
}, 100);
|
|
6852
|
-
}, 100),
|
|
6881
|
+
}, 100), y.current = he;
|
|
6853
6882
|
}
|
|
6854
6883
|
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
6884
|
await H(), p.current && p.current.lipsync && (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(L, ge));
|
|
6856
6885
|
}, 100);
|
|
6857
|
-
} catch (
|
|
6858
|
-
console.error("Error speaking text:",
|
|
6886
|
+
} catch (N) {
|
|
6887
|
+
console.error("Error speaking text:", N), X(N.message || "Failed to speak text");
|
|
6859
6888
|
}
|
|
6860
6889
|
}, [$, H, v.lipsyncLang]), _ = T(() => {
|
|
6861
6890
|
p.current && (p.current.stopSpeaking(), p.current.setSlowdownRate && p.current.setSlowdownRate(1), z.current = null, pe(!1));
|
|
@@ -6863,17 +6892,17 @@ const Ve = Me(({
|
|
|
6863
6892
|
if (p.current && p.current.pauseSpeaking) {
|
|
6864
6893
|
const L = p.current;
|
|
6865
6894
|
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 &&
|
|
6871
|
-
const be = L.speechQueue.filter((ye) => ye && ye.text && Array.isArray(ye.text) && ye.text.length > 0).map((ye) => ye.text.map((
|
|
6872
|
-
be && be.trim() && (
|
|
6895
|
+
y.current && (clearInterval(y.current), y.current = null);
|
|
6896
|
+
let N = "";
|
|
6897
|
+
if (z.current && W.current.length > 0) {
|
|
6898
|
+
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), ke = J - he;
|
|
6899
|
+
if (he > 0 && ke < J && (N = W.current.slice(ke).join(". ").trim(), !N && ge > 0 && L.speechQueue)) {
|
|
6900
|
+
const be = L.speechQueue.filter((ye) => ye && ye.text && Array.isArray(ye.text) && ye.text.length > 0).map((ye) => ye.text.map((Se) => Se.word || "").filter((Se) => Se.length > 0).join(" ")).filter((ye) => ye.length > 0).join(" ");
|
|
6901
|
+
be && be.trim() && (N = be.trim());
|
|
6873
6902
|
}
|
|
6874
6903
|
}
|
|
6875
6904
|
z.current && (P.current = {
|
|
6876
|
-
remainingText:
|
|
6905
|
+
remainingText: N || null,
|
|
6877
6906
|
originalText: z.current.text,
|
|
6878
6907
|
options: z.current.options
|
|
6879
6908
|
}), L.speechQueue && (L.speechQueue.length = 0), p.current.pauseSpeaking(), E.current = !0, pe(!0);
|
|
@@ -6892,16 +6921,16 @@ const Ve = Me(({
|
|
|
6892
6921
|
return;
|
|
6893
6922
|
}
|
|
6894
6923
|
pe(!1), E.current = !1, await H();
|
|
6895
|
-
const
|
|
6924
|
+
const N = {
|
|
6896
6925
|
...F,
|
|
6897
6926
|
lipsyncLang: F.lipsyncLang || v.lipsyncLang || "en"
|
|
6898
6927
|
};
|
|
6899
6928
|
try {
|
|
6900
|
-
await
|
|
6929
|
+
await U(L, N);
|
|
6901
6930
|
} catch (J) {
|
|
6902
6931
|
console.error("Error resuming speech:", J), pe(!1), E.current = !1;
|
|
6903
6932
|
}
|
|
6904
|
-
}, [H, ae,
|
|
6933
|
+
}, [H, ae, U, v]), Le = T((L) => {
|
|
6905
6934
|
p.current && p.current.setMood(L);
|
|
6906
6935
|
}, []), we = T((L) => {
|
|
6907
6936
|
p.current && p.current.setSlowdownRate && p.current.setSlowdownRate(L);
|
|
@@ -6947,7 +6976,7 @@ const Ve = Me(({
|
|
|
6947
6976
|
p.current && p.current.onResize && p.current.onResize();
|
|
6948
6977
|
}, []);
|
|
6949
6978
|
return Ee(I, () => ({
|
|
6950
|
-
speakText:
|
|
6979
|
+
speakText: U,
|
|
6951
6980
|
stopSpeaking: _,
|
|
6952
6981
|
pauseSpeaking: j,
|
|
6953
6982
|
resumeSpeaking: q,
|
|
@@ -7024,13 +7053,13 @@ const Ve = Me(({
|
|
|
7024
7053
|
width: "100%",
|
|
7025
7054
|
height: "100%",
|
|
7026
7055
|
position: "relative",
|
|
7027
|
-
...
|
|
7056
|
+
...x
|
|
7028
7057
|
},
|
|
7029
7058
|
children: [
|
|
7030
7059
|
/* @__PURE__ */ me(
|
|
7031
7060
|
"div",
|
|
7032
7061
|
{
|
|
7033
|
-
ref:
|
|
7062
|
+
ref: B,
|
|
7034
7063
|
className: "talking-head-viewer",
|
|
7035
7064
|
style: {
|
|
7036
7065
|
width: "100%",
|
|
@@ -7039,7 +7068,7 @@ const Ve = Me(({
|
|
|
7039
7068
|
}
|
|
7040
7069
|
}
|
|
7041
7070
|
),
|
|
7042
|
-
|
|
7071
|
+
k && /* @__PURE__ */ me("div", { className: "loading-overlay", style: {
|
|
7043
7072
|
position: "absolute",
|
|
7044
7073
|
top: "50%",
|
|
7045
7074
|
left: "50%",
|
|
@@ -7077,7 +7106,7 @@ const pt = Me(({
|
|
|
7077
7106
|
style: s = {},
|
|
7078
7107
|
avatarConfig: o = {}
|
|
7079
7108
|
}, l) => {
|
|
7080
|
-
const h = O(null), r = O(null), [u, a] = ce(!0), [
|
|
7109
|
+
const h = O(null), r = O(null), [u, a] = ce(!0), [c, d] = ce(null), [g, x] = ce(!1), b = Fe(), I = o.ttsService || b.service, B = I === "browser" ? {
|
|
7081
7110
|
endpoint: "",
|
|
7082
7111
|
apiKey: null,
|
|
7083
7112
|
defaultVoice: "Google US English"
|
|
@@ -7093,7 +7122,7 @@ const pt = Me(({
|
|
|
7093
7122
|
body: "F",
|
|
7094
7123
|
avatarMood: "neutral",
|
|
7095
7124
|
ttsLang: I === "browser" ? "en-US" : "en",
|
|
7096
|
-
ttsVoice: o.ttsVoice ||
|
|
7125
|
+
ttsVoice: o.ttsVoice || B.defaultVoice,
|
|
7097
7126
|
lipsyncLang: "en",
|
|
7098
7127
|
// English lip-sync
|
|
7099
7128
|
showFullAvatar: !0,
|
|
@@ -7102,15 +7131,15 @@ const pt = Me(({
|
|
|
7102
7131
|
movementIntensity: 0.5,
|
|
7103
7132
|
...o
|
|
7104
7133
|
}, M = {
|
|
7105
|
-
ttsEndpoint:
|
|
7106
|
-
ttsApikey:
|
|
7134
|
+
ttsEndpoint: B.endpoint,
|
|
7135
|
+
ttsApikey: B.apiKey,
|
|
7107
7136
|
ttsService: I,
|
|
7108
7137
|
lipsyncModules: ["en"],
|
|
7109
7138
|
cameraView: "upper"
|
|
7110
7139
|
}, z = T(async () => {
|
|
7111
7140
|
if (!(!h.current || r.current))
|
|
7112
7141
|
try {
|
|
7113
|
-
if (a(!0),
|
|
7142
|
+
if (a(!0), d(null), r.current = new Be(h.current, M), await r.current.showAvatar(p, (K) => {
|
|
7114
7143
|
if (K.lengthComputable) {
|
|
7115
7144
|
const X = Math.min(100, Math.round(K.loaded / K.total * 100));
|
|
7116
7145
|
t(X);
|
|
@@ -7132,38 +7161,38 @@ const pt = Me(({
|
|
|
7132
7161
|
} catch (K) {
|
|
7133
7162
|
console.warn("Error setting full body mode on initialization:", K);
|
|
7134
7163
|
}
|
|
7135
|
-
a(!1),
|
|
7164
|
+
a(!1), x(!0), n(r.current);
|
|
7136
7165
|
const Z = () => {
|
|
7137
7166
|
document.visibilityState === "visible" ? r.current?.start() : r.current?.stop();
|
|
7138
7167
|
};
|
|
7139
7168
|
return document.addEventListener("visibilitychange", Z), () => {
|
|
7140
7169
|
document.removeEventListener("visibilitychange", Z);
|
|
7141
7170
|
};
|
|
7142
|
-
} catch (
|
|
7143
|
-
console.error("Error initializing TalkingHead:",
|
|
7171
|
+
} catch (k) {
|
|
7172
|
+
console.error("Error initializing TalkingHead:", k), d(k.message || "Failed to initialize avatar"), a(!1), e(k);
|
|
7144
7173
|
}
|
|
7145
7174
|
}, []);
|
|
7146
7175
|
de(() => (z(), () => {
|
|
7147
7176
|
r.current && (r.current.stop(), r.current.dispose(), r.current = null);
|
|
7148
7177
|
}), [z]);
|
|
7149
|
-
const
|
|
7178
|
+
const y = T((k) => {
|
|
7150
7179
|
if (r.current && g)
|
|
7151
7180
|
try {
|
|
7152
|
-
console.log("Speaking text:",
|
|
7153
|
-
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(
|
|
7181
|
+
console.log("Speaking text:", k), 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(k)) : (console.warn("Lip-sync modules not ready, waiting..."), setTimeout(() => {
|
|
7182
|
+
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(k)) : console.error("Lip-sync still not ready after waiting");
|
|
7154
7183
|
}, 500));
|
|
7155
7184
|
} catch (Z) {
|
|
7156
|
-
console.error("Error speaking text:", Z),
|
|
7185
|
+
console.error("Error speaking text:", Z), d(Z.message || "Failed to speak text");
|
|
7157
7186
|
}
|
|
7158
7187
|
else
|
|
7159
7188
|
console.warn("Avatar not ready for speaking. isReady:", g, "talkingHeadRef:", !!r.current);
|
|
7160
7189
|
}, [g, p]), E = T(() => {
|
|
7161
7190
|
r.current && (r.current.stopSpeaking(), r.current.setSlowdownRate && (r.current.setSlowdownRate(1), console.log("Reset timing to normal")));
|
|
7162
|
-
}, []), P = T((
|
|
7163
|
-
r.current && r.current.setMood(
|
|
7164
|
-
}, []),
|
|
7165
|
-
r.current && r.current.setSlowdownRate && (r.current.setSlowdownRate(
|
|
7166
|
-
}, []), oe = T((
|
|
7191
|
+
}, []), P = T((k) => {
|
|
7192
|
+
r.current && r.current.setMood(k);
|
|
7193
|
+
}, []), W = T((k) => {
|
|
7194
|
+
r.current && r.current.setSlowdownRate && (r.current.setSlowdownRate(k), console.log("Timing adjustment set to:", k));
|
|
7195
|
+
}, []), oe = T((k, Z = !1) => {
|
|
7167
7196
|
if (r.current && r.current.playAnimation) {
|
|
7168
7197
|
if (r.current.setShowFullAvatar)
|
|
7169
7198
|
try {
|
|
@@ -7171,11 +7200,11 @@ const pt = Me(({
|
|
|
7171
7200
|
} catch (X) {
|
|
7172
7201
|
console.warn("Error setting full body mode:", X);
|
|
7173
7202
|
}
|
|
7174
|
-
if (
|
|
7203
|
+
if (k.includes("."))
|
|
7175
7204
|
try {
|
|
7176
|
-
r.current.playAnimation(
|
|
7205
|
+
r.current.playAnimation(k, null, 10, 0, 0.01, Z), console.log("Playing animation:", k);
|
|
7177
7206
|
} catch (X) {
|
|
7178
|
-
console.log(`Failed to play ${
|
|
7207
|
+
console.log(`Failed to play ${k}:`, X);
|
|
7179
7208
|
try {
|
|
7180
7209
|
r.current.setBodyMovement("idle"), console.log("Fallback to idle animation");
|
|
7181
7210
|
} catch ($) {
|
|
@@ -7187,13 +7216,13 @@ const pt = Me(({
|
|
|
7187
7216
|
let $ = !1;
|
|
7188
7217
|
for (const se of X)
|
|
7189
7218
|
try {
|
|
7190
|
-
r.current.playAnimation(
|
|
7219
|
+
r.current.playAnimation(k + se, null, 10, 0, 0.01, Z), console.log("Playing animation:", k + se), $ = !0;
|
|
7191
7220
|
break;
|
|
7192
7221
|
} catch {
|
|
7193
|
-
console.log(`Failed to play ${
|
|
7222
|
+
console.log(`Failed to play ${k}${se}, trying next format...`);
|
|
7194
7223
|
}
|
|
7195
7224
|
if (!$) {
|
|
7196
|
-
console.warn("Animation system not available or animation not found:",
|
|
7225
|
+
console.warn("Animation system not available or animation not found:", k);
|
|
7197
7226
|
try {
|
|
7198
7227
|
r.current.setBodyMovement("idle"), console.log("Fallback to idle animation");
|
|
7199
7228
|
} catch (se) {
|
|
@@ -7202,37 +7231,37 @@ const pt = Me(({
|
|
|
7202
7231
|
}
|
|
7203
7232
|
}
|
|
7204
7233
|
} else
|
|
7205
|
-
console.warn("Animation system not available or animation not found:",
|
|
7234
|
+
console.warn("Animation system not available or animation not found:", k);
|
|
7206
7235
|
}, []);
|
|
7207
7236
|
return Ee(l, () => ({
|
|
7208
|
-
speakText:
|
|
7237
|
+
speakText: y,
|
|
7209
7238
|
stopSpeaking: E,
|
|
7210
7239
|
setMood: P,
|
|
7211
|
-
setTimingAdjustment:
|
|
7240
|
+
setTimingAdjustment: W,
|
|
7212
7241
|
playAnimation: oe,
|
|
7213
7242
|
isReady: g,
|
|
7214
7243
|
talkingHead: r.current,
|
|
7215
|
-
setBodyMovement: (
|
|
7244
|
+
setBodyMovement: (k) => {
|
|
7216
7245
|
if (r.current && r.current.setShowFullAvatar && r.current.setBodyMovement)
|
|
7217
7246
|
try {
|
|
7218
|
-
r.current.setShowFullAvatar(!0), r.current.setBodyMovement(
|
|
7247
|
+
r.current.setShowFullAvatar(!0), r.current.setBodyMovement(k), console.log("Body movement set with full body mode:", k);
|
|
7219
7248
|
} catch (Z) {
|
|
7220
7249
|
console.warn("Error setting body movement:", Z);
|
|
7221
7250
|
}
|
|
7222
7251
|
},
|
|
7223
|
-
setMovementIntensity: (
|
|
7252
|
+
setMovementIntensity: (k) => r.current?.setMovementIntensity(k),
|
|
7224
7253
|
playRandomDance: () => {
|
|
7225
7254
|
if (r.current && r.current.setShowFullAvatar && r.current.playRandomDance)
|
|
7226
7255
|
try {
|
|
7227
7256
|
r.current.setShowFullAvatar(!0), r.current.playRandomDance(), console.log("Random dance played with full body mode");
|
|
7228
|
-
} catch (
|
|
7229
|
-
console.warn("Error playing random dance:",
|
|
7257
|
+
} catch (k) {
|
|
7258
|
+
console.warn("Error playing random dance:", k);
|
|
7230
7259
|
}
|
|
7231
7260
|
},
|
|
7232
|
-
playReaction: (
|
|
7261
|
+
playReaction: (k) => {
|
|
7233
7262
|
if (r.current && r.current.setShowFullAvatar && r.current.playReaction)
|
|
7234
7263
|
try {
|
|
7235
|
-
r.current.setShowFullAvatar(!0), r.current.playReaction(
|
|
7264
|
+
r.current.setShowFullAvatar(!0), r.current.playReaction(k), console.log("Reaction played with full body mode:", k);
|
|
7236
7265
|
} catch (Z) {
|
|
7237
7266
|
console.warn("Error playing reaction:", Z);
|
|
7238
7267
|
}
|
|
@@ -7241,14 +7270,14 @@ const pt = Me(({
|
|
|
7241
7270
|
if (r.current && r.current.setShowFullAvatar && r.current.playCelebration)
|
|
7242
7271
|
try {
|
|
7243
7272
|
r.current.setShowFullAvatar(!0), r.current.playCelebration(), console.log("Celebration played with full body mode");
|
|
7244
|
-
} catch (
|
|
7245
|
-
console.warn("Error playing celebration:",
|
|
7273
|
+
} catch (k) {
|
|
7274
|
+
console.warn("Error playing celebration:", k);
|
|
7246
7275
|
}
|
|
7247
7276
|
},
|
|
7248
|
-
setShowFullAvatar: (
|
|
7277
|
+
setShowFullAvatar: (k) => {
|
|
7249
7278
|
if (r.current && r.current.setShowFullAvatar)
|
|
7250
7279
|
try {
|
|
7251
|
-
r.current.setShowFullAvatar(
|
|
7280
|
+
r.current.setShowFullAvatar(k), console.log("Show full avatar set to:", k);
|
|
7252
7281
|
} catch (Z) {
|
|
7253
7282
|
console.warn("Error setting showFullAvatar:", Z);
|
|
7254
7283
|
}
|
|
@@ -7257,16 +7286,16 @@ const pt = Me(({
|
|
|
7257
7286
|
if (r.current && r.current.lockAvatarPosition)
|
|
7258
7287
|
try {
|
|
7259
7288
|
r.current.lockAvatarPosition();
|
|
7260
|
-
} catch (
|
|
7261
|
-
console.warn("Error locking avatar position:",
|
|
7289
|
+
} catch (k) {
|
|
7290
|
+
console.warn("Error locking avatar position:", k);
|
|
7262
7291
|
}
|
|
7263
7292
|
},
|
|
7264
7293
|
unlockAvatarPosition: () => {
|
|
7265
7294
|
if (r.current && r.current.unlockAvatarPosition)
|
|
7266
7295
|
try {
|
|
7267
7296
|
r.current.unlockAvatarPosition();
|
|
7268
|
-
} catch (
|
|
7269
|
-
console.warn("Error unlocking avatar position:",
|
|
7297
|
+
} catch (k) {
|
|
7298
|
+
console.warn("Error unlocking avatar position:", k);
|
|
7270
7299
|
}
|
|
7271
7300
|
}
|
|
7272
7301
|
})), /* @__PURE__ */ Pe("div", { className: `talking-head-container ${i}`, style: s, children: [
|
|
@@ -7291,7 +7320,7 @@ const pt = Me(({
|
|
|
7291
7320
|
fontSize: "18px",
|
|
7292
7321
|
zIndex: 10
|
|
7293
7322
|
}, children: "Loading avatar..." }),
|
|
7294
|
-
|
|
7323
|
+
c && /* @__PURE__ */ me("div", { className: "error-overlay", style: {
|
|
7295
7324
|
position: "absolute",
|
|
7296
7325
|
top: "50%",
|
|
7297
7326
|
left: "50%",
|
|
@@ -7302,7 +7331,7 @@ const pt = Me(({
|
|
|
7302
7331
|
zIndex: 10,
|
|
7303
7332
|
padding: "20px",
|
|
7304
7333
|
borderRadius: "8px"
|
|
7305
|
-
}, children:
|
|
7334
|
+
}, children: c })
|
|
7306
7335
|
] });
|
|
7307
7336
|
});
|
|
7308
7337
|
pt.displayName = "TalkingHeadComponent";
|
|
@@ -7319,20 +7348,20 @@ const gt = Me(({
|
|
|
7319
7348
|
movementIntensity: r = 0.5,
|
|
7320
7349
|
showFullAvatar: u = !1,
|
|
7321
7350
|
cameraView: a = "upper",
|
|
7322
|
-
onReady:
|
|
7351
|
+
onReady: c = () => {
|
|
7323
7352
|
},
|
|
7324
|
-
onLoading:
|
|
7353
|
+
onLoading: d = () => {
|
|
7325
7354
|
},
|
|
7326
7355
|
onError: g = () => {
|
|
7327
7356
|
},
|
|
7328
|
-
onSpeechEnd:
|
|
7357
|
+
onSpeechEnd: x = () => {
|
|
7329
7358
|
},
|
|
7330
7359
|
className: b = "",
|
|
7331
7360
|
style: I = {},
|
|
7332
|
-
animations:
|
|
7361
|
+
animations: B = {},
|
|
7333
7362
|
autoSpeak: p = !1
|
|
7334
7363
|
}, M) => {
|
|
7335
|
-
const z = O(null),
|
|
7364
|
+
const z = O(null), y = O(null), E = O(u), P = O(null), W = O(null), oe = O(!1), k = O({ remainingText: null, originalText: null, options: null }), Z = O([]), [K, X] = ce(!0), [$, se] = ce(null), [ae, pe] = ce(!1), [ee, le] = ce(!1);
|
|
7336
7365
|
de(() => {
|
|
7337
7366
|
oe.current = ee;
|
|
7338
7367
|
}, [ee]), de(() => {
|
|
@@ -7361,7 +7390,7 @@ const gt = Me(({
|
|
|
7361
7390
|
...D,
|
|
7362
7391
|
apiKey: l !== null ? l : D.apiKey
|
|
7363
7392
|
};
|
|
7364
|
-
const
|
|
7393
|
+
const S = {
|
|
7365
7394
|
url: t,
|
|
7366
7395
|
body: e,
|
|
7367
7396
|
avatarMood: n,
|
|
@@ -7377,21 +7406,21 @@ const gt = Me(({
|
|
|
7377
7406
|
ttsService: v,
|
|
7378
7407
|
lipsyncModules: ["en"],
|
|
7379
7408
|
cameraView: a
|
|
7380
|
-
},
|
|
7381
|
-
if (!(!z.current ||
|
|
7409
|
+
}, U = T(async () => {
|
|
7410
|
+
if (!(!z.current || y.current))
|
|
7382
7411
|
try {
|
|
7383
|
-
X(!0), se(null),
|
|
7384
|
-
url:
|
|
7385
|
-
body:
|
|
7386
|
-
avatarMood:
|
|
7387
|
-
}), await
|
|
7412
|
+
X(!0), se(null), y.current = new Be(z.current, H), console.log("Avatar config being passed:", {
|
|
7413
|
+
url: S.url,
|
|
7414
|
+
body: S.body,
|
|
7415
|
+
avatarMood: S.avatarMood
|
|
7416
|
+
}), await y.current.showAvatar(S, (te) => {
|
|
7388
7417
|
if (te.lengthComputable) {
|
|
7389
7418
|
const L = Math.min(100, Math.round(te.loaded / te.total * 100));
|
|
7390
|
-
|
|
7419
|
+
d(L);
|
|
7391
7420
|
}
|
|
7392
|
-
}),
|
|
7421
|
+
}), y.current?.avatar && console.log("Avatar body after initialization:", y.current.avatar.body), X(!1), pe(!0), c(y.current);
|
|
7393
7422
|
const C = () => {
|
|
7394
|
-
document.visibilityState === "visible" ?
|
|
7423
|
+
document.visibilityState === "visible" ? y.current?.start() : y.current?.stop();
|
|
7395
7424
|
};
|
|
7396
7425
|
return document.addEventListener("visibilitychange", C), () => {
|
|
7397
7426
|
document.removeEventListener("visibilitychange", C);
|
|
@@ -7400,19 +7429,19 @@ const gt = Me(({
|
|
|
7400
7429
|
console.error("Error initializing TalkingHead:", C), se(C.message || "Failed to initialize avatar"), X(!1), g(C);
|
|
7401
7430
|
}
|
|
7402
7431
|
}, []);
|
|
7403
|
-
de(() => (
|
|
7404
|
-
|
|
7405
|
-
}), [
|
|
7432
|
+
de(() => (U(), () => {
|
|
7433
|
+
y.current && (y.current.stop(), y.current.dispose(), y.current = null);
|
|
7434
|
+
}), [U]);
|
|
7406
7435
|
const _ = T(async () => {
|
|
7407
|
-
if (
|
|
7436
|
+
if (y.current)
|
|
7408
7437
|
try {
|
|
7409
|
-
const C =
|
|
7438
|
+
const C = y.current.audioCtx || y.current.audioContext;
|
|
7410
7439
|
C && (C.state === "suspended" || C.state === "interrupted") && (await C.resume(), console.log("Audio context resumed"));
|
|
7411
7440
|
} catch (C) {
|
|
7412
7441
|
console.warn("Failed to resume audio context:", C);
|
|
7413
7442
|
}
|
|
7414
7443
|
}, []), j = T(async (C, te = {}) => {
|
|
7415
|
-
if (!
|
|
7444
|
+
if (!y.current || !ae) {
|
|
7416
7445
|
console.warn("Avatar not ready for speaking");
|
|
7417
7446
|
return;
|
|
7418
7447
|
}
|
|
@@ -7420,51 +7449,51 @@ const gt = Me(({
|
|
|
7420
7449
|
console.warn("No text provided to speak");
|
|
7421
7450
|
return;
|
|
7422
7451
|
}
|
|
7423
|
-
await _(),
|
|
7424
|
-
const L = C.split(/[.!?]+/).filter((
|
|
7452
|
+
await _(), k.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;
|
|
7453
|
+
const L = C.split(/[.!?]+/).filter((N) => N.trim().length > 0);
|
|
7425
7454
|
Z.current = L;
|
|
7426
7455
|
const F = {
|
|
7427
7456
|
lipsyncLang: te.lipsyncLang || "en",
|
|
7428
7457
|
onSpeechEnd: () => {
|
|
7429
|
-
|
|
7458
|
+
W.current && (clearInterval(W.current), W.current = null), te.onSpeechEnd && te.onSpeechEnd(), x();
|
|
7430
7459
|
}
|
|
7431
7460
|
};
|
|
7432
7461
|
try {
|
|
7433
|
-
|
|
7434
|
-
} catch (
|
|
7435
|
-
console.error("Error speaking text:",
|
|
7462
|
+
y.current.speakText(C, F);
|
|
7463
|
+
} catch (N) {
|
|
7464
|
+
console.error("Error speaking text:", N), se(N.message || "Failed to speak text");
|
|
7436
7465
|
}
|
|
7437
|
-
}, [ae,
|
|
7466
|
+
}, [ae, x, _]);
|
|
7438
7467
|
de(() => {
|
|
7439
|
-
ae && G && p &&
|
|
7468
|
+
ae && G && p && y.current && j(G);
|
|
7440
7469
|
}, [ae, G, p, j]);
|
|
7441
7470
|
const q = T(() => {
|
|
7442
|
-
if (
|
|
7471
|
+
if (y.current)
|
|
7443
7472
|
try {
|
|
7444
|
-
const C =
|
|
7473
|
+
const C = y.current.isSpeaking || !1, te = y.current.audioPlaylist || [], L = y.current.speechQueue || [];
|
|
7445
7474
|
if (C || te.length > 0 || L.length > 0) {
|
|
7446
|
-
|
|
7475
|
+
W.current && (clearInterval(W.current), W.current = null);
|
|
7447
7476
|
let F = "";
|
|
7448
|
-
L.length > 0 && (F = L.map((
|
|
7477
|
+
L.length > 0 && (F = L.map((N) => N.text && Array.isArray(N.text) ? N.text.map((J) => J.word).join(" ") : N.text || "").join(" ")), k.current = {
|
|
7449
7478
|
remainingText: F || null,
|
|
7450
7479
|
originalText: P.current?.text || null,
|
|
7451
7480
|
options: P.current?.options || null
|
|
7452
|
-
},
|
|
7481
|
+
}, y.current.speechQueue.length = 0, y.current.pauseSpeaking(), le(!0), oe.current = !0;
|
|
7453
7482
|
}
|
|
7454
7483
|
} catch (C) {
|
|
7455
7484
|
console.warn("Error pausing speech:", C);
|
|
7456
7485
|
}
|
|
7457
7486
|
}, []), Le = T(async () => {
|
|
7458
|
-
if (!(!
|
|
7487
|
+
if (!(!y.current || !ee))
|
|
7459
7488
|
try {
|
|
7460
7489
|
await _(), le(!1), oe.current = !1;
|
|
7461
|
-
const C =
|
|
7490
|
+
const C = k.current?.remainingText, te = k.current?.originalText || P.current?.text, L = k.current?.options || P.current?.options || {}, F = C || te;
|
|
7462
7491
|
F && j(F, L);
|
|
7463
7492
|
} catch (C) {
|
|
7464
7493
|
console.warn("Error resuming speech:", C), le(!1), oe.current = !1;
|
|
7465
7494
|
}
|
|
7466
7495
|
}, [ee, j, _]), we = T(() => {
|
|
7467
|
-
|
|
7496
|
+
y.current && (y.current.stopSpeaking(), W.current && (clearInterval(W.current), W.current = null), le(!1), oe.current = !1);
|
|
7468
7497
|
}, []);
|
|
7469
7498
|
return Ee(M, () => ({
|
|
7470
7499
|
speakText: j,
|
|
@@ -7473,20 +7502,20 @@ const gt = Me(({
|
|
|
7473
7502
|
stopSpeaking: we,
|
|
7474
7503
|
resumeAudioContext: _,
|
|
7475
7504
|
isPaused: () => ee,
|
|
7476
|
-
setMood: (C) =>
|
|
7505
|
+
setMood: (C) => y.current?.setMood(C),
|
|
7477
7506
|
setBodyMovement: (C) => {
|
|
7478
|
-
|
|
7507
|
+
y.current && y.current.setBodyMovement(C);
|
|
7479
7508
|
},
|
|
7480
7509
|
playAnimation: (C, te = !1) => {
|
|
7481
|
-
|
|
7510
|
+
y.current && y.current.playAnimation && y.current.playAnimation(C, null, 10, 0, 0.01, te);
|
|
7482
7511
|
},
|
|
7483
|
-
playReaction: (C) =>
|
|
7484
|
-
playCelebration: () =>
|
|
7512
|
+
playReaction: (C) => y.current?.playReaction(C),
|
|
7513
|
+
playCelebration: () => y.current?.playCelebration(),
|
|
7485
7514
|
setShowFullAvatar: (C) => {
|
|
7486
|
-
|
|
7515
|
+
y.current && (E.current = C, y.current.setShowFullAvatar(C));
|
|
7487
7516
|
},
|
|
7488
7517
|
isReady: ae,
|
|
7489
|
-
talkingHead:
|
|
7518
|
+
talkingHead: y.current
|
|
7490
7519
|
})), /* @__PURE__ */ Pe("div", { className: `simple-talking-avatar-container ${b}`, style: I, children: [
|
|
7491
7520
|
/* @__PURE__ */ me(
|
|
7492
7521
|
"div",
|
|
@@ -7550,13 +7579,13 @@ const yt = Me(({
|
|
|
7550
7579
|
curriculumCompleted: !1,
|
|
7551
7580
|
score: 0,
|
|
7552
7581
|
totalQuestions: 0
|
|
7553
|
-
}),
|
|
7582
|
+
}), c = O({
|
|
7554
7583
|
onLessonStart: n,
|
|
7555
7584
|
onLessonComplete: i,
|
|
7556
7585
|
onQuestionAnswer: s,
|
|
7557
7586
|
onCurriculumComplete: o,
|
|
7558
7587
|
onCustomAction: l
|
|
7559
|
-
}),
|
|
7588
|
+
}), d = O(null), g = O(null), x = O(null), b = O(null), I = O(null), B = O(null), p = O(null), M = O(G?.curriculum || {
|
|
7560
7589
|
title: "Default Curriculum",
|
|
7561
7590
|
description: "No curriculum data provided",
|
|
7562
7591
|
language: "en",
|
|
@@ -7576,7 +7605,7 @@ const yt = Me(({
|
|
|
7576
7605
|
lipsyncLang: "en"
|
|
7577
7606
|
});
|
|
7578
7607
|
de(() => {
|
|
7579
|
-
|
|
7608
|
+
c.current = {
|
|
7580
7609
|
onLessonStart: n,
|
|
7581
7610
|
onLessonComplete: i,
|
|
7582
7611
|
onQuestionAnswer: s,
|
|
@@ -7604,17 +7633,17 @@ const yt = Me(({
|
|
|
7604
7633
|
lipsyncLang: "en"
|
|
7605
7634
|
};
|
|
7606
7635
|
}, [G, t, e]);
|
|
7607
|
-
const
|
|
7636
|
+
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, R) => R.type === "multiple_choice" || R.type === "true_false" ? v === R.answer : R.type === "code_test" && typeof v == "object" && v !== null ? v.passed === !0 : !1, []), W = T(() => {
|
|
7608
7637
|
a.current.lessonCompleted = !0, a.current.isQuestionMode = !1;
|
|
7609
7638
|
const v = a.current.totalQuestions > 0 ? Math.round(a.current.score / a.current.totalQuestions * 100) : 100;
|
|
7610
7639
|
let R = "Congratulations! You've completed this lesson";
|
|
7611
|
-
if (a.current.totalQuestions > 0 ? R += ` You got ${a.current.score} correct out of ${a.current.totalQuestions} question${a.current.totalQuestions === 1 ? "" : "s"}, achieving a score of ${v} percent. ` : R += "! ", v >= 80 ? R += "Excellent work! You have a great understanding of this topic." : v >= 60 ? R += "Good job! You understand most of the concepts." : R += "Keep practicing! You're making progress.",
|
|
7640
|
+
if (a.current.totalQuestions > 0 ? R += ` You got ${a.current.score} correct out of ${a.current.totalQuestions} question${a.current.totalQuestions === 1 ? "" : "s"}, achieving a score of ${v} percent. ` : R += "! ", v >= 80 ? R += "Excellent work! You have a great understanding of this topic." : v >= 60 ? R += "Good job! You understand most of the concepts." : R += "Keep practicing! You're making progress.", c.current.onLessonComplete({
|
|
7612
7641
|
moduleIndex: a.current.currentModuleIndex,
|
|
7613
7642
|
lessonIndex: a.current.currentLessonIndex,
|
|
7614
7643
|
score: a.current.score,
|
|
7615
7644
|
totalQuestions: a.current.totalQuestions,
|
|
7616
7645
|
percentage: v
|
|
7617
|
-
}),
|
|
7646
|
+
}), c.current.onCustomAction({
|
|
7618
7647
|
type: "lessonComplete",
|
|
7619
7648
|
moduleIndex: a.current.currentModuleIndex,
|
|
7620
7649
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7628,11 +7657,11 @@ const yt = Me(({
|
|
|
7628
7657
|
} catch {
|
|
7629
7658
|
u.current.playCelebration();
|
|
7630
7659
|
}
|
|
7631
|
-
const
|
|
7660
|
+
const S = M.current || { modules: [] }, H = S.modules[a.current.currentModuleIndex], U = a.current.currentLessonIndex < (H?.lessons?.length || 0) - 1, _ = a.current.currentModuleIndex < (S.modules?.length || 0) - 1, j = U || _, q = z.current || { lipsyncLang: "en" };
|
|
7632
7661
|
u.current.speakText(R, {
|
|
7633
7662
|
lipsyncLang: q.lipsyncLang,
|
|
7634
7663
|
onSpeechEnd: () => {
|
|
7635
|
-
|
|
7664
|
+
c.current.onCustomAction({
|
|
7636
7665
|
type: "lessonCompleteFeedbackDone",
|
|
7637
7666
|
moduleIndex: a.current.currentModuleIndex,
|
|
7638
7667
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7647,9 +7676,9 @@ const yt = Me(({
|
|
|
7647
7676
|
}, [e.lessonComplete]), oe = T(() => {
|
|
7648
7677
|
a.current.curriculumCompleted = !0;
|
|
7649
7678
|
const v = M.current || { modules: [] };
|
|
7650
|
-
if (
|
|
7679
|
+
if (c.current.onCurriculumComplete({
|
|
7651
7680
|
modules: v.modules.length,
|
|
7652
|
-
totalLessons: v.modules.reduce((R,
|
|
7681
|
+
totalLessons: v.modules.reduce((R, S) => R + S.lessons.length, 0)
|
|
7653
7682
|
}), u.current) {
|
|
7654
7683
|
if (u.current.setMood("celebrating"), e.curriculumComplete)
|
|
7655
7684
|
try {
|
|
@@ -7660,11 +7689,11 @@ const yt = Me(({
|
|
|
7660
7689
|
const R = z.current || { lipsyncLang: "en" };
|
|
7661
7690
|
u.current.speakText("Amazing! You've completed the entire curriculum! You're now ready to move on to more advanced topics. Well done!", { lipsyncLang: R.lipsyncLang });
|
|
7662
7691
|
}
|
|
7663
|
-
}, [e.curriculumComplete]),
|
|
7664
|
-
const v =
|
|
7692
|
+
}, [e.curriculumComplete]), k = T(() => {
|
|
7693
|
+
const v = y();
|
|
7665
7694
|
a.current.isQuestionMode = !0, a.current.currentQuestionIndex = 0, a.current.totalQuestions = v?.questions?.length || 0, a.current.score = 0;
|
|
7666
7695
|
const R = E();
|
|
7667
|
-
R &&
|
|
7696
|
+
R && c.current.onCustomAction({
|
|
7668
7697
|
type: "questionStart",
|
|
7669
7698
|
moduleIndex: a.current.currentModuleIndex,
|
|
7670
7699
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7673,36 +7702,36 @@ const yt = Me(({
|
|
|
7673
7702
|
question: R,
|
|
7674
7703
|
score: a.current.score
|
|
7675
7704
|
});
|
|
7676
|
-
const
|
|
7705
|
+
const S = () => {
|
|
7677
7706
|
if (!u.current || !R) return;
|
|
7678
7707
|
if (u.current.setMood("happy"), e.questionStart)
|
|
7679
7708
|
try {
|
|
7680
7709
|
u.current.playAnimation(e.questionStart, !0);
|
|
7681
|
-
} catch (
|
|
7682
|
-
console.warn("Failed to play questionStart animation:",
|
|
7710
|
+
} catch (U) {
|
|
7711
|
+
console.warn("Failed to play questionStart animation:", U);
|
|
7683
7712
|
}
|
|
7684
7713
|
const H = z.current || { lipsyncLang: "en" };
|
|
7685
7714
|
R.type === "code_test" ? u.current.speakText(`Let's test your coding skills! Here's your first challenge: ${R.question}`, { lipsyncLang: H.lipsyncLang }) : R.type === "multiple_choice" ? u.current.speakText(`Now let me ask you some questions. Here's the first one: ${R.question}`, { lipsyncLang: H.lipsyncLang }) : R.type === "true_false" ? u.current.speakText(`Let's start with some true or false questions. First question: ${R.question}`, { lipsyncLang: H.lipsyncLang }) : u.current.speakText(`Now let me ask you some questions. Here's the first one: ${R.question}`, { lipsyncLang: H.lipsyncLang });
|
|
7686
7715
|
};
|
|
7687
7716
|
if (u.current && u.current.isReady && R)
|
|
7688
|
-
|
|
7717
|
+
S();
|
|
7689
7718
|
else if (u.current && u.current.isReady) {
|
|
7690
7719
|
const H = z.current || { lipsyncLang: "en" };
|
|
7691
7720
|
u.current.speakText("Now let me ask you some questions to test your understanding.", { lipsyncLang: H.lipsyncLang });
|
|
7692
7721
|
} else {
|
|
7693
7722
|
const H = setInterval(() => {
|
|
7694
|
-
u.current && u.current.isReady && (clearInterval(H), R &&
|
|
7723
|
+
u.current && u.current.isReady && (clearInterval(H), R && S());
|
|
7695
7724
|
}, 100);
|
|
7696
7725
|
setTimeout(() => {
|
|
7697
7726
|
clearInterval(H);
|
|
7698
7727
|
}, 5e3);
|
|
7699
7728
|
}
|
|
7700
|
-
}, [e.questionStart,
|
|
7701
|
-
const v =
|
|
7729
|
+
}, [e.questionStart, y, E]), Z = T(() => {
|
|
7730
|
+
const v = y();
|
|
7702
7731
|
if (a.current.currentQuestionIndex < (v?.questions?.length || 0) - 1) {
|
|
7703
7732
|
u.current && u.current.stopSpeaking && u.current.stopSpeaking(), a.current.currentQuestionIndex += 1;
|
|
7704
7733
|
const R = E();
|
|
7705
|
-
R &&
|
|
7734
|
+
R && c.current.onCustomAction({
|
|
7706
7735
|
type: "nextQuestion",
|
|
7707
7736
|
moduleIndex: a.current.currentModuleIndex,
|
|
7708
7737
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7711,7 +7740,7 @@ const yt = Me(({
|
|
|
7711
7740
|
question: R,
|
|
7712
7741
|
score: a.current.score
|
|
7713
7742
|
});
|
|
7714
|
-
const
|
|
7743
|
+
const S = () => {
|
|
7715
7744
|
if (!u.current || !R) return;
|
|
7716
7745
|
if (u.current.setMood("happy"), u.current.setBodyMovement("idle"), e.nextQuestion)
|
|
7717
7746
|
try {
|
|
@@ -7719,7 +7748,7 @@ const yt = Me(({
|
|
|
7719
7748
|
} catch (q) {
|
|
7720
7749
|
console.warn("Failed to play nextQuestion animation:", q);
|
|
7721
7750
|
}
|
|
7722
|
-
const H = z.current || { lipsyncLang: "en" }, _ =
|
|
7751
|
+
const H = z.current || { lipsyncLang: "en" }, _ = y()?.questions?.length || 0, j = a.current.currentQuestionIndex >= _ - 1;
|
|
7723
7752
|
if (R.type === "code_test") {
|
|
7724
7753
|
const q = j ? `Great! Here's your final coding challenge: ${R.question}` : `Great! Now let's move on to your next coding challenge: ${R.question}`;
|
|
7725
7754
|
u.current.speakText(q, {
|
|
@@ -7743,77 +7772,77 @@ const yt = Me(({
|
|
|
7743
7772
|
}
|
|
7744
7773
|
};
|
|
7745
7774
|
if (u.current && u.current.isReady && R)
|
|
7746
|
-
|
|
7775
|
+
S();
|
|
7747
7776
|
else if (R) {
|
|
7748
7777
|
const H = setInterval(() => {
|
|
7749
|
-
u.current && u.current.isReady && (clearInterval(H),
|
|
7778
|
+
u.current && u.current.isReady && (clearInterval(H), S());
|
|
7750
7779
|
}, 100);
|
|
7751
7780
|
setTimeout(() => {
|
|
7752
7781
|
clearInterval(H);
|
|
7753
7782
|
}, 5e3);
|
|
7754
7783
|
}
|
|
7755
7784
|
} else
|
|
7756
|
-
|
|
7785
|
+
c.current.onCustomAction({
|
|
7757
7786
|
type: "allQuestionsComplete",
|
|
7758
7787
|
moduleIndex: a.current.currentModuleIndex,
|
|
7759
7788
|
lessonIndex: a.current.currentLessonIndex,
|
|
7760
7789
|
totalQuestions: a.current.totalQuestions,
|
|
7761
7790
|
score: a.current.score
|
|
7762
7791
|
});
|
|
7763
|
-
}, [e.nextQuestion,
|
|
7792
|
+
}, [e.nextQuestion, y, E]), K = T(() => {
|
|
7764
7793
|
const v = M.current || { modules: [] }, R = v.modules[a.current.currentModuleIndex];
|
|
7765
7794
|
if (a.current.currentLessonIndex < (R?.lessons?.length || 0) - 1) {
|
|
7766
7795
|
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
|
-
|
|
7796
|
+
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 || _;
|
|
7797
|
+
c.current.onCustomAction({
|
|
7769
7798
|
type: "lessonStart",
|
|
7770
7799
|
moduleIndex: a.current.currentModuleIndex,
|
|
7771
7800
|
lessonIndex: a.current.currentLessonIndex,
|
|
7772
7801
|
hasNextLesson: j
|
|
7773
|
-
}),
|
|
7802
|
+
}), c.current.onLessonStart({
|
|
7774
7803
|
moduleIndex: a.current.currentModuleIndex,
|
|
7775
7804
|
lessonIndex: a.current.currentLessonIndex,
|
|
7776
|
-
lesson:
|
|
7805
|
+
lesson: y()
|
|
7777
7806
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7778
7807
|
} else if (a.current.currentModuleIndex < (v.modules?.length || 0) - 1) {
|
|
7779
7808
|
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
|
-
|
|
7809
|
+
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;
|
|
7810
|
+
c.current.onCustomAction({
|
|
7782
7811
|
type: "lessonStart",
|
|
7783
7812
|
moduleIndex: a.current.currentModuleIndex,
|
|
7784
7813
|
lessonIndex: a.current.currentLessonIndex,
|
|
7785
7814
|
hasNextLesson: q
|
|
7786
|
-
}),
|
|
7815
|
+
}), c.current.onLessonStart({
|
|
7787
7816
|
moduleIndex: a.current.currentModuleIndex,
|
|
7788
7817
|
lessonIndex: a.current.currentLessonIndex,
|
|
7789
|
-
lesson:
|
|
7818
|
+
lesson: y()
|
|
7790
7819
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7791
7820
|
} else
|
|
7792
7821
|
I.current && I.current();
|
|
7793
7822
|
}, []), X = T(() => {
|
|
7794
|
-
const v =
|
|
7823
|
+
const v = y();
|
|
7795
7824
|
let R = null;
|
|
7796
7825
|
if (v?.avatar_script && v?.body) {
|
|
7797
|
-
const
|
|
7798
|
-
R = `${
|
|
7826
|
+
const S = v.avatar_script.trim(), H = v.body.trim(), U = S.match(/[.!?]$/) ? " " : ". ";
|
|
7827
|
+
R = `${S}${U}${H}`;
|
|
7799
7828
|
} else
|
|
7800
7829
|
R = v?.avatar_script || v?.body || null;
|
|
7801
7830
|
if (u.current && u.current.isReady && R) {
|
|
7802
7831
|
a.current.isTeaching = !0, a.current.isQuestionMode = !1, a.current.score = 0, a.current.totalQuestions = 0, u.current.setMood("happy");
|
|
7803
|
-
let
|
|
7832
|
+
let S = !1;
|
|
7804
7833
|
if (e.teaching)
|
|
7805
7834
|
try {
|
|
7806
|
-
u.current.playAnimation(e.teaching, !0),
|
|
7807
|
-
} catch (
|
|
7808
|
-
console.warn("Failed to play teaching animation:",
|
|
7835
|
+
u.current.playAnimation(e.teaching, !0), S = !0;
|
|
7836
|
+
} catch (U) {
|
|
7837
|
+
console.warn("Failed to play teaching animation:", U);
|
|
7809
7838
|
}
|
|
7810
|
-
|
|
7839
|
+
S || u.current.setBodyMovement("gesturing");
|
|
7811
7840
|
const H = z.current || { lipsyncLang: "en" };
|
|
7812
|
-
|
|
7841
|
+
c.current.onLessonStart({
|
|
7813
7842
|
moduleIndex: a.current.currentModuleIndex,
|
|
7814
7843
|
lessonIndex: a.current.currentLessonIndex,
|
|
7815
7844
|
lesson: v
|
|
7816
|
-
}),
|
|
7845
|
+
}), c.current.onCustomAction({
|
|
7817
7846
|
type: "teachingStart",
|
|
7818
7847
|
moduleIndex: a.current.currentModuleIndex,
|
|
7819
7848
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7821,13 +7850,13 @@ const yt = Me(({
|
|
|
7821
7850
|
}), u.current.speakText(R, {
|
|
7822
7851
|
lipsyncLang: H.lipsyncLang,
|
|
7823
7852
|
onSpeechEnd: () => {
|
|
7824
|
-
a.current.isTeaching = !1,
|
|
7853
|
+
a.current.isTeaching = !1, c.current.onCustomAction({
|
|
7825
7854
|
type: "teachingComplete",
|
|
7826
7855
|
moduleIndex: a.current.currentModuleIndex,
|
|
7827
7856
|
lessonIndex: a.current.currentLessonIndex,
|
|
7828
7857
|
lesson: v,
|
|
7829
7858
|
hasQuestions: v.questions && v.questions.length > 0
|
|
7830
|
-
}), v?.code_example &&
|
|
7859
|
+
}), v?.code_example && c.current.onCustomAction({
|
|
7831
7860
|
type: "codeExampleReady",
|
|
7832
7861
|
moduleIndex: a.current.currentModuleIndex,
|
|
7833
7862
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7837,17 +7866,17 @@ const yt = Me(({
|
|
|
7837
7866
|
}
|
|
7838
7867
|
});
|
|
7839
7868
|
}
|
|
7840
|
-
}, [e.teaching,
|
|
7841
|
-
const R = E(),
|
|
7842
|
-
if (
|
|
7869
|
+
}, [e.teaching, y]), $ = T((v) => {
|
|
7870
|
+
const R = E(), S = P(v, R);
|
|
7871
|
+
if (S && (a.current.score += 1), c.current.onQuestionAnswer({
|
|
7843
7872
|
moduleIndex: a.current.currentModuleIndex,
|
|
7844
7873
|
lessonIndex: a.current.currentLessonIndex,
|
|
7845
7874
|
questionIndex: a.current.currentQuestionIndex,
|
|
7846
7875
|
answer: v,
|
|
7847
|
-
isCorrect:
|
|
7876
|
+
isCorrect: S,
|
|
7848
7877
|
question: R
|
|
7849
7878
|
}), u.current)
|
|
7850
|
-
if (
|
|
7879
|
+
if (S) {
|
|
7851
7880
|
if (u.current.setMood("happy"), e.correct)
|
|
7852
7881
|
try {
|
|
7853
7882
|
u.current.playReaction("happy");
|
|
@@ -7855,15 +7884,15 @@ const yt = Me(({
|
|
|
7855
7884
|
u.current.setBodyMovement("happy");
|
|
7856
7885
|
}
|
|
7857
7886
|
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:",
|
|
7887
|
+
const U = y()?.questions?.length || 0;
|
|
7888
|
+
a.current.currentQuestionIndex >= U - 1;
|
|
7889
|
+
const _ = a.current.currentQuestionIndex < U - 1;
|
|
7890
|
+
console.log("[CurriculumLearning] Answer feedback - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:", U, "hasNextQuestion:", _);
|
|
7862
7891
|
const j = R.type === "code_test" ? `Great job! Your code passed all the tests! ${R.explanation || ""}` : `Excellent! That's correct! ${R.explanation || ""}`, q = z.current || { lipsyncLang: "en" };
|
|
7863
7892
|
u.current.speakText(j, {
|
|
7864
7893
|
lipsyncLang: q.lipsyncLang,
|
|
7865
7894
|
onSpeechEnd: () => {
|
|
7866
|
-
|
|
7895
|
+
c.current.onCustomAction({
|
|
7867
7896
|
type: "answerFeedbackComplete",
|
|
7868
7897
|
moduleIndex: a.current.currentModuleIndex,
|
|
7869
7898
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7883,13 +7912,13 @@ const yt = Me(({
|
|
|
7883
7912
|
u.current.setBodyMovement("idle");
|
|
7884
7913
|
}
|
|
7885
7914
|
u.current.setBodyMovement("gesturing");
|
|
7886
|
-
const
|
|
7887
|
-
console.log("[CurriculumLearning] Answer feedback (incorrect) - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:",
|
|
7915
|
+
const U = y()?.questions?.length || 0, _ = a.current.currentQuestionIndex >= U - 1, j = a.current.currentQuestionIndex < U - 1;
|
|
7916
|
+
console.log("[CurriculumLearning] Answer feedback (incorrect) - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:", U, "hasNextQuestion:", j);
|
|
7888
7917
|
const q = R.type === "code_test" ? `Your code didn't pass all the tests. ${R.explanation || "Try again!"}` : `Not quite right, but don't worry! ${R.explanation || ""}${_ ? "" : " Let's move on to the next question."}`, Le = z.current || { lipsyncLang: "en" };
|
|
7889
7918
|
u.current.speakText(q, {
|
|
7890
7919
|
lipsyncLang: Le.lipsyncLang,
|
|
7891
7920
|
onSpeechEnd: () => {
|
|
7892
|
-
|
|
7921
|
+
c.current.onCustomAction({
|
|
7893
7922
|
type: "answerFeedbackComplete",
|
|
7894
7923
|
moduleIndex: a.current.currentModuleIndex,
|
|
7895
7924
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7903,20 +7932,20 @@ const yt = Me(({
|
|
|
7903
7932
|
});
|
|
7904
7933
|
}
|
|
7905
7934
|
else {
|
|
7906
|
-
const
|
|
7907
|
-
|
|
7935
|
+
const U = y()?.questions?.length || 0;
|
|
7936
|
+
c.current.onCustomAction({
|
|
7908
7937
|
type: "answerFeedbackComplete",
|
|
7909
7938
|
moduleIndex: a.current.currentModuleIndex,
|
|
7910
7939
|
lessonIndex: a.current.currentLessonIndex,
|
|
7911
7940
|
questionIndex: a.current.currentQuestionIndex,
|
|
7912
|
-
isCorrect:
|
|
7913
|
-
hasNextQuestion: a.current.currentQuestionIndex <
|
|
7941
|
+
isCorrect: S,
|
|
7942
|
+
hasNextQuestion: a.current.currentQuestionIndex < U - 1,
|
|
7914
7943
|
score: a.current.score,
|
|
7915
7944
|
totalQuestions: a.current.totalQuestions,
|
|
7916
7945
|
avatarNotReady: !0
|
|
7917
7946
|
});
|
|
7918
7947
|
}
|
|
7919
|
-
}, [e.correct, e.incorrect, E,
|
|
7948
|
+
}, [e.correct, e.incorrect, E, y, P]), se = T((v) => {
|
|
7920
7949
|
const R = E();
|
|
7921
7950
|
if (!v || typeof v != "object") {
|
|
7922
7951
|
console.error("Invalid code test result format. Expected object with {passed: boolean, ...}");
|
|
@@ -7926,7 +7955,7 @@ const yt = Me(({
|
|
|
7926
7955
|
console.warn("Current question is not a code test. Use handleAnswerSelect for other question types.");
|
|
7927
7956
|
return;
|
|
7928
7957
|
}
|
|
7929
|
-
const
|
|
7958
|
+
const S = {
|
|
7930
7959
|
passed: v.passed === !0,
|
|
7931
7960
|
results: v.results || [],
|
|
7932
7961
|
output: v.output || "",
|
|
@@ -7936,19 +7965,19 @@ const yt = Me(({
|
|
|
7936
7965
|
passedCount: v.passedCount || 0,
|
|
7937
7966
|
failedCount: v.failedCount || 0
|
|
7938
7967
|
};
|
|
7939
|
-
|
|
7968
|
+
c.current.onCustomAction({
|
|
7940
7969
|
type: "codeTestSubmitted",
|
|
7941
7970
|
moduleIndex: a.current.currentModuleIndex,
|
|
7942
7971
|
lessonIndex: a.current.currentLessonIndex,
|
|
7943
7972
|
questionIndex: a.current.currentQuestionIndex,
|
|
7944
|
-
testResult:
|
|
7973
|
+
testResult: S,
|
|
7945
7974
|
question: R
|
|
7946
|
-
}), p.current && p.current(
|
|
7975
|
+
}), p.current && p.current(S);
|
|
7947
7976
|
}, [E, P]), ae = T(() => {
|
|
7948
7977
|
if (a.current.currentQuestionIndex > 0) {
|
|
7949
7978
|
a.current.currentQuestionIndex -= 1;
|
|
7950
7979
|
const v = E();
|
|
7951
|
-
v &&
|
|
7980
|
+
v && c.current.onCustomAction({
|
|
7952
7981
|
type: "questionStart",
|
|
7953
7982
|
moduleIndex: a.current.currentModuleIndex,
|
|
7954
7983
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7960,82 +7989,82 @@ const yt = Me(({
|
|
|
7960
7989
|
const R = () => {
|
|
7961
7990
|
if (!u.current || !v) return;
|
|
7962
7991
|
u.current.setMood("happy"), u.current.setBodyMovement("idle");
|
|
7963
|
-
const
|
|
7992
|
+
const S = z.current || { lipsyncLang: "en" };
|
|
7964
7993
|
v.type === "code_test" ? u.current.speakText(`Let's go back to this coding challenge: ${v.question}`, {
|
|
7965
|
-
lipsyncLang:
|
|
7994
|
+
lipsyncLang: S.lipsyncLang
|
|
7966
7995
|
}) : u.current.speakText(`Going back to: ${v.question}`, {
|
|
7967
|
-
lipsyncLang:
|
|
7996
|
+
lipsyncLang: S.lipsyncLang
|
|
7968
7997
|
});
|
|
7969
7998
|
};
|
|
7970
7999
|
if (u.current && u.current.isReady && v)
|
|
7971
8000
|
R();
|
|
7972
8001
|
else if (v) {
|
|
7973
|
-
const
|
|
7974
|
-
u.current && u.current.isReady && (clearInterval(
|
|
8002
|
+
const S = setInterval(() => {
|
|
8003
|
+
u.current && u.current.isReady && (clearInterval(S), R());
|
|
7975
8004
|
}, 100);
|
|
7976
8005
|
setTimeout(() => {
|
|
7977
|
-
clearInterval(
|
|
8006
|
+
clearInterval(S);
|
|
7978
8007
|
}, 5e3);
|
|
7979
8008
|
}
|
|
7980
8009
|
}
|
|
7981
8010
|
}, [E]), pe = T(() => {
|
|
7982
8011
|
const v = M.current || { modules: [] };
|
|
7983
8012
|
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,
|
|
8013
|
+
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
8014
|
type: "lessonStart",
|
|
7986
8015
|
moduleIndex: a.current.currentModuleIndex,
|
|
7987
8016
|
lessonIndex: a.current.currentLessonIndex
|
|
7988
|
-
}),
|
|
8017
|
+
}), c.current.onLessonStart({
|
|
7989
8018
|
moduleIndex: a.current.currentModuleIndex,
|
|
7990
8019
|
lessonIndex: a.current.currentLessonIndex,
|
|
7991
|
-
lesson:
|
|
8020
|
+
lesson: y()
|
|
7992
8021
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7993
8022
|
else if (a.current.currentModuleIndex > 0) {
|
|
7994
8023
|
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,
|
|
8024
|
+
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
8025
|
type: "lessonStart",
|
|
7997
8026
|
moduleIndex: a.current.currentModuleIndex,
|
|
7998
8027
|
lessonIndex: a.current.currentLessonIndex
|
|
7999
|
-
}),
|
|
8028
|
+
}), c.current.onLessonStart({
|
|
8000
8029
|
moduleIndex: a.current.currentModuleIndex,
|
|
8001
8030
|
lessonIndex: a.current.currentLessonIndex,
|
|
8002
|
-
lesson:
|
|
8031
|
+
lesson: y()
|
|
8003
8032
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
8004
8033
|
}
|
|
8005
|
-
}, [
|
|
8034
|
+
}, [y]), ee = T(() => {
|
|
8006
8035
|
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
8036
|
}, []), le = T((v) => {
|
|
8008
8037
|
console.log("Avatar is ready!", v);
|
|
8009
|
-
const R =
|
|
8010
|
-
h &&
|
|
8011
|
-
|
|
8038
|
+
const R = y(), S = R?.avatar_script || R?.body;
|
|
8039
|
+
h && S && setTimeout(() => {
|
|
8040
|
+
d.current && d.current();
|
|
8012
8041
|
}, 10);
|
|
8013
|
-
}, [h,
|
|
8042
|
+
}, [h, y]);
|
|
8014
8043
|
Xe(() => {
|
|
8015
|
-
|
|
8044
|
+
d.current = X, g.current = K, x.current = W, b.current = Z, I.current = oe, B.current = k, p.current = $;
|
|
8016
8045
|
}), Ee(r, () => ({
|
|
8017
8046
|
// Curriculum control methods
|
|
8018
8047
|
startTeaching: X,
|
|
8019
|
-
startQuestions:
|
|
8048
|
+
startQuestions: k,
|
|
8020
8049
|
handleAnswerSelect: $,
|
|
8021
8050
|
handleCodeTestResult: se,
|
|
8022
8051
|
nextQuestion: Z,
|
|
8023
8052
|
previousQuestion: ae,
|
|
8024
8053
|
nextLesson: K,
|
|
8025
8054
|
previousLesson: pe,
|
|
8026
|
-
completeLesson:
|
|
8055
|
+
completeLesson: W,
|
|
8027
8056
|
completeCurriculum: oe,
|
|
8028
8057
|
resetCurriculum: ee,
|
|
8029
8058
|
getState: () => ({ ...a.current }),
|
|
8030
8059
|
getCurrentQuestion: () => E(),
|
|
8031
|
-
getCurrentLesson: () =>
|
|
8060
|
+
getCurrentLesson: () => y(),
|
|
8032
8061
|
// Direct access to avatar ref (always returns current value)
|
|
8033
8062
|
getAvatarRef: () => u.current,
|
|
8034
8063
|
// Convenience methods that delegate to avatar (always check current ref)
|
|
8035
8064
|
speakText: async (v, R = {}) => {
|
|
8036
8065
|
await u.current?.resumeAudioContext?.();
|
|
8037
|
-
const
|
|
8038
|
-
u.current?.speakText(v, { ...R, lipsyncLang: R.lipsyncLang ||
|
|
8066
|
+
const S = z.current || { lipsyncLang: "en" };
|
|
8067
|
+
u.current?.speakText(v, { ...R, lipsyncLang: R.lipsyncLang || S.lipsyncLang });
|
|
8039
8068
|
},
|
|
8040
8069
|
resumeAudioContext: async () => {
|
|
8041
8070
|
if (u.current?.resumeAudioContext)
|
|
@@ -8046,8 +8075,8 @@ const yt = Me(({
|
|
|
8046
8075
|
if (R.state === "suspended" || R.state === "interrupted")
|
|
8047
8076
|
try {
|
|
8048
8077
|
await R.resume(), console.log("Audio context resumed via talkingHead");
|
|
8049
|
-
} catch (
|
|
8050
|
-
console.warn("Failed to resume audio context:",
|
|
8078
|
+
} catch (S) {
|
|
8079
|
+
console.warn("Failed to resume audio context:", S);
|
|
8051
8080
|
}
|
|
8052
8081
|
} else
|
|
8053
8082
|
console.warn("Audio context not available yet");
|
|
@@ -8069,7 +8098,7 @@ const yt = Me(({
|
|
|
8069
8098
|
unlockAvatarPosition: () => u.current?.unlockAvatarPosition(),
|
|
8070
8099
|
// Custom action trigger
|
|
8071
8100
|
triggerCustomAction: (v, R) => {
|
|
8072
|
-
|
|
8101
|
+
c.current.onCustomAction({
|
|
8073
8102
|
type: v,
|
|
8074
8103
|
...R,
|
|
8075
8104
|
state: { ...a.current }
|
|
@@ -8079,7 +8108,7 @@ const yt = Me(({
|
|
|
8079
8108
|
handleResize: () => u.current?.handleResize(),
|
|
8080
8109
|
// Avatar readiness check (always returns current value)
|
|
8081
8110
|
isAvatarReady: () => u.current?.isReady || !1
|
|
8082
|
-
}), [X,
|
|
8111
|
+
}), [X, k, $, se, Z, K, W, oe, ee, E, y]);
|
|
8083
8112
|
const D = z.current || {
|
|
8084
8113
|
avatarUrl: "/avatars/brunette.glb",
|
|
8085
8114
|
avatarBody: "F",
|
|
@@ -8231,6 +8260,6 @@ export {
|
|
|
8231
8260
|
Ge as animations,
|
|
8232
8261
|
Fe as getActiveTTSConfig,
|
|
8233
8262
|
wt as getAnimation,
|
|
8234
|
-
|
|
8263
|
+
St as getVoiceOptions,
|
|
8235
8264
|
zt as hasAnimation
|
|
8236
8265
|
};
|