@sage-rsc/talking-head-react 1.0.63 → 1.0.64

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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsxs as Ee, jsx as ue } from "react/jsx-runtime";
2
- import { forwardRef as Ie, useRef as G, useState as de, useEffect as me, useCallback as T, useImperativeHandle as Le, useLayoutEffect as We } from "react";
2
+ import { forwardRef as Ie, useRef as G, useState as me, useEffect as pe, useCallback as E, useImperativeHandle as Le, useLayoutEffect as We } from "react";
3
3
  import * as f from "three";
4
4
  import { OrbitControls as Ve } from "three/addons/controls/OrbitControls.js";
5
5
  import { GLTFLoader as Ge } from "three/addons/loaders/GLTFLoader.js";
@@ -7,7 +7,7 @@ import { DRACOLoader as Ze } from "three/addons/loaders/DRACOLoader.js";
7
7
  import { FBXLoader as ze } from "three/addons/loaders/FBXLoader.js";
8
8
  import { RoomEnvironment as Xe } from "three/addons/environments/RoomEnvironment.js";
9
9
  import Ye from "three/addons/libs/stats.module.js";
10
- let m, _, $;
10
+ let m, K, $;
11
11
  const A = [0, 0, 0, 0], k = new f.Vector3(), be = new f.Vector3(), Q = new f.Vector3(), ve = new f.Vector3();
12
12
  new f.Plane();
13
13
  new f.Ray();
@@ -371,7 +371,7 @@ class _e {
371
371
  );
372
372
  else if (o.boneParent.quaternion.copy(o.qBasis), o.pivot && this.opt.isPivots && (o.boneParent.updateWorldMatrix(!1, !1), o.boneParent.matrixWorld.decompose(k, q, Q), k.copy(Re).applyQuaternion(q).setY(0).normalize(), q.premultiply(Ce.setFromUnitVectors(Re, k).invert()).normalize(), o.boneParent.quaternion.multiply(q.invert()), o.boneParent.quaternion.multiply(o.qWorldInverseYaw)), o.isZ && (m = Math.atan(A[0] / o.l), q.setFromAxisAngle(qe, -m), o.boneParent.quaternion.multiply(q)), o.isY && (m = o.l / 3, m = m * Math.tanh(A[1] / m), o.bone.position.setLength(o.l + m)), o.isX && (m = Math.atan(A[2] / o.l), q.setFromAxisAngle(je, -m), o.boneParent.quaternion.multiply(q)), o.isT && (m = 1.5 * Math.tanh(A[3] * 1.5), q.setFromAxisAngle(Qe, -m), o.boneParent.quaternion.multiply(q)), 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], Q.set(0, 0, 0), m.deltaLocal && (Q.x += m.deltaLocal[0], Q.y += m.deltaLocal[1], Q.z += m.deltaLocal[2]), Q.applyMatrix4(m.bone.matrixWorld), ae.copy(o.boneParent.matrixWorld).invert(), Q.applyMatrix4(ae), k.copy(o.bone.position), !(k.distanceToSquared(Q) >= m.radiusSq) && ($ = k.length(), _ = Q.length(), !(_ > m.radius + $) && (_ < Math.abs(m.radius - $) || (_ = (_ * _ + $ * $ - m.radiusSq) / (2 * _), Q.normalize(), ve.copy(Q).multiplyScalar(_), _ = Math.sqrt($ * $ - _ * _), k.subVectors(k, ve).projectOnPlane(Q).normalize().multiplyScalar(_), be.subVectors(o.vBasis, ve).projectOnPlane(Q).normalize(), $ = be.dot(k), $ < 0 && ($ = Math.sqrt(_ * _ - $ * $), be.multiplyScalar($), k.add(be)), k.add(ve).normalize(), Q.copy(o.bone.position).normalize(), q.setFromUnitVectors(Q, k), o.boneParent.quaternion.premultiply(q), o.boneParent.updateWorldMatrix(!1, !0))));
374
+ m = o.excludes[n], Q.set(0, 0, 0), m.deltaLocal && (Q.x += m.deltaLocal[0], Q.y += m.deltaLocal[1], Q.z += m.deltaLocal[2]), Q.applyMatrix4(m.bone.matrixWorld), ae.copy(o.boneParent.matrixWorld).invert(), Q.applyMatrix4(ae), k.copy(o.bone.position), !(k.distanceToSquared(Q) >= m.radiusSq) && ($ = k.length(), K = Q.length(), !(K > m.radius + $) && (K < Math.abs(m.radius - $) || (K = (K * K + $ * $ - m.radiusSq) / (2 * K), Q.normalize(), ve.copy(Q).multiplyScalar(K), K = Math.sqrt($ * $ - K * K), k.subVectors(k, ve).projectOnPlane(Q).normalize().multiplyScalar(K), be.subVectors(o.vBasis, ve).projectOnPlane(Q).normalize(), $ = be.dot(k), $ < 0 && ($ = Math.sqrt(K * K - $ * $), be.multiplyScalar($), k.add(be)), k.add(ve).normalize(), Q.copy(o.bone.position).normalize(), q.setFromUnitVectors(Q, k), o.boneParent.quaternion.premultiply(q), o.boneParent.updateWorldMatrix(!1, !0))));
375
375
  }
376
376
  this.helpers.isActive && this.updateHelpers();
377
377
  }
@@ -2629,7 +2629,7 @@ const rt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2629
2629
  fr: it,
2630
2630
  fi: st,
2631
2631
  lt: rt
2632
- }, W = new f.Quaternion(), F = new f.Euler(), le = new f.Vector3(), he = new f.Vector3(), Te = new f.Box3();
2632
+ }, U = new f.Quaternion(), F = new f.Euler(), le = new f.Vector3(), he = new f.Vector3(), Te = new f.Box3();
2633
2633
  new f.Matrix4();
2634
2634
  new f.Matrix4();
2635
2635
  new f.Vector3();
@@ -4376,7 +4376,7 @@ class Fe {
4376
4376
  if (e.x === 0 && e.y === 0 && e.z === 0) continue;
4377
4377
  F.set(e.x, e.y, e.z);
4378
4378
  const n = this.poseAvatar.props[t];
4379
- n.isQuaternion ? (W.setFromEuler(F), n.multiply(W)) : n.isVector3 && n.add(F);
4379
+ n.isQuaternion ? (U.setFromEuler(F), n.multiply(U)) : n.isVector3 && n.add(F);
4380
4380
  }
4381
4381
  }
4382
4382
  /**
@@ -5180,7 +5180,7 @@ class Fe {
5180
5180
  eyeLookOutRight: [null, 0],
5181
5181
  eyeContact: [0]
5182
5182
  }
5183
- })))), 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) && u ? 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 && (W.setFromAxisAngle(ht, this.volumeHeadCurrent), this.objectNeck.quaternion.multiply(W)), Te.setFromObject(this.armature), this.objectLeftToeBase.getWorldPosition(le), le.sub(this.armature.position), this.objectRightToeBase.getWorldPosition(he), he.sub(this.armature.position), this.objectHips.position.y -= Te.min.y / 2, this.objectHips.position.x -= (le.x + he.x) / 4, this.objectHips.position.z -= (le.z + he.z) / 2, this.dynamicbones.update(e), this.fbxAnimationLoader && this.fbxAnimationLoader.update(), this.opt.update && this.opt.update(e), this.updateMorphTargets(e), this.isAvatarOnly)
5183
+ })))), 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) && u ? 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 && (U.setFromAxisAngle(ht, this.volumeHeadCurrent), this.objectNeck.quaternion.multiply(U)), Te.setFromObject(this.armature), this.objectLeftToeBase.getWorldPosition(le), le.sub(this.armature.position), this.objectRightToeBase.getWorldPosition(he), he.sub(this.armature.position), this.objectHips.position.y -= Te.min.y / 2, this.objectHips.position.x -= (le.x + he.x) / 4, this.objectHips.position.z -= (le.z + he.z) / 2, this.dynamicbones.update(e), this.fbxAnimationLoader && this.fbxAnimationLoader.update(), this.opt.update && this.opt.update(e), this.updateMorphTargets(e), this.isAvatarOnly)
5184
5184
  this.stats && this.stats.end();
5185
5185
  else {
5186
5186
  if (this.cameraClock !== null && this.cameraClock < 1e3) {
@@ -5267,12 +5267,12 @@ class Fe {
5267
5267
  }), h = ""), r.length)) {
5268
5268
  const R = this.lipsyncWordsToVisemes(r, a);
5269
5269
  if (R && R.visemes && R.visemes.length) {
5270
- const M = R.times[R.visemes.length - 1] + R.durations[R.visemes.length - 1];
5270
+ const T = R.times[R.visemes.length - 1] + R.durations[R.visemes.length - 1];
5271
5271
  for (let P = 0; P < R.visemes.length; P++)
5272
5272
  g.push({
5273
5273
  mark: c,
5274
5274
  template: { name: "viseme" },
5275
- ts: [(R.times[P] - 0.6) / M, (R.times[P] + 0.5) / M, (R.times[P] + R.durations[P] + 0.5) / M],
5275
+ ts: [(R.times[P] - 0.6) / T, (R.times[P] + 0.5) / T, (R.times[P] + R.durations[P] + 0.5) / T],
5276
5276
  vs: {
5277
5277
  ["viseme_" + R.visemes[P]]: [null, R.visemes[P] === "PP" || R.visemes[P] === "FF" ? 0.9 : 0.6, 0]
5278
5278
  }
@@ -5486,7 +5486,7 @@ class Fe {
5486
5486
  if (x && x.visemes && x.visemes.length > 0) {
5487
5487
  const p = x.times[x.visemes.length - 1] + x.durations[x.visemes.length - 1];
5488
5488
  for (let H = 0; H < x.visemes.length; H++) {
5489
- const z = x.visemes[H], R = x.times[H] / p, M = x.durations[H] / p, P = R * c, ee = M * c;
5489
+ const z = x.visemes[H], R = x.times[H] / p, T = x.durations[H] / p, P = R * c, ee = T * c;
5490
5490
  I.push({
5491
5491
  template: { name: "viseme" },
5492
5492
  ts: [P - Math.min(60, 2 * ee / 3), P + Math.min(25, ee / 2), P + ee + Math.min(60, ee / 2)],
@@ -6146,10 +6146,10 @@ class Fe {
6146
6146
  this.lookAt(null, null, t);
6147
6147
  return;
6148
6148
  }
6149
- this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0), le.setFromMatrixPosition(this.objectLeftEye.matrixWorld), he.setFromMatrixPosition(this.objectRightEye.matrixWorld), le.add(he).divideScalar(2), W.copy(this.armature.quaternion), W.multiply(this.poseTarget.props["Hips.quaternion"]), W.multiply(this.poseTarget.props["Spine.quaternion"]), W.multiply(this.poseTarget.props["Spine1.quaternion"]), W.multiply(this.poseTarget.props["Spine2.quaternion"]), W.multiply(this.poseTarget.props["Neck.quaternion"]), W.multiply(this.poseTarget.props["Head.quaternion"]);
6149
+ this.objectLeftEye.updateMatrixWorld(!0), this.objectRightEye.updateMatrixWorld(!0), le.setFromMatrixPosition(this.objectLeftEye.matrixWorld), he.setFromMatrixPosition(this.objectRightEye.matrixWorld), le.add(he).divideScalar(2), U.copy(this.armature.quaternion), U.multiply(this.poseTarget.props["Hips.quaternion"]), U.multiply(this.poseTarget.props["Spine.quaternion"]), U.multiply(this.poseTarget.props["Spine1.quaternion"]), U.multiply(this.poseTarget.props["Spine2.quaternion"]), U.multiply(this.poseTarget.props["Neck.quaternion"]), U.multiply(this.poseTarget.props["Head.quaternion"]);
6150
6150
  const n = new f.Vector3().subVectors(e, le).normalize(), i = Math.atan2(n.x, n.z), s = Math.asin(-n.y);
6151
6151
  F.set(s, i, 0, "YXZ");
6152
- const l = new f.Quaternion().setFromEuler(F), u = new f.Quaternion().copy(l).multiply(W.clone().invert());
6152
+ const l = new f.Quaternion().setFromEuler(F), u = new f.Quaternion().copy(l).multiply(U.clone().invert());
6153
6153
  F.setFromQuaternion(u, "YXZ");
6154
6154
  let a = F.x / (40 / 24) + 0.2, h = F.y / (9 / 4), r = Math.min(0.6, Math.max(-0.3, a)), c = Math.min(0.8, Math.max(-0.8, h)), d = (Math.random() - 0.5) / 4, g = (Math.random() - 0.5) / 4;
6155
6155
  if (t) {
@@ -6186,7 +6186,7 @@ class Fe {
6186
6186
  const s = new f.Vector3().setFromMatrixPosition(this.objectLeftEye.matrixWorld), o = new f.Vector3().setFromMatrixPosition(this.objectRightEye.matrixWorld), l = new f.Vector3().addVectors(s, o).divideScalar(2);
6187
6187
  l.project(this.camera);
6188
6188
  let u = (l.x + 1) / 2 * i.width + i.left, a = -(l.y - 1) / 2 * i.height + i.top;
6189
- t === null && (t = u), e === null && (e = a), W.copy(this.armature.quaternion), W.multiply(this.poseTarget.props["Hips.quaternion"]), W.multiply(this.poseTarget.props["Spine.quaternion"]), W.multiply(this.poseTarget.props["Spine1.quaternion"]), W.multiply(this.poseTarget.props["Spine2.quaternion"]), W.multiply(this.poseTarget.props["Neck.quaternion"]), W.multiply(this.poseTarget.props["Head.quaternion"]), F.setFromQuaternion(W);
6189
+ t === null && (t = u), e === null && (e = a), U.copy(this.armature.quaternion), U.multiply(this.poseTarget.props["Hips.quaternion"]), U.multiply(this.poseTarget.props["Spine.quaternion"]), U.multiply(this.poseTarget.props["Spine1.quaternion"]), U.multiply(this.poseTarget.props["Spine2.quaternion"]), U.multiply(this.poseTarget.props["Neck.quaternion"]), U.multiply(this.poseTarget.props["Head.quaternion"]), F.setFromQuaternion(U);
6190
6190
  let h = F.x / (40 / 24), r = F.y / (9 / 4), c = Math.min(0.4, Math.max(-0.4, this.camera.rotation.x)), d = Math.min(0.4, Math.max(-0.4, this.camera.rotation.y)), g = Math.max(window.innerWidth - u, u), y = Math.max(window.innerHeight - a, a), x = this.convertRange(e, [a - y, a + y], [-0.3, 0.6]) - h + c, I = this.convertRange(t, [u - g, u + g], [-0.8, 0.8]) - r + d;
6191
6191
  x = Math.min(0.6, Math.max(-0.3, x)), I = Math.min(0.8, Math.max(-0.8, I));
6192
6192
  let D = (Math.random() - 0.5) / 4, p = (Math.random() - 0.5) / 4;
@@ -6582,7 +6582,7 @@ class Fe {
6582
6582
  const z = y[p].bone;
6583
6583
  z.matrixWorld.decompose(u, a, h), a.invert(), o.setFromMatrixPosition(g.matrixWorld), l.subVectors(o, u), l.applyQuaternion(a), l.normalize(), s.subVectors(e, u), s.applyQuaternion(a), s.normalize();
6584
6584
  let R = s.dot(l);
6585
- R > 1 ? R = 1 : R < -1 && (R = -1), R = Math.acos(R), !(R < 1e-5) && (y[p].minAngle !== void 0 && R < y[p].minAngle && (R = y[p].minAngle), y[p].maxAngle !== void 0 && R > y[p].maxAngle && (R = y[p].maxAngle), r.crossVectors(l, s), r.normalize(), W.setFromAxisAngle(r, R), z.quaternion.multiply(W), z.rotation.setFromVector3(c.setFromEuler(z.rotation).clamp(new f.Vector3(
6585
+ R > 1 ? R = 1 : R < -1 && (R = -1), R = Math.acos(R), !(R < 1e-5) && (y[p].minAngle !== void 0 && R < y[p].minAngle && (R = y[p].minAngle), y[p].maxAngle !== void 0 && R > y[p].maxAngle && (R = y[p].maxAngle), r.crossVectors(l, s), r.normalize(), U.setFromAxisAngle(r, R), z.quaternion.multiply(U), z.rotation.setFromVector3(c.setFromEuler(z.rotation).clamp(new f.Vector3(
6586
6586
  y[p].minx !== void 0 ? y[p].minx : -1 / 0,
6587
6587
  y[p].miny !== void 0 ? y[p].miny : -1 / 0,
6588
6588
  y[p].minz !== void 0 ? y[p].minz : -1 / 0
@@ -6685,10 +6685,10 @@ const Pe = Ie(({
6685
6685
  style: y = {},
6686
6686
  animations: x = {}
6687
6687
  }, I) => {
6688
- const D = G(null), p = G(null), H = G(a), z = G(null), R = G(null), M = G(!1), P = G({ remainingText: null, originalText: null, options: null }), [ee, re] = de(!0), [S, N] = de(null), [Z, X] = de(!1), [j, K] = de(!1);
6689
- me(() => {
6690
- M.current = j;
6691
- }, [j]), me(() => {
6688
+ const D = G(null), p = G(null), H = G(a), z = G(null), R = G(null), T = G(!1), P = G({ remainingText: null, originalText: null, options: null }), [ee, re] = me(!0), [S, N] = me(null), [Z, X] = me(!1), [j, _] = me(!1);
6689
+ pe(() => {
6690
+ T.current = j;
6691
+ }, [j]), pe(() => {
6692
6692
  H.current = a;
6693
6693
  }, [a]);
6694
6694
  const te = Ae(), ce = i || te.service;
@@ -6715,7 +6715,7 @@ const Pe = Ie(({
6715
6715
  // Override API key if provided via props
6716
6716
  apiKey: o !== null ? o : te.apiKey
6717
6717
  };
6718
- const pe = {
6718
+ const de = {
6719
6719
  url: O,
6720
6720
  body: t,
6721
6721
  avatarMood: e,
@@ -6731,24 +6731,24 @@ const Pe = Ie(({
6731
6731
  ttsService: ce,
6732
6732
  lipsyncModules: ["en"],
6733
6733
  cameraView: h
6734
- }, b = T(async () => {
6734
+ }, b = E(async () => {
6735
6735
  if (!(!D.current || p.current))
6736
6736
  try {
6737
- if (re(!0), N(null), p.current = new Fe(D.current, J), p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1), x && Object.keys(x).length > 0 && (p.current.customAnimations = x), await p.current.showAvatar(pe, (U) => {
6738
- if (U.lengthComputable) {
6739
- const E = Math.min(100, Math.round(U.loaded / U.total * 100));
6740
- c(E);
6737
+ if (re(!0), N(null), p.current = new Fe(D.current, J), p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1), x && Object.keys(x).length > 0 && (p.current.customAnimations = x), await p.current.showAvatar(de, (V) => {
6738
+ if (V.lengthComputable) {
6739
+ const M = Math.min(100, Math.round(V.loaded / V.total * 100));
6740
+ c(M);
6741
6741
  }
6742
- }), await new Promise((U) => {
6743
- const E = () => {
6744
- p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? U() : setTimeout(E, 100);
6742
+ }), await new Promise((V) => {
6743
+ const M = () => {
6744
+ p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? V() : setTimeout(M, 100);
6745
6745
  };
6746
- E();
6746
+ M();
6747
6747
  }), p.current && p.current.setShowFullAvatar)
6748
6748
  try {
6749
6749
  p.current.setShowFullAvatar(a);
6750
- } catch (U) {
6751
- console.warn("Error setting full body mode on initialization:", U);
6750
+ } catch (V) {
6751
+ console.warn("Error setting full body mode on initialization:", V);
6752
6752
  }
6753
6753
  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()), re(!1), X(!0), r(p.current);
6754
6754
  const B = () => {
@@ -6761,12 +6761,12 @@ const Pe = Ie(({
6761
6761
  console.error("Error initializing TalkingHead:", L), N(L.message || "Failed to initialize avatar"), re(!1), d(L);
6762
6762
  }
6763
6763
  }, [O, t, e, n, i, s, o, a, l, u, h]);
6764
- me(() => (b(), () => {
6764
+ pe(() => (b(), () => {
6765
6765
  p.current && (p.current.stop(), p.current.dispose(), p.current = null);
6766
- }), [b]), me(() => {
6766
+ }), [b]), pe(() => {
6767
6767
  if (!D.current || !p.current) return;
6768
- const L = new ResizeObserver((U) => {
6769
- for (const E of U)
6768
+ const L = new ResizeObserver((V) => {
6769
+ for (const M of V)
6770
6770
  p.current && p.current.onResize && p.current.onResize();
6771
6771
  });
6772
6772
  L.observe(D.current);
@@ -6777,31 +6777,31 @@ const Pe = Ie(({
6777
6777
  L.disconnect(), window.removeEventListener("resize", B);
6778
6778
  };
6779
6779
  }, [Z]);
6780
- const v = T(async () => {
6780
+ const v = E(async () => {
6781
6781
  if (p.current && p.current.audioCtx)
6782
6782
  try {
6783
6783
  (p.current.audioCtx.state === "suspended" || p.current.audioCtx.state === "interrupted") && (await p.current.audioCtx.resume(), console.log("Audio context resumed"));
6784
6784
  } catch (L) {
6785
6785
  console.warn("Failed to resume audio context:", L);
6786
6786
  }
6787
- }, []), w = T(async (L, B = {}) => {
6787
+ }, []), w = E(async (L, B = {}) => {
6788
6788
  if (p.current && Z)
6789
6789
  try {
6790
- R.current && (clearInterval(R.current), R.current = null), z.current = { text: L, options: B }, P.current = { remainingText: null, originalText: null, options: null }, K(!1), M.current = !1, await v();
6791
- const U = {
6790
+ R.current && (clearInterval(R.current), R.current = null), z.current = { text: L, options: B }, P.current = { remainingText: null, originalText: null, options: null }, _(!1), T.current = !1, await v();
6791
+ const V = {
6792
6792
  ...B,
6793
- lipsyncLang: B.lipsyncLang || pe.lipsyncLang || "en"
6793
+ lipsyncLang: B.lipsyncLang || de.lipsyncLang || "en"
6794
6794
  };
6795
6795
  if (B.onSpeechEnd && p.current) {
6796
- const E = p.current;
6796
+ const M = p.current;
6797
6797
  let Y = null, ge = 0;
6798
6798
  const ke = 1200;
6799
6799
  let xe = !1;
6800
6800
  Y = setInterval(() => {
6801
- if (ge++, M.current)
6801
+ if (ge++, T.current)
6802
6802
  return;
6803
6803
  if (ge > ke) {
6804
- if (Y && (clearInterval(Y), Y = null, R.current = null), !xe && !M.current) {
6804
+ if (Y && (clearInterval(Y), Y = null, R.current = null), !xe && !T.current) {
6805
6805
  xe = !0;
6806
6806
  try {
6807
6807
  B.onSpeechEnd();
@@ -6811,9 +6811,9 @@ const Pe = Ie(({
6811
6811
  }
6812
6812
  return;
6813
6813
  }
6814
- const Oe = !E.speechQueue || E.speechQueue.length === 0, Ne = !E.audioPlaylist || E.audioPlaylist.length === 0;
6815
- E && E.isSpeaking === !1 && Oe && Ne && E.isAudioPlaying === !1 && !xe && !M.current && setTimeout(() => {
6816
- if (E && !M.current && E.isSpeaking === !1 && (!E.speechQueue || E.speechQueue.length === 0) && (!E.audioPlaylist || E.audioPlaylist.length === 0) && E.isAudioPlaying === !1 && !xe && !M.current) {
6814
+ const Oe = !M.speechQueue || M.speechQueue.length === 0, Ne = !M.audioPlaylist || M.audioPlaylist.length === 0;
6815
+ M && M.isSpeaking === !1 && Oe && Ne && M.isAudioPlaying === !1 && !xe && !T.current && setTimeout(() => {
6816
+ if (M && !T.current && M.isSpeaking === !1 && (!M.speechQueue || M.speechQueue.length === 0) && (!M.audioPlaylist || M.audioPlaylist.length === 0) && M.isAudioPlaying === !1 && !xe && !T.current) {
6817
6817
  xe = !0, Y && (clearInterval(Y), Y = null, R.current = null);
6818
6818
  try {
6819
6819
  B.onSpeechEnd();
@@ -6824,64 +6824,70 @@ const Pe = Ie(({
6824
6824
  }, 100);
6825
6825
  }, 100), R.current = Y;
6826
6826
  }
6827
- p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(L, U)) : setTimeout(async () => {
6828
- await v(), p.current && p.current.lipsync && (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(L, U));
6827
+ p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(L, V)) : setTimeout(async () => {
6828
+ await v(), p.current && p.current.lipsync && (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(L, V));
6829
6829
  }, 100);
6830
- } catch (U) {
6831
- console.error("Error speaking text:", U), N(U.message || "Failed to speak text");
6830
+ } catch (V) {
6831
+ console.error("Error speaking text:", V), N(V.message || "Failed to speak text");
6832
6832
  }
6833
- }, [Z, v, pe.lipsyncLang]), C = T(() => {
6834
- p.current && (p.current.stopSpeaking(), p.current.setSlowdownRate && p.current.setSlowdownRate(1), z.current = null, K(!1));
6835
- }, []), V = T(() => {
6833
+ }, [Z, v, de.lipsyncLang]), C = E(() => {
6834
+ p.current && (p.current.stopSpeaking(), p.current.setSlowdownRate && p.current.setSlowdownRate(1), z.current = null, _(!1));
6835
+ }, []), W = E(() => {
6836
6836
  if (p.current && p.current.pauseSpeaking) {
6837
6837
  const L = p.current;
6838
6838
  if (L.isSpeaking || L.audioPlaylist && L.audioPlaylist.length > 0 || L.speechQueue && L.speechQueue.length > 0) {
6839
6839
  R.current && (clearInterval(R.current), R.current = null);
6840
- let U = "";
6841
- if (L.speechQueue && L.speechQueue.length > 0) {
6842
- const E = L.speechQueue.filter((Y) => Y.text).map((Y) => Y.text).join(" ");
6843
- E && (U = E.trim());
6840
+ let V = "";
6841
+ if (L.speechQueue && L.speechQueue.length > 0 && z.current) {
6842
+ const M = L.speechQueue.filter((Y) => Y && Y.text).map((Y) => Y.text).join(" ");
6843
+ M && M.trim() && (V = M.trim());
6844
6844
  }
6845
- U && z.current && (P.current = {
6846
- remainingText: U,
6845
+ z.current && (P.current = {
6846
+ remainingText: V || null,
6847
6847
  originalText: z.current.text,
6848
6848
  options: z.current.options
6849
- }), L.speechQueue && (L.speechQueue.length = 0), p.current.pauseSpeaking(), M.current = !0, K(!0);
6849
+ }), L.speechQueue && (L.speechQueue.length = 0), p.current.pauseSpeaking(), T.current = !0, _(!0);
6850
6850
  }
6851
6851
  }
6852
- }, []), ne = T(async () => {
6853
- if (p.current && j) {
6854
- K(!1), M.current = !1, await v();
6855
- let L = "", B = {};
6856
- if (P.current && P.current.remainingText)
6857
- L = P.current.remainingText, B = P.current.options || {}, P.current = { remainingText: null, originalText: null, options: null };
6858
- else if (z.current && z.current.text)
6859
- L = z.current.text, B = z.current.options || {};
6860
- else
6861
- return;
6862
- const U = {
6863
- ...B,
6864
- lipsyncLang: B.lipsyncLang || pe.lipsyncLang || "en"
6865
- };
6866
- p.current.lipsync && Object.keys(p.current.lipsync).length > 0 && (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), await w(L, U));
6852
+ }, []), ne = E(async () => {
6853
+ if (!p.current || !j)
6854
+ return;
6855
+ let L = "", B = {};
6856
+ if (P.current && P.current.remainingText)
6857
+ L = P.current.remainingText, B = P.current.options || {}, P.current = { remainingText: null, originalText: null, options: null };
6858
+ else if (z.current && z.current.text)
6859
+ L = z.current.text, B = z.current.options || {};
6860
+ else {
6861
+ console.warn("Resume called but no paused speech found"), _(!1), T.current = !1;
6862
+ return;
6867
6863
  }
6868
- }, [v, j, w]), ie = T((L) => {
6864
+ _(!1), T.current = !1, await v();
6865
+ const V = {
6866
+ ...B,
6867
+ lipsyncLang: B.lipsyncLang || de.lipsyncLang || "en"
6868
+ };
6869
+ try {
6870
+ await w(L, V);
6871
+ } catch (M) {
6872
+ console.error("Error resuming speech:", M), _(!1), T.current = !1;
6873
+ }
6874
+ }, [v, j, w, de]), ie = E((L) => {
6869
6875
  p.current && p.current.setMood(L);
6870
- }, []), fe = T((L) => {
6876
+ }, []), fe = E((L) => {
6871
6877
  p.current && p.current.setSlowdownRate && p.current.setSlowdownRate(L);
6872
- }, []), Se = T((L, B = !1) => {
6878
+ }, []), Se = E((L, B = !1) => {
6873
6879
  if (p.current && p.current.playAnimation) {
6874
6880
  if (x && x[L] && (L = x[L]), p.current.setShowFullAvatar)
6875
6881
  try {
6876
6882
  p.current.setShowFullAvatar(H.current);
6877
- } catch (E) {
6878
- console.warn("Error setting full body mode:", E);
6883
+ } catch (M) {
6884
+ console.warn("Error setting full body mode:", M);
6879
6885
  }
6880
6886
  if (L.includes("."))
6881
6887
  try {
6882
6888
  p.current.playAnimation(L, null, 10, 0, 0.01, B);
6883
- } catch (E) {
6884
- console.warn(`Failed to play ${L}:`, E);
6889
+ } catch (M) {
6890
+ console.warn(`Failed to play ${L}:`, M);
6885
6891
  try {
6886
6892
  p.current.setBodyMovement("idle");
6887
6893
  } catch (Y) {
@@ -6889,9 +6895,9 @@ const Pe = Ie(({
6889
6895
  }
6890
6896
  }
6891
6897
  else {
6892
- const E = [".fbx", ".glb", ".gltf"];
6898
+ const M = [".fbx", ".glb", ".gltf"];
6893
6899
  let Y = !1;
6894
- for (const ge of E)
6900
+ for (const ge of M)
6895
6901
  try {
6896
6902
  p.current.playAnimation(L + ge, null, 10, 0, 0.01, B), Y = !0;
6897
6903
  break;
@@ -6907,13 +6913,13 @@ const Pe = Ie(({
6907
6913
  }
6908
6914
  }
6909
6915
  }
6910
- }, [x]), De = T(() => {
6916
+ }, [x]), De = E(() => {
6911
6917
  p.current && p.current.onResize && p.current.onResize();
6912
6918
  }, []);
6913
6919
  return Le(I, () => ({
6914
6920
  speakText: w,
6915
6921
  stopSpeaking: C,
6916
- pauseSpeaking: V,
6922
+ pauseSpeaking: W,
6917
6923
  resumeSpeaking: ne,
6918
6924
  resumeAudioContext: v,
6919
6925
  setMood: ie,
@@ -7041,7 +7047,7 @@ const ut = Ie(({
7041
7047
  style: s = {},
7042
7048
  avatarConfig: o = {}
7043
7049
  }, l) => {
7044
- const u = G(null), a = G(null), [h, r] = de(!0), [c, d] = de(null), [g, y] = de(!1), x = Ae(), I = o.ttsService || x.service, D = I === "browser" ? {
7050
+ const u = G(null), a = G(null), [h, r] = me(!0), [c, d] = me(null), [g, y] = me(!1), x = Ae(), I = o.ttsService || x.service, D = I === "browser" ? {
7045
7051
  endpoint: "",
7046
7052
  apiKey: null,
7047
7053
  defaultVoice: "Google US English"
@@ -7071,7 +7077,7 @@ const ut = Ie(({
7071
7077
  ttsService: I,
7072
7078
  lipsyncModules: ["en"],
7073
7079
  cameraView: "upper"
7074
- }, z = T(async () => {
7080
+ }, z = E(async () => {
7075
7081
  if (!(!u.current || a.current))
7076
7082
  try {
7077
7083
  if (r(!0), d(null), a.current = new Fe(u.current, H), await a.current.showAvatar(p, (Z) => {
@@ -7107,10 +7113,10 @@ const ut = Ie(({
7107
7113
  console.error("Error initializing TalkingHead:", S), d(S.message || "Failed to initialize avatar"), r(!1), e(S);
7108
7114
  }
7109
7115
  }, []);
7110
- me(() => (z(), () => {
7116
+ pe(() => (z(), () => {
7111
7117
  a.current && (a.current.stop(), a.current.dispose(), a.current = null);
7112
7118
  }), [z]);
7113
- const R = T((S) => {
7119
+ const R = E((S) => {
7114
7120
  if (a.current && g)
7115
7121
  try {
7116
7122
  console.log("Speaking text:", S), console.log("Avatar config:", p), console.log("TalkingHead instance:", a.current), a.current.lipsync && Object.keys(a.current.lipsync).length > 0 ? (console.log("Lip-sync modules loaded:", Object.keys(a.current.lipsync)), a.current.setSlowdownRate && (a.current.setSlowdownRate(1.05), console.log("Applied timing adjustment for better lip-sync")), a.current.speakText(S)) : (console.warn("Lip-sync modules not ready, waiting..."), setTimeout(() => {
@@ -7121,13 +7127,13 @@ const ut = Ie(({
7121
7127
  }
7122
7128
  else
7123
7129
  console.warn("Avatar not ready for speaking. isReady:", g, "talkingHeadRef:", !!a.current);
7124
- }, [g, p]), M = T(() => {
7130
+ }, [g, p]), T = E(() => {
7125
7131
  a.current && (a.current.stopSpeaking(), a.current.setSlowdownRate && (a.current.setSlowdownRate(1), console.log("Reset timing to normal")));
7126
- }, []), P = T((S) => {
7132
+ }, []), P = E((S) => {
7127
7133
  a.current && a.current.setMood(S);
7128
- }, []), ee = T((S) => {
7134
+ }, []), ee = E((S) => {
7129
7135
  a.current && a.current.setSlowdownRate && (a.current.setSlowdownRate(S), console.log("Timing adjustment set to:", S));
7130
- }, []), re = T((S, N = !1) => {
7136
+ }, []), re = E((S, N = !1) => {
7131
7137
  if (a.current && a.current.playAnimation) {
7132
7138
  if (a.current.setShowFullAvatar)
7133
7139
  try {
@@ -7149,19 +7155,19 @@ const ut = Ie(({
7149
7155
  else {
7150
7156
  const X = [".fbx", ".glb", ".gltf"];
7151
7157
  let j = !1;
7152
- for (const K of X)
7158
+ for (const _ of X)
7153
7159
  try {
7154
- a.current.playAnimation(S + K, null, 10, 0, 0.01, N), console.log("Playing animation:", S + K), j = !0;
7160
+ a.current.playAnimation(S + _, null, 10, 0, 0.01, N), console.log("Playing animation:", S + _), j = !0;
7155
7161
  break;
7156
7162
  } catch {
7157
- console.log(`Failed to play ${S}${K}, trying next format...`);
7163
+ console.log(`Failed to play ${S}${_}, trying next format...`);
7158
7164
  }
7159
7165
  if (!j) {
7160
7166
  console.warn("Animation system not available or animation not found:", S);
7161
7167
  try {
7162
7168
  a.current.setBodyMovement("idle"), console.log("Fallback to idle animation");
7163
- } catch (K) {
7164
- console.warn("Fallback animation also failed:", K);
7169
+ } catch (_) {
7170
+ console.warn("Fallback animation also failed:", _);
7165
7171
  }
7166
7172
  }
7167
7173
  }
@@ -7170,7 +7176,7 @@ const ut = Ie(({
7170
7176
  }, []);
7171
7177
  return Le(l, () => ({
7172
7178
  speakText: R,
7173
- stopSpeaking: M,
7179
+ stopSpeaking: T,
7174
7180
  setMood: P,
7175
7181
  setTimingAdjustment: ee,
7176
7182
  playAnimation: re,
@@ -7321,7 +7327,7 @@ const ct = Ie(({
7321
7327
  animations: e,
7322
7328
  lipsyncLang: "en"
7323
7329
  });
7324
- me(() => {
7330
+ pe(() => {
7325
7331
  c.current = {
7326
7332
  onLessonStart: n,
7327
7333
  onLessonComplete: i,
@@ -7329,7 +7335,7 @@ const ct = Ie(({
7329
7335
  onCurriculumComplete: o,
7330
7336
  onCustomAction: l
7331
7337
  };
7332
- }, [n, i, s, o, l]), me(() => {
7338
+ }, [n, i, s, o, l]), pe(() => {
7333
7339
  H.current = O?.curriculum || {
7334
7340
  title: "Default Curriculum",
7335
7341
  description: "No curriculum data provided",
@@ -7350,7 +7356,7 @@ const ct = Ie(({
7350
7356
  lipsyncLang: "en"
7351
7357
  };
7352
7358
  }, [O, t, e]);
7353
- const R = T(() => (H.current || { modules: [] }).modules[r.current.currentModuleIndex]?.lessons[r.current.currentLessonIndex], []), M = T(() => R()?.questions[r.current.currentQuestionIndex], [R]), P = T((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, []), ee = T(() => {
7359
+ const R = E(() => (H.current || { modules: [] }).modules[r.current.currentModuleIndex]?.lessons[r.current.currentLessonIndex], []), T = E(() => R()?.questions[r.current.currentQuestionIndex], [R]), P = E((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, []), ee = E(() => {
7354
7360
  r.current.lessonCompleted = !0, r.current.isQuestionMode = !1;
7355
7361
  const b = r.current.totalQuestions > 0 ? Math.round(r.current.score / r.current.totalQuestions * 100) : 100;
7356
7362
  let v = "Congratulations! You've completed this lesson";
@@ -7374,7 +7380,7 @@ const ct = Ie(({
7374
7380
  } catch {
7375
7381
  h.current.playCelebration();
7376
7382
  }
7377
- const w = H.current || { modules: [] }, C = w.modules[r.current.currentModuleIndex], V = r.current.currentLessonIndex < (C?.lessons?.length || 0) - 1, ne = r.current.currentModuleIndex < (w.modules?.length || 0) - 1, ie = V || ne, fe = z.current || { lipsyncLang: "en" };
7383
+ const w = H.current || { modules: [] }, C = w.modules[r.current.currentModuleIndex], W = r.current.currentLessonIndex < (C?.lessons?.length || 0) - 1, ne = r.current.currentModuleIndex < (w.modules?.length || 0) - 1, ie = W || ne, fe = z.current || { lipsyncLang: "en" };
7378
7384
  h.current.speakText(v, {
7379
7385
  lipsyncLang: fe.lipsyncLang,
7380
7386
  onSpeechEnd: () => {
@@ -7390,7 +7396,7 @@ const ct = Ie(({
7390
7396
  }
7391
7397
  });
7392
7398
  }
7393
- }, [e.lessonComplete]), re = T(() => {
7399
+ }, [e.lessonComplete]), re = E(() => {
7394
7400
  r.current.curriculumCompleted = !0;
7395
7401
  const b = H.current || { modules: [] };
7396
7402
  if (c.current.onCurriculumComplete({
@@ -7406,10 +7412,10 @@ const ct = Ie(({
7406
7412
  const v = z.current || { lipsyncLang: "en" };
7407
7413
  h.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 });
7408
7414
  }
7409
- }, [e.curriculumComplete]), S = T(() => {
7415
+ }, [e.curriculumComplete]), S = E(() => {
7410
7416
  const b = R();
7411
7417
  r.current.isQuestionMode = !0, r.current.currentQuestionIndex = 0, r.current.totalQuestions = b?.questions?.length || 0, r.current.score = 0;
7412
- const v = M();
7418
+ const v = T();
7413
7419
  v && c.current.onCustomAction({
7414
7420
  type: "questionStart",
7415
7421
  moduleIndex: r.current.currentModuleIndex,
@@ -7424,8 +7430,8 @@ const ct = Ie(({
7424
7430
  if (h.current.setMood("happy"), e.questionStart)
7425
7431
  try {
7426
7432
  h.current.playAnimation(e.questionStart, !0);
7427
- } catch (V) {
7428
- console.warn("Failed to play questionStart animation:", V);
7433
+ } catch (W) {
7434
+ console.warn("Failed to play questionStart animation:", W);
7429
7435
  }
7430
7436
  const C = z.current || { lipsyncLang: "en" };
7431
7437
  v.type === "code_test" ? h.current.speakText(`Let's test your coding skills! Here's your first challenge: ${v.question}`, { lipsyncLang: C.lipsyncLang }) : v.type === "multiple_choice" ? h.current.speakText(`Now let me ask you some questions. Here's the first one: ${v.question}`, { lipsyncLang: C.lipsyncLang }) : v.type === "true_false" ? h.current.speakText(`Let's start with some true or false questions. First question: ${v.question}`, { lipsyncLang: C.lipsyncLang }) : h.current.speakText(`Now let me ask you some questions. Here's the first one: ${v.question}`, { lipsyncLang: C.lipsyncLang });
@@ -7443,11 +7449,11 @@ const ct = Ie(({
7443
7449
  clearInterval(C);
7444
7450
  }, 5e3);
7445
7451
  }
7446
- }, [e.questionStart, R, M]), N = T(() => {
7452
+ }, [e.questionStart, R, T]), N = E(() => {
7447
7453
  const b = R();
7448
7454
  if (r.current.currentQuestionIndex < (b?.questions?.length || 0) - 1) {
7449
7455
  h.current && h.current.stopSpeaking && h.current.stopSpeaking(), r.current.currentQuestionIndex += 1;
7450
- const v = M();
7456
+ const v = T();
7451
7457
  v && c.current.onCustomAction({
7452
7458
  type: "nextQuestion",
7453
7459
  moduleIndex: r.current.currentModuleIndex,
@@ -7462,8 +7468,8 @@ const ct = Ie(({
7462
7468
  if (h.current.setMood("happy"), h.current.setBodyMovement("idle"), e.nextQuestion)
7463
7469
  try {
7464
7470
  h.current.playAnimation(e.nextQuestion, !0);
7465
- } catch (V) {
7466
- console.warn("Failed to play nextQuestion animation:", V);
7471
+ } catch (W) {
7472
+ console.warn("Failed to play nextQuestion animation:", W);
7467
7473
  }
7468
7474
  const C = z.current || { lipsyncLang: "en" };
7469
7475
  v.type === "code_test" ? h.current.speakText(`Great! Now let's move on to your next coding challenge: ${v.question}`, {
@@ -7494,11 +7500,11 @@ const ct = Ie(({
7494
7500
  totalQuestions: r.current.totalQuestions,
7495
7501
  score: r.current.score
7496
7502
  });
7497
- }, [e.nextQuestion, R, M]), Z = T(() => {
7503
+ }, [e.nextQuestion, R, T]), Z = E(() => {
7498
7504
  const b = H.current || { modules: [] }, v = b.modules[r.current.currentModuleIndex];
7499
7505
  if (r.current.currentLessonIndex < (v?.lessons?.length || 0) - 1) {
7500
7506
  r.current.currentLessonIndex += 1, r.current.currentQuestionIndex = 0, r.current.lessonCompleted = !1, r.current.isQuestionMode = !1, r.current.isTeaching = !1, r.current.score = 0, r.current.totalQuestions = 0;
7501
- const C = b.modules[r.current.currentModuleIndex], V = r.current.currentLessonIndex < (C?.lessons?.length || 0) - 1, ne = r.current.currentModuleIndex < (b.modules?.length || 0) - 1, ie = V || ne;
7507
+ const C = b.modules[r.current.currentModuleIndex], W = r.current.currentLessonIndex < (C?.lessons?.length || 0) - 1, ne = r.current.currentModuleIndex < (b.modules?.length || 0) - 1, ie = W || ne;
7502
7508
  c.current.onCustomAction({
7503
7509
  type: "lessonStart",
7504
7510
  moduleIndex: r.current.currentModuleIndex,
@@ -7511,7 +7517,7 @@ const ct = Ie(({
7511
7517
  }), h.current && (h.current.setMood("happy"), h.current.setBodyMovement("idle"));
7512
7518
  } else if (r.current.currentModuleIndex < (b.modules?.length || 0) - 1) {
7513
7519
  r.current.currentModuleIndex += 1, r.current.currentLessonIndex = 0, r.current.currentQuestionIndex = 0, r.current.lessonCompleted = !1, r.current.isQuestionMode = !1, r.current.isTeaching = !1, r.current.score = 0, r.current.totalQuestions = 0;
7514
- const V = b.modules[r.current.currentModuleIndex], ne = r.current.currentLessonIndex < (V?.lessons?.length || 0) - 1, ie = r.current.currentModuleIndex < (b.modules?.length || 0) - 1, fe = ne || ie;
7520
+ const W = b.modules[r.current.currentModuleIndex], ne = r.current.currentLessonIndex < (W?.lessons?.length || 0) - 1, ie = r.current.currentModuleIndex < (b.modules?.length || 0) - 1, fe = ne || ie;
7515
7521
  c.current.onCustomAction({
7516
7522
  type: "lessonStart",
7517
7523
  moduleIndex: r.current.currentModuleIndex,
@@ -7524,12 +7530,12 @@ const ct = Ie(({
7524
7530
  }), h.current && (h.current.setMood("happy"), h.current.setBodyMovement("idle"));
7525
7531
  } else
7526
7532
  I.current && I.current();
7527
- }, []), X = T(() => {
7533
+ }, []), X = E(() => {
7528
7534
  const b = R();
7529
7535
  let v = null;
7530
7536
  if (b?.avatar_script && b?.body) {
7531
- const w = b.avatar_script.trim(), C = b.body.trim(), V = w.match(/[.!?]$/) ? " " : ". ";
7532
- v = `${w}${V}${C}`;
7537
+ const w = b.avatar_script.trim(), C = b.body.trim(), W = w.match(/[.!?]$/) ? " " : ". ";
7538
+ v = `${w}${W}${C}`;
7533
7539
  } else
7534
7540
  v = b?.avatar_script || b?.body || null;
7535
7541
  if (h.current && h.current.isReady && v) {
@@ -7538,8 +7544,8 @@ const ct = Ie(({
7538
7544
  if (e.teaching)
7539
7545
  try {
7540
7546
  h.current.playAnimation(e.teaching, !0), w = !0;
7541
- } catch (V) {
7542
- console.warn("Failed to play teaching animation:", V);
7547
+ } catch (W) {
7548
+ console.warn("Failed to play teaching animation:", W);
7543
7549
  }
7544
7550
  w || h.current.setBodyMovement("gesturing");
7545
7551
  const C = z.current || { lipsyncLang: "en" };
@@ -7565,8 +7571,8 @@ const ct = Ie(({
7565
7571
  }
7566
7572
  });
7567
7573
  }
7568
- }, [e.teaching, R]), j = T((b) => {
7569
- const v = M(), w = P(b, v);
7574
+ }, [e.teaching, R]), j = E((b) => {
7575
+ const v = T(), w = P(b, v);
7570
7576
  if (w && (r.current.score += 1), c.current.onQuestionAnswer({
7571
7577
  moduleIndex: r.current.currentModuleIndex,
7572
7578
  lessonIndex: r.current.currentLessonIndex,
@@ -7583,9 +7589,9 @@ const ct = Ie(({
7583
7589
  h.current.setBodyMovement("happy");
7584
7590
  }
7585
7591
  h.current.setBodyMovement("gesturing");
7586
- const C = v.type === "code_test" ? `Great job! Your code passed all the tests! ${v.explanation || ""}` : `Excellent! That's correct! ${v.explanation || ""}`, V = z.current || { lipsyncLang: "en" };
7592
+ const C = v.type === "code_test" ? `Great job! Your code passed all the tests! ${v.explanation || ""}` : `Excellent! That's correct! ${v.explanation || ""}`, W = z.current || { lipsyncLang: "en" };
7587
7593
  h.current.speakText(C, {
7588
- lipsyncLang: V.lipsyncLang,
7594
+ lipsyncLang: W.lipsyncLang,
7589
7595
  onSpeechEnd: () => {
7590
7596
  const ie = R()?.questions?.length || 0;
7591
7597
  c.current.onCustomAction({
@@ -7608,9 +7614,9 @@ const ct = Ie(({
7608
7614
  h.current.setBodyMovement("idle");
7609
7615
  }
7610
7616
  h.current.setBodyMovement("gesturing");
7611
- const C = 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 || ""} Let's move on to the next question.`, V = z.current || { lipsyncLang: "en" };
7617
+ const C = 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 || ""} Let's move on to the next question.`, W = z.current || { lipsyncLang: "en" };
7612
7618
  h.current.speakText(C, {
7613
- lipsyncLang: V.lipsyncLang,
7619
+ lipsyncLang: W.lipsyncLang,
7614
7620
  onSpeechEnd: () => {
7615
7621
  const ie = R()?.questions?.length || 0;
7616
7622
  c.current.onCustomAction({
@@ -7627,21 +7633,21 @@ const ct = Ie(({
7627
7633
  });
7628
7634
  }
7629
7635
  else {
7630
- const V = R()?.questions?.length || 0;
7636
+ const W = R()?.questions?.length || 0;
7631
7637
  c.current.onCustomAction({
7632
7638
  type: "answerFeedbackComplete",
7633
7639
  moduleIndex: r.current.currentModuleIndex,
7634
7640
  lessonIndex: r.current.currentLessonIndex,
7635
7641
  questionIndex: r.current.currentQuestionIndex,
7636
7642
  isCorrect: w,
7637
- hasNextQuestion: r.current.currentQuestionIndex < V - 1,
7643
+ hasNextQuestion: r.current.currentQuestionIndex < W - 1,
7638
7644
  score: r.current.score,
7639
7645
  totalQuestions: r.current.totalQuestions,
7640
7646
  avatarNotReady: !0
7641
7647
  });
7642
7648
  }
7643
- }, [e.correct, e.incorrect, M, R, P]), K = T((b) => {
7644
- const v = M();
7649
+ }, [e.correct, e.incorrect, T, R, P]), _ = E((b) => {
7650
+ const v = T();
7645
7651
  if (!b || typeof b != "object") {
7646
7652
  console.error("Invalid code test result format. Expected object with {passed: boolean, ...}");
7647
7653
  return;
@@ -7668,10 +7674,10 @@ const ct = Ie(({
7668
7674
  testResult: w,
7669
7675
  question: v
7670
7676
  }), p.current && p.current(w);
7671
- }, [M, P]), te = T(() => {
7677
+ }, [T, P]), te = E(() => {
7672
7678
  if (r.current.currentQuestionIndex > 0) {
7673
7679
  r.current.currentQuestionIndex -= 1;
7674
- const b = M();
7680
+ const b = T();
7675
7681
  b && c.current.onCustomAction({
7676
7682
  type: "questionStart",
7677
7683
  moduleIndex: r.current.currentModuleIndex,
@@ -7702,7 +7708,7 @@ const ct = Ie(({
7702
7708
  }, 5e3);
7703
7709
  }
7704
7710
  }
7705
- }, [M]), ce = T(() => {
7711
+ }, [T]), ce = E(() => {
7706
7712
  const b = H.current || { modules: [] };
7707
7713
  if (b.modules[r.current.currentModuleIndex], r.current.currentLessonIndex > 0)
7708
7714
  r.current.currentLessonIndex -= 1, r.current.currentQuestionIndex = 0, r.current.lessonCompleted = !1, r.current.isQuestionMode = !1, r.current.isTeaching = !1, r.current.score = 0, r.current.totalQuestions = 0, c.current.onCustomAction({
@@ -7726,9 +7732,9 @@ const ct = Ie(({
7726
7732
  lesson: R()
7727
7733
  }), h.current && (h.current.setMood("happy"), h.current.setBodyMovement("idle"));
7728
7734
  }
7729
- }, [R]), oe = T(() => {
7735
+ }, [R]), oe = E(() => {
7730
7736
  r.current.currentModuleIndex = 0, r.current.currentLessonIndex = 0, r.current.currentQuestionIndex = 0, r.current.isTeaching = !1, r.current.isQuestionMode = !1, r.current.lessonCompleted = !1, r.current.curriculumCompleted = !1, r.current.score = 0, r.current.totalQuestions = 0;
7731
- }, []), pe = T((b) => {
7737
+ }, []), de = E((b) => {
7732
7738
  console.log("Avatar is ready!", b);
7733
7739
  const v = R(), w = v?.avatar_script || v?.body;
7734
7740
  u && w && setTimeout(() => {
@@ -7742,7 +7748,7 @@ const ct = Ie(({
7742
7748
  startTeaching: X,
7743
7749
  startQuestions: S,
7744
7750
  handleAnswerSelect: j,
7745
- handleCodeTestResult: K,
7751
+ handleCodeTestResult: _,
7746
7752
  nextQuestion: N,
7747
7753
  previousQuestion: te,
7748
7754
  nextLesson: Z,
@@ -7751,7 +7757,7 @@ const ct = Ie(({
7751
7757
  completeCurriculum: re,
7752
7758
  resetCurriculum: oe,
7753
7759
  getState: () => ({ ...r.current }),
7754
- getCurrentQuestion: () => M(),
7760
+ getCurrentQuestion: () => T(),
7755
7761
  getCurrentLesson: () => R(),
7756
7762
  // Direct access to avatar ref (always returns current value)
7757
7763
  getAvatarRef: () => h.current,
@@ -7803,7 +7809,7 @@ const ct = Ie(({
7803
7809
  handleResize: () => h.current?.handleResize(),
7804
7810
  // Avatar readiness check (always returns current value)
7805
7811
  isAvatarReady: () => h.current?.isReady || !1
7806
- }), [X, S, j, K, N, Z, ee, re, oe, M, R]);
7812
+ }), [X, S, j, _, N, Z, ee, re, oe, T, R]);
7807
7813
  const J = z.current || {
7808
7814
  avatarUrl: "/avatars/brunette.glb",
7809
7815
  avatarBody: "F",
@@ -7833,7 +7839,7 @@ const ct = Ie(({
7833
7839
  showFullAvatar: J.showFullAvatar,
7834
7840
  cameraView: "upper",
7835
7841
  animations: J.animations,
7836
- onReady: pe,
7842
+ onReady: de,
7837
7843
  onLoading: () => {
7838
7844
  },
7839
7845
  onError: (b) => {