@sage-rsc/talking-head-react 1.3.4 → 1.3.6
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 +350 -311
- package/package.json +1 -1
- package/src/components/SimpleTalkingAvatar.jsx +49 -13
- package/src/lib/talkinghead.mjs +28 -0
- package/src/utils/animationLoader.js +19 -2
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsxs as Pe, jsx as ye } from "react/jsx-runtime";
|
|
2
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";
|
|
@@ -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);
|
|
@@ -4391,6 +4391,21 @@ class Be {
|
|
|
4391
4391
|
s > 1 || !this.poseBase.props.hasOwnProperty(e) ? i.copy(n) : i.isQuaternion ? i.copy(this.poseBase.props[e].slerp(n, this.easing(s))) : i.isVector3 && i.copy(this.poseBase.props[e].lerp(n, this.easing(s)));
|
|
4392
4392
|
}
|
|
4393
4393
|
}
|
|
4394
|
+
this.applyShoulderAdjustment();
|
|
4395
|
+
}
|
|
4396
|
+
/**
|
|
4397
|
+
* Apply shoulder adjustment to lower shoulders to a more natural position
|
|
4398
|
+
*/
|
|
4399
|
+
applyShoulderAdjustment() {
|
|
4400
|
+
const e = new y.Euler();
|
|
4401
|
+
if (this.poseAvatar.props["LeftShoulder.quaternion"]) {
|
|
4402
|
+
const n = this.poseAvatar.props["LeftShoulder.quaternion"];
|
|
4403
|
+
e.setFromQuaternion(n, "XYZ"), e.x += -0.35, n.setFromEuler(e, "XYZ");
|
|
4404
|
+
}
|
|
4405
|
+
if (this.poseAvatar.props["RightShoulder.quaternion"]) {
|
|
4406
|
+
const n = this.poseAvatar.props["RightShoulder.quaternion"];
|
|
4407
|
+
e.setFromQuaternion(n, "XYZ"), e.x += -0.35, n.setFromEuler(e, "XYZ");
|
|
4408
|
+
}
|
|
4394
4409
|
}
|
|
4395
4410
|
/**
|
|
4396
4411
|
* Update avatar pose deltas
|
|
@@ -4398,9 +4413,9 @@ class Be {
|
|
|
4398
4413
|
updatePoseDelta() {
|
|
4399
4414
|
for (const [t, e] of Object.entries(this.poseDelta.props)) {
|
|
4400
4415
|
if (e.x === 0 && e.y === 0 && e.z === 0) continue;
|
|
4401
|
-
|
|
4416
|
+
Z.set(e.x, e.y, e.z);
|
|
4402
4417
|
const n = this.poseAvatar.props[t];
|
|
4403
|
-
n.isQuaternion ? (
|
|
4418
|
+
n.isQuaternion ? ($.setFromEuler(Z), n.multiply($)) : n.isVector3 && n.add(Z);
|
|
4404
4419
|
}
|
|
4405
4420
|
}
|
|
4406
4421
|
/**
|
|
@@ -5172,7 +5187,7 @@ class Be {
|
|
|
5172
5187
|
}, i.x ? new y.Vector3(i.x, i.y, i.z) : null, !0, i.d);
|
|
5173
5188
|
break;
|
|
5174
5189
|
}
|
|
5175
|
-
if ((h || r) && (
|
|
5190
|
+
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
5191
|
name: "headmove",
|
|
5177
5192
|
dt: [[1e3, 2e3], [1e3, 2e3, 1, 2], [1e3, 2e3], [1e3, 2e3, 1, 2]],
|
|
5178
5193
|
vs: {
|
|
@@ -5193,7 +5208,7 @@ class Be {
|
|
|
5193
5208
|
eyeLookOutRight: [null, 0],
|
|
5194
5209
|
eyeContact: [0]
|
|
5195
5210
|
}
|
|
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 && (
|
|
5211
|
+
})))), 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
5212
|
this.stats && this.stats.end();
|
|
5198
5213
|
else {
|
|
5199
5214
|
if (this.cameraClock !== null && this.cameraClock < 1e3) {
|
|
@@ -5264,10 +5279,10 @@ class Be {
|
|
|
5264
5279
|
let u = "", a = "", d = 0, c = [], g = [];
|
|
5265
5280
|
const x = Array.from(this.segmenter.segment(t), (f) => f.segment);
|
|
5266
5281
|
for (let f = 0; f < x.length; f++) {
|
|
5267
|
-
const k = f === x.length - 1,
|
|
5282
|
+
const k = f === x.length - 1, D = x[f].match(l);
|
|
5268
5283
|
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]),
|
|
5284
|
+
const B = x[f].match(h), T = x[f].match(o);
|
|
5285
|
+
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
5286
|
mark: d,
|
|
5272
5287
|
word: a
|
|
5273
5288
|
})), u.length && (g.push({
|
|
@@ -5398,10 +5413,10 @@ class Be {
|
|
|
5398
5413
|
let x = 0.6 + this.convertRange(g, [0, u], [0, 0.4]);
|
|
5399
5414
|
if (u = Math.min(u, d.visemes.length * 200), c > 0)
|
|
5400
5415
|
for (let f = 0; f < d.visemes.length; f++) {
|
|
5401
|
-
const k = r + d.times[f] / c * u,
|
|
5416
|
+
const k = r + d.times[f] / c * u, D = d.durations[f] / c * u;
|
|
5402
5417
|
o.push({
|
|
5403
5418
|
template: { name: "viseme" },
|
|
5404
|
-
ts: [k - Math.min(60, 2 *
|
|
5419
|
+
ts: [k - Math.min(60, 2 * D / 3), k + Math.min(25, D / 2), k + D + Math.min(60, D / 2)],
|
|
5405
5420
|
vs: {
|
|
5406
5421
|
["viseme_" + d.visemes[f]]: [null, d.visemes[f] === "PP" || d.visemes[f] === "FF" ? 0.9 : x, 0]
|
|
5407
5422
|
}
|
|
@@ -5499,18 +5514,18 @@ class Be {
|
|
|
5499
5514
|
if (f && f.visemes && f.visemes.length > 0) {
|
|
5500
5515
|
const p = f.times[f.visemes.length - 1] + f.durations[f.visemes.length - 1];
|
|
5501
5516
|
for (let B = 0; B < f.visemes.length; B++) {
|
|
5502
|
-
const
|
|
5517
|
+
const T = f.visemes[B], R = f.times[B] / p, L = f.durations[B] / p, I = R * d, z = L * d;
|
|
5503
5518
|
k.push({
|
|
5504
5519
|
template: { name: "viseme" },
|
|
5505
5520
|
ts: [I - Math.min(60, 2 * z / 3), I + Math.min(25, z / 2), I + z + Math.min(60, z / 2)],
|
|
5506
5521
|
vs: {
|
|
5507
|
-
["viseme_" +
|
|
5522
|
+
["viseme_" + T]: [null, T === "PP" || T === "FF" ? 0.9 : 0.6, 0]
|
|
5508
5523
|
}
|
|
5509
5524
|
});
|
|
5510
5525
|
}
|
|
5511
5526
|
}
|
|
5512
|
-
const
|
|
5513
|
-
this.audioPlaylist.push({ anim:
|
|
5527
|
+
const D = [...t.anim, ...k];
|
|
5528
|
+
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
5529
|
e();
|
|
5515
5530
|
}, s.onerror = (p) => {
|
|
5516
5531
|
console.error("Speech synthesis error:", p.error), n(p.error);
|
|
@@ -6159,12 +6174,12 @@ class Be {
|
|
|
6159
6174
|
this.lookAt(null, null, t);
|
|
6160
6175
|
return;
|
|
6161
6176
|
}
|
|
6162
|
-
this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0), ve.setFromMatrixPosition(this.objectLeftEye.matrixWorld), Re.setFromMatrixPosition(this.objectRightEye.matrixWorld), ve.add(Re).divideScalar(2),
|
|
6177
|
+
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
6178
|
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 =
|
|
6179
|
+
Z.set(s, i, 0, "YXZ");
|
|
6180
|
+
const l = new y.Quaternion().setFromEuler(Z), h = new y.Quaternion().copy(l).multiply($.clone().invert());
|
|
6181
|
+
Z.setFromQuaternion(h, "YXZ");
|
|
6182
|
+
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
6183
|
if (t) {
|
|
6169
6184
|
let x = this.animQueue.findIndex((k) => k.template.name === "lookat");
|
|
6170
6185
|
x !== -1 && this.animQueue.splice(x, 1);
|
|
@@ -6199,20 +6214,20 @@ class Be {
|
|
|
6199
6214
|
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
6215
|
l.project(this.camera);
|
|
6201
6216
|
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 =
|
|
6217
|
+
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($);
|
|
6218
|
+
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
6219
|
f = Math.min(0.6, Math.max(-0.3, f)), k = Math.min(0.8, Math.max(-0.8, k));
|
|
6205
|
-
let
|
|
6220
|
+
let D = (Math.random() - 0.5) / 4, p = (Math.random() - 0.5) / 4;
|
|
6206
6221
|
if (n) {
|
|
6207
6222
|
let B = this.animQueue.findIndex((R) => R.template.name === "lookat");
|
|
6208
6223
|
B !== -1 && this.animQueue.splice(B, 1);
|
|
6209
|
-
const
|
|
6224
|
+
const T = {
|
|
6210
6225
|
name: "lookat",
|
|
6211
6226
|
dt: [750, n],
|
|
6212
6227
|
vs: {
|
|
6213
|
-
bodyRotateX: [f +
|
|
6228
|
+
bodyRotateX: [f + D],
|
|
6214
6229
|
bodyRotateY: [k + p],
|
|
6215
|
-
eyesRotateX: [-3 *
|
|
6230
|
+
eyesRotateX: [-3 * D + 0.1],
|
|
6216
6231
|
eyesRotateY: [-5 * p],
|
|
6217
6232
|
browInnerUp: [[0, 0.7]],
|
|
6218
6233
|
mouthLeft: [[0, 0.7]],
|
|
@@ -6221,7 +6236,7 @@ class Be {
|
|
|
6221
6236
|
headMove: [0]
|
|
6222
6237
|
}
|
|
6223
6238
|
};
|
|
6224
|
-
this.animQueue.push(this.animFactory(
|
|
6239
|
+
this.animQueue.push(this.animFactory(T));
|
|
6225
6240
|
}
|
|
6226
6241
|
}
|
|
6227
6242
|
/**
|
|
@@ -6535,16 +6550,16 @@ class Be {
|
|
|
6535
6550
|
}), 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
6551
|
const k = Array.from(f).filter(
|
|
6537
6552
|
(L) => L.toLowerCase().includes("arm") || L.toLowerCase().includes("hand") || L.toLowerCase().includes("shoulder")
|
|
6538
|
-
),
|
|
6553
|
+
), D = Array.from(c).filter(
|
|
6539
6554
|
(L) => L.includes("Arm") || L.includes("Hand") || L.includes("Shoulder")
|
|
6540
6555
|
);
|
|
6541
|
-
console.log("FBX arm/hand/shoulder bones:", k.sort().join(", ")), console.log("Avatar arm/hand/shoulder bones:",
|
|
6556
|
+
console.log("FBX arm/hand/shoulder bones:", k.sort().join(", ")), console.log("Avatar arm/hand/shoulder bones:", D.sort().join(", "));
|
|
6542
6557
|
const p = [], B = /* @__PURE__ */ new Set();
|
|
6543
6558
|
if (d.tracks.forEach((L) => {
|
|
6544
6559
|
const z = L.name.replaceAll("mixamorig", "").split("."), Y = z[0], S = z[1], E = x(Y);
|
|
6545
6560
|
if (E && S) {
|
|
6546
|
-
const
|
|
6547
|
-
|
|
6561
|
+
const j = `${E}.${S}`, X = L.clone();
|
|
6562
|
+
X.name = j, p.push(X), Y !== E && g.set(Y, E);
|
|
6548
6563
|
} else
|
|
6549
6564
|
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
6565
|
}), B.size > 0 && console.warn(`⚠️ ${B.size} bone(s) could not be mapped:`, Array.from(B).sort().join(", ")), p.length > 0) {
|
|
@@ -6558,18 +6573,18 @@ class Be {
|
|
|
6558
6573
|
L.length > 0 ? console.log(`✓ Arm bones mapped: ${L.join(", ")}`) : console.warn("⚠️ No arm bones were mapped! This may cause arm rigging issues.");
|
|
6559
6574
|
} else
|
|
6560
6575
|
console.error("❌ No tracks could be mapped! Animation may not work correctly.");
|
|
6561
|
-
const
|
|
6576
|
+
const T = {};
|
|
6562
6577
|
d.tracks.forEach((L) => {
|
|
6563
6578
|
L.name = L.name.replaceAll("mixamorig", "");
|
|
6564
6579
|
const I = L.name.split(".");
|
|
6565
6580
|
if (I[1] === "position") {
|
|
6566
6581
|
for (let z = 0; z < L.values.length; z++)
|
|
6567
6582
|
L.values[z] = L.values[z] * s;
|
|
6568
|
-
|
|
6569
|
-
} else I[1] === "quaternion" ?
|
|
6583
|
+
T[L.name] = new y.Vector3(L.values[0], L.values[1], L.values[2]);
|
|
6584
|
+
} 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
6585
|
});
|
|
6571
|
-
const R = { props:
|
|
6572
|
-
|
|
6586
|
+
const R = { props: T };
|
|
6587
|
+
T["Hips.position"] && (T["Hips.position"].y < 0.5 ? R.lying = !0 : R.standing = !0), this.animClips.push({
|
|
6573
6588
|
url: t + "-" + i,
|
|
6574
6589
|
clip: d,
|
|
6575
6590
|
pose: R
|
|
@@ -6707,12 +6722,12 @@ class Be {
|
|
|
6707
6722
|
const f = t.iterations || 10;
|
|
6708
6723
|
if (e)
|
|
6709
6724
|
for (let k = 0; k < f; k++) {
|
|
6710
|
-
let
|
|
6725
|
+
let D = !1;
|
|
6711
6726
|
for (let p = 0, B = x.length; p < B; p++) {
|
|
6712
|
-
const
|
|
6713
|
-
|
|
6727
|
+
const T = x[p].bone;
|
|
6728
|
+
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
6729
|
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(),
|
|
6730
|
+
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
6731
|
x[p].minx !== void 0 ? x[p].minx : -1 / 0,
|
|
6717
6732
|
x[p].miny !== void 0 ? x[p].miny : -1 / 0,
|
|
6718
6733
|
x[p].minz !== void 0 ? x[p].minz : -1 / 0
|
|
@@ -6720,9 +6735,9 @@ class Be {
|
|
|
6720
6735
|
x[p].maxx !== void 0 ? x[p].maxx : 1 / 0,
|
|
6721
6736
|
x[p].maxy !== void 0 ? x[p].maxy : 1 / 0,
|
|
6722
6737
|
x[p].maxz !== void 0 ? x[p].maxz : 1 / 0
|
|
6723
|
-
))),
|
|
6738
|
+
))), T.updateMatrixWorld(!0), D = !0);
|
|
6724
6739
|
}
|
|
6725
|
-
if (!
|
|
6740
|
+
if (!D) break;
|
|
6726
6741
|
}
|
|
6727
6742
|
i && x.forEach((k) => {
|
|
6728
6743
|
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,70 +6830,70 @@ const Ve = Me(({
|
|
|
6815
6830
|
style: x = {},
|
|
6816
6831
|
animations: f = {}
|
|
6817
6832
|
}, k) => {
|
|
6818
|
-
const
|
|
6833
|
+
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
6834
|
ce(() => {
|
|
6820
6835
|
L.current = ge;
|
|
6821
6836
|
}, [ge]), ce(() => {
|
|
6822
6837
|
B.current = r;
|
|
6823
6838
|
}, [r]);
|
|
6824
|
-
const
|
|
6825
|
-
let
|
|
6826
|
-
be === "browser" ?
|
|
6839
|
+
const ee = Ee(), be = i || ee.service;
|
|
6840
|
+
let Q;
|
|
6841
|
+
be === "browser" ? Q = {
|
|
6827
6842
|
service: "browser",
|
|
6828
6843
|
endpoint: "",
|
|
6829
6844
|
apiKey: null,
|
|
6830
6845
|
defaultVoice: "Google US English"
|
|
6831
|
-
} : be === "elevenlabs" ?
|
|
6846
|
+
} : be === "elevenlabs" ? Q = {
|
|
6832
6847
|
service: "elevenlabs",
|
|
6833
6848
|
endpoint: "https://api.elevenlabs.io/v1/text-to-speech",
|
|
6834
|
-
apiKey: o ||
|
|
6835
|
-
defaultVoice: s ||
|
|
6836
|
-
voices:
|
|
6837
|
-
} : be === "deepgram" ?
|
|
6849
|
+
apiKey: o || ee.apiKey,
|
|
6850
|
+
defaultVoice: s || ee.defaultVoice || Ie.defaultVoice,
|
|
6851
|
+
voices: ee.voices || Ie.voices
|
|
6852
|
+
} : be === "deepgram" ? Q = {
|
|
6838
6853
|
service: "deepgram",
|
|
6839
6854
|
endpoint: "https://api.deepgram.com/v1/speak",
|
|
6840
|
-
apiKey: o ||
|
|
6841
|
-
defaultVoice: s ||
|
|
6842
|
-
voices:
|
|
6843
|
-
} :
|
|
6844
|
-
|
|
6855
|
+
apiKey: o || ee.apiKey,
|
|
6856
|
+
defaultVoice: s || ee.defaultVoice || Te.defaultVoice,
|
|
6857
|
+
voices: ee.voices || Te.voices
|
|
6858
|
+
} : Q = {
|
|
6859
|
+
...ee,
|
|
6845
6860
|
// Override API key if provided via props
|
|
6846
|
-
apiKey: o !== null ? o :
|
|
6861
|
+
apiKey: o !== null ? o : ee.apiKey
|
|
6847
6862
|
};
|
|
6848
6863
|
const b = {
|
|
6849
6864
|
url: V,
|
|
6850
6865
|
body: t,
|
|
6851
6866
|
avatarMood: e,
|
|
6852
6867
|
ttsLang: be === "browser" ? "en-US" : n,
|
|
6853
|
-
ttsVoice: s ||
|
|
6868
|
+
ttsVoice: s || Q.defaultVoice,
|
|
6854
6869
|
lipsyncLang: "en",
|
|
6855
6870
|
showFullAvatar: r,
|
|
6856
6871
|
bodyMovement: l,
|
|
6857
6872
|
movementIntensity: h
|
|
6858
6873
|
}, v = {
|
|
6859
|
-
ttsEndpoint:
|
|
6860
|
-
ttsApikey:
|
|
6874
|
+
ttsEndpoint: Q.endpoint,
|
|
6875
|
+
ttsApikey: Q.apiKey,
|
|
6861
6876
|
ttsService: be,
|
|
6862
6877
|
lipsyncModules: ["en"],
|
|
6863
6878
|
cameraView: u
|
|
6864
6879
|
}, F = O(async () => {
|
|
6865
|
-
if (!(!
|
|
6880
|
+
if (!(!D.current || p.current))
|
|
6866
6881
|
try {
|
|
6867
|
-
if (E(!0),
|
|
6868
|
-
if (
|
|
6869
|
-
const
|
|
6870
|
-
d(
|
|
6882
|
+
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) => {
|
|
6883
|
+
if (K.lengthComputable) {
|
|
6884
|
+
const ne = Math.min(100, Math.round(K.loaded / K.total * 100));
|
|
6885
|
+
d(ne);
|
|
6871
6886
|
}
|
|
6872
|
-
}), await new Promise((
|
|
6873
|
-
const
|
|
6874
|
-
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ?
|
|
6887
|
+
}), await new Promise((K) => {
|
|
6888
|
+
const ne = () => {
|
|
6889
|
+
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? K() : setTimeout(ne, 100);
|
|
6875
6890
|
};
|
|
6876
|
-
|
|
6891
|
+
ne();
|
|
6877
6892
|
}), p.current && p.current.setShowFullAvatar)
|
|
6878
6893
|
try {
|
|
6879
6894
|
p.current.setShowFullAvatar(r);
|
|
6880
|
-
} catch (
|
|
6881
|
-
console.warn("Error setting full body mode on initialization:",
|
|
6895
|
+
} catch (K) {
|
|
6896
|
+
console.warn("Error setting full body mode on initialization:", K);
|
|
6882
6897
|
}
|
|
6883
6898
|
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
6899
|
const U = () => {
|
|
@@ -6888,18 +6903,18 @@ const Ve = Me(({
|
|
|
6888
6903
|
document.removeEventListener("visibilitychange", U);
|
|
6889
6904
|
};
|
|
6890
6905
|
} catch (w) {
|
|
6891
|
-
console.error("Error initializing TalkingHead:", w),
|
|
6906
|
+
console.error("Error initializing TalkingHead:", w), X(w.message || "Failed to initialize avatar"), E(!1), c(w);
|
|
6892
6907
|
}
|
|
6893
6908
|
}, [V, t, e, n, i, s, o, r, l, h, u]);
|
|
6894
6909
|
ce(() => (F(), () => {
|
|
6895
6910
|
p.current && (p.current.stop(), p.current.dispose(), p.current = null);
|
|
6896
6911
|
}), [F]), ce(() => {
|
|
6897
|
-
if (!
|
|
6898
|
-
const w = new ResizeObserver((
|
|
6899
|
-
for (const
|
|
6912
|
+
if (!D.current || !p.current) return;
|
|
6913
|
+
const w = new ResizeObserver((K) => {
|
|
6914
|
+
for (const ne of K)
|
|
6900
6915
|
p.current && p.current.onResize && p.current.onResize();
|
|
6901
6916
|
});
|
|
6902
|
-
w.observe(
|
|
6917
|
+
w.observe(D.current);
|
|
6903
6918
|
const U = () => {
|
|
6904
6919
|
p.current && p.current.onResize && p.current.onResize();
|
|
6905
6920
|
};
|
|
@@ -6914,26 +6929,26 @@ const Ve = Me(({
|
|
|
6914
6929
|
} catch (w) {
|
|
6915
6930
|
console.warn("Failed to resume audio context:", w);
|
|
6916
6931
|
}
|
|
6917
|
-
}, []),
|
|
6932
|
+
}, []), N = O(async (w, U = {}) => {
|
|
6918
6933
|
if (p.current && oe)
|
|
6919
6934
|
try {
|
|
6920
|
-
R.current && (clearInterval(R.current), R.current = null),
|
|
6921
|
-
const
|
|
6922
|
-
z.current =
|
|
6935
|
+
R.current && (clearInterval(R.current), R.current = null), T.current = { text: w, options: U }, I.current = { remainingText: null, originalText: null, options: null };
|
|
6936
|
+
const K = /[!\.\?\n\p{Extended_Pictographic}]/ug, ne = w.split(K).map((A) => A.trim()).filter((A) => A.length > 0);
|
|
6937
|
+
z.current = ne, Y.current = 0, de(!1), L.current = !1, await P();
|
|
6923
6938
|
const me = {
|
|
6924
6939
|
...U,
|
|
6925
6940
|
lipsyncLang: U.lipsyncLang || b.lipsyncLang || "en"
|
|
6926
6941
|
};
|
|
6927
6942
|
if (U.onSpeechEnd && p.current) {
|
|
6928
6943
|
const A = p.current;
|
|
6929
|
-
let
|
|
6930
|
-
const
|
|
6944
|
+
let H = null, G = 0;
|
|
6945
|
+
const J = 1200;
|
|
6931
6946
|
let ie = !1;
|
|
6932
|
-
|
|
6933
|
-
if (
|
|
6947
|
+
H = setInterval(() => {
|
|
6948
|
+
if (G++, L.current)
|
|
6934
6949
|
return;
|
|
6935
|
-
if (
|
|
6936
|
-
if (
|
|
6950
|
+
if (G > J) {
|
|
6951
|
+
if (H && (clearInterval(H), H = null, R.current = null), !ie && !L.current) {
|
|
6937
6952
|
ie = !0;
|
|
6938
6953
|
try {
|
|
6939
6954
|
U.onSpeechEnd();
|
|
@@ -6946,7 +6961,7 @@ const Ve = Me(({
|
|
|
6946
6961
|
const se = !A.speechQueue || A.speechQueue.length === 0, we = !A.audioPlaylist || A.audioPlaylist.length === 0;
|
|
6947
6962
|
A && A.isSpeaking === !1 && se && we && A.isAudioPlaying === !1 && !ie && !L.current && setTimeout(() => {
|
|
6948
6963
|
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,
|
|
6964
|
+
ie = !0, H && (clearInterval(H), H = null, R.current = null);
|
|
6950
6965
|
try {
|
|
6951
6966
|
U.onSpeechEnd();
|
|
6952
6967
|
} catch (Ze) {
|
|
@@ -6954,59 +6969,59 @@ const Ve = Me(({
|
|
|
6954
6969
|
}
|
|
6955
6970
|
}
|
|
6956
6971
|
}, 100);
|
|
6957
|
-
}, 100), R.current =
|
|
6972
|
+
}, 100), R.current = H;
|
|
6958
6973
|
}
|
|
6959
6974
|
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
6975
|
await P(), p.current && p.current.lipsync && (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(w, me));
|
|
6961
6976
|
}, 100);
|
|
6962
|
-
} catch (
|
|
6963
|
-
console.error("Error speaking text:",
|
|
6977
|
+
} catch (K) {
|
|
6978
|
+
console.error("Error speaking text:", K), X(K.message || "Failed to speak text");
|
|
6964
6979
|
}
|
|
6965
|
-
}, [oe, P, b.lipsyncLang]),
|
|
6966
|
-
p.current && (p.current.stopSpeaking(), p.current.setSlowdownRate && p.current.setSlowdownRate(1),
|
|
6967
|
-
}, []),
|
|
6980
|
+
}, [oe, P, b.lipsyncLang]), te = O(() => {
|
|
6981
|
+
p.current && (p.current.stopSpeaking(), p.current.setSlowdownRate && p.current.setSlowdownRate(1), T.current = null, de(!1));
|
|
6982
|
+
}, []), q = O(() => {
|
|
6968
6983
|
if (p.current && p.current.pauseSpeaking) {
|
|
6969
6984
|
const w = p.current;
|
|
6970
6985
|
if (w.isSpeaking || w.audioPlaylist && w.audioPlaylist.length > 0 || w.speechQueue && w.speechQueue.length > 0) {
|
|
6971
6986
|
R.current && (clearInterval(R.current), R.current = null);
|
|
6972
|
-
let
|
|
6973
|
-
if (
|
|
6974
|
-
const
|
|
6975
|
-
if (
|
|
6987
|
+
let K = "";
|
|
6988
|
+
if (T.current && z.current.length > 0) {
|
|
6989
|
+
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;
|
|
6990
|
+
if (H > 0 && G < ne && (K = z.current.slice(G).join(". ").trim(), !K && me > 0 && w.speechQueue)) {
|
|
6976
6991
|
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() && (
|
|
6992
|
+
ie && ie.trim() && (K = ie.trim());
|
|
6978
6993
|
}
|
|
6979
6994
|
}
|
|
6980
|
-
|
|
6981
|
-
remainingText:
|
|
6982
|
-
originalText:
|
|
6983
|
-
options:
|
|
6995
|
+
T.current && (I.current = {
|
|
6996
|
+
remainingText: K || null,
|
|
6997
|
+
originalText: T.current.text,
|
|
6998
|
+
options: T.current.options
|
|
6984
6999
|
}), w.speechQueue && (w.speechQueue.length = 0), p.current.pauseSpeaking(), L.current = !0, de(!0);
|
|
6985
7000
|
}
|
|
6986
7001
|
}
|
|
6987
|
-
}, []),
|
|
7002
|
+
}, []), _ = O(async () => {
|
|
6988
7003
|
if (!p.current || !ge)
|
|
6989
7004
|
return;
|
|
6990
7005
|
let w = "", U = {};
|
|
6991
7006
|
if (I.current && I.current.remainingText)
|
|
6992
7007
|
w = I.current.remainingText, U = I.current.options || {}, I.current = { remainingText: null, originalText: null, options: null };
|
|
6993
|
-
else if (
|
|
6994
|
-
w =
|
|
7008
|
+
else if (T.current && T.current.text)
|
|
7009
|
+
w = T.current.text, U = T.current.options || {};
|
|
6995
7010
|
else {
|
|
6996
7011
|
console.warn("Resume called but no paused speech found"), de(!1), L.current = !1;
|
|
6997
7012
|
return;
|
|
6998
7013
|
}
|
|
6999
7014
|
de(!1), L.current = !1, await P();
|
|
7000
|
-
const
|
|
7015
|
+
const K = {
|
|
7001
7016
|
...U,
|
|
7002
7017
|
lipsyncLang: U.lipsyncLang || b.lipsyncLang || "en"
|
|
7003
7018
|
};
|
|
7004
7019
|
try {
|
|
7005
|
-
await
|
|
7006
|
-
} catch (
|
|
7007
|
-
console.error("Error resuming speech:",
|
|
7020
|
+
await N(w, K);
|
|
7021
|
+
} catch (ne) {
|
|
7022
|
+
console.error("Error resuming speech:", ne), de(!1), L.current = !1;
|
|
7008
7023
|
}
|
|
7009
|
-
}, [P, ge,
|
|
7024
|
+
}, [P, ge, N, b]), Ae = O((w) => {
|
|
7010
7025
|
p.current && p.current.setMood(w);
|
|
7011
7026
|
}, []), Se = O((w) => {
|
|
7012
7027
|
p.current && p.current.setSlowdownRate && p.current.setSlowdownRate(w);
|
|
@@ -7015,14 +7030,14 @@ const Ve = Me(({
|
|
|
7015
7030
|
if (f && f[w] && (w = f[w]), p.current.setShowFullAvatar)
|
|
7016
7031
|
try {
|
|
7017
7032
|
p.current.setShowFullAvatar(B.current);
|
|
7018
|
-
} catch (
|
|
7019
|
-
console.warn("Error setting full body mode:",
|
|
7033
|
+
} catch (ne) {
|
|
7034
|
+
console.warn("Error setting full body mode:", ne);
|
|
7020
7035
|
}
|
|
7021
7036
|
if (w.includes("."))
|
|
7022
7037
|
try {
|
|
7023
7038
|
p.current.playAnimation(w, null, 10, 0, 0.01, U);
|
|
7024
|
-
} catch (
|
|
7025
|
-
console.warn(`Failed to play ${w}:`,
|
|
7039
|
+
} catch (ne) {
|
|
7040
|
+
console.warn(`Failed to play ${w}:`, ne);
|
|
7026
7041
|
try {
|
|
7027
7042
|
p.current.setBodyMovement("idle");
|
|
7028
7043
|
} catch (me) {
|
|
@@ -7030,9 +7045,9 @@ const Ve = Me(({
|
|
|
7030
7045
|
}
|
|
7031
7046
|
}
|
|
7032
7047
|
else {
|
|
7033
|
-
const
|
|
7048
|
+
const ne = [".fbx", ".glb", ".gltf"];
|
|
7034
7049
|
let me = !1;
|
|
7035
|
-
for (const A of
|
|
7050
|
+
for (const A of ne)
|
|
7036
7051
|
try {
|
|
7037
7052
|
p.current.playAnimation(w + A, null, 10, 0, 0.01, U), me = !0;
|
|
7038
7053
|
break;
|
|
@@ -7052,10 +7067,10 @@ const Ve = Me(({
|
|
|
7052
7067
|
p.current && p.current.onResize && p.current.onResize();
|
|
7053
7068
|
}, []);
|
|
7054
7069
|
return Fe(k, () => ({
|
|
7055
|
-
speakText:
|
|
7056
|
-
stopSpeaking:
|
|
7057
|
-
pauseSpeaking:
|
|
7058
|
-
resumeSpeaking:
|
|
7070
|
+
speakText: N,
|
|
7071
|
+
stopSpeaking: te,
|
|
7072
|
+
pauseSpeaking: q,
|
|
7073
|
+
resumeSpeaking: _,
|
|
7059
7074
|
resumeAudioContext: P,
|
|
7060
7075
|
setMood: Ae,
|
|
7061
7076
|
setTimingAdjustment: Se,
|
|
@@ -7135,7 +7150,7 @@ const Ve = Me(({
|
|
|
7135
7150
|
/* @__PURE__ */ ye(
|
|
7136
7151
|
"div",
|
|
7137
7152
|
{
|
|
7138
|
-
ref:
|
|
7153
|
+
ref: D,
|
|
7139
7154
|
className: "talking-head-viewer",
|
|
7140
7155
|
style: {
|
|
7141
7156
|
width: "100%",
|
|
@@ -7153,7 +7168,7 @@ const Ve = Me(({
|
|
|
7153
7168
|
fontSize: "18px",
|
|
7154
7169
|
zIndex: 10
|
|
7155
7170
|
}, children: "Loading avatar..." }),
|
|
7156
|
-
|
|
7171
|
+
j && /* @__PURE__ */ ye("div", { className: "error-overlay", style: {
|
|
7157
7172
|
position: "absolute",
|
|
7158
7173
|
top: "50%",
|
|
7159
7174
|
left: "50%",
|
|
@@ -7164,7 +7179,7 @@ const Ve = Me(({
|
|
|
7164
7179
|
zIndex: 10,
|
|
7165
7180
|
padding: "20px",
|
|
7166
7181
|
borderRadius: "8px"
|
|
7167
|
-
}, children:
|
|
7182
|
+
}, children: j })
|
|
7168
7183
|
]
|
|
7169
7184
|
}
|
|
7170
7185
|
);
|
|
@@ -7182,7 +7197,7 @@ const pt = Me(({
|
|
|
7182
7197
|
style: s = {},
|
|
7183
7198
|
avatarConfig: o = {}
|
|
7184
7199
|
}, 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,
|
|
7200
|
+
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
7201
|
endpoint: "",
|
|
7187
7202
|
apiKey: null,
|
|
7188
7203
|
defaultVoice: "Google US English"
|
|
@@ -7198,7 +7213,7 @@ const pt = Me(({
|
|
|
7198
7213
|
body: "F",
|
|
7199
7214
|
avatarMood: "neutral",
|
|
7200
7215
|
ttsLang: k === "browser" ? "en-US" : "en",
|
|
7201
|
-
ttsVoice: o.ttsVoice ||
|
|
7216
|
+
ttsVoice: o.ttsVoice || D.defaultVoice,
|
|
7202
7217
|
lipsyncLang: "en",
|
|
7203
7218
|
// English lip-sync
|
|
7204
7219
|
showFullAvatar: !0,
|
|
@@ -7207,35 +7222,35 @@ const pt = Me(({
|
|
|
7207
7222
|
movementIntensity: 0.5,
|
|
7208
7223
|
...o
|
|
7209
7224
|
}, B = {
|
|
7210
|
-
ttsEndpoint:
|
|
7211
|
-
ttsApikey:
|
|
7225
|
+
ttsEndpoint: D.endpoint,
|
|
7226
|
+
ttsApikey: D.apiKey,
|
|
7212
7227
|
ttsService: k,
|
|
7213
7228
|
lipsyncModules: ["en"],
|
|
7214
7229
|
cameraView: "upper"
|
|
7215
|
-
},
|
|
7230
|
+
}, T = O(async () => {
|
|
7216
7231
|
if (!(!h.current || r.current))
|
|
7217
7232
|
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(
|
|
7233
|
+
if (a(!0), c(null), r.current = new Be(h.current, B), await r.current.showAvatar(p, (j) => {
|
|
7234
|
+
if (j.lengthComputable) {
|
|
7235
|
+
const X = Math.min(100, Math.round(j.loaded / j.total * 100));
|
|
7236
|
+
t(X);
|
|
7222
7237
|
}
|
|
7223
7238
|
}), 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:",
|
|
7239
|
+
const j = r.current.morphs[0].morphTargetDictionary;
|
|
7240
|
+
console.log("Available morph targets:", Object.keys(j));
|
|
7241
|
+
const X = Object.keys(j).filter((oe) => oe.startsWith("viseme_"));
|
|
7242
|
+
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
7243
|
}
|
|
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)),
|
|
7244
|
+
if (await new Promise((j) => {
|
|
7245
|
+
const X = () => {
|
|
7246
|
+
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
7247
|
};
|
|
7233
|
-
|
|
7248
|
+
X();
|
|
7234
7249
|
}), r.current && r.current.setShowFullAvatar)
|
|
7235
7250
|
try {
|
|
7236
7251
|
r.current.setShowFullAvatar(!0), console.log("Avatar initialized in full body mode");
|
|
7237
|
-
} catch (
|
|
7238
|
-
console.warn("Error setting full body mode on initialization:",
|
|
7252
|
+
} catch (j) {
|
|
7253
|
+
console.warn("Error setting full body mode on initialization:", j);
|
|
7239
7254
|
}
|
|
7240
7255
|
a(!1), x(!0), n(r.current);
|
|
7241
7256
|
const E = () => {
|
|
@@ -7248,9 +7263,9 @@ const pt = Me(({
|
|
|
7248
7263
|
console.error("Error initializing TalkingHead:", S), c(S.message || "Failed to initialize avatar"), a(!1), e(S);
|
|
7249
7264
|
}
|
|
7250
7265
|
}, []);
|
|
7251
|
-
ce(() => (
|
|
7266
|
+
ce(() => (T(), () => {
|
|
7252
7267
|
r.current && (r.current.stop(), r.current.dispose(), r.current = null);
|
|
7253
|
-
}), [
|
|
7268
|
+
}), [T]);
|
|
7254
7269
|
const R = O((S) => {
|
|
7255
7270
|
if (r.current && g)
|
|
7256
7271
|
try {
|
|
@@ -7273,14 +7288,14 @@ const pt = Me(({
|
|
|
7273
7288
|
if (r.current.setShowFullAvatar)
|
|
7274
7289
|
try {
|
|
7275
7290
|
r.current.setShowFullAvatar(!0);
|
|
7276
|
-
} catch (
|
|
7277
|
-
console.warn("Error setting full body mode:",
|
|
7291
|
+
} catch (X) {
|
|
7292
|
+
console.warn("Error setting full body mode:", X);
|
|
7278
7293
|
}
|
|
7279
7294
|
if (S.includes("."))
|
|
7280
7295
|
try {
|
|
7281
7296
|
r.current.playAnimation(S, null, 10, 0, 0.01, E), console.log("Playing animation:", S);
|
|
7282
|
-
} catch (
|
|
7283
|
-
console.log(`Failed to play ${S}:`,
|
|
7297
|
+
} catch (X) {
|
|
7298
|
+
console.log(`Failed to play ${S}:`, X);
|
|
7284
7299
|
try {
|
|
7285
7300
|
r.current.setBodyMovement("idle"), console.log("Fallback to idle animation");
|
|
7286
7301
|
} catch (oe) {
|
|
@@ -7288,9 +7303,9 @@ const pt = Me(({
|
|
|
7288
7303
|
}
|
|
7289
7304
|
}
|
|
7290
7305
|
else {
|
|
7291
|
-
const
|
|
7306
|
+
const X = [".fbx", ".glb", ".gltf"];
|
|
7292
7307
|
let oe = !1;
|
|
7293
|
-
for (const le of
|
|
7308
|
+
for (const le of X)
|
|
7294
7309
|
try {
|
|
7295
7310
|
r.current.playAnimation(S + le, null, 10, 0, 0.01, E), console.log("Playing animation:", S + le), oe = !0;
|
|
7296
7311
|
break;
|
|
@@ -7413,9 +7428,20 @@ const pt = Me(({
|
|
|
7413
7428
|
pt.displayName = "TalkingHeadComponent";
|
|
7414
7429
|
async function gt(V) {
|
|
7415
7430
|
try {
|
|
7416
|
-
|
|
7431
|
+
console.log(`📥 Loading animation manifest from: ${V}`);
|
|
7432
|
+
const t = await fetch(V);
|
|
7433
|
+
if (!t.ok)
|
|
7434
|
+
throw new Error(`Failed to fetch manifest: ${t.status} ${t.statusText}`);
|
|
7435
|
+
const e = await t.json();
|
|
7436
|
+
console.log("📦 Raw manifest loaded:", e);
|
|
7437
|
+
const n = e.animations || {};
|
|
7438
|
+
return console.log("✅ Processed animations object:", n), n._genderSpecific && console.log("👥 Gender-specific structure detected:", {
|
|
7439
|
+
male: Object.keys(n._genderSpecific.male || {}),
|
|
7440
|
+
female: Object.keys(n._genderSpecific.female || {}),
|
|
7441
|
+
shared: Object.keys(n._genderSpecific.shared || {})
|
|
7442
|
+
}), n;
|
|
7417
7443
|
} catch (t) {
|
|
7418
|
-
return console.error("Failed to load animation manifest:", t), {};
|
|
7444
|
+
return console.error("❌ Failed to load animation manifest:", t), {};
|
|
7419
7445
|
}
|
|
7420
7446
|
}
|
|
7421
7447
|
const yt = Me(({
|
|
@@ -7441,84 +7467,86 @@ const yt = Me(({
|
|
|
7441
7467
|
},
|
|
7442
7468
|
className: f = "",
|
|
7443
7469
|
style: k = {},
|
|
7444
|
-
animations:
|
|
7470
|
+
animations: D = {},
|
|
7445
7471
|
autoAnimationGroup: p = null,
|
|
7446
7472
|
// e.g., "talking" - will randomly select from this group when speaking
|
|
7447
7473
|
autoIdleGroup: B = null,
|
|
7448
7474
|
// e.g., "idle" - will randomly select from this group when idle
|
|
7449
|
-
autoSpeak:
|
|
7475
|
+
autoSpeak: T = !1
|
|
7450
7476
|
}, R) => {
|
|
7451
|
-
const L = W(null), I = W(null), z = W(u), Y = W(null), S = W(null), E = W(!1),
|
|
7477
|
+
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
7478
|
ce(() => {
|
|
7453
|
-
E.current =
|
|
7454
|
-
}, [
|
|
7479
|
+
E.current = Q;
|
|
7480
|
+
}, [Q]), ce(() => {
|
|
7455
7481
|
(async () => {
|
|
7456
|
-
if (
|
|
7482
|
+
if (D.manifest)
|
|
7457
7483
|
try {
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
console.
|
|
7484
|
+
console.log("🔄 Loading animations from manifest:", D.manifest);
|
|
7485
|
+
const H = await gt(D.manifest);
|
|
7486
|
+
F(H), console.log("✅ Animations loaded and set:", H), H._genderSpecific ? console.log("👥 Gender-specific animations detected:", {
|
|
7487
|
+
male: Object.keys(H._genderSpecific.male || {}),
|
|
7488
|
+
female: Object.keys(H._genderSpecific.female || {}),
|
|
7489
|
+
shared: Object.keys(H._genderSpecific.shared || {})
|
|
7490
|
+
}) : console.log("⚠️ No gender-specific animations found in manifest");
|
|
7491
|
+
} catch (H) {
|
|
7492
|
+
console.error("❌ Failed to load animation manifest:", H), F(D);
|
|
7465
7493
|
}
|
|
7466
7494
|
else
|
|
7467
|
-
F(
|
|
7495
|
+
console.log("📝 Using animations from props (no manifest):", D), F(D);
|
|
7468
7496
|
})();
|
|
7469
|
-
}, [
|
|
7497
|
+
}, [D]), ce(() => {
|
|
7470
7498
|
z.current = u;
|
|
7471
7499
|
}, [u]);
|
|
7472
|
-
const
|
|
7473
|
-
let
|
|
7474
|
-
|
|
7500
|
+
const N = Ee(), te = s || N.service;
|
|
7501
|
+
let q;
|
|
7502
|
+
te === "browser" ? q = {
|
|
7475
7503
|
service: "browser",
|
|
7476
7504
|
endpoint: "",
|
|
7477
7505
|
apiKey: null,
|
|
7478
7506
|
defaultVoice: "Google US English"
|
|
7479
|
-
} :
|
|
7507
|
+
} : te === "elevenlabs" ? q = {
|
|
7480
7508
|
service: "elevenlabs",
|
|
7481
7509
|
endpoint: "https://api.elevenlabs.io/v1/text-to-speech",
|
|
7482
|
-
apiKey: l ||
|
|
7483
|
-
defaultVoice: o ||
|
|
7484
|
-
voices:
|
|
7485
|
-
} :
|
|
7510
|
+
apiKey: l || N.apiKey,
|
|
7511
|
+
defaultVoice: o || N.defaultVoice || Ie.defaultVoice,
|
|
7512
|
+
voices: N.voices || Ie.voices
|
|
7513
|
+
} : te === "deepgram" ? q = {
|
|
7486
7514
|
service: "deepgram",
|
|
7487
7515
|
endpoint: "https://api.deepgram.com/v1/speak",
|
|
7488
|
-
apiKey: l ||
|
|
7489
|
-
defaultVoice: o ||
|
|
7490
|
-
voices:
|
|
7491
|
-
} :
|
|
7492
|
-
...
|
|
7493
|
-
apiKey: l !== null ? l :
|
|
7516
|
+
apiKey: l || N.apiKey,
|
|
7517
|
+
defaultVoice: o || N.defaultVoice || Te.defaultVoice,
|
|
7518
|
+
voices: N.voices || Te.voices
|
|
7519
|
+
} : q = {
|
|
7520
|
+
...N,
|
|
7521
|
+
apiKey: l !== null ? l : N.apiKey
|
|
7494
7522
|
};
|
|
7495
|
-
const
|
|
7523
|
+
const _ = {
|
|
7496
7524
|
url: t,
|
|
7497
7525
|
body: e,
|
|
7498
7526
|
avatarMood: n,
|
|
7499
|
-
ttsLang:
|
|
7500
|
-
ttsVoice: o ||
|
|
7527
|
+
ttsLang: te === "browser" ? "en-US" : i,
|
|
7528
|
+
ttsVoice: o || q.defaultVoice,
|
|
7501
7529
|
lipsyncLang: "en",
|
|
7502
7530
|
showFullAvatar: u,
|
|
7503
7531
|
bodyMovement: h,
|
|
7504
7532
|
movementIntensity: r
|
|
7505
7533
|
}, Ae = {
|
|
7506
|
-
ttsEndpoint:
|
|
7507
|
-
ttsApikey:
|
|
7508
|
-
ttsService:
|
|
7534
|
+
ttsEndpoint: q.endpoint,
|
|
7535
|
+
ttsApikey: q.apiKey,
|
|
7536
|
+
ttsService: te,
|
|
7509
7537
|
lipsyncModules: ["en"],
|
|
7510
7538
|
cameraView: a
|
|
7511
7539
|
}, Se = O(async () => {
|
|
7512
7540
|
if (!(!L.current || I.current))
|
|
7513
7541
|
try {
|
|
7514
7542
|
le(!0), de(null), I.current = new Be(L.current, Ae), console.log("Avatar config being passed:", {
|
|
7515
|
-
url:
|
|
7516
|
-
body:
|
|
7517
|
-
avatarMood:
|
|
7518
|
-
}), await I.current.showAvatar(
|
|
7519
|
-
if (
|
|
7520
|
-
const
|
|
7521
|
-
c(
|
|
7543
|
+
url: _.url,
|
|
7544
|
+
body: _.body,
|
|
7545
|
+
avatarMood: _.avatarMood
|
|
7546
|
+
}), await I.current.showAvatar(_, (H) => {
|
|
7547
|
+
if (H.lengthComputable) {
|
|
7548
|
+
const G = Math.min(100, Math.round(H.loaded / H.total * 100));
|
|
7549
|
+
c(G);
|
|
7522
7550
|
}
|
|
7523
7551
|
}), I.current?.avatar && console.log("Avatar body after initialization:", I.current.avatar.body), le(!1), be(!0), d(I.current);
|
|
7524
7552
|
const A = () => {
|
|
@@ -7543,29 +7571,40 @@ const yt = Me(({
|
|
|
7543
7571
|
console.warn("Failed to resume audio context:", A);
|
|
7544
7572
|
}
|
|
7545
7573
|
}, []), ke = O((A) => {
|
|
7546
|
-
if (!v
|
|
7547
|
-
return null;
|
|
7548
|
-
let
|
|
7574
|
+
if (!v)
|
|
7575
|
+
return console.warn("No animations loaded"), null;
|
|
7576
|
+
let H = null;
|
|
7549
7577
|
if (v._genderSpecific) {
|
|
7550
|
-
const
|
|
7551
|
-
ie && ie[A] ? (
|
|
7578
|
+
const J = (e?.toUpperCase() || "F") === "M" ? "male" : "female", ie = v._genderSpecific[J];
|
|
7579
|
+
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));
|
|
7580
|
+
}
|
|
7581
|
+
if (!H && v[A] && (H = v[A], console.log(`Using root-level animations for "${A}":`, H)), !H) {
|
|
7582
|
+
if (console.warn(`Animation group "${A}" not found. Available groups:`, Object.keys(v).filter((G) => G !== "_genderSpecific")), v._genderSpecific) {
|
|
7583
|
+
const J = (e?.toUpperCase() || "F") === "M" ? "male" : "female";
|
|
7584
|
+
console.warn(`Gender-specific groups (${J}):`, Object.keys(v._genderSpecific[J] || {}));
|
|
7585
|
+
}
|
|
7586
|
+
return null;
|
|
7552
7587
|
}
|
|
7553
|
-
if (Array.isArray(
|
|
7554
|
-
const
|
|
7555
|
-
return
|
|
7588
|
+
if (Array.isArray(H) && H.length > 0) {
|
|
7589
|
+
const G = Math.floor(Math.random() * H.length);
|
|
7590
|
+
return H[G];
|
|
7556
7591
|
}
|
|
7557
|
-
return typeof
|
|
7558
|
-
}, [v, e]), w = O((A,
|
|
7559
|
-
|
|
7560
|
-
|
|
7592
|
+
return typeof H == "string" ? H : (console.warn(`Animation group "${A}" is not a valid format (expected array or string):`, H), null);
|
|
7593
|
+
}, [v, e]), w = O((A, H = !1) => {
|
|
7594
|
+
if (!I.current)
|
|
7595
|
+
return console.warn("TalkingHead not initialized yet"), null;
|
|
7596
|
+
const G = ke(A);
|
|
7597
|
+
if (G)
|
|
7561
7598
|
try {
|
|
7562
|
-
return I.current.playAnimation(
|
|
7563
|
-
} catch (
|
|
7564
|
-
return console.
|
|
7599
|
+
return I.current.playAnimation(G, null, 10, 0, 0.01, H), console.log(`✅ Playing random animation from "${A}" group:`, G), G;
|
|
7600
|
+
} catch (J) {
|
|
7601
|
+
return console.error(`❌ Failed to play random animation from "${A}" group:`, J), null;
|
|
7565
7602
|
}
|
|
7603
|
+
else
|
|
7604
|
+
console.warn(`⚠️ No animation found for group "${A}"`);
|
|
7566
7605
|
return null;
|
|
7567
|
-
}, [ke]), U = O(async (A,
|
|
7568
|
-
if (!I.current ||
|
|
7606
|
+
}, [ke]), U = O(async (A, H = {}) => {
|
|
7607
|
+
if (!I.current || !ee) {
|
|
7569
7608
|
console.warn("Avatar not ready for speaking");
|
|
7570
7609
|
return;
|
|
7571
7610
|
}
|
|
@@ -7574,14 +7613,14 @@ const yt = Me(({
|
|
|
7574
7613
|
return;
|
|
7575
7614
|
}
|
|
7576
7615
|
await Le();
|
|
7577
|
-
const
|
|
7578
|
-
|
|
7579
|
-
const
|
|
7580
|
-
|
|
7616
|
+
const G = H.animationGroup || p;
|
|
7617
|
+
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;
|
|
7618
|
+
const J = A.split(/[.!?]+/).filter((se) => se.trim().length > 0);
|
|
7619
|
+
X.current = J;
|
|
7581
7620
|
const ie = {
|
|
7582
|
-
lipsyncLang:
|
|
7621
|
+
lipsyncLang: H.lipsyncLang || "en",
|
|
7583
7622
|
onSpeechEnd: () => {
|
|
7584
|
-
S.current && (clearInterval(S.current), S.current = null),
|
|
7623
|
+
S.current && (clearInterval(S.current), S.current = null), H.onSpeechEnd && H.onSpeechEnd(), x();
|
|
7585
7624
|
}
|
|
7586
7625
|
};
|
|
7587
7626
|
try {
|
|
@@ -7589,9 +7628,9 @@ const yt = Me(({
|
|
|
7589
7628
|
} catch (se) {
|
|
7590
7629
|
console.error("Error speaking text:", se), de(se.message || "Failed to speak text");
|
|
7591
7630
|
}
|
|
7592
|
-
}, [
|
|
7631
|
+
}, [ee, x, Le, p, w]);
|
|
7593
7632
|
ce(() => {
|
|
7594
|
-
if (
|
|
7633
|
+
if (!ee || !B || !I.current)
|
|
7595
7634
|
return;
|
|
7596
7635
|
P.current && clearInterval(P.current);
|
|
7597
7636
|
const A = () => {
|
|
@@ -7602,18 +7641,18 @@ const yt = Me(({
|
|
|
7602
7641
|
}, 12e3 + Math.random() * 3e3), () => {
|
|
7603
7642
|
P.current && (clearInterval(P.current), P.current = null);
|
|
7604
7643
|
};
|
|
7605
|
-
}, [
|
|
7606
|
-
|
|
7607
|
-
}, [
|
|
7608
|
-
const
|
|
7644
|
+
}, [ee, B, w]), ce(() => {
|
|
7645
|
+
ee && V && T && I.current && U(V);
|
|
7646
|
+
}, [ee, V, T, U]);
|
|
7647
|
+
const K = O(() => {
|
|
7609
7648
|
if (I.current)
|
|
7610
7649
|
try {
|
|
7611
|
-
const A = I.current.isSpeaking || !1,
|
|
7612
|
-
if (A ||
|
|
7650
|
+
const A = I.current.isSpeaking || !1, H = I.current.audioPlaylist || [], G = I.current.speechQueue || [];
|
|
7651
|
+
if (A || H.length > 0 || G.length > 0) {
|
|
7613
7652
|
S.current && (clearInterval(S.current), S.current = null);
|
|
7614
|
-
let
|
|
7615
|
-
|
|
7616
|
-
remainingText:
|
|
7653
|
+
let J = "";
|
|
7654
|
+
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 = {
|
|
7655
|
+
remainingText: J || null,
|
|
7617
7656
|
originalText: Y.current?.text || null,
|
|
7618
7657
|
options: Y.current?.options || null
|
|
7619
7658
|
}, I.current.speechQueue.length = 0, I.current.pauseSpeaking(), b(!0), E.current = !0;
|
|
@@ -7621,40 +7660,40 @@ const yt = Me(({
|
|
|
7621
7660
|
} catch (A) {
|
|
7622
7661
|
console.warn("Error pausing speech:", A);
|
|
7623
7662
|
}
|
|
7624
|
-
}, []),
|
|
7625
|
-
if (!(!I.current || !
|
|
7663
|
+
}, []), ne = O(async () => {
|
|
7664
|
+
if (!(!I.current || !Q))
|
|
7626
7665
|
try {
|
|
7627
7666
|
await Le(), b(!1), E.current = !1;
|
|
7628
|
-
const A =
|
|
7629
|
-
|
|
7667
|
+
const A = j.current?.remainingText, H = j.current?.originalText || Y.current?.text, G = j.current?.options || Y.current?.options || {}, J = A || H;
|
|
7668
|
+
J && U(J, G);
|
|
7630
7669
|
} catch (A) {
|
|
7631
7670
|
console.warn("Error resuming speech:", A), b(!1), E.current = !1;
|
|
7632
7671
|
}
|
|
7633
|
-
}, [
|
|
7672
|
+
}, [Q, U, Le]), me = O(() => {
|
|
7634
7673
|
I.current && (I.current.stopSpeaking(), S.current && (clearInterval(S.current), S.current = null), b(!1), E.current = !1);
|
|
7635
7674
|
}, []);
|
|
7636
7675
|
return Fe(R, () => ({
|
|
7637
7676
|
speakText: U,
|
|
7638
|
-
pauseSpeaking:
|
|
7639
|
-
resumeSpeaking:
|
|
7677
|
+
pauseSpeaking: K,
|
|
7678
|
+
resumeSpeaking: ne,
|
|
7640
7679
|
stopSpeaking: me,
|
|
7641
7680
|
resumeAudioContext: Le,
|
|
7642
|
-
isPaused: () =>
|
|
7681
|
+
isPaused: () => Q,
|
|
7643
7682
|
setMood: (A) => I.current?.setMood(A),
|
|
7644
7683
|
setBodyMovement: (A) => {
|
|
7645
7684
|
I.current && I.current.setBodyMovement(A);
|
|
7646
7685
|
},
|
|
7647
|
-
playAnimation: (A,
|
|
7648
|
-
I.current && I.current.playAnimation && I.current.playAnimation(A, null, 10, 0, 0.01,
|
|
7686
|
+
playAnimation: (A, H = !1) => {
|
|
7687
|
+
I.current && I.current.playAnimation && I.current.playAnimation(A, null, 10, 0, 0.01, H);
|
|
7649
7688
|
},
|
|
7650
|
-
playRandomAnimation: (A,
|
|
7689
|
+
playRandomAnimation: (A, H = !1) => w(A, H),
|
|
7651
7690
|
getRandomAnimation: (A) => ke(A),
|
|
7652
7691
|
playReaction: (A) => I.current?.playReaction(A),
|
|
7653
7692
|
playCelebration: () => I.current?.playCelebration(),
|
|
7654
7693
|
setShowFullAvatar: (A) => {
|
|
7655
7694
|
I.current && (z.current = A, I.current.setShowFullAvatar(A));
|
|
7656
7695
|
},
|
|
7657
|
-
isReady:
|
|
7696
|
+
isReady: ee,
|
|
7658
7697
|
talkingHead: I.current
|
|
7659
7698
|
})), /* @__PURE__ */ Pe("div", { className: `simple-talking-avatar-container ${f}`, style: k, children: [
|
|
7660
7699
|
/* @__PURE__ */ ye(
|
|
@@ -7725,12 +7764,12 @@ const ft = Me(({
|
|
|
7725
7764
|
onQuestionAnswer: s,
|
|
7726
7765
|
onCurriculumComplete: o,
|
|
7727
7766
|
onCustomAction: l
|
|
7728
|
-
}), c = W(null), g = W(null), x = W(null), f = W(null), k = W(null),
|
|
7767
|
+
}), 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 || {
|
|
7729
7768
|
title: "Default Curriculum",
|
|
7730
7769
|
description: "No curriculum data provided",
|
|
7731
7770
|
language: "en",
|
|
7732
7771
|
modules: []
|
|
7733
|
-
}),
|
|
7772
|
+
}), T = W({
|
|
7734
7773
|
avatarUrl: t.avatarUrl || "/avatars/brunette.glb",
|
|
7735
7774
|
avatarBody: t.avatarBody || "F",
|
|
7736
7775
|
mood: t.mood || "happy",
|
|
@@ -7758,7 +7797,7 @@ const ft = Me(({
|
|
|
7758
7797
|
description: "No curriculum data provided",
|
|
7759
7798
|
language: "en",
|
|
7760
7799
|
modules: []
|
|
7761
|
-
},
|
|
7800
|
+
}, T.current = {
|
|
7762
7801
|
avatarUrl: t.avatarUrl || "/avatars/brunette.glb",
|
|
7763
7802
|
avatarBody: t.avatarBody || "F",
|
|
7764
7803
|
mood: t.mood || "happy",
|
|
@@ -7797,9 +7836,9 @@ const ft = Me(({
|
|
|
7797
7836
|
} catch {
|
|
7798
7837
|
u.current.playCelebration();
|
|
7799
7838
|
}
|
|
7800
|
-
const F = B.current || { modules: [] }, P = F.modules[a.current.currentModuleIndex],
|
|
7839
|
+
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" };
|
|
7801
7840
|
u.current.speakText(v, {
|
|
7802
|
-
lipsyncLang:
|
|
7841
|
+
lipsyncLang: _.lipsyncLang,
|
|
7803
7842
|
onSpeechEnd: () => {
|
|
7804
7843
|
d.current.onCustomAction({
|
|
7805
7844
|
type: "lessonCompleteFeedbackDone",
|
|
@@ -7808,7 +7847,7 @@ const ft = Me(({
|
|
|
7808
7847
|
score: a.current.score,
|
|
7809
7848
|
totalQuestions: a.current.totalQuestions,
|
|
7810
7849
|
percentage: b,
|
|
7811
|
-
hasNextLesson:
|
|
7850
|
+
hasNextLesson: q
|
|
7812
7851
|
});
|
|
7813
7852
|
}
|
|
7814
7853
|
});
|
|
@@ -7826,7 +7865,7 @@ const ft = Me(({
|
|
|
7826
7865
|
} catch {
|
|
7827
7866
|
u.current.playCelebration();
|
|
7828
7867
|
}
|
|
7829
|
-
const v =
|
|
7868
|
+
const v = T.current || { lipsyncLang: "en" };
|
|
7830
7869
|
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 });
|
|
7831
7870
|
}
|
|
7832
7871
|
}, [e.curriculumComplete]), S = O(() => {
|
|
@@ -7847,16 +7886,16 @@ const ft = Me(({
|
|
|
7847
7886
|
if (u.current.setMood("happy"), e.questionStart)
|
|
7848
7887
|
try {
|
|
7849
7888
|
u.current.playAnimation(e.questionStart, !0);
|
|
7850
|
-
} catch (
|
|
7851
|
-
console.warn("Failed to play questionStart animation:",
|
|
7889
|
+
} catch (N) {
|
|
7890
|
+
console.warn("Failed to play questionStart animation:", N);
|
|
7852
7891
|
}
|
|
7853
|
-
const P =
|
|
7892
|
+
const P = T.current || { lipsyncLang: "en" };
|
|
7854
7893
|
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 });
|
|
7855
7894
|
};
|
|
7856
7895
|
if (u.current && u.current.isReady && v)
|
|
7857
7896
|
F();
|
|
7858
7897
|
else if (u.current && u.current.isReady) {
|
|
7859
|
-
const P =
|
|
7898
|
+
const P = T.current || { lipsyncLang: "en" };
|
|
7860
7899
|
u.current.speakText("Now let me ask you some questions to test your understanding.", { lipsyncLang: P.lipsyncLang });
|
|
7861
7900
|
} else {
|
|
7862
7901
|
const P = setInterval(() => {
|
|
@@ -7885,28 +7924,28 @@ const ft = Me(({
|
|
|
7885
7924
|
if (u.current.setMood("happy"), u.current.setBodyMovement("idle"), e.nextQuestion)
|
|
7886
7925
|
try {
|
|
7887
7926
|
u.current.playAnimation(e.nextQuestion, !0);
|
|
7888
|
-
} catch (
|
|
7889
|
-
console.warn("Failed to play nextQuestion animation:",
|
|
7927
|
+
} catch (_) {
|
|
7928
|
+
console.warn("Failed to play nextQuestion animation:", _);
|
|
7890
7929
|
}
|
|
7891
|
-
const P =
|
|
7930
|
+
const P = T.current || { lipsyncLang: "en" }, te = R()?.questions?.length || 0, q = a.current.currentQuestionIndex >= te - 1;
|
|
7892
7931
|
if (v.type === "code_test") {
|
|
7893
|
-
const
|
|
7894
|
-
u.current.speakText(
|
|
7932
|
+
const _ = q ? `Great! Here's your final coding challenge: ${v.question}` : `Great! Now let's move on to your next coding challenge: ${v.question}`;
|
|
7933
|
+
u.current.speakText(_, {
|
|
7895
7934
|
lipsyncLang: P.lipsyncLang
|
|
7896
7935
|
});
|
|
7897
7936
|
} else if (v.type === "multiple_choice") {
|
|
7898
|
-
const
|
|
7899
|
-
u.current.speakText(
|
|
7937
|
+
const _ = q ? `Alright! Here's your final question: ${v.question}` : `Alright! Here's your next question: ${v.question}`;
|
|
7938
|
+
u.current.speakText(_, {
|
|
7900
7939
|
lipsyncLang: P.lipsyncLang
|
|
7901
7940
|
});
|
|
7902
7941
|
} else if (v.type === "true_false") {
|
|
7903
|
-
const
|
|
7904
|
-
u.current.speakText(
|
|
7942
|
+
const _ = q ? `Now let's try this final one: ${v.question}` : `Now let's try this one: ${v.question}`;
|
|
7943
|
+
u.current.speakText(_, {
|
|
7905
7944
|
lipsyncLang: P.lipsyncLang
|
|
7906
7945
|
});
|
|
7907
7946
|
} else {
|
|
7908
|
-
const
|
|
7909
|
-
u.current.speakText(
|
|
7947
|
+
const _ = q ? `Here's your final question: ${v.question}` : `Here's the next question: ${v.question}`;
|
|
7948
|
+
u.current.speakText(_, {
|
|
7910
7949
|
lipsyncLang: P.lipsyncLang
|
|
7911
7950
|
});
|
|
7912
7951
|
}
|
|
@@ -7929,16 +7968,16 @@ const ft = Me(({
|
|
|
7929
7968
|
totalQuestions: a.current.totalQuestions,
|
|
7930
7969
|
score: a.current.score
|
|
7931
7970
|
});
|
|
7932
|
-
}, [e.nextQuestion, R, L]),
|
|
7971
|
+
}, [e.nextQuestion, R, L]), j = O(() => {
|
|
7933
7972
|
const b = B.current || { modules: [] }, v = b.modules[a.current.currentModuleIndex];
|
|
7934
7973
|
if (a.current.currentLessonIndex < (v?.lessons?.length || 0) - 1) {
|
|
7935
7974
|
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;
|
|
7936
|
-
const P = b.modules[a.current.currentModuleIndex],
|
|
7975
|
+
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;
|
|
7937
7976
|
d.current.onCustomAction({
|
|
7938
7977
|
type: "lessonStart",
|
|
7939
7978
|
moduleIndex: a.current.currentModuleIndex,
|
|
7940
7979
|
lessonIndex: a.current.currentLessonIndex,
|
|
7941
|
-
hasNextLesson:
|
|
7980
|
+
hasNextLesson: q
|
|
7942
7981
|
}), d.current.onLessonStart({
|
|
7943
7982
|
moduleIndex: a.current.currentModuleIndex,
|
|
7944
7983
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7946,12 +7985,12 @@ const ft = Me(({
|
|
|
7946
7985
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7947
7986
|
} else if (a.current.currentModuleIndex < (b.modules?.length || 0) - 1) {
|
|
7948
7987
|
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;
|
|
7949
|
-
const
|
|
7988
|
+
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;
|
|
7950
7989
|
d.current.onCustomAction({
|
|
7951
7990
|
type: "lessonStart",
|
|
7952
7991
|
moduleIndex: a.current.currentModuleIndex,
|
|
7953
7992
|
lessonIndex: a.current.currentLessonIndex,
|
|
7954
|
-
hasNextLesson:
|
|
7993
|
+
hasNextLesson: _
|
|
7955
7994
|
}), d.current.onLessonStart({
|
|
7956
7995
|
moduleIndex: a.current.currentModuleIndex,
|
|
7957
7996
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -7959,12 +7998,12 @@ const ft = Me(({
|
|
|
7959
7998
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
7960
7999
|
} else
|
|
7961
8000
|
k.current && k.current();
|
|
7962
|
-
}, []),
|
|
8001
|
+
}, []), X = O(() => {
|
|
7963
8002
|
const b = R();
|
|
7964
8003
|
let v = null;
|
|
7965
8004
|
if (b?.avatar_script && b?.body) {
|
|
7966
|
-
const F = b.avatar_script.trim(), P = b.body.trim(),
|
|
7967
|
-
v = `${F}${
|
|
8005
|
+
const F = b.avatar_script.trim(), P = b.body.trim(), N = F.match(/[.!?]$/) ? " " : ". ";
|
|
8006
|
+
v = `${F}${N}${P}`;
|
|
7968
8007
|
} else
|
|
7969
8008
|
v = b?.avatar_script || b?.body || null;
|
|
7970
8009
|
if (u.current && u.current.isReady && v) {
|
|
@@ -7973,11 +8012,11 @@ const ft = Me(({
|
|
|
7973
8012
|
if (e.teaching)
|
|
7974
8013
|
try {
|
|
7975
8014
|
u.current.playAnimation(e.teaching, !0), F = !0;
|
|
7976
|
-
} catch (
|
|
7977
|
-
console.warn("Failed to play teaching animation:",
|
|
8015
|
+
} catch (N) {
|
|
8016
|
+
console.warn("Failed to play teaching animation:", N);
|
|
7978
8017
|
}
|
|
7979
8018
|
F || u.current.setBodyMovement("gesturing");
|
|
7980
|
-
const P =
|
|
8019
|
+
const P = T.current || { lipsyncLang: "en" };
|
|
7981
8020
|
d.current.onLessonStart({
|
|
7982
8021
|
moduleIndex: a.current.currentModuleIndex,
|
|
7983
8022
|
lessonIndex: a.current.currentLessonIndex,
|
|
@@ -8024,13 +8063,13 @@ const ft = Me(({
|
|
|
8024
8063
|
u.current.setBodyMovement("happy");
|
|
8025
8064
|
}
|
|
8026
8065
|
u.current.setBodyMovement("gesturing");
|
|
8027
|
-
const
|
|
8028
|
-
a.current.currentQuestionIndex >=
|
|
8029
|
-
const
|
|
8030
|
-
console.log("[CurriculumLearning] Answer feedback - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:",
|
|
8031
|
-
const
|
|
8032
|
-
u.current.speakText(
|
|
8033
|
-
lipsyncLang:
|
|
8066
|
+
const N = R()?.questions?.length || 0;
|
|
8067
|
+
a.current.currentQuestionIndex >= N - 1;
|
|
8068
|
+
const te = a.current.currentQuestionIndex < N - 1;
|
|
8069
|
+
console.log("[CurriculumLearning] Answer feedback - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:", N, "hasNextQuestion:", te);
|
|
8070
|
+
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" };
|
|
8071
|
+
u.current.speakText(q, {
|
|
8072
|
+
lipsyncLang: _.lipsyncLang,
|
|
8034
8073
|
onSpeechEnd: () => {
|
|
8035
8074
|
d.current.onCustomAction({
|
|
8036
8075
|
type: "answerFeedbackComplete",
|
|
@@ -8038,7 +8077,7 @@ const ft = Me(({
|
|
|
8038
8077
|
lessonIndex: a.current.currentLessonIndex,
|
|
8039
8078
|
questionIndex: a.current.currentQuestionIndex,
|
|
8040
8079
|
isCorrect: !0,
|
|
8041
|
-
hasNextQuestion:
|
|
8080
|
+
hasNextQuestion: te,
|
|
8042
8081
|
score: a.current.score,
|
|
8043
8082
|
totalQuestions: a.current.totalQuestions
|
|
8044
8083
|
});
|
|
@@ -8052,10 +8091,10 @@ const ft = Me(({
|
|
|
8052
8091
|
u.current.setBodyMovement("idle");
|
|
8053
8092
|
}
|
|
8054
8093
|
u.current.setBodyMovement("gesturing");
|
|
8055
|
-
const
|
|
8056
|
-
console.log("[CurriculumLearning] Answer feedback (incorrect) - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:",
|
|
8057
|
-
const
|
|
8058
|
-
u.current.speakText(
|
|
8094
|
+
const N = R()?.questions?.length || 0, te = a.current.currentQuestionIndex >= N - 1, q = a.current.currentQuestionIndex < N - 1;
|
|
8095
|
+
console.log("[CurriculumLearning] Answer feedback (incorrect) - questionIndex:", a.current.currentQuestionIndex, "totalQuestions:", N, "hasNextQuestion:", q);
|
|
8096
|
+
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" };
|
|
8097
|
+
u.current.speakText(_, {
|
|
8059
8098
|
lipsyncLang: Ae.lipsyncLang,
|
|
8060
8099
|
onSpeechEnd: () => {
|
|
8061
8100
|
d.current.onCustomAction({
|
|
@@ -8064,7 +8103,7 @@ const ft = Me(({
|
|
|
8064
8103
|
lessonIndex: a.current.currentLessonIndex,
|
|
8065
8104
|
questionIndex: a.current.currentQuestionIndex,
|
|
8066
8105
|
isCorrect: !1,
|
|
8067
|
-
hasNextQuestion:
|
|
8106
|
+
hasNextQuestion: q,
|
|
8068
8107
|
score: a.current.score,
|
|
8069
8108
|
totalQuestions: a.current.totalQuestions
|
|
8070
8109
|
});
|
|
@@ -8072,14 +8111,14 @@ const ft = Me(({
|
|
|
8072
8111
|
});
|
|
8073
8112
|
}
|
|
8074
8113
|
else {
|
|
8075
|
-
const
|
|
8114
|
+
const N = R()?.questions?.length || 0;
|
|
8076
8115
|
d.current.onCustomAction({
|
|
8077
8116
|
type: "answerFeedbackComplete",
|
|
8078
8117
|
moduleIndex: a.current.currentModuleIndex,
|
|
8079
8118
|
lessonIndex: a.current.currentLessonIndex,
|
|
8080
8119
|
questionIndex: a.current.currentQuestionIndex,
|
|
8081
8120
|
isCorrect: F,
|
|
8082
|
-
hasNextQuestion: a.current.currentQuestionIndex <
|
|
8121
|
+
hasNextQuestion: a.current.currentQuestionIndex < N - 1,
|
|
8083
8122
|
score: a.current.score,
|
|
8084
8123
|
totalQuestions: a.current.totalQuestions,
|
|
8085
8124
|
avatarNotReady: !0
|
|
@@ -8129,7 +8168,7 @@ const ft = Me(({
|
|
|
8129
8168
|
const v = () => {
|
|
8130
8169
|
if (!u.current || !b) return;
|
|
8131
8170
|
u.current.setMood("happy"), u.current.setBodyMovement("idle");
|
|
8132
|
-
const F =
|
|
8171
|
+
const F = T.current || { lipsyncLang: "en" };
|
|
8133
8172
|
b.type === "code_test" ? u.current.speakText(`Let's go back to this coding challenge: ${b.question}`, {
|
|
8134
8173
|
lipsyncLang: F.lipsyncLang
|
|
8135
8174
|
}) : u.current.speakText(`Going back to: ${b.question}`, {
|
|
@@ -8171,7 +8210,7 @@ const ft = Me(({
|
|
|
8171
8210
|
lesson: R()
|
|
8172
8211
|
}), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"));
|
|
8173
8212
|
}
|
|
8174
|
-
}, [R]),
|
|
8213
|
+
}, [R]), ee = O(() => {
|
|
8175
8214
|
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;
|
|
8176
8215
|
}, []), be = O((b) => {
|
|
8177
8216
|
console.log("Avatar is ready!", b);
|
|
@@ -8181,20 +8220,20 @@ const ft = Me(({
|
|
|
8181
8220
|
}, 10);
|
|
8182
8221
|
}, [h, R]);
|
|
8183
8222
|
Xe(() => {
|
|
8184
|
-
c.current =
|
|
8223
|
+
c.current = X, g.current = j, x.current = z, f.current = E, k.current = Y, D.current = S, p.current = oe;
|
|
8185
8224
|
}), Fe(r, () => ({
|
|
8186
8225
|
// Curriculum control methods
|
|
8187
|
-
startTeaching:
|
|
8226
|
+
startTeaching: X,
|
|
8188
8227
|
startQuestions: S,
|
|
8189
8228
|
handleAnswerSelect: oe,
|
|
8190
8229
|
handleCodeTestResult: le,
|
|
8191
8230
|
nextQuestion: E,
|
|
8192
8231
|
previousQuestion: ge,
|
|
8193
|
-
nextLesson:
|
|
8232
|
+
nextLesson: j,
|
|
8194
8233
|
previousLesson: de,
|
|
8195
8234
|
completeLesson: z,
|
|
8196
8235
|
completeCurriculum: Y,
|
|
8197
|
-
resetCurriculum:
|
|
8236
|
+
resetCurriculum: ee,
|
|
8198
8237
|
getState: () => ({ ...a.current }),
|
|
8199
8238
|
getCurrentQuestion: () => L(),
|
|
8200
8239
|
getCurrentLesson: () => R(),
|
|
@@ -8203,7 +8242,7 @@ const ft = Me(({
|
|
|
8203
8242
|
// Convenience methods that delegate to avatar (always check current ref)
|
|
8204
8243
|
speakText: async (b, v = {}) => {
|
|
8205
8244
|
await u.current?.resumeAudioContext?.();
|
|
8206
|
-
const F =
|
|
8245
|
+
const F = T.current || { lipsyncLang: "en" };
|
|
8207
8246
|
u.current?.speakText(b, { ...v, lipsyncLang: v.lipsyncLang || F.lipsyncLang });
|
|
8208
8247
|
},
|
|
8209
8248
|
resumeAudioContext: async () => {
|
|
@@ -8248,8 +8287,8 @@ const ft = Me(({
|
|
|
8248
8287
|
handleResize: () => u.current?.handleResize(),
|
|
8249
8288
|
// Avatar readiness check (always returns current value)
|
|
8250
8289
|
isAvatarReady: () => u.current?.isReady || !1
|
|
8251
|
-
}), [
|
|
8252
|
-
const
|
|
8290
|
+
}), [X, S, oe, le, E, j, z, Y, ee, L, R]);
|
|
8291
|
+
const Q = T.current || {
|
|
8253
8292
|
avatarUrl: "/avatars/brunette.glb",
|
|
8254
8293
|
avatarBody: "F",
|
|
8255
8294
|
mood: "happy",
|
|
@@ -8266,18 +8305,18 @@ const ft = Me(({
|
|
|
8266
8305
|
Ve,
|
|
8267
8306
|
{
|
|
8268
8307
|
ref: u,
|
|
8269
|
-
avatarUrl:
|
|
8270
|
-
avatarBody:
|
|
8271
|
-
mood:
|
|
8272
|
-
ttsLang:
|
|
8273
|
-
ttsService:
|
|
8274
|
-
ttsVoice:
|
|
8275
|
-
ttsApiKey:
|
|
8276
|
-
bodyMovement:
|
|
8277
|
-
movementIntensity:
|
|
8278
|
-
showFullAvatar:
|
|
8308
|
+
avatarUrl: Q.avatarUrl,
|
|
8309
|
+
avatarBody: Q.avatarBody,
|
|
8310
|
+
mood: Q.mood,
|
|
8311
|
+
ttsLang: Q.ttsLang,
|
|
8312
|
+
ttsService: Q.ttsService,
|
|
8313
|
+
ttsVoice: Q.ttsVoice,
|
|
8314
|
+
ttsApiKey: Q.ttsApiKey,
|
|
8315
|
+
bodyMovement: Q.bodyMovement,
|
|
8316
|
+
movementIntensity: Q.movementIntensity,
|
|
8317
|
+
showFullAvatar: Q.showFullAvatar,
|
|
8279
8318
|
cameraView: "upper",
|
|
8280
|
-
animations:
|
|
8319
|
+
animations: Q.animations,
|
|
8281
8320
|
onReady: be,
|
|
8282
8321
|
onLoading: () => {
|
|
8283
8322
|
},
|