@sage-rsc/talking-head-react 1.3.3 → 1.3.5
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 +528 -497
- package/package.json +1 -1
- package/scripts/generate-animation-manifest.js +90 -17
- package/src/components/SimpleTalkingAvatar.jsx +69 -9
- package/src/utils/animationLoader.js +19 -2
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { jsxs as Pe, jsx as ye } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef as Me, useRef as W, useState as pe, useEffect as ce, useCallback as
|
|
2
|
+
import { forwardRef as Me, useRef as W, useState as pe, useEffect as ce, useCallback as O, useImperativeHandle as Fe, useLayoutEffect as Xe } from "react";
|
|
3
3
|
import * as y from "three";
|
|
4
|
-
import { OrbitControls as
|
|
5
|
-
import { GLTFLoader as
|
|
4
|
+
import { OrbitControls as je } from "three/addons/controls/OrbitControls.js";
|
|
5
|
+
import { GLTFLoader as Ye } from "three/addons/loaders/GLTFLoader.js";
|
|
6
6
|
import { DRACOLoader as Qe } from "three/addons/loaders/DRACOLoader.js";
|
|
7
7
|
import { FBXLoader as De } from "three/addons/loaders/FBXLoader.js";
|
|
8
8
|
import { RoomEnvironment as qe } from "three/addons/environments/RoomEnvironment.js";
|
|
9
9
|
import _e from "three/addons/libs/stats.module.js";
|
|
10
10
|
let m, ue, he;
|
|
11
|
-
const C = [0, 0, 0, 0],
|
|
11
|
+
const C = [0, 0, 0, 0], M = new y.Vector3(), ze = new y.Vector3(), ae = new y.Vector3(), Ce = new y.Vector3();
|
|
12
12
|
new y.Plane();
|
|
13
13
|
new y.Ray();
|
|
14
14
|
new y.Euler();
|
|
15
|
-
const re = new y.Quaternion(),
|
|
15
|
+
const re = new y.Quaternion(), Ne = new y.Quaternion(), fe = new y.Matrix4(), xe = new y.Matrix4();
|
|
16
16
|
new y.Vector3();
|
|
17
17
|
const He = new y.Vector3(0, 0, 1), Ke = new y.Vector3(1, 0, 0), Je = new y.Vector3(0, 1, 0), $e = new y.Vector3(0, 0, 1);
|
|
18
18
|
class et {
|
|
@@ -321,7 +321,7 @@ class et {
|
|
|
321
321
|
/// Bone's parent object
|
|
322
322
|
vBasis: r.position.clone(),
|
|
323
323
|
// Original local position
|
|
324
|
-
vWorld: r.parent.getWorldPosition(
|
|
324
|
+
vWorld: r.parent.getWorldPosition(M).clone(),
|
|
325
325
|
// World position, parent
|
|
326
326
|
qBasis: r.parent.quaternion.clone(),
|
|
327
327
|
// Original quaternion, parent
|
|
@@ -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(
|
|
341
|
+
u.boneParent.matrixWorld.decompose(M, re, ae), M.copy(He).applyQuaternion(re).setY(0).normalize(), re.premultiply(Ne.setFromUnitVectors(He, M).invert()).normalize(), u.qWorldInverseYaw = re.clone().normalize(), this.data.push(u), this.dict[h] = u;
|
|
342
342
|
try {
|
|
343
343
|
this.setValue(h, "type", s.type), this.setValue(h, "stiffness", s.stiffness), this.setValue(h, "damping", s.damping), this.setValue(h, "external", s.external), this.setValue(h, "limits", s.limits), this.setValue(h, "excludes", s.excludes), this.setValue(h, "deltaLocal", s.deltaLocal), this.setValue(h, "deltaWorld", s.deltaWorld), this.setValue(h, "pivot", s.pivot), this.setValue(h, "helper", s.helper);
|
|
344
344
|
} catch (a) {
|
|
@@ -356,22 +356,22 @@ class et {
|
|
|
356
356
|
for (this.timerMs += t, t > 1e3 && (this.timerMs = 0), t /= 1e3, e = 0, i = this.objectsUpdate.length; e < i; e++)
|
|
357
357
|
o = this.objectsUpdate[e], o.updateMatrix(), o.parent === null ? o.matrixWorld.copy(o.matrix) : o.matrixWorld.multiplyMatrices(o.parent.matrixWorld, o.matrix), o.matrixWorldNeedsUpdate = !1;
|
|
358
358
|
for (e = 0, i = this.data.length; e < i; e++) {
|
|
359
|
-
if (o = this.data[e],
|
|
359
|
+
if (o = this.data[e], M.copy(o.vWorld), fe.copy(o.boneParent.matrixWorld), xe.copy(fe).invert(), o.vWorld.setFromMatrixPosition(fe), M.applyMatrix4(xe), M.length() > 0.5 && (console.info("Info: Unrealistic jump of " + M.length().toFixed(2) + " meters."), M.setLength(0.5)), M.applyQuaternion(o.bone.quaternion), C[0] = M.x, C[1] = M.y, C[2] = -M.z, C[3] = M.length() / 3, o.children)
|
|
360
360
|
for (n = 0, s = o.children.length; n < s; n++)
|
|
361
361
|
m = o.children[n], C[0] -= m.v[0] * t / 3, C[1] -= m.v[1] * t / 3, C[2] += m.v[2] * t / 3, C[3] -= m.v[3] * t / 3;
|
|
362
|
-
if (m = this.opt.sensitivityFactor, C[0] *= o.ext * m, C[1] *= o.ext * m, C[2] *= o.ext * m, C[3] *= o.ext * m, o.isX && (m = C[0] / t, o.ea[0] = (m - o.ev[0]) / t, o.ev[0] = m, o.a[0] = -o.k[0] * o.p[0] - o.c[0] * o.v[0] - o.ea[0], o.p[0] += o.v[0] * t + o.a[0] * t * t / 2 + C[0], m = o.v[0] + o.a[0] * t / 2, m = -o.k[0] * o.p[0] - o.c[0] * m - o.ea[0], o.v[0] = o.v[0] + (m + o.a[0]) * t / 2), o.isY && (m = C[1] / t, o.ea[1] = (m - o.ev[1]) / t, o.ev[1] = m, o.a[1] = -o.k[1] * o.p[1] - o.c[1] * o.v[1] - o.ea[1], o.p[1] += o.v[1] * t + o.a[1] * t * t / 2 + C[1], m = o.v[1] + o.a[1] * t / 2, m = -o.k[1] * o.p[1] - o.c[1] * m - o.ea[1], o.v[1] = o.v[1] + (m + o.a[1]) * t / 2), o.isZ && (m = C[2] / t, o.ea[2] = (m - o.ev[2]) / t, o.ev[2] = m, o.a[2] = -o.k[2] * o.p[2] - o.c[2] * o.v[2] - o.ea[2], o.p[2] += o.v[2] * t + o.a[2] * t * t / 2 + C[2], m = o.v[2] + o.a[2] * t / 2, m = -o.k[2] * o.p[2] - o.c[2] * m - o.ea[2], o.v[2] = o.v[2] + (m + o.a[2]) * t / 2), o.isT && (m = C[3] / t, o.ea[3] = (m - o.ev[3]) / t, o.ev[3] = m, o.a[3] = -o.k[3] * o.p[3] - o.c[3] * o.v[3] - o.ea[3], o.p[3] += o.v[3] * t + o.a[3] * t * t / 2 + C[3], m = o.v[3] + o.a[3] * t / 2, m = -o.k[3] * o.p[3] - o.c[3] * m - o.ea[3], o.v[3] = o.v[3] + (m + o.a[3]) * t / 2), this.timerMs < this.opt.warmupMs && (o.v[0] *= 1e-4, o.p[0] *= 1e-4, o.v[1] *= 1e-4, o.p[1] *= 1e-4, o.v[2] *= 1e-4, o.p[2] *= 1e-4, o.v[3] *= 1e-4, o.p[3] *= 1e-4), C[0] = o.p[0], C[1] = o.p[1], C[2] = o.p[2], C[3] = o.p[3], m = this.opt.movementFactor, C[0] *= m, C[1] *= m, C[2] *= m, C[3] *= m, o.dl && (m = o.dl, C[0] += m[0], C[1] += m[1], C[2] += m[2]), o.dw && (m = o.dw,
|
|
362
|
+
if (m = this.opt.sensitivityFactor, C[0] *= o.ext * m, C[1] *= o.ext * m, C[2] *= o.ext * m, C[3] *= o.ext * m, o.isX && (m = C[0] / t, o.ea[0] = (m - o.ev[0]) / t, o.ev[0] = m, o.a[0] = -o.k[0] * o.p[0] - o.c[0] * o.v[0] - o.ea[0], o.p[0] += o.v[0] * t + o.a[0] * t * t / 2 + C[0], m = o.v[0] + o.a[0] * t / 2, m = -o.k[0] * o.p[0] - o.c[0] * m - o.ea[0], o.v[0] = o.v[0] + (m + o.a[0]) * t / 2), o.isY && (m = C[1] / t, o.ea[1] = (m - o.ev[1]) / t, o.ev[1] = m, o.a[1] = -o.k[1] * o.p[1] - o.c[1] * o.v[1] - o.ea[1], o.p[1] += o.v[1] * t + o.a[1] * t * t / 2 + C[1], m = o.v[1] + o.a[1] * t / 2, m = -o.k[1] * o.p[1] - o.c[1] * m - o.ea[1], o.v[1] = o.v[1] + (m + o.a[1]) * t / 2), o.isZ && (m = C[2] / t, o.ea[2] = (m - o.ev[2]) / t, o.ev[2] = m, o.a[2] = -o.k[2] * o.p[2] - o.c[2] * o.v[2] - o.ea[2], o.p[2] += o.v[2] * t + o.a[2] * t * t / 2 + C[2], m = o.v[2] + o.a[2] * t / 2, m = -o.k[2] * o.p[2] - o.c[2] * m - o.ea[2], o.v[2] = o.v[2] + (m + o.a[2]) * t / 2), o.isT && (m = C[3] / t, o.ea[3] = (m - o.ev[3]) / t, o.ev[3] = m, o.a[3] = -o.k[3] * o.p[3] - o.c[3] * o.v[3] - o.ea[3], o.p[3] += o.v[3] * t + o.a[3] * t * t / 2 + C[3], m = o.v[3] + o.a[3] * t / 2, m = -o.k[3] * o.p[3] - o.c[3] * m - o.ea[3], o.v[3] = o.v[3] + (m + o.a[3]) * t / 2), this.timerMs < this.opt.warmupMs && (o.v[0] *= 1e-4, o.p[0] *= 1e-4, o.v[1] *= 1e-4, o.p[1] *= 1e-4, o.v[2] *= 1e-4, o.p[2] *= 1e-4, o.v[3] *= 1e-4, o.p[3] *= 1e-4), C[0] = o.p[0], C[1] = o.p[1], C[2] = o.p[2], C[3] = o.p[3], m = this.opt.movementFactor, C[0] *= m, C[1] *= m, C[2] *= m, C[3] *= m, o.dl && (m = o.dl, C[0] += m[0], C[1] += m[1], C[2] += m[2]), o.dw && (m = o.dw, M.set(
|
|
363
363
|
o.vBasis.x + C[0],
|
|
364
364
|
o.vBasis.y + C[1],
|
|
365
365
|
o.vBasis.z + C[2]
|
|
366
|
-
),
|
|
366
|
+
), M.applyMatrix4(fe), M.x += m[0], M.y += m[1], M.z += m[2], M.applyMatrix4(xe), C[0] += M.x - o.vBasis.x, C[1] += M.y - o.vBasis.y, C[2] += M.z - o.vBasis.z), o.limits && this.opt.isLimits && (m = o.limits, m[0] && (m[0][0] !== null && C[0] < m[0][0] && (C[0] = m[0][0]), m[0][1] !== null && C[0] > m[0][1] && (C[0] = m[0][1])), m[1] && (m[1][0] !== null && C[1] < m[1][0] && (C[1] = m[1][0]), m[1][1] !== null && C[1] > m[1][1] && (C[1] = m[1][1])), m[2] && (m[2][0] !== null && C[2] < m[2][0] && (C[2] = m[2][0]), m[2][1] !== null && C[2] > m[2][1] && (C[2] = m[2][1])), m[3] && (m[3][0] !== null && C[3] < m[3][0] && (C[3] = m[3][0]), m[3][1] !== null && C[3] > m[3][1] && (C[3] = m[3][1]))), o.isPoint)
|
|
367
367
|
o.bone.position.set(
|
|
368
368
|
o.vBasis.x + C[0],
|
|
369
369
|
o.vBasis.y + C[1],
|
|
370
370
|
o.vBasis.z - C[2]
|
|
371
371
|
);
|
|
372
|
-
else if (o.boneParent.quaternion.copy(o.qBasis), o.pivot && this.opt.isPivots && (o.boneParent.updateWorldMatrix(!1, !1), o.boneParent.matrixWorld.decompose(
|
|
372
|
+
else if (o.boneParent.quaternion.copy(o.qBasis), o.pivot && this.opt.isPivots && (o.boneParent.updateWorldMatrix(!1, !1), o.boneParent.matrixWorld.decompose(M, re, ae), M.copy(He).applyQuaternion(re).setY(0).normalize(), re.premultiply(Ne.setFromUnitVectors(He, M).invert()).normalize(), o.boneParent.quaternion.multiply(re.invert()), o.boneParent.quaternion.multiply(o.qWorldInverseYaw)), o.isZ && (m = Math.atan(C[0] / o.l), re.setFromAxisAngle($e, -m), o.boneParent.quaternion.multiply(re)), o.isY && (m = o.l / 3, m = m * Math.tanh(C[1] / m), o.bone.position.setLength(o.l + m)), o.isX && (m = Math.atan(C[2] / o.l), re.setFromAxisAngle(Ke, -m), o.boneParent.quaternion.multiply(re)), o.isT && (m = 1.5 * Math.tanh(C[3] * 1.5), re.setFromAxisAngle(Je, -m), o.boneParent.quaternion.multiply(re)), o.boneParent.updateWorldMatrix(!1, !0), o.excludes && this.opt.isExcludes)
|
|
373
373
|
for (n = 0, s = o.excludes.length; n < s; n++)
|
|
374
|
-
m = o.excludes[n], ae.set(0, 0, 0), m.deltaLocal && (ae.x += m.deltaLocal[0], ae.y += m.deltaLocal[1], ae.z += m.deltaLocal[2]), ae.applyMatrix4(m.bone.matrixWorld), xe.copy(o.boneParent.matrixWorld).invert(), ae.applyMatrix4(xe),
|
|
374
|
+
m = o.excludes[n], ae.set(0, 0, 0), m.deltaLocal && (ae.x += m.deltaLocal[0], ae.y += m.deltaLocal[1], ae.z += m.deltaLocal[2]), ae.applyMatrix4(m.bone.matrixWorld), xe.copy(o.boneParent.matrixWorld).invert(), ae.applyMatrix4(xe), M.copy(o.bone.position), !(M.distanceToSquared(ae) >= m.radiusSq) && (he = M.length(), ue = ae.length(), !(ue > m.radius + he) && (ue < Math.abs(m.radius - he) || (ue = (ue * ue + he * he - m.radiusSq) / (2 * ue), ae.normalize(), Ce.copy(ae).multiplyScalar(ue), ue = Math.sqrt(he * he - ue * ue), M.subVectors(M, Ce).projectOnPlane(ae).normalize().multiplyScalar(ue), ze.subVectors(o.vBasis, Ce).projectOnPlane(ae).normalize(), he = ze.dot(M), he < 0 && (he = Math.sqrt(ue * ue - he * he), ze.multiplyScalar(he), M.add(ze)), M.add(Ce).normalize(), ae.copy(o.bone.position).normalize(), re.setFromUnitVectors(ae, M), o.boneParent.quaternion.premultiply(re), o.boneParent.updateWorldMatrix(!1, !0))));
|
|
375
375
|
}
|
|
376
376
|
this.helpers.isActive && this.updateHelpers();
|
|
377
377
|
}
|
|
@@ -445,14 +445,14 @@ class et {
|
|
|
445
445
|
xe.copy(this.armature.matrixWorld).invert();
|
|
446
446
|
const t = m.object.geometry.getAttribute("position");
|
|
447
447
|
for (let e = 0, n = m.bones.length; e < n; e++)
|
|
448
|
-
fe.multiplyMatrices(xe, m.bones[e].matrixWorld),
|
|
448
|
+
fe.multiplyMatrices(xe, m.bones[e].matrixWorld), M.setFromMatrixPosition(fe), t.setXYZ(e, M.x, M.y, M.z);
|
|
449
449
|
t.needsUpdate = !0, m.object.updateMatrixWorld();
|
|
450
450
|
}
|
|
451
451
|
if (m = this.helpers.lines, m.bones.length) {
|
|
452
452
|
xe.copy(this.armature.matrixWorld).invert();
|
|
453
453
|
const t = m.object.geometry.getAttribute("position");
|
|
454
454
|
for (let e = 0, n = 0, i = m.bones.length; e < i; e++, n += 2)
|
|
455
|
-
fe.multiplyMatrices(xe, m.bones[e].matrixWorld),
|
|
455
|
+
fe.multiplyMatrices(xe, m.bones[e].matrixWorld), M.setFromMatrixPosition(fe), t.setXYZ(n, M.x, M.y, M.z), fe.multiplyMatrices(xe, m.bones[e].parent.matrixWorld), M.setFromMatrixPosition(fe), t.setXYZ(n + 1, M.x, M.y, M.z);
|
|
456
456
|
t.needsUpdate = !0, m.object.updateMatrixWorld();
|
|
457
457
|
}
|
|
458
458
|
}
|
|
@@ -2629,7 +2629,7 @@ const ct = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
|
2629
2629
|
fr: rt,
|
|
2630
2630
|
fi: ut,
|
|
2631
2631
|
lt: ct
|
|
2632
|
-
},
|
|
2632
|
+
}, $ = new y.Quaternion(), Z = new y.Euler(), ve = new y.Vector3(), Re = new y.Vector3(), We = new y.Box3();
|
|
2633
2633
|
new y.Matrix4();
|
|
2634
2634
|
new y.Matrix4();
|
|
2635
2635
|
new y.Vector3();
|
|
@@ -4086,7 +4086,7 @@ class Be {
|
|
|
4086
4086
|
this.opt.lightSpotDispersion
|
|
4087
4087
|
), this.setLighting(this.opt);
|
|
4088
4088
|
const l = new y.PMREMGenerator(this.renderer);
|
|
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
|
|
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 je(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
4091
|
this.ikMesh = new y.SkinnedMesh();
|
|
4092
4092
|
const s = {
|
|
@@ -4252,7 +4252,7 @@ class Be {
|
|
|
4252
4252
|
async showAvatar(t, e = null) {
|
|
4253
4253
|
if (!t || !t.hasOwnProperty("url"))
|
|
4254
4254
|
throw new Error("Invalid parameter. The avatar must have at least 'url' specified.");
|
|
4255
|
-
const n = new
|
|
4255
|
+
const n = new Ye();
|
|
4256
4256
|
if (this.dracoEnabled) {
|
|
4257
4257
|
const r = new Qe();
|
|
4258
4258
|
r.setDecoderPath(this.dracoDecoderPath), n.setDRACOLoader(r);
|
|
@@ -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
|
+
Z.set(e.x, e.y, e.z);
|
|
4402
4402
|
const n = this.poseAvatar.props[t];
|
|
4403
|
-
n.isQuaternion ? (
|
|
4403
|
+
n.isQuaternion ? ($.setFromEuler(Z), n.multiply($)) : n.isVector3 && n.add(Z);
|
|
4404
4404
|
}
|
|
4405
4405
|
}
|
|
4406
4406
|
/**
|
|
@@ -5172,7 +5172,7 @@ class Be {
|
|
|
5172
5172
|
}, i.x ? new y.Vector3(i.x, i.y, i.z) : null, !0, i.d);
|
|
5173
5173
|
break;
|
|
5174
5174
|
}
|
|
5175
|
-
if ((h || r) && (
|
|
5175
|
+
if ((h || r) && (Z.setFromQuaternion(this.poseAvatar.props["Head.quaternion"]), Z.x = Math.max(-0.9, Math.min(0.9, 2 * Z.x - 0.5)), Z.y = Math.max(-0.9, Math.min(0.9, -2.5 * Z.y)), h ? (Object.assign(this.mtAvatar.eyesLookDown, { system: Z.x < 0 ? -Z.x : 0, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyesLookUp, { system: Z.x < 0 ? 0 : Z.x, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookInLeft, { system: Z.y < 0 ? -Z.y : 0, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookOutLeft, { system: Z.y < 0 ? 0 : Z.y, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookInRight, { system: Z.y < 0 ? 0 : Z.y, needsUpdate: !0 }), Object.assign(this.mtAvatar.eyeLookOutRight, { system: Z.y < 0 ? -Z.y : 0, needsUpdate: !0 }), r && (n = -this.mtAvatar.bodyRotateY.value, i = this.gaussianRandom(-0.2, 0.2), this.animQueue.push(this.animFactory({
|
|
5176
5176
|
name: "headmove",
|
|
5177
5177
|
dt: [[1e3, 2e3], [1e3, 2e3, 1, 2], [1e3, 2e3], [1e3, 2e3, 1, 2]],
|
|
5178
5178
|
vs: {
|
|
@@ -5193,7 +5193,7 @@ class Be {
|
|
|
5193
5193
|
eyeLookOutRight: [null, 0],
|
|
5194
5194
|
eyeContact: [0]
|
|
5195
5195
|
}
|
|
5196
|
-
})))), e > 2 * this.animFrameDur && (e = 2 * this.animFrameDur), (this.viewName !== "full" || this.isAvatarOnly) && (n = this.mtRandomized[Math.floor(Math.random() * this.mtRandomized.length)], i = this.mtAvatar[n], i.needsUpdate || Object.assign(i, { base: (this.mood.baseline[n] || 0) + (1 + l / 255) * Math.random() / 5, needsUpdate: !0 })), this.updatePoseBase(this.animClock), this.mixer && this.mixer.update(e / 1e3 * this.mixer.timeScale), this.updatePoseDelta(), (this.isSpeaking || this.isListening) && h ? l > this.volumeMax ? (this.volumeHeadBase = 0.05, Math.random() > 0.6 && (this.volumeHeadTarget = -0.05 - Math.random() / 15), this.volumeMax = l) : (this.volumeMax *= 0.92, this.volumeHeadTarget = this.volumeHeadBase - 0.9 * (this.volumeHeadBase - this.volumeHeadTarget)) : (this.volumeHeadTarget = 0, this.volumeMax = 0), n = this.volumeHeadTarget - this.volumeHeadCurrent, i = Math.abs(n), i > 1e-4 && (o = i * (this.volumeHeadEasing(Math.min(1, this.volumeHeadVelocity * e / 1e3 / i) / 2 + 0.5) - 0.5), this.volumeHeadCurrent += Math.sign(n) * Math.min(i, o)), Math.abs(this.volumeHeadCurrent) > 1e-4 && (
|
|
5196
|
+
})))), e > 2 * this.animFrameDur && (e = 2 * this.animFrameDur), (this.viewName !== "full" || this.isAvatarOnly) && (n = this.mtRandomized[Math.floor(Math.random() * this.mtRandomized.length)], i = this.mtAvatar[n], i.needsUpdate || Object.assign(i, { base: (this.mood.baseline[n] || 0) + (1 + l / 255) * Math.random() / 5, needsUpdate: !0 })), this.updatePoseBase(this.animClock), this.mixer && this.mixer.update(e / 1e3 * this.mixer.timeScale), this.updatePoseDelta(), (this.isSpeaking || this.isListening) && h ? l > this.volumeMax ? (this.volumeHeadBase = 0.05, Math.random() > 0.6 && (this.volumeHeadTarget = -0.05 - Math.random() / 15), this.volumeMax = l) : (this.volumeMax *= 0.92, this.volumeHeadTarget = this.volumeHeadBase - 0.9 * (this.volumeHeadBase - this.volumeHeadTarget)) : (this.volumeHeadTarget = 0, this.volumeMax = 0), n = this.volumeHeadTarget - this.volumeHeadCurrent, i = Math.abs(n), i > 1e-4 && (o = i * (this.volumeHeadEasing(Math.min(1, this.volumeHeadVelocity * e / 1e3 / i) / 2 + 0.5) - 0.5), this.volumeHeadCurrent += Math.sign(n) * Math.min(i, o)), Math.abs(this.volumeHeadCurrent) > 1e-4 && ($.setFromAxisAngle(mt, this.volumeHeadCurrent), this.objectNeck.quaternion.multiply($)), We.setFromObject(this.armature), this.objectLeftToeBase.getWorldPosition(ve), ve.sub(this.armature.position), this.objectRightToeBase.getWorldPosition(Re), Re.sub(this.armature.position), this.objectHips.position.y -= We.min.y / 2, this.objectHips.position.x -= (ve.x + Re.x) / 4, this.objectHips.position.z -= (ve.z + Re.z) / 2, this.dynamicbones.update(e), this.fbxAnimationLoader && this.fbxAnimationLoader.update(), this.opt.update && this.opt.update(e), this.updateMorphTargets(e), this.isAvatarOnly)
|
|
5197
5197
|
this.stats && this.stats.end();
|
|
5198
5198
|
else {
|
|
5199
5199
|
if (this.cameraClock !== null && this.cameraClock < 1e3) {
|
|
@@ -5264,10 +5264,10 @@ class Be {
|
|
|
5264
5264
|
let u = "", a = "", d = 0, c = [], g = [];
|
|
5265
5265
|
const x = Array.from(this.segmenter.segment(t), (f) => f.segment);
|
|
5266
5266
|
for (let f = 0; f < x.length; f++) {
|
|
5267
|
-
const k = f === x.length - 1,
|
|
5267
|
+
const k = f === x.length - 1, D = x[f].match(l);
|
|
5268
5268
|
let p = x[f].match(s);
|
|
5269
|
-
const B = x[f].match(h),
|
|
5270
|
-
if (p && !k && !B && x[f + 1].match(s) && (p = !1), n && (u += x[f]),
|
|
5269
|
+
const B = x[f].match(h), T = x[f].match(o);
|
|
5270
|
+
if (p && !k && !B && x[f + 1].match(s) && (p = !1), n && (u += x[f]), D && (!i || i.every((R) => f < R[0] || f > R[1])) && (a += x[f]), (T || p || k) && (a.length && (a = this.lipsyncPreProcessText(a, r), a.length && c.push({
|
|
5271
5271
|
mark: d,
|
|
5272
5272
|
word: a
|
|
5273
5273
|
})), u.length && (g.push({
|
|
@@ -5278,16 +5278,16 @@ class Be {
|
|
|
5278
5278
|
subtitles: [u]
|
|
5279
5279
|
}
|
|
5280
5280
|
}), u = ""), a.length)) {
|
|
5281
|
-
const
|
|
5282
|
-
if (
|
|
5283
|
-
const L =
|
|
5284
|
-
for (let I = 0; I <
|
|
5281
|
+
const R = this.lipsyncWordsToVisemes(a, r);
|
|
5282
|
+
if (R && R.visemes && R.visemes.length) {
|
|
5283
|
+
const L = R.times[R.visemes.length - 1] + R.durations[R.visemes.length - 1];
|
|
5284
|
+
for (let I = 0; I < R.visemes.length; I++)
|
|
5285
5285
|
g.push({
|
|
5286
5286
|
mark: d,
|
|
5287
5287
|
template: { name: "viseme" },
|
|
5288
|
-
ts: [(
|
|
5288
|
+
ts: [(R.times[I] - 0.6) / L, (R.times[I] + 0.5) / L, (R.times[I] + R.durations[I] + 0.5) / L],
|
|
5289
5289
|
vs: {
|
|
5290
|
-
["viseme_" +
|
|
5290
|
+
["viseme_" + R.visemes[I]]: [null, R.visemes[I] === "PP" || R.visemes[I] === "FF" ? 0.9 : 0.6, 0]
|
|
5291
5291
|
}
|
|
5292
5292
|
});
|
|
5293
5293
|
}
|
|
@@ -5295,14 +5295,14 @@ class Be {
|
|
|
5295
5295
|
}
|
|
5296
5296
|
if (p || k) {
|
|
5297
5297
|
if (c.length || k && g.length) {
|
|
5298
|
-
const
|
|
5298
|
+
const R = {
|
|
5299
5299
|
anim: g
|
|
5300
5300
|
};
|
|
5301
|
-
n && (
|
|
5301
|
+
n && (R.onSubtitles = n), c.length && !e.avatarMute && (R.text = c, e.avatarMood && (R.mood = e.avatarMood), e.ttsLang && (R.lang = e.ttsLang), e.ttsVoice && (R.voice = e.ttsVoice), e.ttsRate && (R.rate = e.ttsRate), e.ttsVoice && (R.pitch = e.ttsPitch), e.ttsVolume && (R.volume = e.ttsVolume)), this.speechQueue.push(R), c = [], a = "", d = 0, g = [];
|
|
5302
5302
|
}
|
|
5303
5303
|
if (B) {
|
|
5304
|
-
let
|
|
5305
|
-
|
|
5304
|
+
let R = this.animEmojis[x[f]];
|
|
5305
|
+
R && R.link && (R = this.animEmojis[R.link]), R && this.speechQueue.push({ emoji: R });
|
|
5306
5306
|
}
|
|
5307
5307
|
this.speechQueue.push({ break: 100 });
|
|
5308
5308
|
}
|
|
@@ -5398,10 +5398,10 @@ class Be {
|
|
|
5398
5398
|
let x = 0.6 + this.convertRange(g, [0, u], [0, 0.4]);
|
|
5399
5399
|
if (u = Math.min(u, d.visemes.length * 200), c > 0)
|
|
5400
5400
|
for (let f = 0; f < d.visemes.length; f++) {
|
|
5401
|
-
const k = r + d.times[f] / c * u,
|
|
5401
|
+
const k = r + d.times[f] / c * u, D = d.durations[f] / c * u;
|
|
5402
5402
|
o.push({
|
|
5403
5403
|
template: { name: "viseme" },
|
|
5404
|
-
ts: [k - Math.min(60, 2 *
|
|
5404
|
+
ts: [k - Math.min(60, 2 * D / 3), k + Math.min(25, D / 2), k + D + Math.min(60, D / 2)],
|
|
5405
5405
|
vs: {
|
|
5406
5406
|
["viseme_" + d.visemes[f]]: [null, d.visemes[f] === "PP" || d.visemes[f] === "FF" ? 0.9 : x, 0]
|
|
5407
5407
|
}
|
|
@@ -5499,18 +5499,18 @@ class Be {
|
|
|
5499
5499
|
if (f && f.visemes && f.visemes.length > 0) {
|
|
5500
5500
|
const p = f.times[f.visemes.length - 1] + f.durations[f.visemes.length - 1];
|
|
5501
5501
|
for (let B = 0; B < f.visemes.length; B++) {
|
|
5502
|
-
const
|
|
5502
|
+
const T = f.visemes[B], R = f.times[B] / p, L = f.durations[B] / p, I = R * d, z = L * d;
|
|
5503
5503
|
k.push({
|
|
5504
5504
|
template: { name: "viseme" },
|
|
5505
5505
|
ts: [I - Math.min(60, 2 * z / 3), I + Math.min(25, z / 2), I + z + Math.min(60, z / 2)],
|
|
5506
5506
|
vs: {
|
|
5507
|
-
["viseme_" +
|
|
5507
|
+
["viseme_" + T]: [null, T === "PP" || T === "FF" ? 0.9 : 0.6, 0]
|
|
5508
5508
|
}
|
|
5509
5509
|
});
|
|
5510
5510
|
}
|
|
5511
5511
|
}
|
|
5512
|
-
const
|
|
5513
|
-
this.audioPlaylist.push({ anim:
|
|
5512
|
+
const D = [...t.anim, ...k];
|
|
5513
|
+
this.audioPlaylist.push({ anim: D, audio: c }), this.onSubtitles = t.onSubtitles || null, this.resetLips(), t.mood && this.setMood(t.mood), this.playAudio(), s.onend = () => {
|
|
5514
5514
|
e();
|
|
5515
5515
|
}, s.onerror = (p) => {
|
|
5516
5516
|
console.error("Speech synthesis error:", p.error), n(p.error);
|
|
@@ -6159,12 +6159,12 @@ class Be {
|
|
|
6159
6159
|
this.lookAt(null, null, t);
|
|
6160
6160
|
return;
|
|
6161
6161
|
}
|
|
6162
|
-
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0), ve.setFromMatrixPosition(this.objectLeftEye.matrixWorld), Re.setFromMatrixPosition(this.objectRightEye.matrixWorld), ve.add(Re).divideScalar(2),
|
|
6162
|
+
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0), ve.setFromMatrixPosition(this.objectLeftEye.matrixWorld), Re.setFromMatrixPosition(this.objectRightEye.matrixWorld), ve.add(Re).divideScalar(2), $.copy(this.armature.quaternion), $.multiply(this.poseTarget.props["Hips.quaternion"]), $.multiply(this.poseTarget.props["Spine.quaternion"]), $.multiply(this.poseTarget.props["Spine1.quaternion"]), $.multiply(this.poseTarget.props["Spine2.quaternion"]), $.multiply(this.poseTarget.props["Neck.quaternion"]), $.multiply(this.poseTarget.props["Head.quaternion"]);
|
|
6163
6163
|
const n = new y.Vector3().subVectors(e, ve).normalize(), i = Math.atan2(n.x, n.z), s = Math.asin(-n.y);
|
|
6164
|
-
|
|
6165
|
-
const l = new y.Quaternion().setFromEuler(
|
|
6166
|
-
|
|
6167
|
-
let r =
|
|
6164
|
+
Z.set(s, i, 0, "YXZ");
|
|
6165
|
+
const l = new y.Quaternion().setFromEuler(Z), h = new y.Quaternion().copy(l).multiply($.clone().invert());
|
|
6166
|
+
Z.setFromQuaternion(h, "YXZ");
|
|
6167
|
+
let r = Z.x / (40 / 24) + 0.2, u = Z.y / (9 / 4), a = Math.min(0.6, Math.max(-0.3, r)), d = Math.min(0.8, Math.max(-0.8, u)), c = (Math.random() - 0.5) / 4, g = (Math.random() - 0.5) / 4;
|
|
6168
6168
|
if (t) {
|
|
6169
6169
|
let x = this.animQueue.findIndex((k) => k.template.name === "lookat");
|
|
6170
6170
|
x !== -1 && this.animQueue.splice(x, 1);
|
|
@@ -6199,20 +6199,20 @@ class Be {
|
|
|
6199
6199
|
const s = new y.Vector3().setFromMatrixPosition(this.objectLeftEye.matrixWorld), o = new y.Vector3().setFromMatrixPosition(this.objectRightEye.matrixWorld), l = new y.Vector3().addVectors(s, o).divideScalar(2);
|
|
6200
6200
|
l.project(this.camera);
|
|
6201
6201
|
let h = (l.x + 1) / 2 * i.width + i.left, r = -(l.y - 1) / 2 * i.height + i.top;
|
|
6202
|
-
t === null && (t = h), e === null && (e = r),
|
|
6203
|
-
let u =
|
|
6202
|
+
t === null && (t = h), e === null && (e = r), $.copy(this.armature.quaternion), $.multiply(this.poseTarget.props["Hips.quaternion"]), $.multiply(this.poseTarget.props["Spine.quaternion"]), $.multiply(this.poseTarget.props["Spine1.quaternion"]), $.multiply(this.poseTarget.props["Spine2.quaternion"]), $.multiply(this.poseTarget.props["Neck.quaternion"]), $.multiply(this.poseTarget.props["Head.quaternion"]), Z.setFromQuaternion($);
|
|
6203
|
+
let u = Z.x / (40 / 24), a = Z.y / (9 / 4), d = Math.min(0.4, Math.max(-0.4, this.camera.rotation.x)), c = Math.min(0.4, Math.max(-0.4, this.camera.rotation.y)), g = Math.max(window.innerWidth - h, h), x = Math.max(window.innerHeight - r, r), f = this.convertRange(e, [r - x, r + x], [-0.3, 0.6]) - u + d, k = this.convertRange(t, [h - g, h + g], [-0.8, 0.8]) - a + c;
|
|
6204
6204
|
f = Math.min(0.6, Math.max(-0.3, f)), k = Math.min(0.8, Math.max(-0.8, k));
|
|
6205
|
-
let
|
|
6205
|
+
let D = (Math.random() - 0.5) / 4, p = (Math.random() - 0.5) / 4;
|
|
6206
6206
|
if (n) {
|
|
6207
|
-
let B = this.animQueue.findIndex((
|
|
6207
|
+
let B = this.animQueue.findIndex((R) => R.template.name === "lookat");
|
|
6208
6208
|
B !== -1 && this.animQueue.splice(B, 1);
|
|
6209
|
-
const
|
|
6209
|
+
const T = {
|
|
6210
6210
|
name: "lookat",
|
|
6211
6211
|
dt: [750, n],
|
|
6212
6212
|
vs: {
|
|
6213
|
-
bodyRotateX: [f +
|
|
6213
|
+
bodyRotateX: [f + D],
|
|
6214
6214
|
bodyRotateY: [k + p],
|
|
6215
|
-
eyesRotateX: [-3 *
|
|
6215
|
+
eyesRotateX: [-3 * D + 0.1],
|
|
6216
6216
|
eyesRotateY: [-5 * p],
|
|
6217
6217
|
browInnerUp: [[0, 0.7]],
|
|
6218
6218
|
mouthLeft: [[0, 0.7]],
|
|
@@ -6221,7 +6221,7 @@ class Be {
|
|
|
6221
6221
|
headMove: [0]
|
|
6222
6222
|
}
|
|
6223
6223
|
};
|
|
6224
|
-
this.animQueue.push(this.animFactory(
|
|
6224
|
+
this.animQueue.push(this.animFactory(T));
|
|
6225
6225
|
}
|
|
6226
6226
|
}
|
|
6227
6227
|
/**
|
|
@@ -6523,8 +6523,8 @@ class Be {
|
|
|
6523
6523
|
if (S.toLowerCase() === z)
|
|
6524
6524
|
return S;
|
|
6525
6525
|
for (const S of c) {
|
|
6526
|
-
const
|
|
6527
|
-
if ((z.includes("left") &&
|
|
6526
|
+
const E = S.toLowerCase();
|
|
6527
|
+
if ((z.includes("left") && E.includes("left") || z.includes("right") && E.includes("right")) && (z.includes("arm") && E.includes("arm") && !E.includes("fore") || z.includes("forearm") && E.includes("forearm") || z.includes("hand") && E.includes("hand") && !E.includes("index") && !E.includes("thumb") || z.includes("shoulder") && E.includes("shoulder")))
|
|
6528
6528
|
return S;
|
|
6529
6529
|
}
|
|
6530
6530
|
return null;
|
|
@@ -6535,16 +6535,16 @@ class Be {
|
|
|
6535
6535
|
}), console.log("=== Ready Player Me Animation Bone Analysis ==="), console.log("FBX bone names:", Array.from(f).sort().join(", ")), console.log("Avatar skeleton bone names:", Array.from(c).sort().join(", "));
|
|
6536
6536
|
const k = Array.from(f).filter(
|
|
6537
6537
|
(L) => L.toLowerCase().includes("arm") || L.toLowerCase().includes("hand") || L.toLowerCase().includes("shoulder")
|
|
6538
|
-
),
|
|
6538
|
+
), D = Array.from(c).filter(
|
|
6539
6539
|
(L) => L.includes("Arm") || L.includes("Hand") || L.includes("Shoulder")
|
|
6540
6540
|
);
|
|
6541
|
-
console.log("FBX arm/hand/shoulder bones:", k.sort().join(", ")), console.log("Avatar arm/hand/shoulder bones:",
|
|
6541
|
+
console.log("FBX arm/hand/shoulder bones:", k.sort().join(", ")), console.log("Avatar arm/hand/shoulder bones:", D.sort().join(", "));
|
|
6542
6542
|
const p = [], B = /* @__PURE__ */ new Set();
|
|
6543
6543
|
if (d.tracks.forEach((L) => {
|
|
6544
|
-
const z = L.name.replaceAll("mixamorig", "").split("."), Y = z[0], S = z[1],
|
|
6545
|
-
if (
|
|
6546
|
-
const
|
|
6547
|
-
|
|
6544
|
+
const z = L.name.replaceAll("mixamorig", "").split("."), Y = z[0], S = z[1], E = x(Y);
|
|
6545
|
+
if (E && S) {
|
|
6546
|
+
const j = `${E}.${S}`, X = L.clone();
|
|
6547
|
+
X.name = j, p.push(X), Y !== E && g.set(Y, E);
|
|
6548
6548
|
} else
|
|
6549
6549
|
B.add(Y), (Y.toLowerCase().includes("arm") || Y.toLowerCase().includes("hand") || Y.toLowerCase().includes("shoulder")) && console.warn(`⚠️ Arm bone "${Y}" could not be mapped to avatar skeleton`);
|
|
6550
6550
|
}), B.size > 0 && console.warn(`⚠️ ${B.size} bone(s) could not be mapped:`, Array.from(B).sort().join(", ")), p.length > 0) {
|
|
@@ -6558,21 +6558,21 @@ class Be {
|
|
|
6558
6558
|
L.length > 0 ? console.log(`✓ Arm bones mapped: ${L.join(", ")}`) : console.warn("⚠️ No arm bones were mapped! This may cause arm rigging issues.");
|
|
6559
6559
|
} else
|
|
6560
6560
|
console.error("❌ No tracks could be mapped! Animation may not work correctly.");
|
|
6561
|
-
const
|
|
6561
|
+
const T = {};
|
|
6562
6562
|
d.tracks.forEach((L) => {
|
|
6563
6563
|
L.name = L.name.replaceAll("mixamorig", "");
|
|
6564
6564
|
const I = L.name.split(".");
|
|
6565
6565
|
if (I[1] === "position") {
|
|
6566
6566
|
for (let z = 0; z < L.values.length; z++)
|
|
6567
6567
|
L.values[z] = L.values[z] * s;
|
|
6568
|
-
|
|
6569
|
-
} else I[1] === "quaternion" ?
|
|
6568
|
+
T[L.name] = new y.Vector3(L.values[0], L.values[1], L.values[2]);
|
|
6569
|
+
} else I[1] === "quaternion" ? T[L.name] = new y.Quaternion(L.values[0], L.values[1], L.values[2], L.values[3]) : I[1] === "rotation" && (T[I[0] + ".quaternion"] = new y.Quaternion().setFromEuler(new y.Euler(L.values[0], L.values[1], L.values[2], "XYZ")).normalize());
|
|
6570
6570
|
});
|
|
6571
|
-
const
|
|
6572
|
-
|
|
6571
|
+
const R = { props: T };
|
|
6572
|
+
T["Hips.position"] && (T["Hips.position"].y < 0.5 ? R.lying = !0 : R.standing = !0), this.animClips.push({
|
|
6573
6573
|
url: t + "-" + i,
|
|
6574
6574
|
clip: d,
|
|
6575
|
-
pose:
|
|
6575
|
+
pose: R
|
|
6576
6576
|
}), this.playAnimation(t, e, n, i, s);
|
|
6577
6577
|
} else {
|
|
6578
6578
|
const d = "Animation " + t + " (ndx=" + i + ") not found";
|
|
@@ -6707,12 +6707,12 @@ class Be {
|
|
|
6707
6707
|
const f = t.iterations || 10;
|
|
6708
6708
|
if (e)
|
|
6709
6709
|
for (let k = 0; k < f; k++) {
|
|
6710
|
-
let
|
|
6710
|
+
let D = !1;
|
|
6711
6711
|
for (let p = 0, B = x.length; p < B; p++) {
|
|
6712
|
-
const
|
|
6713
|
-
|
|
6714
|
-
let
|
|
6715
|
-
|
|
6712
|
+
const T = x[p].bone;
|
|
6713
|
+
T.matrixWorld.decompose(h, r, u), r.invert(), o.setFromMatrixPosition(g.matrixWorld), l.subVectors(o, h), l.applyQuaternion(r), l.normalize(), s.subVectors(e, h), s.applyQuaternion(r), s.normalize();
|
|
6714
|
+
let R = s.dot(l);
|
|
6715
|
+
R > 1 ? R = 1 : R < -1 && (R = -1), R = Math.acos(R), !(R < 1e-5) && (x[p].minAngle !== void 0 && R < x[p].minAngle && (R = x[p].minAngle), x[p].maxAngle !== void 0 && R > x[p].maxAngle && (R = x[p].maxAngle), a.crossVectors(l, s), a.normalize(), $.setFromAxisAngle(a, R), T.quaternion.multiply($), T.rotation.setFromVector3(d.setFromEuler(T.rotation).clamp(new y.Vector3(
|
|
6716
6716
|
x[p].minx !== void 0 ? x[p].minx : -1 / 0,
|
|
6717
6717
|
x[p].miny !== void 0 ? x[p].miny : -1 / 0,
|
|
6718
6718
|
x[p].minz !== void 0 ? x[p].minz : -1 / 0
|
|
@@ -6720,9 +6720,9 @@ class Be {
|
|
|
6720
6720
|
x[p].maxx !== void 0 ? x[p].maxx : 1 / 0,
|
|
6721
6721
|
x[p].maxy !== void 0 ? x[p].maxy : 1 / 0,
|
|
6722
6722
|
x[p].maxz !== void 0 ? x[p].maxz : 1 / 0
|
|
6723
|
-
))),
|
|
6723
|
+
))), T.updateMatrixWorld(!0), D = !0);
|
|
6724
6724
|
}
|
|
6725
|
-
if (!
|
|
6725
|
+
if (!D) break;
|
|
6726
6726
|
}
|
|
6727
6727
|
i && x.forEach((k) => {
|
|
6728
6728
|
this.poseTarget.props[k.link + ".quaternion"].copy(k.bone.quaternion), this.poseTarget.props[k.link + ".quaternion"].t = this.animClock, this.poseTarget.props[k.link + ".quaternion"].d = i;
|
|
@@ -6815,72 +6815,72 @@ const Ve = Me(({
|
|
|
6815
6815
|
style: x = {},
|
|
6816
6816
|
animations: f = {}
|
|
6817
6817
|
}, k) => {
|
|
6818
|
-
const
|
|
6818
|
+
const D = W(null), p = W(null), B = W(r), T = W(null), R = W(null), L = W(!1), I = W({ remainingText: null, originalText: null, options: null }), z = W([]), Y = W(0), [S, E] = pe(!0), [j, X] = pe(null), [oe, le] = pe(!1), [ge, de] = pe(!1);
|
|
6819
6819
|
ce(() => {
|
|
6820
6820
|
L.current = ge;
|
|
6821
6821
|
}, [ge]), ce(() => {
|
|
6822
6822
|
B.current = r;
|
|
6823
6823
|
}, [r]);
|
|
6824
|
-
const
|
|
6825
|
-
let
|
|
6826
|
-
be === "browser" ?
|
|
6824
|
+
const ee = Ee(), be = i || ee.service;
|
|
6825
|
+
let Q;
|
|
6826
|
+
be === "browser" ? Q = {
|
|
6827
6827
|
service: "browser",
|
|
6828
6828
|
endpoint: "",
|
|
6829
6829
|
apiKey: null,
|
|
6830
6830
|
defaultVoice: "Google US English"
|
|
6831
|
-
} : be === "elevenlabs" ?
|
|
6831
|
+
} : be === "elevenlabs" ? Q = {
|
|
6832
6832
|
service: "elevenlabs",
|
|
6833
6833
|
endpoint: "https://api.elevenlabs.io/v1/text-to-speech",
|
|
6834
|
-
apiKey: o ||
|
|
6835
|
-
defaultVoice: s ||
|
|
6836
|
-
voices:
|
|
6837
|
-
} : be === "deepgram" ?
|
|
6834
|
+
apiKey: o || ee.apiKey,
|
|
6835
|
+
defaultVoice: s || ee.defaultVoice || Ie.defaultVoice,
|
|
6836
|
+
voices: ee.voices || Ie.voices
|
|
6837
|
+
} : be === "deepgram" ? Q = {
|
|
6838
6838
|
service: "deepgram",
|
|
6839
6839
|
endpoint: "https://api.deepgram.com/v1/speak",
|
|
6840
|
-
apiKey: o ||
|
|
6841
|
-
defaultVoice: s ||
|
|
6842
|
-
voices:
|
|
6843
|
-
} :
|
|
6844
|
-
|
|
6840
|
+
apiKey: o || ee.apiKey,
|
|
6841
|
+
defaultVoice: s || ee.defaultVoice || Te.defaultVoice,
|
|
6842
|
+
voices: ee.voices || Te.voices
|
|
6843
|
+
} : Q = {
|
|
6844
|
+
...ee,
|
|
6845
6845
|
// Override API key if provided via props
|
|
6846
|
-
apiKey: o !== null ? o :
|
|
6846
|
+
apiKey: o !== null ? o : ee.apiKey
|
|
6847
6847
|
};
|
|
6848
6848
|
const b = {
|
|
6849
6849
|
url: V,
|
|
6850
6850
|
body: t,
|
|
6851
6851
|
avatarMood: e,
|
|
6852
6852
|
ttsLang: be === "browser" ? "en-US" : n,
|
|
6853
|
-
ttsVoice: s ||
|
|
6853
|
+
ttsVoice: s || Q.defaultVoice,
|
|
6854
6854
|
lipsyncLang: "en",
|
|
6855
6855
|
showFullAvatar: r,
|
|
6856
6856
|
bodyMovement: l,
|
|
6857
6857
|
movementIntensity: h
|
|
6858
|
-
},
|
|
6859
|
-
ttsEndpoint:
|
|
6860
|
-
ttsApikey:
|
|
6858
|
+
}, v = {
|
|
6859
|
+
ttsEndpoint: Q.endpoint,
|
|
6860
|
+
ttsApikey: Q.apiKey,
|
|
6861
6861
|
ttsService: be,
|
|
6862
6862
|
lipsyncModules: ["en"],
|
|
6863
6863
|
cameraView: u
|
|
6864
|
-
},
|
|
6865
|
-
if (!(!
|
|
6864
|
+
}, F = O(async () => {
|
|
6865
|
+
if (!(!D.current || p.current))
|
|
6866
6866
|
try {
|
|
6867
|
-
if (
|
|
6868
|
-
if (
|
|
6869
|
-
const
|
|
6870
|
-
d(
|
|
6867
|
+
if (E(!0), X(null), p.current = new Be(D.current, v), p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1), f && Object.keys(f).length > 0 && (p.current.customAnimations = f), await p.current.showAvatar(b, (K) => {
|
|
6868
|
+
if (K.lengthComputable) {
|
|
6869
|
+
const ne = Math.min(100, Math.round(K.loaded / K.total * 100));
|
|
6870
|
+
d(ne);
|
|
6871
6871
|
}
|
|
6872
|
-
}), await new Promise((
|
|
6873
|
-
const
|
|
6874
|
-
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ?
|
|
6872
|
+
}), await new Promise((K) => {
|
|
6873
|
+
const ne = () => {
|
|
6874
|
+
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? K() : setTimeout(ne, 100);
|
|
6875
6875
|
};
|
|
6876
|
-
|
|
6876
|
+
ne();
|
|
6877
6877
|
}), p.current && p.current.setShowFullAvatar)
|
|
6878
6878
|
try {
|
|
6879
6879
|
p.current.setShowFullAvatar(r);
|
|
6880
|
-
} catch (
|
|
6881
|
-
console.warn("Error setting full body mode on initialization:",
|
|
6880
|
+
} catch (K) {
|
|
6881
|
+
console.warn("Error setting full body mode on initialization:", K);
|
|
6882
6882
|
}
|
|
6883
|
-
p.current && p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1, p.current.controls.update()),
|
|
6883
|
+
p.current && p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1, p.current.controls.update()), E(!1), le(!0), a(p.current);
|
|
6884
6884
|
const U = () => {
|
|
6885
6885
|
document.visibilityState === "visible" ? p.current?.start() : p.current?.stop();
|
|
6886
6886
|
};
|
|
@@ -6888,65 +6888,65 @@ const Ve = Me(({
|
|
|
6888
6888
|
document.removeEventListener("visibilitychange", U);
|
|
6889
6889
|
};
|
|
6890
6890
|
} catch (w) {
|
|
6891
|
-
console.error("Error initializing TalkingHead:", w),
|
|
6891
|
+
console.error("Error initializing TalkingHead:", w), X(w.message || "Failed to initialize avatar"), E(!1), c(w);
|
|
6892
6892
|
}
|
|
6893
6893
|
}, [V, t, e, n, i, s, o, r, l, h, u]);
|
|
6894
|
-
ce(() => (
|
|
6894
|
+
ce(() => (F(), () => {
|
|
6895
6895
|
p.current && (p.current.stop(), p.current.dispose(), p.current = null);
|
|
6896
|
-
}), [
|
|
6897
|
-
if (!
|
|
6898
|
-
const w = new ResizeObserver((
|
|
6899
|
-
for (const
|
|
6896
|
+
}), [F]), ce(() => {
|
|
6897
|
+
if (!D.current || !p.current) return;
|
|
6898
|
+
const w = new ResizeObserver((K) => {
|
|
6899
|
+
for (const ne of K)
|
|
6900
6900
|
p.current && p.current.onResize && p.current.onResize();
|
|
6901
6901
|
});
|
|
6902
|
-
w.observe(
|
|
6902
|
+
w.observe(D.current);
|
|
6903
6903
|
const U = () => {
|
|
6904
6904
|
p.current && p.current.onResize && p.current.onResize();
|
|
6905
6905
|
};
|
|
6906
6906
|
return window.addEventListener("resize", U), () => {
|
|
6907
6907
|
w.disconnect(), window.removeEventListener("resize", U);
|
|
6908
6908
|
};
|
|
6909
|
-
}, [
|
|
6910
|
-
const
|
|
6909
|
+
}, [oe]);
|
|
6910
|
+
const P = O(async () => {
|
|
6911
6911
|
if (p.current && p.current.audioCtx)
|
|
6912
6912
|
try {
|
|
6913
6913
|
(p.current.audioCtx.state === "suspended" || p.current.audioCtx.state === "interrupted") && (await p.current.audioCtx.resume(), console.log("Audio context resumed"));
|
|
6914
6914
|
} catch (w) {
|
|
6915
6915
|
console.warn("Failed to resume audio context:", w);
|
|
6916
6916
|
}
|
|
6917
|
-
}, []),
|
|
6918
|
-
if (p.current &&
|
|
6917
|
+
}, []), N = O(async (w, U = {}) => {
|
|
6918
|
+
if (p.current && oe)
|
|
6919
6919
|
try {
|
|
6920
|
-
|
|
6921
|
-
const
|
|
6922
|
-
z.current =
|
|
6920
|
+
R.current && (clearInterval(R.current), R.current = null), T.current = { text: w, options: U }, I.current = { remainingText: null, originalText: null, options: null };
|
|
6921
|
+
const K = /[!\.\?\n\p{Extended_Pictographic}]/ug, ne = w.split(K).map((A) => A.trim()).filter((A) => A.length > 0);
|
|
6922
|
+
z.current = ne, Y.current = 0, de(!1), L.current = !1, await P();
|
|
6923
6923
|
const me = {
|
|
6924
6924
|
...U,
|
|
6925
6925
|
lipsyncLang: U.lipsyncLang || b.lipsyncLang || "en"
|
|
6926
6926
|
};
|
|
6927
6927
|
if (U.onSpeechEnd && p.current) {
|
|
6928
6928
|
const A = p.current;
|
|
6929
|
-
let
|
|
6930
|
-
const
|
|
6931
|
-
let
|
|
6932
|
-
|
|
6933
|
-
if (
|
|
6929
|
+
let H = null, G = 0;
|
|
6930
|
+
const J = 1200;
|
|
6931
|
+
let ie = !1;
|
|
6932
|
+
H = setInterval(() => {
|
|
6933
|
+
if (G++, L.current)
|
|
6934
6934
|
return;
|
|
6935
|
-
if (
|
|
6936
|
-
if (
|
|
6937
|
-
|
|
6935
|
+
if (G > J) {
|
|
6936
|
+
if (H && (clearInterval(H), H = null, R.current = null), !ie && !L.current) {
|
|
6937
|
+
ie = !0;
|
|
6938
6938
|
try {
|
|
6939
6939
|
U.onSpeechEnd();
|
|
6940
|
-
} catch (
|
|
6941
|
-
console.error("Error in onSpeechEnd callback (timeout):",
|
|
6940
|
+
} catch (Oe) {
|
|
6941
|
+
console.error("Error in onSpeechEnd callback (timeout):", Oe);
|
|
6942
6942
|
}
|
|
6943
6943
|
}
|
|
6944
6944
|
return;
|
|
6945
6945
|
}
|
|
6946
|
-
const
|
|
6947
|
-
A && A.isSpeaking === !1 &&
|
|
6948
|
-
if (A && !L.current && A.isSpeaking === !1 && (!A.speechQueue || A.speechQueue.length === 0) && (!A.audioPlaylist || A.audioPlaylist.length === 0) && A.isAudioPlaying === !1 && !
|
|
6949
|
-
|
|
6946
|
+
const se = !A.speechQueue || A.speechQueue.length === 0, we = !A.audioPlaylist || A.audioPlaylist.length === 0;
|
|
6947
|
+
A && A.isSpeaking === !1 && se && we && A.isAudioPlaying === !1 && !ie && !L.current && setTimeout(() => {
|
|
6948
|
+
if (A && !L.current && A.isSpeaking === !1 && (!A.speechQueue || A.speechQueue.length === 0) && (!A.audioPlaylist || A.audioPlaylist.length === 0) && A.isAudioPlaying === !1 && !ie && !L.current) {
|
|
6949
|
+
ie = !0, H && (clearInterval(H), H = null, R.current = null);
|
|
6950
6950
|
try {
|
|
6951
6951
|
U.onSpeechEnd();
|
|
6952
6952
|
} catch (Ze) {
|
|
@@ -6954,75 +6954,75 @@ const Ve = Me(({
|
|
|
6954
6954
|
}
|
|
6955
6955
|
}
|
|
6956
6956
|
}, 100);
|
|
6957
|
-
}, 100),
|
|
6957
|
+
}, 100), R.current = H;
|
|
6958
6958
|
}
|
|
6959
6959
|
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(w, me)) : setTimeout(async () => {
|
|
6960
|
-
await
|
|
6960
|
+
await P(), p.current && p.current.lipsync && (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(w, me));
|
|
6961
6961
|
}, 100);
|
|
6962
|
-
} catch (
|
|
6963
|
-
console.error("Error speaking text:",
|
|
6962
|
+
} catch (K) {
|
|
6963
|
+
console.error("Error speaking text:", K), X(K.message || "Failed to speak text");
|
|
6964
6964
|
}
|
|
6965
|
-
}, [
|
|
6966
|
-
p.current && (p.current.stopSpeaking(), p.current.setSlowdownRate && p.current.setSlowdownRate(1),
|
|
6967
|
-
}, []),
|
|
6965
|
+
}, [oe, P, b.lipsyncLang]), te = O(() => {
|
|
6966
|
+
p.current && (p.current.stopSpeaking(), p.current.setSlowdownRate && p.current.setSlowdownRate(1), T.current = null, de(!1));
|
|
6967
|
+
}, []), q = O(() => {
|
|
6968
6968
|
if (p.current && p.current.pauseSpeaking) {
|
|
6969
6969
|
const w = p.current;
|
|
6970
6970
|
if (w.isSpeaking || w.audioPlaylist && w.audioPlaylist.length > 0 || w.speechQueue && w.speechQueue.length > 0) {
|
|
6971
|
-
|
|
6972
|
-
let
|
|
6973
|
-
if (
|
|
6974
|
-
const
|
|
6975
|
-
if (
|
|
6976
|
-
const
|
|
6977
|
-
|
|
6971
|
+
R.current && (clearInterval(R.current), R.current = null);
|
|
6972
|
+
let K = "";
|
|
6973
|
+
if (T.current && z.current.length > 0) {
|
|
6974
|
+
const ne = z.current.length, me = w.speechQueue ? w.speechQueue.filter((J) => J && J.text && Array.isArray(J.text) && J.text.length > 0).length : 0, A = w.audioPlaylist && w.audioPlaylist.length > 0, H = me + (A ? 1 : 0), G = ne - H;
|
|
6975
|
+
if (H > 0 && G < ne && (K = z.current.slice(G).join(". ").trim(), !K && me > 0 && w.speechQueue)) {
|
|
6976
|
+
const ie = w.speechQueue.filter((se) => se && se.text && Array.isArray(se.text) && se.text.length > 0).map((se) => se.text.map((we) => we.word || "").filter((we) => we.length > 0).join(" ")).filter((se) => se.length > 0).join(" ");
|
|
6977
|
+
ie && ie.trim() && (K = ie.trim());
|
|
6978
6978
|
}
|
|
6979
6979
|
}
|
|
6980
|
-
|
|
6981
|
-
remainingText:
|
|
6982
|
-
originalText:
|
|
6983
|
-
options:
|
|
6980
|
+
T.current && (I.current = {
|
|
6981
|
+
remainingText: K || null,
|
|
6982
|
+
originalText: T.current.text,
|
|
6983
|
+
options: T.current.options
|
|
6984
6984
|
}), w.speechQueue && (w.speechQueue.length = 0), p.current.pauseSpeaking(), L.current = !0, de(!0);
|
|
6985
6985
|
}
|
|
6986
6986
|
}
|
|
6987
|
-
}, []),
|
|
6987
|
+
}, []), _ = O(async () => {
|
|
6988
6988
|
if (!p.current || !ge)
|
|
6989
6989
|
return;
|
|
6990
6990
|
let w = "", U = {};
|
|
6991
6991
|
if (I.current && I.current.remainingText)
|
|
6992
6992
|
w = I.current.remainingText, U = I.current.options || {}, I.current = { remainingText: null, originalText: null, options: null };
|
|
6993
|
-
else if (
|
|
6994
|
-
w =
|
|
6993
|
+
else if (T.current && T.current.text)
|
|
6994
|
+
w = T.current.text, U = T.current.options || {};
|
|
6995
6995
|
else {
|
|
6996
6996
|
console.warn("Resume called but no paused speech found"), de(!1), L.current = !1;
|
|
6997
6997
|
return;
|
|
6998
6998
|
}
|
|
6999
|
-
de(!1), L.current = !1, await
|
|
7000
|
-
const
|
|
6999
|
+
de(!1), L.current = !1, await P();
|
|
7000
|
+
const K = {
|
|
7001
7001
|
...U,
|
|
7002
7002
|
lipsyncLang: U.lipsyncLang || b.lipsyncLang || "en"
|
|
7003
7003
|
};
|
|
7004
7004
|
try {
|
|
7005
|
-
await
|
|
7006
|
-
} catch (
|
|
7007
|
-
console.error("Error resuming speech:",
|
|
7005
|
+
await N(w, K);
|
|
7006
|
+
} catch (ne) {
|
|
7007
|
+
console.error("Error resuming speech:", ne), de(!1), L.current = !1;
|
|
7008
7008
|
}
|
|
7009
|
-
}, [
|
|
7009
|
+
}, [P, ge, N, b]), Ae = O((w) => {
|
|
7010
7010
|
p.current && p.current.setMood(w);
|
|
7011
|
-
}, []), Se =
|
|
7011
|
+
}, []), Se = O((w) => {
|
|
7012
7012
|
p.current && p.current.setSlowdownRate && p.current.setSlowdownRate(w);
|
|
7013
|
-
}, []), Le =
|
|
7013
|
+
}, []), Le = O((w, U = !1) => {
|
|
7014
7014
|
if (p.current && p.current.playAnimation) {
|
|
7015
7015
|
if (f && f[w] && (w = f[w]), p.current.setShowFullAvatar)
|
|
7016
7016
|
try {
|
|
7017
7017
|
p.current.setShowFullAvatar(B.current);
|
|
7018
|
-
} catch (
|
|
7019
|
-
console.warn("Error setting full body mode:",
|
|
7018
|
+
} catch (ne) {
|
|
7019
|
+
console.warn("Error setting full body mode:", ne);
|
|
7020
7020
|
}
|
|
7021
7021
|
if (w.includes("."))
|
|
7022
7022
|
try {
|
|
7023
7023
|
p.current.playAnimation(w, null, 10, 0, 0.01, U);
|
|
7024
|
-
} catch (
|
|
7025
|
-
console.warn(`Failed to play ${w}:`,
|
|
7024
|
+
} catch (ne) {
|
|
7025
|
+
console.warn(`Failed to play ${w}:`, ne);
|
|
7026
7026
|
try {
|
|
7027
7027
|
p.current.setBodyMovement("idle");
|
|
7028
7028
|
} catch (me) {
|
|
@@ -7030,9 +7030,9 @@ const Ve = Me(({
|
|
|
7030
7030
|
}
|
|
7031
7031
|
}
|
|
7032
7032
|
else {
|
|
7033
|
-
const
|
|
7033
|
+
const ne = [".fbx", ".glb", ".gltf"];
|
|
7034
7034
|
let me = !1;
|
|
7035
|
-
for (const A of
|
|
7035
|
+
for (const A of ne)
|
|
7036
7036
|
try {
|
|
7037
7037
|
p.current.playAnimation(w + A, null, 10, 0, 0.01, U), me = !0;
|
|
7038
7038
|
break;
|
|
@@ -7048,19 +7048,19 @@ const Ve = Me(({
|
|
|
7048
7048
|
}
|
|
7049
7049
|
}
|
|
7050
7050
|
}
|
|
7051
|
-
}, [f]), ke =
|
|
7051
|
+
}, [f]), ke = O(() => {
|
|
7052
7052
|
p.current && p.current.onResize && p.current.onResize();
|
|
7053
7053
|
}, []);
|
|
7054
7054
|
return Fe(k, () => ({
|
|
7055
|
-
speakText:
|
|
7056
|
-
stopSpeaking:
|
|
7057
|
-
pauseSpeaking:
|
|
7058
|
-
resumeSpeaking:
|
|
7059
|
-
resumeAudioContext:
|
|
7055
|
+
speakText: N,
|
|
7056
|
+
stopSpeaking: te,
|
|
7057
|
+
pauseSpeaking: q,
|
|
7058
|
+
resumeSpeaking: _,
|
|
7059
|
+
resumeAudioContext: P,
|
|
7060
7060
|
setMood: Ae,
|
|
7061
7061
|
setTimingAdjustment: Se,
|
|
7062
7062
|
playAnimation: Le,
|
|
7063
|
-
isReady:
|
|
7063
|
+
isReady: oe,
|
|
7064
7064
|
isPaused: ge,
|
|
7065
7065
|
talkingHead: p.current,
|
|
7066
7066
|
handleResize: ke,
|
|
@@ -7135,7 +7135,7 @@ const Ve = Me(({
|
|
|
7135
7135
|
/* @__PURE__ */ ye(
|
|
7136
7136
|
"div",
|
|
7137
7137
|
{
|
|
7138
|
-
ref:
|
|
7138
|
+
ref: D,
|
|
7139
7139
|
className: "talking-head-viewer",
|
|
7140
7140
|
style: {
|
|
7141
7141
|
width: "100%",
|
|
@@ -7153,7 +7153,7 @@ const Ve = Me(({
|
|
|
7153
7153
|
fontSize: "18px",
|
|
7154
7154
|
zIndex: 10
|
|
7155
7155
|
}, children: "Loading avatar..." }),
|
|
7156
|
-
|
|
7156
|
+
j && /* @__PURE__ */ ye("div", { className: "error-overlay", style: {
|
|
7157
7157
|
position: "absolute",
|
|
7158
7158
|
top: "50%",
|
|
7159
7159
|
left: "50%",
|
|
@@ -7164,7 +7164,7 @@ const Ve = Me(({
|
|
|
7164
7164
|
zIndex: 10,
|
|
7165
7165
|
padding: "20px",
|
|
7166
7166
|
borderRadius: "8px"
|
|
7167
|
-
}, children:
|
|
7167
|
+
}, children: j })
|
|
7168
7168
|
]
|
|
7169
7169
|
}
|
|
7170
7170
|
);
|
|
@@ -7182,7 +7182,7 @@ const pt = Me(({
|
|
|
7182
7182
|
style: s = {},
|
|
7183
7183
|
avatarConfig: o = {}
|
|
7184
7184
|
}, l) => {
|
|
7185
|
-
const h = W(null), r = W(null), [u, a] = pe(!0), [d, c] = pe(null), [g, x] = pe(!1), f = Ee(), k = o.ttsService || f.service,
|
|
7185
|
+
const h = W(null), r = W(null), [u, a] = pe(!0), [d, c] = pe(null), [g, x] = pe(!1), f = Ee(), k = o.ttsService || f.service, D = k === "browser" ? {
|
|
7186
7186
|
endpoint: "",
|
|
7187
7187
|
apiKey: null,
|
|
7188
7188
|
defaultVoice: "Google US English"
|
|
@@ -7198,7 +7198,7 @@ const pt = Me(({
|
|
|
7198
7198
|
body: "F",
|
|
7199
7199
|
avatarMood: "neutral",
|
|
7200
7200
|
ttsLang: k === "browser" ? "en-US" : "en",
|
|
7201
|
-
ttsVoice: o.ttsVoice ||
|
|
7201
|
+
ttsVoice: o.ttsVoice || D.defaultVoice,
|
|
7202
7202
|
lipsyncLang: "en",
|
|
7203
7203
|
// English lip-sync
|
|
7204
7204
|
showFullAvatar: !0,
|
|
@@ -7207,97 +7207,97 @@ const pt = Me(({
|
|
|
7207
7207
|
movementIntensity: 0.5,
|
|
7208
7208
|
...o
|
|
7209
7209
|
}, B = {
|
|
7210
|
-
ttsEndpoint:
|
|
7211
|
-
ttsApikey:
|
|
7210
|
+
ttsEndpoint: D.endpoint,
|
|
7211
|
+
ttsApikey: D.apiKey,
|
|
7212
7212
|
ttsService: k,
|
|
7213
7213
|
lipsyncModules: ["en"],
|
|
7214
7214
|
cameraView: "upper"
|
|
7215
|
-
},
|
|
7215
|
+
}, T = O(async () => {
|
|
7216
7216
|
if (!(!h.current || r.current))
|
|
7217
7217
|
try {
|
|
7218
|
-
if (a(!0), c(null), r.current = new Be(h.current, B), await r.current.showAvatar(p, (
|
|
7219
|
-
if (
|
|
7220
|
-
const
|
|
7221
|
-
t(
|
|
7218
|
+
if (a(!0), c(null), r.current = new Be(h.current, B), await r.current.showAvatar(p, (j) => {
|
|
7219
|
+
if (j.lengthComputable) {
|
|
7220
|
+
const X = Math.min(100, Math.round(j.loaded / j.total * 100));
|
|
7221
|
+
t(X);
|
|
7222
7222
|
}
|
|
7223
7223
|
}), r.current.morphs && r.current.morphs.length > 0) {
|
|
7224
|
-
const
|
|
7225
|
-
console.log("Available morph targets:", Object.keys(
|
|
7226
|
-
const
|
|
7227
|
-
console.log("Viseme morph targets found:",
|
|
7224
|
+
const j = r.current.morphs[0].morphTargetDictionary;
|
|
7225
|
+
console.log("Available morph targets:", Object.keys(j));
|
|
7226
|
+
const X = Object.keys(j).filter((oe) => oe.startsWith("viseme_"));
|
|
7227
|
+
console.log("Viseme morph targets found:", X), X.length === 0 && (console.warn("No viseme morph targets found! Lip-sync will not work properly."), console.log("Expected viseme targets: viseme_aa, viseme_E, viseme_I, viseme_O, viseme_U, viseme_PP, viseme_SS, viseme_TH, viseme_DD, viseme_FF, viseme_kk, viseme_nn, viseme_RR, viseme_CH, viseme_sil"));
|
|
7228
7228
|
}
|
|
7229
|
-
if (await new Promise((
|
|
7230
|
-
const
|
|
7231
|
-
r.current.lipsync && Object.keys(r.current.lipsync).length > 0 ? (console.log("Lip-sync modules loaded:", Object.keys(r.current.lipsync)),
|
|
7229
|
+
if (await new Promise((j) => {
|
|
7230
|
+
const X = () => {
|
|
7231
|
+
r.current.lipsync && Object.keys(r.current.lipsync).length > 0 ? (console.log("Lip-sync modules loaded:", Object.keys(r.current.lipsync)), j()) : (console.log("Waiting for lip-sync modules to load..."), setTimeout(X, 100));
|
|
7232
7232
|
};
|
|
7233
|
-
|
|
7233
|
+
X();
|
|
7234
7234
|
}), r.current && r.current.setShowFullAvatar)
|
|
7235
7235
|
try {
|
|
7236
7236
|
r.current.setShowFullAvatar(!0), console.log("Avatar initialized in full body mode");
|
|
7237
|
-
} catch (
|
|
7238
|
-
console.warn("Error setting full body mode on initialization:",
|
|
7237
|
+
} catch (j) {
|
|
7238
|
+
console.warn("Error setting full body mode on initialization:", j);
|
|
7239
7239
|
}
|
|
7240
7240
|
a(!1), x(!0), n(r.current);
|
|
7241
|
-
const
|
|
7241
|
+
const E = () => {
|
|
7242
7242
|
document.visibilityState === "visible" ? r.current?.start() : r.current?.stop();
|
|
7243
7243
|
};
|
|
7244
|
-
return document.addEventListener("visibilitychange",
|
|
7245
|
-
document.removeEventListener("visibilitychange",
|
|
7244
|
+
return document.addEventListener("visibilitychange", E), () => {
|
|
7245
|
+
document.removeEventListener("visibilitychange", E);
|
|
7246
7246
|
};
|
|
7247
7247
|
} catch (S) {
|
|
7248
7248
|
console.error("Error initializing TalkingHead:", S), c(S.message || "Failed to initialize avatar"), a(!1), e(S);
|
|
7249
7249
|
}
|
|
7250
7250
|
}, []);
|
|
7251
|
-
ce(() => (
|
|
7251
|
+
ce(() => (T(), () => {
|
|
7252
7252
|
r.current && (r.current.stop(), r.current.dispose(), r.current = null);
|
|
7253
|
-
}), [
|
|
7254
|
-
const
|
|
7253
|
+
}), [T]);
|
|
7254
|
+
const R = O((S) => {
|
|
7255
7255
|
if (r.current && g)
|
|
7256
7256
|
try {
|
|
7257
7257
|
console.log("Speaking text:", S), console.log("Avatar config:", p), console.log("TalkingHead instance:", r.current), r.current.lipsync && Object.keys(r.current.lipsync).length > 0 ? (console.log("Lip-sync modules loaded:", Object.keys(r.current.lipsync)), r.current.setSlowdownRate && (r.current.setSlowdownRate(1.05), console.log("Applied timing adjustment for better lip-sync")), r.current.speakText(S)) : (console.warn("Lip-sync modules not ready, waiting..."), setTimeout(() => {
|
|
7258
7258
|
r.current && r.current.lipsync ? (console.log("Lip-sync now ready, speaking..."), r.current.setSlowdownRate && (r.current.setSlowdownRate(1.05), console.log("Applied timing adjustment for better lip-sync")), r.current.speakText(S)) : console.error("Lip-sync still not ready after waiting");
|
|
7259
7259
|
}, 500));
|
|
7260
|
-
} catch (
|
|
7261
|
-
console.error("Error speaking text:",
|
|
7260
|
+
} catch (E) {
|
|
7261
|
+
console.error("Error speaking text:", E), c(E.message || "Failed to speak text");
|
|
7262
7262
|
}
|
|
7263
7263
|
else
|
|
7264
7264
|
console.warn("Avatar not ready for speaking. isReady:", g, "talkingHeadRef:", !!r.current);
|
|
7265
|
-
}, [g, p]), L =
|
|
7265
|
+
}, [g, p]), L = O(() => {
|
|
7266
7266
|
r.current && (r.current.stopSpeaking(), r.current.setSlowdownRate && (r.current.setSlowdownRate(1), console.log("Reset timing to normal")));
|
|
7267
|
-
}, []), I =
|
|
7267
|
+
}, []), I = O((S) => {
|
|
7268
7268
|
r.current && r.current.setMood(S);
|
|
7269
|
-
}, []), z =
|
|
7269
|
+
}, []), z = O((S) => {
|
|
7270
7270
|
r.current && r.current.setSlowdownRate && (r.current.setSlowdownRate(S), console.log("Timing adjustment set to:", S));
|
|
7271
|
-
}, []), Y =
|
|
7271
|
+
}, []), Y = O((S, E = !1) => {
|
|
7272
7272
|
if (r.current && r.current.playAnimation) {
|
|
7273
7273
|
if (r.current.setShowFullAvatar)
|
|
7274
7274
|
try {
|
|
7275
7275
|
r.current.setShowFullAvatar(!0);
|
|
7276
|
-
} catch (
|
|
7277
|
-
console.warn("Error setting full body mode:",
|
|
7276
|
+
} catch (X) {
|
|
7277
|
+
console.warn("Error setting full body mode:", X);
|
|
7278
7278
|
}
|
|
7279
7279
|
if (S.includes("."))
|
|
7280
7280
|
try {
|
|
7281
|
-
r.current.playAnimation(S, null, 10, 0, 0.01,
|
|
7282
|
-
} catch (
|
|
7283
|
-
console.log(`Failed to play ${S}:`,
|
|
7281
|
+
r.current.playAnimation(S, null, 10, 0, 0.01, E), console.log("Playing animation:", S);
|
|
7282
|
+
} catch (X) {
|
|
7283
|
+
console.log(`Failed to play ${S}:`, X);
|
|
7284
7284
|
try {
|
|
7285
7285
|
r.current.setBodyMovement("idle"), console.log("Fallback to idle animation");
|
|
7286
|
-
} catch (
|
|
7287
|
-
console.warn("Fallback animation also failed:",
|
|
7286
|
+
} catch (oe) {
|
|
7287
|
+
console.warn("Fallback animation also failed:", oe);
|
|
7288
7288
|
}
|
|
7289
7289
|
}
|
|
7290
7290
|
else {
|
|
7291
|
-
const
|
|
7292
|
-
let
|
|
7293
|
-
for (const le of
|
|
7291
|
+
const X = [".fbx", ".glb", ".gltf"];
|
|
7292
|
+
let oe = !1;
|
|
7293
|
+
for (const le of X)
|
|
7294
7294
|
try {
|
|
7295
|
-
r.current.playAnimation(S + le, null, 10, 0, 0.01,
|
|
7295
|
+
r.current.playAnimation(S + le, null, 10, 0, 0.01, E), console.log("Playing animation:", S + le), oe = !0;
|
|
7296
7296
|
break;
|
|
7297
7297
|
} catch {
|
|
7298
7298
|
console.log(`Failed to play ${S}${le}, trying next format...`);
|
|
7299
7299
|
}
|
|
7300
|
-
if (!
|
|
7300
|
+
if (!oe) {
|
|
7301
7301
|
console.warn("Animation system not available or animation not found:", S);
|
|
7302
7302
|
try {
|
|
7303
7303
|
r.current.setBodyMovement("idle"), console.log("Fallback to idle animation");
|
|
@@ -7310,7 +7310,7 @@ const pt = Me(({
|
|
|
7310
7310
|
console.warn("Animation system not available or animation not found:", S);
|
|
7311
7311
|
}, []);
|
|
7312
7312
|
return Fe(l, () => ({
|
|
7313
|
-
speakText:
|
|
7313
|
+
speakText: R,
|
|
7314
7314
|
stopSpeaking: L,
|
|
7315
7315
|
setMood: I,
|
|
7316
7316
|
setTimingAdjustment: z,
|
|
@@ -7321,8 +7321,8 @@ const pt = Me(({
|
|
|
7321
7321
|
if (r.current && r.current.setShowFullAvatar && r.current.setBodyMovement)
|
|
7322
7322
|
try {
|
|
7323
7323
|
r.current.setShowFullAvatar(!0), r.current.setBodyMovement(S), console.log("Body movement set with full body mode:", S);
|
|
7324
|
-
} catch (
|
|
7325
|
-
console.warn("Error setting body movement:",
|
|
7324
|
+
} catch (E) {
|
|
7325
|
+
console.warn("Error setting body movement:", E);
|
|
7326
7326
|
}
|
|
7327
7327
|
},
|
|
7328
7328
|
setMovementIntensity: (S) => r.current?.setMovementIntensity(S),
|
|
@@ -7338,8 +7338,8 @@ const pt = Me(({
|
|
|
7338
7338
|
if (r.current && r.current.setShowFullAvatar && r.current.playReaction)
|
|
7339
7339
|
try {
|
|
7340
7340
|
r.current.setShowFullAvatar(!0), r.current.playReaction(S), console.log("Reaction played with full body mode:", S);
|
|
7341
|
-
} catch (
|
|
7342
|
-
console.warn("Error playing reaction:",
|
|
7341
|
+
} catch (E) {
|
|
7342
|
+
console.warn("Error playing reaction:", E);
|
|
7343
7343
|
}
|
|
7344
7344
|
},
|
|
7345
7345
|
playCelebration: () => {
|
|
@@ -7354,8 +7354,8 @@ const pt = Me(({
|
|
|
7354
7354
|
if (r.current && r.current.setShowFullAvatar)
|
|
7355
7355
|
try {
|
|
7356
7356
|
r.current.setShowFullAvatar(S), console.log("Show full avatar set to:", S);
|
|
7357
|
-
} catch (
|
|
7358
|
-
console.warn("Error setting showFullAvatar:",
|
|
7357
|
+
} catch (E) {
|
|
7358
|
+
console.warn("Error setting showFullAvatar:", E);
|
|
7359
7359
|
}
|
|
7360
7360
|
},
|
|
7361
7361
|
lockAvatarPosition: () => {
|
|
@@ -7413,9 +7413,20 @@ const pt = Me(({
|
|
|
7413
7413
|
pt.displayName = "TalkingHeadComponent";
|
|
7414
7414
|
async function gt(V) {
|
|
7415
7415
|
try {
|
|
7416
|
-
|
|
7416
|
+
console.log(`📥 Loading animation manifest from: ${V}`);
|
|
7417
|
+
const t = await fetch(V);
|
|
7418
|
+
if (!t.ok)
|
|
7419
|
+
throw new Error(`Failed to fetch manifest: ${t.status} ${t.statusText}`);
|
|
7420
|
+
const e = await t.json();
|
|
7421
|
+
console.log("📦 Raw manifest loaded:", e);
|
|
7422
|
+
const n = e.animations || {};
|
|
7423
|
+
return console.log("✅ Processed animations object:", n), n._genderSpecific && console.log("👥 Gender-specific structure detected:", {
|
|
7424
|
+
male: Object.keys(n._genderSpecific.male || {}),
|
|
7425
|
+
female: Object.keys(n._genderSpecific.female || {}),
|
|
7426
|
+
shared: Object.keys(n._genderSpecific.shared || {})
|
|
7427
|
+
}), n;
|
|
7417
7428
|
} catch (t) {
|
|
7418
|
-
return console.error("Failed to load animation manifest:", t), {};
|
|
7429
|
+
return console.error("❌ Failed to load animation manifest:", t), {};
|
|
7419
7430
|
}
|
|
7420
7431
|
}
|
|
7421
7432
|
const yt = Me(({
|
|
@@ -7441,81 +7452,86 @@ const yt = Me(({
|
|
|
7441
7452
|
},
|
|
7442
7453
|
className: f = "",
|
|
7443
7454
|
style: k = {},
|
|
7444
|
-
animations:
|
|
7455
|
+
animations: D = {},
|
|
7445
7456
|
autoAnimationGroup: p = null,
|
|
7446
7457
|
// e.g., "talking" - will randomly select from this group when speaking
|
|
7447
7458
|
autoIdleGroup: B = null,
|
|
7448
7459
|
// e.g., "idle" - will randomly select from this group when idle
|
|
7449
|
-
autoSpeak:
|
|
7450
|
-
},
|
|
7451
|
-
const L = W(null), I = W(null), z = W(u), Y = W(null), S = W(null),
|
|
7460
|
+
autoSpeak: T = !1
|
|
7461
|
+
}, R) => {
|
|
7462
|
+
const L = W(null), I = W(null), z = W(u), Y = W(null), S = W(null), E = W(!1), j = W({ remainingText: null, originalText: null, options: null }), X = W([]), [oe, le] = pe(!0), [ge, de] = pe(null), [ee, be] = pe(!1), [Q, b] = pe(!1), [v, F] = pe(D), P = W(null);
|
|
7452
7463
|
ce(() => {
|
|
7453
|
-
|
|
7454
|
-
}, [
|
|
7464
|
+
E.current = Q;
|
|
7465
|
+
}, [Q]), ce(() => {
|
|
7455
7466
|
(async () => {
|
|
7456
|
-
if (
|
|
7467
|
+
if (D.manifest)
|
|
7457
7468
|
try {
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7469
|
+
console.log("🔄 Loading animations from manifest:", D.manifest);
|
|
7470
|
+
const H = await gt(D.manifest);
|
|
7471
|
+
F(H), console.log("✅ Animations loaded and set:", H), H._genderSpecific ? console.log("👥 Gender-specific animations detected:", {
|
|
7472
|
+
male: Object.keys(H._genderSpecific.male || {}),
|
|
7473
|
+
female: Object.keys(H._genderSpecific.female || {}),
|
|
7474
|
+
shared: Object.keys(H._genderSpecific.shared || {})
|
|
7475
|
+
}) : console.log("⚠️ No gender-specific animations found in manifest");
|
|
7476
|
+
} catch (H) {
|
|
7477
|
+
console.error("❌ Failed to load animation manifest:", H), F(D);
|
|
7462
7478
|
}
|
|
7463
7479
|
else
|
|
7464
|
-
|
|
7480
|
+
console.log("📝 Using animations from props (no manifest):", D), F(D);
|
|
7465
7481
|
})();
|
|
7466
|
-
}, [
|
|
7482
|
+
}, [D]), ce(() => {
|
|
7467
7483
|
z.current = u;
|
|
7468
7484
|
}, [u]);
|
|
7469
|
-
const
|
|
7470
|
-
let
|
|
7471
|
-
|
|
7485
|
+
const N = Ee(), te = s || N.service;
|
|
7486
|
+
let q;
|
|
7487
|
+
te === "browser" ? q = {
|
|
7472
7488
|
service: "browser",
|
|
7473
7489
|
endpoint: "",
|
|
7474
7490
|
apiKey: null,
|
|
7475
7491
|
defaultVoice: "Google US English"
|
|
7476
|
-
} :
|
|
7492
|
+
} : te === "elevenlabs" ? q = {
|
|
7477
7493
|
service: "elevenlabs",
|
|
7478
7494
|
endpoint: "https://api.elevenlabs.io/v1/text-to-speech",
|
|
7479
|
-
apiKey: l ||
|
|
7480
|
-
defaultVoice: o ||
|
|
7481
|
-
voices:
|
|
7482
|
-
} :
|
|
7495
|
+
apiKey: l || N.apiKey,
|
|
7496
|
+
defaultVoice: o || N.defaultVoice || Ie.defaultVoice,
|
|
7497
|
+
voices: N.voices || Ie.voices
|
|
7498
|
+
} : te === "deepgram" ? q = {
|
|
7483
7499
|
service: "deepgram",
|
|
7484
7500
|
endpoint: "https://api.deepgram.com/v1/speak",
|
|
7485
|
-
apiKey: l ||
|
|
7486
|
-
defaultVoice: o ||
|
|
7487
|
-
voices:
|
|
7488
|
-
} :
|
|
7489
|
-
...
|
|
7490
|
-
apiKey: l !== null ? l :
|
|
7501
|
+
apiKey: l || N.apiKey,
|
|
7502
|
+
defaultVoice: o || N.defaultVoice || Te.defaultVoice,
|
|
7503
|
+
voices: N.voices || Te.voices
|
|
7504
|
+
} : q = {
|
|
7505
|
+
...N,
|
|
7506
|
+
apiKey: l !== null ? l : N.apiKey
|
|
7491
7507
|
};
|
|
7492
|
-
const
|
|
7508
|
+
const _ = {
|
|
7493
7509
|
url: t,
|
|
7494
7510
|
body: e,
|
|
7495
7511
|
avatarMood: n,
|
|
7496
|
-
ttsLang:
|
|
7497
|
-
ttsVoice: o ||
|
|
7512
|
+
ttsLang: te === "browser" ? "en-US" : i,
|
|
7513
|
+
ttsVoice: o || q.defaultVoice,
|
|
7498
7514
|
lipsyncLang: "en",
|
|
7499
7515
|
showFullAvatar: u,
|
|
7500
7516
|
bodyMovement: h,
|
|
7501
7517
|
movementIntensity: r
|
|
7502
7518
|
}, Ae = {
|
|
7503
|
-
ttsEndpoint:
|
|
7504
|
-
ttsApikey:
|
|
7505
|
-
ttsService:
|
|
7519
|
+
ttsEndpoint: q.endpoint,
|
|
7520
|
+
ttsApikey: q.apiKey,
|
|
7521
|
+
ttsService: te,
|
|
7506
7522
|
lipsyncModules: ["en"],
|
|
7507
7523
|
cameraView: a
|
|
7508
|
-
}, Se =
|
|
7524
|
+
}, Se = O(async () => {
|
|
7509
7525
|
if (!(!L.current || I.current))
|
|
7510
7526
|
try {
|
|
7511
7527
|
le(!0), de(null), I.current = new Be(L.current, Ae), console.log("Avatar config being passed:", {
|
|
7512
|
-
url:
|
|
7513
|
-
body:
|
|
7514
|
-
avatarMood:
|
|
7515
|
-
}), await I.current.showAvatar(
|
|
7516
|
-
if (
|
|
7517
|
-
const
|
|
7518
|
-
c(
|
|
7528
|
+
url: _.url,
|
|
7529
|
+
body: _.body,
|
|
7530
|
+
avatarMood: _.avatarMood
|
|
7531
|
+
}), await I.current.showAvatar(_, (H) => {
|
|
7532
|
+
if (H.lengthComputable) {
|
|
7533
|
+
const G = Math.min(100, Math.round(H.loaded / H.total * 100));
|
|
7534
|
+
c(G);
|
|
7519
7535
|
}
|
|
7520
7536
|
}), I.current?.avatar && console.log("Avatar body after initialization:", I.current.avatar.body), le(!1), be(!0), d(I.current);
|
|
7521
7537
|
const A = () => {
|
|
@@ -7531,7 +7547,7 @@ const yt = Me(({
|
|
|
7531
7547
|
ce(() => (Se(), () => {
|
|
7532
7548
|
I.current && (I.current.stop(), I.current.dispose(), I.current = null);
|
|
7533
7549
|
}), [Se]);
|
|
7534
|
-
const Le =
|
|
7550
|
+
const Le = O(async () => {
|
|
7535
7551
|
if (I.current)
|
|
7536
7552
|
try {
|
|
7537
7553
|
const A = I.current.audioCtx || I.current.audioContext;
|
|
@@ -7539,26 +7555,41 @@ const yt = Me(({
|
|
|
7539
7555
|
} catch (A) {
|
|
7540
7556
|
console.warn("Failed to resume audio context:", A);
|
|
7541
7557
|
}
|
|
7542
|
-
}, []), ke =
|
|
7543
|
-
if (!
|
|
7558
|
+
}, []), ke = O((A) => {
|
|
7559
|
+
if (!v)
|
|
7560
|
+
return console.warn("No animations loaded"), null;
|
|
7561
|
+
let H = null;
|
|
7562
|
+
if (v._genderSpecific) {
|
|
7563
|
+
const J = (e?.toUpperCase() || "F") === "M" ? "male" : "female", ie = v._genderSpecific[J];
|
|
7564
|
+
ie && ie[A] ? (H = ie[A], console.log(`Using ${J} animations for "${A}":`, H)) : v._genderSpecific.shared && v._genderSpecific.shared[A] && (H = v._genderSpecific.shared[A], console.log(`Using shared animations for "${A}":`, H));
|
|
7565
|
+
}
|
|
7566
|
+
if (!H && v[A] && (H = v[A], console.log(`Using root-level animations for "${A}":`, H)), !H) {
|
|
7567
|
+
if (console.warn(`Animation group "${A}" not found. Available groups:`, Object.keys(v).filter((G) => G !== "_genderSpecific")), v._genderSpecific) {
|
|
7568
|
+
const J = (e?.toUpperCase() || "F") === "M" ? "male" : "female";
|
|
7569
|
+
console.warn(`Gender-specific groups (${J}):`, Object.keys(v._genderSpecific[J] || {}));
|
|
7570
|
+
}
|
|
7544
7571
|
return null;
|
|
7545
|
-
const P = R[A];
|
|
7546
|
-
if (Array.isArray(P) && P.length > 0) {
|
|
7547
|
-
const K = Math.floor(Math.random() * P.length);
|
|
7548
|
-
return P[K];
|
|
7549
7572
|
}
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7573
|
+
if (Array.isArray(H) && H.length > 0) {
|
|
7574
|
+
const G = Math.floor(Math.random() * H.length);
|
|
7575
|
+
return H[G];
|
|
7576
|
+
}
|
|
7577
|
+
return typeof H == "string" ? H : (console.warn(`Animation group "${A}" is not a valid format (expected array or string):`, H), null);
|
|
7578
|
+
}, [v, e]), w = O((A, H = !1) => {
|
|
7579
|
+
if (!I.current)
|
|
7580
|
+
return console.warn("TalkingHead not initialized yet"), null;
|
|
7581
|
+
const G = ke(A);
|
|
7582
|
+
if (G)
|
|
7554
7583
|
try {
|
|
7555
|
-
return I.current.playAnimation(
|
|
7556
|
-
} catch (
|
|
7557
|
-
return console.
|
|
7584
|
+
return I.current.playAnimation(G, null, 10, 0, 0.01, H), console.log(`✅ Playing random animation from "${A}" group:`, G), G;
|
|
7585
|
+
} catch (J) {
|
|
7586
|
+
return console.error(`❌ Failed to play random animation from "${A}" group:`, J), null;
|
|
7558
7587
|
}
|
|
7588
|
+
else
|
|
7589
|
+
console.warn(`⚠️ No animation found for group "${A}"`);
|
|
7559
7590
|
return null;
|
|
7560
|
-
}, [ke]), U =
|
|
7561
|
-
if (!I.current ||
|
|
7591
|
+
}, [ke]), U = O(async (A, H = {}) => {
|
|
7592
|
+
if (!I.current || !ee) {
|
|
7562
7593
|
console.warn("Avatar not ready for speaking");
|
|
7563
7594
|
return;
|
|
7564
7595
|
}
|
|
@@ -7567,87 +7598,87 @@ const yt = Me(({
|
|
|
7567
7598
|
return;
|
|
7568
7599
|
}
|
|
7569
7600
|
await Le();
|
|
7570
|
-
const
|
|
7571
|
-
|
|
7572
|
-
const
|
|
7573
|
-
|
|
7574
|
-
const
|
|
7575
|
-
lipsyncLang:
|
|
7601
|
+
const G = H.animationGroup || p;
|
|
7602
|
+
G && !H.skipAnimation ? (console.log(`🎬 Attempting to play animation from group: "${G}"`), console.log(`📊 Current avatarBody: "${e}", loadedAnimations:`, v), w(G)) : console.log(`⏭️ Skipping animation (group: ${G}, skipAnimation: ${H.skipAnimation})`), j.current = { remainingText: null, originalText: null, options: null }, X.current = [], Y.current = { text: A, options: H }, S.current && (clearInterval(S.current), S.current = null), b(!1), E.current = !1;
|
|
7603
|
+
const J = A.split(/[.!?]+/).filter((se) => se.trim().length > 0);
|
|
7604
|
+
X.current = J;
|
|
7605
|
+
const ie = {
|
|
7606
|
+
lipsyncLang: H.lipsyncLang || "en",
|
|
7576
7607
|
onSpeechEnd: () => {
|
|
7577
|
-
S.current && (clearInterval(S.current), S.current = null),
|
|
7608
|
+
S.current && (clearInterval(S.current), S.current = null), H.onSpeechEnd && H.onSpeechEnd(), x();
|
|
7578
7609
|
}
|
|
7579
7610
|
};
|
|
7580
7611
|
try {
|
|
7581
|
-
I.current.speakText(A,
|
|
7582
|
-
} catch (
|
|
7583
|
-
console.error("Error speaking text:",
|
|
7612
|
+
I.current.speakText(A, ie);
|
|
7613
|
+
} catch (se) {
|
|
7614
|
+
console.error("Error speaking text:", se), de(se.message || "Failed to speak text");
|
|
7584
7615
|
}
|
|
7585
|
-
}, [
|
|
7616
|
+
}, [ee, x, Le, p, w]);
|
|
7586
7617
|
ce(() => {
|
|
7587
|
-
if (
|
|
7618
|
+
if (!ee || !B || !I.current)
|
|
7588
7619
|
return;
|
|
7589
|
-
|
|
7620
|
+
P.current && clearInterval(P.current);
|
|
7590
7621
|
const A = () => {
|
|
7591
|
-
I.current && !
|
|
7622
|
+
I.current && !E.current && w(B);
|
|
7592
7623
|
};
|
|
7593
|
-
return A(),
|
|
7624
|
+
return A(), P.current = setInterval(() => {
|
|
7594
7625
|
A();
|
|
7595
7626
|
}, 12e3 + Math.random() * 3e3), () => {
|
|
7596
|
-
|
|
7627
|
+
P.current && (clearInterval(P.current), P.current = null);
|
|
7597
7628
|
};
|
|
7598
|
-
}, [
|
|
7599
|
-
|
|
7600
|
-
}, [
|
|
7601
|
-
const
|
|
7629
|
+
}, [ee, B, w]), ce(() => {
|
|
7630
|
+
ee && V && T && I.current && U(V);
|
|
7631
|
+
}, [ee, V, T, U]);
|
|
7632
|
+
const K = O(() => {
|
|
7602
7633
|
if (I.current)
|
|
7603
7634
|
try {
|
|
7604
|
-
const A = I.current.isSpeaking || !1,
|
|
7605
|
-
if (A ||
|
|
7635
|
+
const A = I.current.isSpeaking || !1, H = I.current.audioPlaylist || [], G = I.current.speechQueue || [];
|
|
7636
|
+
if (A || H.length > 0 || G.length > 0) {
|
|
7606
7637
|
S.current && (clearInterval(S.current), S.current = null);
|
|
7607
|
-
let
|
|
7608
|
-
|
|
7609
|
-
remainingText:
|
|
7638
|
+
let J = "";
|
|
7639
|
+
G.length > 0 && (J = G.map((ie) => ie.text && Array.isArray(ie.text) ? ie.text.map((se) => se.word).join(" ") : ie.text || "").join(" ")), j.current = {
|
|
7640
|
+
remainingText: J || null,
|
|
7610
7641
|
originalText: Y.current?.text || null,
|
|
7611
7642
|
options: Y.current?.options || null
|
|
7612
|
-
}, I.current.speechQueue.length = 0, I.current.pauseSpeaking(), b(!0),
|
|
7643
|
+
}, I.current.speechQueue.length = 0, I.current.pauseSpeaking(), b(!0), E.current = !0;
|
|
7613
7644
|
}
|
|
7614
7645
|
} catch (A) {
|
|
7615
7646
|
console.warn("Error pausing speech:", A);
|
|
7616
7647
|
}
|
|
7617
|
-
}, []),
|
|
7618
|
-
if (!(!I.current || !
|
|
7648
|
+
}, []), ne = O(async () => {
|
|
7649
|
+
if (!(!I.current || !Q))
|
|
7619
7650
|
try {
|
|
7620
|
-
await Le(), b(!1),
|
|
7621
|
-
const A =
|
|
7622
|
-
|
|
7651
|
+
await Le(), b(!1), E.current = !1;
|
|
7652
|
+
const A = j.current?.remainingText, H = j.current?.originalText || Y.current?.text, G = j.current?.options || Y.current?.options || {}, J = A || H;
|
|
7653
|
+
J && U(J, G);
|
|
7623
7654
|
} catch (A) {
|
|
7624
|
-
console.warn("Error resuming speech:", A), b(!1),
|
|
7655
|
+
console.warn("Error resuming speech:", A), b(!1), E.current = !1;
|
|
7625
7656
|
}
|
|
7626
|
-
}, [
|
|
7627
|
-
I.current && (I.current.stopSpeaking(), S.current && (clearInterval(S.current), S.current = null), b(!1),
|
|
7657
|
+
}, [Q, U, Le]), me = O(() => {
|
|
7658
|
+
I.current && (I.current.stopSpeaking(), S.current && (clearInterval(S.current), S.current = null), b(!1), E.current = !1);
|
|
7628
7659
|
}, []);
|
|
7629
|
-
return Fe(
|
|
7660
|
+
return Fe(R, () => ({
|
|
7630
7661
|
speakText: U,
|
|
7631
|
-
pauseSpeaking:
|
|
7632
|
-
resumeSpeaking:
|
|
7662
|
+
pauseSpeaking: K,
|
|
7663
|
+
resumeSpeaking: ne,
|
|
7633
7664
|
stopSpeaking: me,
|
|
7634
7665
|
resumeAudioContext: Le,
|
|
7635
|
-
isPaused: () =>
|
|
7666
|
+
isPaused: () => Q,
|
|
7636
7667
|
setMood: (A) => I.current?.setMood(A),
|
|
7637
7668
|
setBodyMovement: (A) => {
|
|
7638
7669
|
I.current && I.current.setBodyMovement(A);
|
|
7639
7670
|
},
|
|
7640
|
-
playAnimation: (A,
|
|
7641
|
-
I.current && I.current.playAnimation && I.current.playAnimation(A, null, 10, 0, 0.01,
|
|
7671
|
+
playAnimation: (A, H = !1) => {
|
|
7672
|
+
I.current && I.current.playAnimation && I.current.playAnimation(A, null, 10, 0, 0.01, H);
|
|
7642
7673
|
},
|
|
7643
|
-
playRandomAnimation: (A,
|
|
7674
|
+
playRandomAnimation: (A, H = !1) => w(A, H),
|
|
7644
7675
|
getRandomAnimation: (A) => ke(A),
|
|
7645
7676
|
playReaction: (A) => I.current?.playReaction(A),
|
|
7646
7677
|
playCelebration: () => I.current?.playCelebration(),
|
|
7647
7678
|
setShowFullAvatar: (A) => {
|
|
7648
7679
|
I.current && (z.current = A, I.current.setShowFullAvatar(A));
|
|
7649
7680
|
},
|
|
7650
|
-
isReady:
|
|
7681
|
+
isReady: ee,
|
|
7651
7682
|
talkingHead: I.current
|
|
7652
7683
|
})), /* @__PURE__ */ Pe("div", { className: `simple-talking-avatar-container ${f}`, style: k, children: [
|
|
7653
7684
|
/* @__PURE__ */ ye(
|
|
@@ -7662,7 +7693,7 @@ const yt = Me(({
|
|
|
7662
7693
|
}
|
|
7663
7694
|
}
|
|
7664
7695
|
),
|
|
7665
|
-
|
|
7696
|
+
oe && /* @__PURE__ */ ye("div", { className: "loading-overlay", style: {
|
|
7666
7697
|
position: "absolute",
|
|
7667
7698
|
top: "50%",
|
|
7668
7699
|
left: "50%",
|
|
@@ -7718,12 +7749,12 @@ const ft = Me(({
|
|
|
7718
7749
|
onQuestionAnswer: s,
|
|
7719
7750
|
onCurriculumComplete: o,
|
|
7720
7751
|
onCustomAction: l
|
|
7721
|
-
}), c = W(null), g = W(null), x = W(null), f = W(null), k = W(null),
|
|
7752
|
+
}), c = W(null), g = W(null), x = W(null), f = W(null), k = W(null), D = W(null), p = W(null), B = W(V?.curriculum || {
|
|
7722
7753
|
title: "Default Curriculum",
|
|
7723
7754
|
description: "No curriculum data provided",
|
|
7724
7755
|
language: "en",
|
|
7725
7756
|
modules: []
|
|
7726
|
-
}),
|
|
7757
|
+
}), T = W({
|
|
7727
7758
|
avatarUrl: t.avatarUrl || "/avatars/brunette.glb",
|
|
7728
7759
|
avatarBody: t.avatarBody || "F",
|
|
7729
7760
|
mood: t.mood || "happy",
|
|
@@ -7751,7 +7782,7 @@ const ft = Me(({
|
|
|
7751
7782
|
description: "No curriculum data provided",
|
|
7752
7783
|
language: "en",
|
|
7753
7784
|
modules: []
|
|
7754
|
-
},
|
|
7785
|
+
}, T.current = {
|
|
7755
7786
|
avatarUrl: t.avatarUrl || "/avatars/brunette.glb",
|
|
7756
7787
|
avatarBody: t.avatarBody || "F",
|
|
7757
7788
|
mood: t.mood || "happy",
|
|
@@ -7766,11 +7797,11 @@ const ft = Me(({
|
|
|
7766
7797
|
lipsyncLang: "en"
|
|
7767
7798
|
};
|
|
7768
7799
|
}, [V, t, e]);
|
|
7769
|
-
const
|
|
7800
|
+
const R = O(() => (B.current || { modules: [] }).modules[a.current.currentModuleIndex]?.lessons[a.current.currentLessonIndex], []), L = O(() => R()?.questions[a.current.currentQuestionIndex], [R]), I = O((b, v) => v.type === "multiple_choice" || v.type === "true_false" ? b === v.answer : v.type === "code_test" && typeof b == "object" && b !== null ? b.passed === !0 : !1, []), z = O(() => {
|
|
7770
7801
|
a.current.lessonCompleted = !0, a.current.isQuestionMode = !1;
|
|
7771
7802
|
const b = a.current.totalQuestions > 0 ? Math.round(a.current.score / a.current.totalQuestions * 100) : 100;
|
|
7772
|
-
let
|
|
7773
|
-
if (a.current.totalQuestions > 0 ?
|
|
7803
|
+
let v = "Congratulations! You've completed this lesson";
|
|
7804
|
+
if (a.current.totalQuestions > 0 ? v += ` You got ${a.current.score} correct out of ${a.current.totalQuestions} question${a.current.totalQuestions === 1 ? "" : "s"}, achieving a score of ${b} percent. ` : v += "! ", b >= 80 ? v += "Excellent work! You have a great understanding of this topic." : b >= 60 ? v += "Good job! You understand most of the concepts." : v += "Keep practicing! You're making progress.", d.current.onLessonComplete({
|
|
7774
7805
|
moduleIndex: a.current.currentModuleIndex,
|
|
7775
7806
|
lessonIndex: a.current.currentLessonIndex,
|
|
7776
7807
|
score: a.current.score,
|
|
@@ -7790,9 +7821,9 @@ const ft = Me(({
|
|
|
7790
7821
|
} catch {
|
|
7791
7822
|
u.current.playCelebration();
|
|
7792
7823
|
}
|
|
7793
|
-
const
|
|
7794
|
-
u.current.speakText(
|
|
7795
|
-
lipsyncLang:
|
|
7824
|
+
const F = B.current || { modules: [] }, P = F.modules[a.current.currentModuleIndex], N = a.current.currentLessonIndex < (P?.lessons?.length || 0) - 1, te = a.current.currentModuleIndex < (F.modules?.length || 0) - 1, q = N || te, _ = T.current || { lipsyncLang: "en" };
|
|
7825
|
+
u.current.speakText(v, {
|
|
7826
|
+
lipsyncLang: _.lipsyncLang,
|
|
7796
7827
|
onSpeechEnd: () => {
|
|
7797
7828
|
d.current.onCustomAction({
|
|
7798
7829
|
type: "lessonCompleteFeedbackDone",
|
|
@@ -7801,17 +7832,17 @@ const ft = Me(({
|
|
|
7801
7832
|
score: a.current.score,
|
|
7802
7833
|
totalQuestions: a.current.totalQuestions,
|
|
7803
7834
|
percentage: b,
|
|
7804
|
-
hasNextLesson:
|
|
7835
|
+
hasNextLesson: q
|
|
7805
7836
|
});
|
|
7806
7837
|
}
|
|
7807
7838
|
});
|
|
7808
7839
|
}
|
|
7809
|
-
}, [e.lessonComplete]), Y =
|
|
7840
|
+
}, [e.lessonComplete]), Y = O(() => {
|
|
7810
7841
|
a.current.curriculumCompleted = !0;
|
|
7811
7842
|
const b = B.current || { modules: [] };
|
|
7812
7843
|
if (d.current.onCurriculumComplete({
|
|
7813
7844
|
modules: b.modules.length,
|
|
7814
|
-
totalLessons: b.modules.reduce((
|
|
7845
|
+
totalLessons: b.modules.reduce((v, F) => v + F.lessons.length, 0)
|
|
7815
7846
|
}), u.current) {
|
|
7816
7847
|
if (u.current.setMood("celebrating"), e.curriculumComplete)
|
|
7817
7848
|
try {
|
|
@@ -7819,99 +7850,99 @@ const ft = Me(({
|
|
|
7819
7850
|
} catch {
|
|
7820
7851
|
u.current.playCelebration();
|
|
7821
7852
|
}
|
|
7822
|
-
const
|
|
7823
|
-
u.current.speakText("Amazing! You've completed the entire curriculum! You're now ready to move on to more advanced topics. Well done!", { lipsyncLang:
|
|
7853
|
+
const v = T.current || { lipsyncLang: "en" };
|
|
7854
|
+
u.current.speakText("Amazing! You've completed the entire curriculum! You're now ready to move on to more advanced topics. Well done!", { lipsyncLang: v.lipsyncLang });
|
|
7824
7855
|
}
|
|
7825
|
-
}, [e.curriculumComplete]), S =
|
|
7826
|
-
const b =
|
|
7856
|
+
}, [e.curriculumComplete]), S = O(() => {
|
|
7857
|
+
const b = R();
|
|
7827
7858
|
a.current.isQuestionMode = !0, a.current.currentQuestionIndex = 0, a.current.totalQuestions = b?.questions?.length || 0, a.current.score = 0;
|
|
7828
|
-
const
|
|
7829
|
-
|
|
7859
|
+
const v = L();
|
|
7860
|
+
v && d.current.onCustomAction({
|
|
7830
7861
|
type: "questionStart",
|
|
7831
7862
|
moduleIndex: a.current.currentModuleIndex,
|
|
7832
7863
|
lessonIndex: a.current.currentLessonIndex,
|
|
7833
7864
|
questionIndex: a.current.currentQuestionIndex,
|
|
7834
7865
|
totalQuestions: a.current.totalQuestions,
|
|
7835
|
-
question:
|
|
7866
|
+
question: v,
|
|
7836
7867
|
score: a.current.score
|
|
7837
7868
|
});
|
|
7838
|
-
const
|
|
7839
|
-
if (!u.current || !
|
|
7869
|
+
const F = () => {
|
|
7870
|
+
if (!u.current || !v) return;
|
|
7840
7871
|
if (u.current.setMood("happy"), e.questionStart)
|
|
7841
7872
|
try {
|
|
7842
7873
|
u.current.playAnimation(e.questionStart, !0);
|
|
7843
|
-
} catch (
|
|
7844
|
-
console.warn("Failed to play questionStart animation:",
|
|
7874
|
+
} catch (N) {
|
|
7875
|
+
console.warn("Failed to play questionStart animation:", N);
|
|
7845
7876
|
}
|
|
7846
|
-
const
|
|
7847
|
-
|
|
7877
|
+
const P = T.current || { lipsyncLang: "en" };
|
|
7878
|
+
v.type === "code_test" ? u.current.speakText(`Let's test your coding skills! Here's your first challenge: ${v.question}`, { lipsyncLang: P.lipsyncLang }) : v.type === "multiple_choice" ? u.current.speakText(`Now let me ask you some questions. Here's the first one: ${v.question}`, { lipsyncLang: P.lipsyncLang }) : v.type === "true_false" ? u.current.speakText(`Let's start with some true or false questions. First question: ${v.question}`, { lipsyncLang: P.lipsyncLang }) : u.current.speakText(`Now let me ask you some questions. Here's the first one: ${v.question}`, { lipsyncLang: P.lipsyncLang });
|
|
7848
7879
|
};
|
|
7849
|
-
if (u.current && u.current.isReady &&
|
|
7850
|
-
|
|
7880
|
+
if (u.current && u.current.isReady && v)
|
|
7881
|
+
F();
|
|
7851
7882
|
else if (u.current && u.current.isReady) {
|
|
7852
|
-
const
|
|
7853
|
-
u.current.speakText("Now let me ask you some questions to test your understanding.", { lipsyncLang:
|
|
7883
|
+
const P = T.current || { lipsyncLang: "en" };
|
|
7884
|
+
u.current.speakText("Now let me ask you some questions to test your understanding.", { lipsyncLang: P.lipsyncLang });
|
|
7854
7885
|
} else {
|
|
7855
|
-
const
|
|
7856
|
-
u.current && u.current.isReady && (clearInterval(
|
|
7886
|
+
const P = setInterval(() => {
|
|
7887
|
+
u.current && u.current.isReady && (clearInterval(P), v && F());
|
|
7857
7888
|
}, 100);
|
|
7858
7889
|
setTimeout(() => {
|
|
7859
|
-
clearInterval(
|
|
7890
|
+
clearInterval(P);
|
|
7860
7891
|
}, 5e3);
|
|
7861
7892
|
}
|
|
7862
|
-
}, [e.questionStart,
|
|
7863
|
-
const b =
|
|
7893
|
+
}, [e.questionStart, R, L]), E = O(() => {
|
|
7894
|
+
const b = R();
|
|
7864
7895
|
if (a.current.currentQuestionIndex < (b?.questions?.length || 0) - 1) {
|
|
7865
7896
|
u.current && u.current.stopSpeaking && u.current.stopSpeaking(), a.current.currentQuestionIndex += 1;
|
|
7866
|
-
const
|
|
7867
|
-
|
|
7897
|
+
const v = L();
|
|
7898
|
+
v && d.current.onCustomAction({
|
|
7868
7899
|
type: "nextQuestion",
|
|
7869
7900
|
moduleIndex: a.current.currentModuleIndex,
|
|
7870
7901
|
lessonIndex: a.current.currentLessonIndex,
|
|
7871
7902
|
questionIndex: a.current.currentQuestionIndex,
|
|
7872
7903
|
totalQuestions: a.current.totalQuestions,
|
|
7873
|
-
question:
|
|
7904
|
+
question: v,
|
|
7874
7905
|
score: a.current.score
|
|
7875
7906
|
});
|
|
7876
|
-
const
|
|
7877
|
-
if (!u.current || !
|
|
7907
|
+
const F = () => {
|
|
7908
|
+
if (!u.current || !v) return;
|
|
7878
7909
|
if (u.current.setMood("happy"), u.current.setBodyMovement("idle"), e.nextQuestion)
|
|
7879
7910
|
try {
|
|
7880
7911
|
u.current.playAnimation(e.nextQuestion, !0);
|
|
7881
|
-
} catch (
|
|
7882
|
-
console.warn("Failed to play nextQuestion animation:",
|
|
7912
|
+
} catch (_) {
|
|
7913
|
+
console.warn("Failed to play nextQuestion animation:", _);
|
|
7883
7914
|
}
|
|
7884
|
-
const
|
|
7885
|
-
if (
|
|
7886
|
-
const
|
|
7887
|
-
u.current.speakText(
|
|
7888
|
-
lipsyncLang:
|
|
7915
|
+
const P = T.current || { lipsyncLang: "en" }, te = R()?.questions?.length || 0, q = a.current.currentQuestionIndex >= te - 1;
|
|
7916
|
+
if (v.type === "code_test") {
|
|
7917
|
+
const _ = q ? `Great! Here's your final coding challenge: ${v.question}` : `Great! Now let's move on to your next coding challenge: ${v.question}`;
|
|
7918
|
+
u.current.speakText(_, {
|
|
7919
|
+
lipsyncLang: P.lipsyncLang
|
|
7889
7920
|
});
|
|
7890
|
-
} else if (
|
|
7891
|
-
const
|
|
7892
|
-
u.current.speakText(
|
|
7893
|
-
lipsyncLang:
|
|
7921
|
+
} else if (v.type === "multiple_choice") {
|
|
7922
|
+
const _ = q ? `Alright! Here's your final question: ${v.question}` : `Alright! Here's your next question: ${v.question}`;
|
|
7923
|
+
u.current.speakText(_, {
|
|
7924
|
+
lipsyncLang: P.lipsyncLang
|
|
7894
7925
|
});
|
|
7895
|
-
} else if (
|
|
7896
|
-
const
|
|
7897
|
-
u.current.speakText(
|
|
7898
|
-
lipsyncLang:
|
|
7926
|
+
} else if (v.type === "true_false") {
|
|
7927
|
+
const _ = q ? `Now let's try this final one: ${v.question}` : `Now let's try this one: ${v.question}`;
|
|
7928
|
+
u.current.speakText(_, {
|
|
7929
|
+
lipsyncLang: P.lipsyncLang
|
|
7899
7930
|
});
|
|
7900
7931
|
} else {
|
|
7901
|
-
const
|
|
7902
|
-
u.current.speakText(
|
|
7903
|
-
lipsyncLang:
|
|
7932
|
+
const _ = q ? `Here's your final question: ${v.question}` : `Here's the next question: ${v.question}`;
|
|
7933
|
+
u.current.speakText(_, {
|
|
7934
|
+
lipsyncLang: P.lipsyncLang
|
|
7904
7935
|
});
|
|
7905
7936
|
}
|
|
7906
7937
|
};
|
|
7907
|
-
if (u.current && u.current.isReady &&
|
|
7908
|
-
|
|
7909
|
-
else if (
|
|
7910
|
-
const
|
|
7911
|
-
u.current && u.current.isReady && (clearInterval(
|
|
7938
|
+
if (u.current && u.current.isReady && v)
|
|
7939
|
+
F();
|
|
7940
|
+
else if (v) {
|
|
7941
|
+
const P = setInterval(() => {
|
|
7942
|
+
u.current && u.current.isReady && (clearInterval(P), F());
|
|
7912
7943
|
}, 100);
|
|
7913
7944
|
setTimeout(() => {
|
|
7914
|
-
clearInterval(
|
|
7945
|
+
clearInterval(P);
|
|
7915
7946
|
}, 5e3);
|
|
7916
7947
|
}
|
|
7917
7948
|
} else
|
|
@@ -7922,55 +7953,55 @@ const ft = Me(({
|
|
|
7922
7953
|
totalQuestions: a.current.totalQuestions,
|
|
7923
7954
|
score: a.current.score
|
|
7924
7955
|
});
|
|
7925
|
-
}, [e.nextQuestion,
|
|
7926
|
-
const b = B.current || { modules: [] },
|
|
7927
|
-
if (a.current.currentLessonIndex < (
|
|
7956
|
+
}, [e.nextQuestion, R, L]), j = O(() => {
|
|
7957
|
+
const b = B.current || { modules: [] }, v = b.modules[a.current.currentModuleIndex];
|
|
7958
|
+
if (a.current.currentLessonIndex < (v?.lessons?.length || 0) - 1) {
|
|
7928
7959
|
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;
|
|
7929
|
-
const
|
|
7960
|
+
const P = b.modules[a.current.currentModuleIndex], N = a.current.currentLessonIndex < (P?.lessons?.length || 0) - 1, te = a.current.currentModuleIndex < (b.modules?.length || 0) - 1, q = N || te;
|
|
7930
7961
|
d.current.onCustomAction({
|
|
7931
7962
|
type: "lessonStart",
|
|
7932
7963
|
moduleIndex: a.current.currentModuleIndex,
|
|
7933
7964
|
lessonIndex: a.current.currentLessonIndex,
|
|
7934
|
-
hasNextLesson:
|
|
7965
|
+
hasNextLesson: q
|
|
7935
7966
|
}), d.current.onLessonStart({
|
|
7936
7967
|
moduleIndex: a.current.currentModuleIndex,
|
|
7937
7968
|
lessonIndex: a.current.currentLessonIndex,
|
|
7938
|
-
lesson:
|
|
7969
|
+
lesson: R()
|
|
7939
7970
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7940
7971
|
} else if (a.current.currentModuleIndex < (b.modules?.length || 0) - 1) {
|
|
7941
7972
|
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;
|
|
7942
|
-
const
|
|
7973
|
+
const N = b.modules[a.current.currentModuleIndex], te = a.current.currentLessonIndex < (N?.lessons?.length || 0) - 1, q = a.current.currentModuleIndex < (b.modules?.length || 0) - 1, _ = te || q;
|
|
7943
7974
|
d.current.onCustomAction({
|
|
7944
7975
|
type: "lessonStart",
|
|
7945
7976
|
moduleIndex: a.current.currentModuleIndex,
|
|
7946
7977
|
lessonIndex: a.current.currentLessonIndex,
|
|
7947
|
-
hasNextLesson:
|
|
7978
|
+
hasNextLesson: _
|
|
7948
7979
|
}), d.current.onLessonStart({
|
|
7949
7980
|
moduleIndex: a.current.currentModuleIndex,
|
|
7950
7981
|
lessonIndex: a.current.currentLessonIndex,
|
|
7951
|
-
lesson:
|
|
7982
|
+
lesson: R()
|
|
7952
7983
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7953
7984
|
} else
|
|
7954
7985
|
k.current && k.current();
|
|
7955
|
-
}, []),
|
|
7956
|
-
const b =
|
|
7957
|
-
let
|
|
7986
|
+
}, []), X = O(() => {
|
|
7987
|
+
const b = R();
|
|
7988
|
+
let v = null;
|
|
7958
7989
|
if (b?.avatar_script && b?.body) {
|
|
7959
|
-
const
|
|
7960
|
-
|
|
7990
|
+
const F = b.avatar_script.trim(), P = b.body.trim(), N = F.match(/[.!?]$/) ? " " : ". ";
|
|
7991
|
+
v = `${F}${N}${P}`;
|
|
7961
7992
|
} else
|
|
7962
|
-
|
|
7963
|
-
if (u.current && u.current.isReady &&
|
|
7993
|
+
v = b?.avatar_script || b?.body || null;
|
|
7994
|
+
if (u.current && u.current.isReady && v) {
|
|
7964
7995
|
a.current.isTeaching = !0, a.current.isQuestionMode = !1, a.current.score = 0, a.current.totalQuestions = 0, u.current.setMood("happy");
|
|
7965
|
-
let
|
|
7996
|
+
let F = !1;
|
|
7966
7997
|
if (e.teaching)
|
|
7967
7998
|
try {
|
|
7968
|
-
u.current.playAnimation(e.teaching, !0),
|
|
7969
|
-
} catch (
|
|
7970
|
-
console.warn("Failed to play teaching animation:",
|
|
7999
|
+
u.current.playAnimation(e.teaching, !0), F = !0;
|
|
8000
|
+
} catch (N) {
|
|
8001
|
+
console.warn("Failed to play teaching animation:", N);
|
|
7971
8002
|
}
|
|
7972
|
-
|
|
7973
|
-
const
|
|
8003
|
+
F || u.current.setBodyMovement("gesturing");
|
|
8004
|
+
const P = T.current || { lipsyncLang: "en" };
|
|
7974
8005
|
d.current.onLessonStart({
|
|
7975
8006
|
moduleIndex: a.current.currentModuleIndex,
|
|
7976
8007
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7980,8 +8011,8 @@ const ft = Me(({
|
|
|
7980
8011
|
moduleIndex: a.current.currentModuleIndex,
|
|
7981
8012
|
lessonIndex: a.current.currentLessonIndex,
|
|
7982
8013
|
lesson: b
|
|
7983
|
-
}), u.current.speakText(
|
|
7984
|
-
lipsyncLang:
|
|
8014
|
+
}), u.current.speakText(v, {
|
|
8015
|
+
lipsyncLang: P.lipsyncLang,
|
|
7985
8016
|
onSpeechEnd: () => {
|
|
7986
8017
|
a.current.isTeaching = !1, d.current.onCustomAction({
|
|
7987
8018
|
type: "teachingComplete",
|
|
@@ -7999,17 +8030,17 @@ const ft = Me(({
|
|
|
7999
8030
|
}
|
|
8000
8031
|
});
|
|
8001
8032
|
}
|
|
8002
|
-
}, [e.teaching,
|
|
8003
|
-
const
|
|
8004
|
-
if (
|
|
8033
|
+
}, [e.teaching, R]), oe = O((b) => {
|
|
8034
|
+
const v = L(), F = I(b, v);
|
|
8035
|
+
if (F && (a.current.score += 1), d.current.onQuestionAnswer({
|
|
8005
8036
|
moduleIndex: a.current.currentModuleIndex,
|
|
8006
8037
|
lessonIndex: a.current.currentLessonIndex,
|
|
8007
8038
|
questionIndex: a.current.currentQuestionIndex,
|
|
8008
8039
|
answer: b,
|
|
8009
|
-
isCorrect:
|
|
8010
|
-
question:
|
|
8040
|
+
isCorrect: F,
|
|
8041
|
+
question: v
|
|
8011
8042
|
}), u.current)
|
|
8012
|
-
if (
|
|
8043
|
+
if (F) {
|
|
8013
8044
|
if (u.current.setMood("happy"), e.correct)
|
|
8014
8045
|
try {
|
|
8015
8046
|
u.current.playReaction("happy");
|
|
@@ -8017,13 +8048,13 @@ const ft = Me(({
|
|
|
8017
8048
|
u.current.setBodyMovement("happy");
|
|
8018
8049
|
}
|
|
8019
8050
|
u.current.setBodyMovement("gesturing");
|
|
8020
|
-
const
|
|
8021
|
-
a.current.currentQuestionIndex >=
|
|
8022
|
-
const
|
|
8023
|
-
console.log("[CurriculumLearning] Answer feedback - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:",
|
|
8024
|
-
const
|
|
8025
|
-
u.current.speakText(
|
|
8026
|
-
lipsyncLang:
|
|
8051
|
+
const N = R()?.questions?.length || 0;
|
|
8052
|
+
a.current.currentQuestionIndex >= N - 1;
|
|
8053
|
+
const te = a.current.currentQuestionIndex < N - 1;
|
|
8054
|
+
console.log("[CurriculumLearning] Answer feedback - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:", N, "hasNextQuestion:", te);
|
|
8055
|
+
const q = v.type === "code_test" ? `Great job! Your code passed all the tests! ${v.explanation || ""}` : `Excellent! That's correct! ${v.explanation || ""}`, _ = T.current || { lipsyncLang: "en" };
|
|
8056
|
+
u.current.speakText(q, {
|
|
8057
|
+
lipsyncLang: _.lipsyncLang,
|
|
8027
8058
|
onSpeechEnd: () => {
|
|
8028
8059
|
d.current.onCustomAction({
|
|
8029
8060
|
type: "answerFeedbackComplete",
|
|
@@ -8031,7 +8062,7 @@ const ft = Me(({
|
|
|
8031
8062
|
lessonIndex: a.current.currentLessonIndex,
|
|
8032
8063
|
questionIndex: a.current.currentQuestionIndex,
|
|
8033
8064
|
isCorrect: !0,
|
|
8034
|
-
hasNextQuestion:
|
|
8065
|
+
hasNextQuestion: te,
|
|
8035
8066
|
score: a.current.score,
|
|
8036
8067
|
totalQuestions: a.current.totalQuestions
|
|
8037
8068
|
});
|
|
@@ -8045,10 +8076,10 @@ const ft = Me(({
|
|
|
8045
8076
|
u.current.setBodyMovement("idle");
|
|
8046
8077
|
}
|
|
8047
8078
|
u.current.setBodyMovement("gesturing");
|
|
8048
|
-
const
|
|
8049
|
-
console.log("[CurriculumLearning] Answer feedback (incorrect) - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:",
|
|
8050
|
-
const
|
|
8051
|
-
u.current.speakText(
|
|
8079
|
+
const N = R()?.questions?.length || 0, te = a.current.currentQuestionIndex >= N - 1, q = a.current.currentQuestionIndex < N - 1;
|
|
8080
|
+
console.log("[CurriculumLearning] Answer feedback (incorrect) - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:", N, "hasNextQuestion:", q);
|
|
8081
|
+
const _ = v.type === "code_test" ? `Your code didn't pass all the tests. ${v.explanation || "Try again!"}` : `Not quite right, but don't worry! ${v.explanation || ""}${te ? "" : " Let's move on to the next question."}`, Ae = T.current || { lipsyncLang: "en" };
|
|
8082
|
+
u.current.speakText(_, {
|
|
8052
8083
|
lipsyncLang: Ae.lipsyncLang,
|
|
8053
8084
|
onSpeechEnd: () => {
|
|
8054
8085
|
d.current.onCustomAction({
|
|
@@ -8057,7 +8088,7 @@ const ft = Me(({
|
|
|
8057
8088
|
lessonIndex: a.current.currentLessonIndex,
|
|
8058
8089
|
questionIndex: a.current.currentQuestionIndex,
|
|
8059
8090
|
isCorrect: !1,
|
|
8060
|
-
hasNextQuestion:
|
|
8091
|
+
hasNextQuestion: q,
|
|
8061
8092
|
score: a.current.score,
|
|
8062
8093
|
totalQuestions: a.current.totalQuestions
|
|
8063
8094
|
});
|
|
@@ -8065,30 +8096,30 @@ const ft = Me(({
|
|
|
8065
8096
|
});
|
|
8066
8097
|
}
|
|
8067
8098
|
else {
|
|
8068
|
-
const
|
|
8099
|
+
const N = R()?.questions?.length || 0;
|
|
8069
8100
|
d.current.onCustomAction({
|
|
8070
8101
|
type: "answerFeedbackComplete",
|
|
8071
8102
|
moduleIndex: a.current.currentModuleIndex,
|
|
8072
8103
|
lessonIndex: a.current.currentLessonIndex,
|
|
8073
8104
|
questionIndex: a.current.currentQuestionIndex,
|
|
8074
|
-
isCorrect:
|
|
8075
|
-
hasNextQuestion: a.current.currentQuestionIndex <
|
|
8105
|
+
isCorrect: F,
|
|
8106
|
+
hasNextQuestion: a.current.currentQuestionIndex < N - 1,
|
|
8076
8107
|
score: a.current.score,
|
|
8077
8108
|
totalQuestions: a.current.totalQuestions,
|
|
8078
8109
|
avatarNotReady: !0
|
|
8079
8110
|
});
|
|
8080
8111
|
}
|
|
8081
|
-
}, [e.correct, e.incorrect, L,
|
|
8082
|
-
const
|
|
8112
|
+
}, [e.correct, e.incorrect, L, R, I]), le = O((b) => {
|
|
8113
|
+
const v = L();
|
|
8083
8114
|
if (!b || typeof b != "object") {
|
|
8084
8115
|
console.error("Invalid code test result format. Expected object with {passed: boolean, ...}");
|
|
8085
8116
|
return;
|
|
8086
8117
|
}
|
|
8087
|
-
if (
|
|
8118
|
+
if (v?.type !== "code_test") {
|
|
8088
8119
|
console.warn("Current question is not a code test. Use handleAnswerSelect for other question types.");
|
|
8089
8120
|
return;
|
|
8090
8121
|
}
|
|
8091
|
-
const
|
|
8122
|
+
const F = {
|
|
8092
8123
|
passed: b.passed === !0,
|
|
8093
8124
|
results: b.results || [],
|
|
8094
8125
|
output: b.output || "",
|
|
@@ -8103,10 +8134,10 @@ const ft = Me(({
|
|
|
8103
8134
|
moduleIndex: a.current.currentModuleIndex,
|
|
8104
8135
|
lessonIndex: a.current.currentLessonIndex,
|
|
8105
8136
|
questionIndex: a.current.currentQuestionIndex,
|
|
8106
|
-
testResult:
|
|
8107
|
-
question:
|
|
8108
|
-
}), p.current && p.current(
|
|
8109
|
-
}, [L, I]), ge =
|
|
8137
|
+
testResult: F,
|
|
8138
|
+
question: v
|
|
8139
|
+
}), p.current && p.current(F);
|
|
8140
|
+
}, [L, I]), ge = O(() => {
|
|
8110
8141
|
if (a.current.currentQuestionIndex > 0) {
|
|
8111
8142
|
a.current.currentQuestionIndex -= 1;
|
|
8112
8143
|
const b = L();
|
|
@@ -8119,28 +8150,28 @@ const ft = Me(({
|
|
|
8119
8150
|
question: b,
|
|
8120
8151
|
score: a.current.score
|
|
8121
8152
|
});
|
|
8122
|
-
const
|
|
8153
|
+
const v = () => {
|
|
8123
8154
|
if (!u.current || !b) return;
|
|
8124
8155
|
u.current.setMood("happy"), u.current.setBodyMovement("idle");
|
|
8125
|
-
const
|
|
8156
|
+
const F = T.current || { lipsyncLang: "en" };
|
|
8126
8157
|
b.type === "code_test" ? u.current.speakText(`Let's go back to this coding challenge: ${b.question}`, {
|
|
8127
|
-
lipsyncLang:
|
|
8158
|
+
lipsyncLang: F.lipsyncLang
|
|
8128
8159
|
}) : u.current.speakText(`Going back to: ${b.question}`, {
|
|
8129
|
-
lipsyncLang:
|
|
8160
|
+
lipsyncLang: F.lipsyncLang
|
|
8130
8161
|
});
|
|
8131
8162
|
};
|
|
8132
8163
|
if (u.current && u.current.isReady && b)
|
|
8133
|
-
|
|
8164
|
+
v();
|
|
8134
8165
|
else if (b) {
|
|
8135
|
-
const
|
|
8136
|
-
u.current && u.current.isReady && (clearInterval(
|
|
8166
|
+
const F = setInterval(() => {
|
|
8167
|
+
u.current && u.current.isReady && (clearInterval(F), v());
|
|
8137
8168
|
}, 100);
|
|
8138
8169
|
setTimeout(() => {
|
|
8139
|
-
clearInterval(
|
|
8170
|
+
clearInterval(F);
|
|
8140
8171
|
}, 5e3);
|
|
8141
8172
|
}
|
|
8142
8173
|
}
|
|
8143
|
-
}, [L]), de =
|
|
8174
|
+
}, [L]), de = O(() => {
|
|
8144
8175
|
const b = B.current || { modules: [] };
|
|
8145
8176
|
if (b.modules[a.current.currentModuleIndex], a.current.currentLessonIndex > 0)
|
|
8146
8177
|
a.current.currentLessonIndex -= 1, a.current.currentQuestionIndex = 0, a.current.lessonCompleted = !1, a.current.isQuestionMode = !1, a.current.isTeaching = !1, a.current.score = 0, a.current.totalQuestions = 0, d.current.onCustomAction({
|
|
@@ -8150,66 +8181,66 @@ const ft = Me(({
|
|
|
8150
8181
|
}), d.current.onLessonStart({
|
|
8151
8182
|
moduleIndex: a.current.currentModuleIndex,
|
|
8152
8183
|
lessonIndex: a.current.currentLessonIndex,
|
|
8153
|
-
lesson:
|
|
8184
|
+
lesson: R()
|
|
8154
8185
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
8155
8186
|
else if (a.current.currentModuleIndex > 0) {
|
|
8156
|
-
const
|
|
8157
|
-
a.current.currentModuleIndex -= 1, a.current.currentLessonIndex = (
|
|
8187
|
+
const P = b.modules[a.current.currentModuleIndex - 1];
|
|
8188
|
+
a.current.currentModuleIndex -= 1, a.current.currentLessonIndex = (P?.lessons?.length || 1) - 1, a.current.currentQuestionIndex = 0, a.current.lessonCompleted = !1, a.current.isQuestionMode = !1, a.current.isTeaching = !1, a.current.score = 0, a.current.totalQuestions = 0, d.current.onCustomAction({
|
|
8158
8189
|
type: "lessonStart",
|
|
8159
8190
|
moduleIndex: a.current.currentModuleIndex,
|
|
8160
8191
|
lessonIndex: a.current.currentLessonIndex
|
|
8161
8192
|
}), d.current.onLessonStart({
|
|
8162
8193
|
moduleIndex: a.current.currentModuleIndex,
|
|
8163
8194
|
lessonIndex: a.current.currentLessonIndex,
|
|
8164
|
-
lesson:
|
|
8195
|
+
lesson: R()
|
|
8165
8196
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
8166
8197
|
}
|
|
8167
|
-
}, [
|
|
8198
|
+
}, [R]), ee = O(() => {
|
|
8168
8199
|
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;
|
|
8169
|
-
}, []), be =
|
|
8200
|
+
}, []), be = O((b) => {
|
|
8170
8201
|
console.log("Avatar is ready!", b);
|
|
8171
|
-
const
|
|
8172
|
-
h &&
|
|
8202
|
+
const v = R(), F = v?.avatar_script || v?.body;
|
|
8203
|
+
h && F && setTimeout(() => {
|
|
8173
8204
|
c.current && c.current();
|
|
8174
8205
|
}, 10);
|
|
8175
|
-
}, [h,
|
|
8206
|
+
}, [h, R]);
|
|
8176
8207
|
Xe(() => {
|
|
8177
|
-
c.current =
|
|
8208
|
+
c.current = X, g.current = j, x.current = z, f.current = E, k.current = Y, D.current = S, p.current = oe;
|
|
8178
8209
|
}), Fe(r, () => ({
|
|
8179
8210
|
// Curriculum control methods
|
|
8180
|
-
startTeaching:
|
|
8211
|
+
startTeaching: X,
|
|
8181
8212
|
startQuestions: S,
|
|
8182
|
-
handleAnswerSelect:
|
|
8213
|
+
handleAnswerSelect: oe,
|
|
8183
8214
|
handleCodeTestResult: le,
|
|
8184
|
-
nextQuestion:
|
|
8215
|
+
nextQuestion: E,
|
|
8185
8216
|
previousQuestion: ge,
|
|
8186
|
-
nextLesson:
|
|
8217
|
+
nextLesson: j,
|
|
8187
8218
|
previousLesson: de,
|
|
8188
8219
|
completeLesson: z,
|
|
8189
8220
|
completeCurriculum: Y,
|
|
8190
|
-
resetCurriculum:
|
|
8221
|
+
resetCurriculum: ee,
|
|
8191
8222
|
getState: () => ({ ...a.current }),
|
|
8192
8223
|
getCurrentQuestion: () => L(),
|
|
8193
|
-
getCurrentLesson: () =>
|
|
8224
|
+
getCurrentLesson: () => R(),
|
|
8194
8225
|
// Direct access to avatar ref (always returns current value)
|
|
8195
8226
|
getAvatarRef: () => u.current,
|
|
8196
8227
|
// Convenience methods that delegate to avatar (always check current ref)
|
|
8197
|
-
speakText: async (b,
|
|
8228
|
+
speakText: async (b, v = {}) => {
|
|
8198
8229
|
await u.current?.resumeAudioContext?.();
|
|
8199
|
-
const
|
|
8200
|
-
u.current?.speakText(b, { ...
|
|
8230
|
+
const F = T.current || { lipsyncLang: "en" };
|
|
8231
|
+
u.current?.speakText(b, { ...v, lipsyncLang: v.lipsyncLang || F.lipsyncLang });
|
|
8201
8232
|
},
|
|
8202
8233
|
resumeAudioContext: async () => {
|
|
8203
8234
|
if (u.current?.resumeAudioContext)
|
|
8204
8235
|
return await u.current.resumeAudioContext();
|
|
8205
8236
|
const b = u.current?.talkingHead;
|
|
8206
8237
|
if (b?.audioCtx) {
|
|
8207
|
-
const
|
|
8208
|
-
if (
|
|
8238
|
+
const v = b.audioCtx;
|
|
8239
|
+
if (v.state === "suspended" || v.state === "interrupted")
|
|
8209
8240
|
try {
|
|
8210
|
-
await
|
|
8211
|
-
} catch (
|
|
8212
|
-
console.warn("Failed to resume audio context:",
|
|
8241
|
+
await v.resume(), console.log("Audio context resumed via talkingHead");
|
|
8242
|
+
} catch (F) {
|
|
8243
|
+
console.warn("Failed to resume audio context:", F);
|
|
8213
8244
|
}
|
|
8214
8245
|
} else
|
|
8215
8246
|
console.warn("Audio context not available yet");
|
|
@@ -8219,7 +8250,7 @@ const ft = Me(({
|
|
|
8219
8250
|
resumeSpeaking: async () => await u.current?.resumeSpeaking(),
|
|
8220
8251
|
isPaused: () => u.current && typeof u.current.isPaused < "u" ? u.current.isPaused : !1,
|
|
8221
8252
|
setMood: (b) => u.current?.setMood(b),
|
|
8222
|
-
playAnimation: (b,
|
|
8253
|
+
playAnimation: (b, v) => u.current?.playAnimation(b, v),
|
|
8223
8254
|
setBodyMovement: (b) => u.current?.setBodyMovement(b),
|
|
8224
8255
|
setMovementIntensity: (b) => u.current?.setMovementIntensity(b),
|
|
8225
8256
|
playRandomDance: () => u.current?.playRandomDance(),
|
|
@@ -8230,10 +8261,10 @@ const ft = Me(({
|
|
|
8230
8261
|
lockAvatarPosition: () => u.current?.lockAvatarPosition(),
|
|
8231
8262
|
unlockAvatarPosition: () => u.current?.unlockAvatarPosition(),
|
|
8232
8263
|
// Custom action trigger
|
|
8233
|
-
triggerCustomAction: (b,
|
|
8264
|
+
triggerCustomAction: (b, v) => {
|
|
8234
8265
|
d.current.onCustomAction({
|
|
8235
8266
|
type: b,
|
|
8236
|
-
...
|
|
8267
|
+
...v,
|
|
8237
8268
|
state: { ...a.current }
|
|
8238
8269
|
});
|
|
8239
8270
|
},
|
|
@@ -8241,8 +8272,8 @@ const ft = Me(({
|
|
|
8241
8272
|
handleResize: () => u.current?.handleResize(),
|
|
8242
8273
|
// Avatar readiness check (always returns current value)
|
|
8243
8274
|
isAvatarReady: () => u.current?.isReady || !1
|
|
8244
|
-
}), [
|
|
8245
|
-
const
|
|
8275
|
+
}), [X, S, oe, le, E, j, z, Y, ee, L, R]);
|
|
8276
|
+
const Q = T.current || {
|
|
8246
8277
|
avatarUrl: "/avatars/brunette.glb",
|
|
8247
8278
|
avatarBody: "F",
|
|
8248
8279
|
mood: "happy",
|
|
@@ -8259,18 +8290,18 @@ const ft = Me(({
|
|
|
8259
8290
|
Ve,
|
|
8260
8291
|
{
|
|
8261
8292
|
ref: u,
|
|
8262
|
-
avatarUrl:
|
|
8263
|
-
avatarBody:
|
|
8264
|
-
mood:
|
|
8265
|
-
ttsLang:
|
|
8266
|
-
ttsService:
|
|
8267
|
-
ttsVoice:
|
|
8268
|
-
ttsApiKey:
|
|
8269
|
-
bodyMovement:
|
|
8270
|
-
movementIntensity:
|
|
8271
|
-
showFullAvatar:
|
|
8293
|
+
avatarUrl: Q.avatarUrl,
|
|
8294
|
+
avatarBody: Q.avatarBody,
|
|
8295
|
+
mood: Q.mood,
|
|
8296
|
+
ttsLang: Q.ttsLang,
|
|
8297
|
+
ttsService: Q.ttsService,
|
|
8298
|
+
ttsVoice: Q.ttsVoice,
|
|
8299
|
+
ttsApiKey: Q.ttsApiKey,
|
|
8300
|
+
bodyMovement: Q.bodyMovement,
|
|
8301
|
+
movementIntensity: Q.movementIntensity,
|
|
8302
|
+
showFullAvatar: Q.showFullAvatar,
|
|
8272
8303
|
cameraView: "upper",
|
|
8273
|
-
animations:
|
|
8304
|
+
animations: Q.animations,
|
|
8274
8305
|
onReady: be,
|
|
8275
8306
|
onLoading: () => {
|
|
8276
8307
|
},
|