@sage-rsc/talking-head-react 1.0.46 → 1.0.48

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 Ce, jsx as oe } from "react/jsx-runtime";
2
- import { forwardRef as be, useRef as Y, useState as re, useCallback as E, useEffect as he, useImperativeHandle as Re, useLayoutEffect as Pe } from "react";
2
+ import { forwardRef as be, useRef as X, useState as re, useCallback as E, useEffect as he, useImperativeHandle as Re, useLayoutEffect as Pe } from "react";
3
3
  import * as f from "three";
4
4
  import { OrbitControls as Be } from "three/addons/controls/OrbitControls.js";
5
5
  import { GLTFLoader as De } from "three/addons/loaders/GLTFLoader.js";
@@ -8,11 +8,11 @@ import { FBXLoader as Le } from "three/addons/loaders/FBXLoader.js";
8
8
  import { RoomEnvironment as Ne } from "three/addons/environments/RoomEnvironment.js";
9
9
  import Ue from "three/addons/libs/stats.module.js";
10
10
  let m, Q, J;
11
- const A = [0, 0, 0, 0], k = new f.Vector3(), me = new f.Vector3(), Z = new f.Vector3(), pe = new f.Vector3();
11
+ const A = [0, 0, 0, 0], k = new f.Vector3(), me = new f.Vector3(), G = new f.Vector3(), pe = new f.Vector3();
12
12
  new f.Plane();
13
13
  new f.Ray();
14
14
  new f.Euler();
15
- const X = new f.Quaternion(), Se = new f.Quaternion(), ee = new f.Matrix4(), te = new f.Matrix4();
15
+ const Z = new f.Quaternion(), Se = new f.Quaternion(), ee = new f.Matrix4(), te = new f.Matrix4();
16
16
  new f.Vector3();
17
17
  const ge = new f.Vector3(0, 0, 1), We = new f.Vector3(1, 0, 0), Ve = new f.Vector3(0, 1, 0), Ge = new f.Vector3(0, 0, 1);
18
18
  class Ze {
@@ -338,7 +338,7 @@ class Ze {
338
338
  ea: [0, 0, 0, 0]
339
339
  // External acceleration [m/s^2]
340
340
  };
341
- u.boneParent.matrixWorld.decompose(k, X, Z), k.copy(ge).applyQuaternion(X).setY(0).normalize(), X.premultiply(Se.setFromUnitVectors(ge, k).invert()).normalize(), u.qWorldInverseYaw = X.clone().normalize(), this.data.push(u), this.dict[h] = u;
341
+ u.boneParent.matrixWorld.decompose(k, Z, G), k.copy(ge).applyQuaternion(Z).setY(0).normalize(), Z.premultiply(Se.setFromUnitVectors(ge, k).invert()).normalize(), u.qWorldInverseYaw = Z.clone().normalize(), this.data.push(u), this.dict[h] = u;
342
342
  try {
343
343
  this.setValue(h, "type", s.type), this.setValue(h, "stiffness", s.stiffness), this.setValue(h, "damping", s.damping), this.setValue(h, "external", s.external), this.setValue(h, "limits", s.limits), this.setValue(h, "excludes", s.excludes), this.setValue(h, "deltaLocal", s.deltaLocal), this.setValue(h, "deltaWorld", s.deltaWorld), this.setValue(h, "pivot", s.pivot), this.setValue(h, "helper", s.helper);
344
344
  } catch (l) {
@@ -369,9 +369,9 @@ class Ze {
369
369
  o.vBasis.y + A[1],
370
370
  o.vBasis.z - A[2]
371
371
  );
372
- else if (o.boneParent.quaternion.copy(o.qBasis), o.pivot && this.opt.isPivots && (o.boneParent.updateWorldMatrix(!1, !1), o.boneParent.matrixWorld.decompose(k, X, Z), k.copy(ge).applyQuaternion(X).setY(0).normalize(), X.premultiply(Se.setFromUnitVectors(ge, k).invert()).normalize(), o.boneParent.quaternion.multiply(X.invert()), o.boneParent.quaternion.multiply(o.qWorldInverseYaw)), o.isZ && (m = Math.atan(A[0] / o.l), X.setFromAxisAngle(Ge, -m), o.boneParent.quaternion.multiply(X)), 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), X.setFromAxisAngle(We, -m), o.boneParent.quaternion.multiply(X)), o.isT && (m = 1.5 * Math.tanh(A[3] * 1.5), X.setFromAxisAngle(Ve, -m), o.boneParent.quaternion.multiply(X)), o.boneParent.updateWorldMatrix(!1, !0), o.excludes && this.opt.isExcludes)
372
+ else if (o.boneParent.quaternion.copy(o.qBasis), o.pivot && this.opt.isPivots && (o.boneParent.updateWorldMatrix(!1, !1), o.boneParent.matrixWorld.decompose(k, Z, G), k.copy(ge).applyQuaternion(Z).setY(0).normalize(), Z.premultiply(Se.setFromUnitVectors(ge, k).invert()).normalize(), o.boneParent.quaternion.multiply(Z.invert()), o.boneParent.quaternion.multiply(o.qWorldInverseYaw)), o.isZ && (m = Math.atan(A[0] / o.l), Z.setFromAxisAngle(Ge, -m), o.boneParent.quaternion.multiply(Z)), 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), Z.setFromAxisAngle(We, -m), o.boneParent.quaternion.multiply(Z)), o.isT && (m = 1.5 * Math.tanh(A[3] * 1.5), Z.setFromAxisAngle(Ve, -m), o.boneParent.quaternion.multiply(Z)), o.boneParent.updateWorldMatrix(!1, !0), o.excludes && this.opt.isExcludes)
373
373
  for (i = 0, s = o.excludes.length; i < s; i++)
374
- m = o.excludes[i], Z.set(0, 0, 0), m.deltaLocal && (Z.x += m.deltaLocal[0], Z.y += m.deltaLocal[1], Z.z += m.deltaLocal[2]), Z.applyMatrix4(m.bone.matrixWorld), te.copy(o.boneParent.matrixWorld).invert(), Z.applyMatrix4(te), k.copy(o.bone.position), !(k.distanceToSquared(Z) >= m.radiusSq) && (J = k.length(), Q = Z.length(), !(Q > m.radius + J) && (Q < Math.abs(m.radius - J) || (Q = (Q * Q + J * J - m.radiusSq) / (2 * Q), Z.normalize(), pe.copy(Z).multiplyScalar(Q), Q = Math.sqrt(J * J - Q * Q), k.subVectors(k, pe).projectOnPlane(Z).normalize().multiplyScalar(Q), me.subVectors(o.vBasis, pe).projectOnPlane(Z).normalize(), J = me.dot(k), J < 0 && (J = Math.sqrt(Q * Q - J * J), me.multiplyScalar(J), k.add(me)), k.add(pe).normalize(), Z.copy(o.bone.position).normalize(), X.setFromUnitVectors(Z, k), o.boneParent.quaternion.premultiply(X), o.boneParent.updateWorldMatrix(!1, !0))));
374
+ m = o.excludes[i], G.set(0, 0, 0), m.deltaLocal && (G.x += m.deltaLocal[0], G.y += m.deltaLocal[1], G.z += m.deltaLocal[2]), G.applyMatrix4(m.bone.matrixWorld), te.copy(o.boneParent.matrixWorld).invert(), G.applyMatrix4(te), k.copy(o.bone.position), !(k.distanceToSquared(G) >= m.radiusSq) && (J = k.length(), Q = G.length(), !(Q > m.radius + J) && (Q < Math.abs(m.radius - J) || (Q = (Q * Q + J * J - m.radiusSq) / (2 * Q), G.normalize(), pe.copy(G).multiplyScalar(Q), Q = Math.sqrt(J * J - Q * Q), k.subVectors(k, pe).projectOnPlane(G).normalize().multiplyScalar(Q), me.subVectors(o.vBasis, pe).projectOnPlane(G).normalize(), J = me.dot(k), J < 0 && (J = Math.sqrt(Q * Q - J * J), me.multiplyScalar(J), k.add(me)), k.add(pe).normalize(), G.copy(o.bone.position).normalize(), Z.setFromUnitVectors(G, k), o.boneParent.quaternion.premultiply(Z), o.boneParent.updateWorldMatrix(!1, !0))));
375
375
  }
376
376
  this.helpers.isActive && this.updateHelpers();
377
377
  }
@@ -608,8 +608,8 @@ class Xe {
608
608
  for (let l = 0; l < n / 2; l++) {
609
609
  const c = i[(h + l) * 2], d = i[(h + l) * 2 + 1], g = i[(h + l + n / 2) * 2] * a - i[(h + l + n / 2) * 2 + 1] * u, y = i[(h + l + n / 2) * 2] * u + i[(h + l + n / 2) * 2 + 1] * a;
610
610
  i[(h + l) * 2] = c + g, i[(h + l) * 2 + 1] = d + y, i[(h + l + n / 2) * 2] = c - g, i[(h + l + n / 2) * 2 + 1] = d - y;
611
- const x = a * o - u * r, v = a * r + u * o;
612
- a = x, u = v;
611
+ const x = a * o - u * r, I = a * r + u * o;
612
+ a = x, u = I;
613
613
  }
614
614
  }
615
615
  }
@@ -4204,13 +4204,13 @@ class He {
4204
4204
  const l = s.morphTargetDictionary[a], c = o.morphAttributes.position[l], d = o.morphAttributes.normal?.[l];
4205
4205
  r || (r = new f.Float32BufferAttribute(c.count * 3, 3), d && (h = new f.Float32BufferAttribute(c.count * 3, 3)));
4206
4206
  for (let g = 0; g < c.count; g++) {
4207
- const y = r.getX(g) + c.getX(g) * u, x = r.getY(g) + c.getY(g) * u, v = r.getZ(g) + c.getZ(g) * u;
4208
- r.setXYZ(g, y, x, v);
4207
+ const y = r.getX(g) + c.getX(g) * u, x = r.getY(g) + c.getY(g) * u, I = r.getZ(g) + c.getZ(g) * u;
4208
+ r.setXYZ(g, y, x, I);
4209
4209
  }
4210
4210
  if (d)
4211
4211
  for (let g = 0; g < c.count; g++) {
4212
- const y = h.getX(g) + d.getX(g) * u, x = h.getY(g) + d.getY(g) * u, v = h.getZ(g) + d.getZ(g) * u;
4213
- h.setXYZ(g, y, x, v);
4212
+ const y = h.getX(g) + d.getX(g) * u, x = h.getY(g) + d.getY(g) * u, I = h.getZ(g) + d.getZ(g) * u;
4213
+ h.setXYZ(g, y, x, I);
4214
4214
  }
4215
4215
  }
4216
4216
  if (r) {
@@ -5251,10 +5251,10 @@ class He {
5251
5251
  let u = "", l = "", c = 0, d = [], g = [];
5252
5252
  const y = Array.from(this.segmenter.segment(t), (x) => x.segment);
5253
5253
  for (let x = 0; x < y.length; x++) {
5254
- const v = x === y.length - 1, T = y[x].match(r);
5254
+ const I = x === y.length - 1, T = y[x].match(r);
5255
5255
  let p = y[x].match(s);
5256
5256
  const F = y[x].match(h), C = y[x].match(o);
5257
- if (p && !v && !F && y[x + 1].match(s) && (p = !1), i && (u += y[x]), T && (!n || n.every((I) => x < I[0] || x > I[1])) && (l += y[x]), (C || p || v) && (l.length && (l = this.lipsyncPreProcessText(l, a), l.length && d.push({
5257
+ if (p && !I && !F && y[x + 1].match(s) && (p = !1), i && (u += y[x]), T && (!n || n.every((R) => x < R[0] || x > R[1])) && (l += y[x]), (C || p || I) && (l.length && (l = this.lipsyncPreProcessText(l, a), l.length && d.push({
5258
5258
  mark: c,
5259
5259
  word: l
5260
5260
  })), u.length && (g.push({
@@ -5265,31 +5265,31 @@ class He {
5265
5265
  subtitles: [u]
5266
5266
  }
5267
5267
  }), u = ""), l.length)) {
5268
- const I = this.lipsyncWordsToVisemes(l, a);
5269
- if (I && I.visemes && I.visemes.length) {
5270
- const O = I.times[I.visemes.length - 1] + I.durations[I.visemes.length - 1];
5271
- for (let B = 0; B < I.visemes.length; B++)
5268
+ const R = this.lipsyncWordsToVisemes(l, a);
5269
+ if (R && R.visemes && R.visemes.length) {
5270
+ const O = R.times[R.visemes.length - 1] + R.durations[R.visemes.length - 1];
5271
+ for (let B = 0; B < R.visemes.length; B++)
5272
5272
  g.push({
5273
5273
  mark: c,
5274
5274
  template: { name: "viseme" },
5275
- ts: [(I.times[B] - 0.6) / O, (I.times[B] + 0.5) / O, (I.times[B] + I.durations[B] + 0.5) / O],
5275
+ ts: [(R.times[B] - 0.6) / O, (R.times[B] + 0.5) / O, (R.times[B] + R.durations[B] + 0.5) / O],
5276
5276
  vs: {
5277
- ["viseme_" + I.visemes[B]]: [null, I.visemes[B] === "PP" || I.visemes[B] === "FF" ? 0.9 : 0.6, 0]
5277
+ ["viseme_" + R.visemes[B]]: [null, R.visemes[B] === "PP" || R.visemes[B] === "FF" ? 0.9 : 0.6, 0]
5278
5278
  }
5279
5279
  });
5280
5280
  }
5281
5281
  l = "", c++;
5282
5282
  }
5283
- if (p || v) {
5284
- if (d.length || v && g.length) {
5285
- const I = {
5283
+ if (p || I) {
5284
+ if (d.length || I && g.length) {
5285
+ const R = {
5286
5286
  anim: g
5287
5287
  };
5288
- i && (I.onSubtitles = i), d.length && !e.avatarMute && (I.text = d, e.avatarMood && (I.mood = e.avatarMood), e.ttsLang && (I.lang = e.ttsLang), e.ttsVoice && (I.voice = e.ttsVoice), e.ttsRate && (I.rate = e.ttsRate), e.ttsVoice && (I.pitch = e.ttsPitch), e.ttsVolume && (I.volume = e.ttsVolume)), this.speechQueue.push(I), d = [], l = "", c = 0, g = [];
5288
+ i && (R.onSubtitles = i), d.length && !e.avatarMute && (R.text = d, e.avatarMood && (R.mood = e.avatarMood), e.ttsLang && (R.lang = e.ttsLang), e.ttsVoice && (R.voice = e.ttsVoice), e.ttsRate && (R.rate = e.ttsRate), e.ttsVoice && (R.pitch = e.ttsPitch), e.ttsVolume && (R.volume = e.ttsVolume)), this.speechQueue.push(R), d = [], l = "", c = 0, g = [];
5289
5289
  }
5290
5290
  if (F) {
5291
- let I = this.animEmojis[y[x]];
5292
- I && I.link && (I = this.animEmojis[I.link]), I && this.speechQueue.push({ emoji: I });
5291
+ let R = this.animEmojis[y[x]];
5292
+ R && R.link && (R = this.animEmojis[R.link]), R && this.speechQueue.push({ emoji: R });
5293
5293
  }
5294
5294
  this.speechQueue.push({ break: 100 });
5295
5295
  }
@@ -5385,10 +5385,10 @@ class He {
5385
5385
  let y = 0.6 + this.convertRange(g, [0, u], [0, 0.4]);
5386
5386
  if (u = Math.min(u, c.visemes.length * 200), d > 0)
5387
5387
  for (let x = 0; x < c.visemes.length; x++) {
5388
- const v = a + c.times[x] / d * u, T = c.durations[x] / d * u;
5388
+ const I = a + c.times[x] / d * u, T = c.durations[x] / d * u;
5389
5389
  o.push({
5390
5390
  template: { name: "viseme" },
5391
- ts: [v - Math.min(60, 2 * T / 3), v + Math.min(25, T / 2), v + T + Math.min(60, T / 2)],
5391
+ ts: [I - Math.min(60, 2 * T / 3), I + Math.min(25, T / 2), I + T + Math.min(60, T / 2)],
5392
5392
  vs: {
5393
5393
  ["viseme_" + c.visemes[x]]: [null, c.visemes[x] === "PP" || c.visemes[x] === "FF" ? 0.9 : y, 0]
5394
5394
  }
@@ -5482,12 +5482,12 @@ class He {
5482
5482
  hasVisemes: x && x.visemes && x.visemes.length > 0,
5483
5483
  estimatedDuration: c
5484
5484
  });
5485
- const v = [];
5485
+ const I = [];
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 F = 0; F < x.visemes.length; F++) {
5489
- const C = x.visemes[F], I = x.times[F] / p, O = x.durations[F] / p, B = I * c, $ = O * c;
5490
- v.push({
5489
+ const C = x.visemes[F], R = x.times[F] / p, O = x.durations[F] / p, B = R * c, $ = O * c;
5490
+ I.push({
5491
5491
  template: { name: "viseme" },
5492
5492
  ts: [B - Math.min(60, 2 * $ / 3), B + Math.min(25, $ / 2), B + $ + Math.min(60, $ / 2)],
5493
5493
  vs: {
@@ -5496,7 +5496,7 @@ class He {
5496
5496
  });
5497
5497
  }
5498
5498
  }
5499
- const T = [...t.anim, ...v];
5499
+ const T = [...t.anim, ...I];
5500
5500
  this.audioPlaylist.push({ anim: T, audio: d }), this.onSubtitles = t.onSubtitles || null, this.resetLips(), t.mood && this.setMood(t.mood), this.playAudio(), s.onend = () => {
5501
5501
  e();
5502
5502
  }, s.onerror = (p) => {
@@ -5564,8 +5564,8 @@ class He {
5564
5564
  const d = e.toLowerCase().split(/\s+/), g = [];
5565
5565
  for (const y of d)
5566
5566
  for (const x of y) {
5567
- let v = "aa";
5568
- "aeiou".includes(x) ? v = "aa" : "bp".includes(x) ? v = "PP" : "fv".includes(x) ? v = "FF" : "st".includes(x) ? v = "SS" : "dln".includes(x) ? v = "DD" : "kg".includes(x) ? v = "kk" : "rw".includes(x) && (v = "RR"), g.push(v);
5567
+ let I = "aa";
5568
+ "aeiou".includes(x) ? I = "aa" : "bp".includes(x) ? I = "PP" : "fv".includes(x) ? I = "FF" : "st".includes(x) ? I = "SS" : "dln".includes(x) ? I = "DD" : "kg".includes(x) ? I = "kk" : "rw".includes(x) && (I = "RR"), g.push(I);
5569
5569
  }
5570
5570
  a = {
5571
5571
  visemes: g.map((y, x) => ({
@@ -5662,8 +5662,8 @@ class He {
5662
5662
  const d = e.toLowerCase().split(/\s+/), g = [];
5663
5663
  for (const y of d)
5664
5664
  for (const x of y) {
5665
- let v = "aa";
5666
- "aeiou".includes(x) ? v = "aa" : "bp".includes(x) ? v = "PP" : "fv".includes(x) ? v = "FF" : "st".includes(x) ? v = "SS" : "dln".includes(x) ? v = "DD" : "kg".includes(x) ? v = "kk" : "rw".includes(x) && (v = "RR"), g.push(v);
5665
+ let I = "aa";
5666
+ "aeiou".includes(x) ? I = "aa" : "bp".includes(x) ? I = "PP" : "fv".includes(x) ? I = "FF" : "st".includes(x) ? I = "SS" : "dln".includes(x) ? I = "DD" : "kg".includes(x) ? I = "kk" : "rw".includes(x) && (I = "RR"), g.push(I);
5667
5667
  }
5668
5668
  a = {
5669
5669
  visemes: g.map((y, x) => ({
@@ -6153,7 +6153,7 @@ class He {
6153
6153
  M.setFromQuaternion(h, "YXZ");
6154
6154
  let a = M.x / (40 / 24) + 0.2, u = M.y / (9 / 4), l = Math.min(0.6, Math.max(-0.3, a)), c = Math.min(0.8, Math.max(-0.8, u)), d = (Math.random() - 0.5) / 4, g = (Math.random() - 0.5) / 4;
6155
6155
  if (t) {
6156
- let y = this.animQueue.findIndex((v) => v.template.name === "lookat");
6156
+ let y = this.animQueue.findIndex((I) => I.template.name === "lookat");
6157
6157
  y !== -1 && this.animQueue.splice(y, 1);
6158
6158
  const x = {
6159
6159
  name: "lookat",
@@ -6187,18 +6187,18 @@ class He {
6187
6187
  r.project(this.camera);
6188
6188
  let h = (r.x + 1) / 2 * n.width + n.left, a = -(r.y - 1) / 2 * n.height + n.top;
6189
6189
  t === null && (t = h), e === null && (e = a), N.copy(this.armature.quaternion), N.multiply(this.poseTarget.props["Hips.quaternion"]), N.multiply(this.poseTarget.props["Spine.quaternion"]), N.multiply(this.poseTarget.props["Spine1.quaternion"]), N.multiply(this.poseTarget.props["Spine2.quaternion"]), N.multiply(this.poseTarget.props["Neck.quaternion"]), N.multiply(this.poseTarget.props["Head.quaternion"]), M.setFromQuaternion(N);
6190
- let u = M.x / (40 / 24), l = M.y / (9 / 4), c = Math.min(0.4, Math.max(-0.4, this.camera.rotation.x)), d = Math.min(0.4, Math.max(-0.4, this.camera.rotation.y)), g = Math.max(window.innerWidth - h, h), y = Math.max(window.innerHeight - a, a), x = this.convertRange(e, [a - y, a + y], [-0.3, 0.6]) - u + c, v = this.convertRange(t, [h - g, h + g], [-0.8, 0.8]) - l + d;
6191
- x = Math.min(0.6, Math.max(-0.3, x)), v = Math.min(0.8, Math.max(-0.8, v));
6190
+ let u = M.x / (40 / 24), l = M.y / (9 / 4), c = Math.min(0.4, Math.max(-0.4, this.camera.rotation.x)), d = Math.min(0.4, Math.max(-0.4, this.camera.rotation.y)), g = Math.max(window.innerWidth - h, h), y = Math.max(window.innerHeight - a, a), x = this.convertRange(e, [a - y, a + y], [-0.3, 0.6]) - u + c, I = this.convertRange(t, [h - g, h + g], [-0.8, 0.8]) - l + d;
6191
+ x = Math.min(0.6, Math.max(-0.3, x)), I = Math.min(0.8, Math.max(-0.8, I));
6192
6192
  let T = (Math.random() - 0.5) / 4, p = (Math.random() - 0.5) / 4;
6193
6193
  if (i) {
6194
- let F = this.animQueue.findIndex((I) => I.template.name === "lookat");
6194
+ let F = this.animQueue.findIndex((R) => R.template.name === "lookat");
6195
6195
  F !== -1 && this.animQueue.splice(F, 1);
6196
6196
  const C = {
6197
6197
  name: "lookat",
6198
6198
  dt: [750, i],
6199
6199
  vs: {
6200
6200
  bodyRotateX: [x + T],
6201
- bodyRotateY: [v + p],
6201
+ bodyRotateY: [I + p],
6202
6202
  eyesRotateX: [-3 * T + 0.1],
6203
6203
  eyesRotateY: [-5 * p],
6204
6204
  browInnerUp: [[0, 0.7]],
@@ -6433,8 +6433,8 @@ class He {
6433
6433
  y.name = y.name.replaceAll("mixamorig", "");
6434
6434
  const x = y.name.split(".");
6435
6435
  if (x[1] === "position") {
6436
- for (let v = 0; v < y.values.length; v++)
6437
- y.values[v] = y.values[v] * s;
6436
+ for (let I = 0; I < y.values.length; I++)
6437
+ y.values[I] = y.values[I] * s;
6438
6438
  d[y.name] = new f.Vector3(y.values[0], y.values[1], y.values[2]);
6439
6439
  } else x[1] === "quaternion" ? d[y.name] = new f.Quaternion(y.values[0], y.values[1], y.values[2], y.values[3]) : x[1] === "rotation" && (d[x[0] + ".quaternion"] = new f.Quaternion().setFromEuler(new f.Euler(y.values[0], y.values[1], y.values[2], "XYZ")).normalize());
6440
6440
  });
@@ -6535,7 +6535,7 @@ class He {
6535
6535
  const c = [];
6536
6536
  for (let y = 1; y < r.ts.length; y++) c.push(r.ts[y] - r.ts[y - 1]);
6537
6537
  const d = o.template?.rescale || c.map((y) => y / u), g = e * 1e3 - u;
6538
- r.ts = r.ts.map((y, x, v) => x === 0 ? h : v[x - 1] + c[x - 1] + d[x - 1] * g);
6538
+ r.ts = r.ts.map((y, x, I) => x === 0 ? h : I[x - 1] + c[x - 1] + d[x - 1] * g);
6539
6539
  } else {
6540
6540
  const c = e * 1e3 / u;
6541
6541
  r.ts = r.ts.map((d) => h + c * (d - h));
@@ -6571,18 +6571,18 @@ class He {
6571
6571
  const s = new f.Vector3(), o = new f.Vector3(), r = new f.Vector3(), h = new f.Vector3(), a = new f.Quaternion(), u = new f.Vector3(), l = new f.Vector3(), c = new f.Vector3(), d = this.ikMesh.getObjectByName(t.root);
6572
6572
  d.position.setFromMatrixPosition(this.armature.getObjectByName(t.root).matrixWorld), d.quaternion.setFromRotationMatrix(this.armature.getObjectByName(t.root).matrixWorld), e && i && e.applyQuaternion(this.armature.quaternion).add(d.position);
6573
6573
  const g = this.ikMesh.getObjectByName(t.effector), y = t.links;
6574
- y.forEach((v) => {
6575
- v.bone = this.ikMesh.getObjectByName(v.link), v.bone.quaternion.copy(this.getPoseTemplateProp(v.link + ".quaternion"));
6574
+ y.forEach((I) => {
6575
+ I.bone = this.ikMesh.getObjectByName(I.link), I.bone.quaternion.copy(this.getPoseTemplateProp(I.link + ".quaternion"));
6576
6576
  }), d.updateMatrixWorld(!0);
6577
6577
  const x = t.iterations || 10;
6578
6578
  if (e)
6579
- for (let v = 0; v < x; v++) {
6579
+ for (let I = 0; I < x; I++) {
6580
6580
  let T = !1;
6581
6581
  for (let p = 0, F = y.length; p < F; p++) {
6582
6582
  const C = y[p].bone;
6583
6583
  C.matrixWorld.decompose(h, a, u), a.invert(), o.setFromMatrixPosition(g.matrixWorld), r.subVectors(o, h), r.applyQuaternion(a), r.normalize(), s.subVectors(e, h), s.applyQuaternion(a), s.normalize();
6584
- let I = s.dot(r);
6585
- I > 1 ? I = 1 : I < -1 && (I = -1), I = Math.acos(I), !(I < 1e-5) && (y[p].minAngle !== void 0 && I < y[p].minAngle && (I = y[p].minAngle), y[p].maxAngle !== void 0 && I > y[p].maxAngle && (I = y[p].maxAngle), l.crossVectors(r, s), l.normalize(), N.setFromAxisAngle(l, I), C.quaternion.multiply(N), C.rotation.setFromVector3(c.setFromEuler(C.rotation).clamp(new f.Vector3(
6584
+ let R = s.dot(r);
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), l.crossVectors(r, s), l.normalize(), N.setFromAxisAngle(l, R), C.quaternion.multiply(N), C.rotation.setFromVector3(c.setFromEuler(C.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
@@ -6594,8 +6594,8 @@ class He {
6594
6594
  }
6595
6595
  if (!T) break;
6596
6596
  }
6597
- n && y.forEach((v) => {
6598
- this.poseTarget.props[v.link + ".quaternion"].copy(v.bone.quaternion), this.poseTarget.props[v.link + ".quaternion"].t = this.animClock, this.poseTarget.props[v.link + ".quaternion"].d = n;
6597
+ n && y.forEach((I) => {
6598
+ this.poseTarget.props[I.link + ".quaternion"].copy(I.bone.quaternion), this.poseTarget.props[I.link + ".quaternion"].t = this.animClock, this.poseTarget.props[I.link + ".quaternion"].d = n;
6599
6599
  });
6600
6600
  }
6601
6601
  /**
@@ -6684,8 +6684,8 @@ const Te = be(({
6684
6684
  className: g = "",
6685
6685
  style: y = {},
6686
6686
  animations: x = {}
6687
- }, v) => {
6688
- const T = Y(null), p = Y(null), [F, C] = re(!0), [I, O] = re(null), [B, $] = re(!1), j = ve(), S = n || j.service;
6687
+ }, I) => {
6688
+ const T = X(null), p = X(null), [F, C] = re(!0), [R, O] = re(null), [B, $] = re(!1), Y = ve(), S = n || Y.service;
6689
6689
  let P;
6690
6690
  S === "browser" ? P = {
6691
6691
  service: "browser",
@@ -6695,19 +6695,19 @@ const Te = be(({
6695
6695
  } : S === "elevenlabs" ? P = {
6696
6696
  service: "elevenlabs",
6697
6697
  endpoint: "https://api.elevenlabs.io/v1/text-to-speech",
6698
- apiKey: o || j.apiKey,
6699
- defaultVoice: s || j.defaultVoice || ae.defaultVoice,
6700
- voices: j.voices || ae.voices
6698
+ apiKey: o || Y.apiKey,
6699
+ defaultVoice: s || Y.defaultVoice || ae.defaultVoice,
6700
+ voices: Y.voices || ae.voices
6701
6701
  } : S === "deepgram" ? P = {
6702
6702
  service: "deepgram",
6703
6703
  endpoint: "https://api.deepgram.com/v1/speak",
6704
- apiKey: o || j.apiKey,
6705
- defaultVoice: s || j.defaultVoice || ze.defaultVoice,
6706
- voices: j.voices || ze.voices
6704
+ apiKey: o || Y.apiKey,
6705
+ defaultVoice: s || Y.defaultVoice || ze.defaultVoice,
6706
+ voices: Y.voices || ze.voices
6707
6707
  } : P = {
6708
- ...j,
6708
+ ...Y,
6709
6709
  // Override API key if provided via props
6710
- apiKey: o !== null ? o : j.apiKey
6710
+ apiKey: o !== null ? o : Y.apiKey
6711
6711
  };
6712
6712
  const W = {
6713
6713
  url: D,
@@ -6788,11 +6788,11 @@ const Te = be(({
6788
6788
  };
6789
6789
  if (H.onSpeechEnd && p.current) {
6790
6790
  const w = p.current;
6791
- let G = null, se = 0, ue = !1;
6791
+ let j = null, se = 0, ue = !1;
6792
6792
  const Ee = 1200, Fe = 1e4;
6793
6793
  let Ie = 0;
6794
6794
  const fe = setInterval(() => {
6795
- Ie++, w && w.isSpeaking && (w.audioPlaylist && w.audioPlaylist.length > 0 || w.isAudioPlaying === !0) && (ue = !0, clearInterval(fe), G = setInterval(Ae, 50));
6795
+ Ie++, w && w.isSpeaking && (w.audioPlaylist && w.audioPlaylist.length > 0 || w.isAudioPlaying === !0) && (ue = !0, clearInterval(fe), j = setInterval(Ae, 50));
6796
6796
  const de = !w.speechQueue || w.speechQueue.length === 0;
6797
6797
  if (w && !w.isSpeaking && de && (!w.audioPlaylist || w.audioPlaylist.length === 0) && (!w.isAudioPlaying || w.isAudioPlaying === !1)) {
6798
6798
  clearInterval(fe);
@@ -6805,7 +6805,7 @@ const Te = be(({
6805
6805
  }
6806
6806
  if (Ie * 50 > Fe) {
6807
6807
  if (clearInterval(fe), w && w.isSpeaking)
6808
- ue = !0, G = setInterval(Ae, 50);
6808
+ ue = !0, j = setInterval(Ae, 50);
6809
6809
  else if (w && !w.isSpeaking && de && (!w.audioPlaylist || w.audioPlaylist.length === 0) && (!w.isAudioPlaying || w.isAudioPlaying === !1))
6810
6810
  try {
6811
6811
  H.onSpeechEnd();
@@ -6815,7 +6815,7 @@ const Te = be(({
6815
6815
  }
6816
6816
  }, 50), Ae = () => {
6817
6817
  if (se++, se > Ee) {
6818
- G && (clearInterval(G), G = null);
6818
+ j && (clearInterval(j), j = null);
6819
6819
  try {
6820
6820
  H.onSpeechEnd();
6821
6821
  } catch (xe) {
@@ -6826,7 +6826,7 @@ const Te = be(({
6826
6826
  if (!ue)
6827
6827
  return;
6828
6828
  const de = !w.speechQueue || w.speechQueue.length === 0;
6829
- w && (!w.isSpeaking || w.isSpeaking === !1) && (!w.audioPlaylist || w.audioPlaylist.length === 0) && (!w.isAudioPlaying || w.isAudioPlaying === !1) && de && (G && (clearInterval(G), G = null), setTimeout(() => {
6829
+ w && (!w.isSpeaking || w.isSpeaking === !1) && (!w.audioPlaylist || w.audioPlaylist.length === 0) && (!w.isAudioPlaying || w.isAudioPlaying === !1) && de && (j && (clearInterval(j), j = null), setTimeout(() => {
6830
6830
  try {
6831
6831
  H.onSpeechEnd();
6832
6832
  } catch (xe) {
@@ -6847,7 +6847,7 @@ const Te = be(({
6847
6847
  p.current && p.current.setMood(L);
6848
6848
  }, []), b = E((L) => {
6849
6849
  p.current && p.current.setSlowdownRate && p.current.setSlowdownRate(L);
6850
- }, []), R = E((L, H = !1) => {
6850
+ }, []), v = E((L, H = !1) => {
6851
6851
  if (p.current && p.current.playAnimation) {
6852
6852
  if (x && x[L] && (L = x[L]), p.current.setShowFullAvatar)
6853
6853
  try {
@@ -6862,20 +6862,20 @@ const Te = be(({
6862
6862
  console.warn(`Failed to play ${L}:`, w);
6863
6863
  try {
6864
6864
  p.current.setBodyMovement("idle");
6865
- } catch (G) {
6866
- console.warn("Fallback animation also failed:", G);
6865
+ } catch (j) {
6866
+ console.warn("Fallback animation also failed:", j);
6867
6867
  }
6868
6868
  }
6869
6869
  else {
6870
6870
  const w = [".fbx", ".glb", ".gltf"];
6871
- let G = !1;
6871
+ let j = !1;
6872
6872
  for (const se of w)
6873
6873
  try {
6874
- p.current.playAnimation(L + se, null, 10, 0, 0.01, H), G = !0;
6874
+ p.current.playAnimation(L + se, null, 10, 0, 0.01, H), j = !0;
6875
6875
  break;
6876
6876
  } catch {
6877
6877
  }
6878
- if (!G) {
6878
+ if (!j) {
6879
6879
  console.warn("Animation not found:", L);
6880
6880
  try {
6881
6881
  p.current.setBodyMovement("idle");
@@ -6888,13 +6888,13 @@ const Te = be(({
6888
6888
  }, [x]), z = E(() => {
6889
6889
  p.current && p.current.onResize && p.current.onResize();
6890
6890
  }, []);
6891
- return Re(v, () => ({
6891
+ return Re(I, () => ({
6892
6892
  speakText: le,
6893
6893
  stopSpeaking: ye,
6894
6894
  resumeAudioContext: _,
6895
6895
  setMood: K,
6896
6896
  setTimingAdjustment: b,
6897
- playAnimation: R,
6897
+ playAnimation: v,
6898
6898
  isReady: B,
6899
6899
  talkingHead: p.current,
6900
6900
  handleResize: z,
@@ -6987,7 +6987,7 @@ const Te = be(({
6987
6987
  fontSize: "18px",
6988
6988
  zIndex: 10
6989
6989
  }, children: "Loading avatar..." }),
6990
- I && /* @__PURE__ */ oe("div", { className: "error-overlay", style: {
6990
+ R && /* @__PURE__ */ oe("div", { className: "error-overlay", style: {
6991
6991
  position: "absolute",
6992
6992
  top: "50%",
6993
6993
  left: "50%",
@@ -6998,7 +6998,7 @@ const Te = be(({
6998
6998
  zIndex: 10,
6999
6999
  padding: "20px",
7000
7000
  borderRadius: "8px"
7001
- }, children: I })
7001
+ }, children: R })
7002
7002
  ]
7003
7003
  }
7004
7004
  );
@@ -7016,7 +7016,7 @@ const ot = be(({
7016
7016
  style: s = {},
7017
7017
  avatarConfig: o = {}
7018
7018
  }, r) => {
7019
- const h = Y(null), a = Y(null), [u, l] = re(!0), [c, d] = re(null), [g, y] = re(!1), x = ve(), v = o.ttsService || x.service, T = v === "browser" ? {
7019
+ const h = X(null), a = X(null), [u, l] = re(!0), [c, d] = re(null), [g, y] = re(!1), x = ve(), I = o.ttsService || x.service, T = I === "browser" ? {
7020
7020
  endpoint: "",
7021
7021
  apiKey: null,
7022
7022
  defaultVoice: "Google US English"
@@ -7025,13 +7025,13 @@ const ot = be(({
7025
7025
  // Override API key if provided via avatarConfig
7026
7026
  apiKey: o.ttsApiKey !== void 0 && o.ttsApiKey !== null ? o.ttsApiKey : x.apiKey,
7027
7027
  // Override endpoint for ElevenLabs if service is explicitly set
7028
- endpoint: v === "elevenlabs" && o.ttsApiKey ? "https://api.elevenlabs.io/v1/text-to-speech" : x.endpoint
7028
+ endpoint: I === "elevenlabs" && o.ttsApiKey ? "https://api.elevenlabs.io/v1/text-to-speech" : x.endpoint
7029
7029
  }, p = {
7030
7030
  url: "/avatars/brunette.glb",
7031
7031
  // Use brunette avatar (working glTF file)
7032
7032
  body: "F",
7033
7033
  avatarMood: "neutral",
7034
- ttsLang: v === "browser" ? "en-US" : "en",
7034
+ ttsLang: I === "browser" ? "en-US" : "en",
7035
7035
  ttsVoice: o.ttsVoice || T.defaultVoice,
7036
7036
  lipsyncLang: "en",
7037
7037
  // English lip-sync
@@ -7043,7 +7043,7 @@ const ot = be(({
7043
7043
  }, F = {
7044
7044
  ttsEndpoint: T.endpoint,
7045
7045
  ttsApikey: T.apiKey,
7046
- ttsService: v,
7046
+ ttsService: I,
7047
7047
  lipsyncModules: ["en"],
7048
7048
  cameraView: "upper"
7049
7049
  }, C = E(async () => {
@@ -7085,7 +7085,7 @@ const ot = be(({
7085
7085
  he(() => (C(), () => {
7086
7086
  a.current && (a.current.stop(), a.current.dispose(), a.current = null);
7087
7087
  }), [C]);
7088
- const I = E((S) => {
7088
+ const R = E((S) => {
7089
7089
  if (a.current && g)
7090
7090
  try {
7091
7091
  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(() => {
@@ -7102,7 +7102,7 @@ const ot = be(({
7102
7102
  a.current && a.current.setMood(S);
7103
7103
  }, []), $ = E((S) => {
7104
7104
  a.current && a.current.setSlowdownRate && (a.current.setSlowdownRate(S), console.log("Timing adjustment set to:", S));
7105
- }, []), j = E((S, P = !1) => {
7105
+ }, []), Y = E((S, P = !1) => {
7106
7106
  if (a.current && a.current.playAnimation) {
7107
7107
  if (a.current.setShowFullAvatar)
7108
7108
  try {
@@ -7144,11 +7144,11 @@ const ot = be(({
7144
7144
  console.warn("Animation system not available or animation not found:", S);
7145
7145
  }, []);
7146
7146
  return Re(r, () => ({
7147
- speakText: I,
7147
+ speakText: R,
7148
7148
  stopSpeaking: O,
7149
7149
  setMood: B,
7150
7150
  setTimingAdjustment: $,
7151
- playAnimation: j,
7151
+ playAnimation: Y,
7152
7152
  isReady: g,
7153
7153
  talkingHead: a.current,
7154
7154
  setBodyMovement: (S) => {
@@ -7261,7 +7261,7 @@ const st = be(({
7261
7261
  },
7262
7262
  autoStart: h = !1
7263
7263
  }, a) => {
7264
- const u = Y(null), l = Y({
7264
+ const u = X(null), l = X({
7265
7265
  currentModuleIndex: 0,
7266
7266
  currentLessonIndex: 0,
7267
7267
  currentQuestionIndex: 0,
@@ -7271,18 +7271,18 @@ const st = be(({
7271
7271
  curriculumCompleted: !1,
7272
7272
  score: 0,
7273
7273
  totalQuestions: 0
7274
- }), c = Y({
7274
+ }), c = X({
7275
7275
  onLessonStart: i,
7276
7276
  onLessonComplete: n,
7277
7277
  onQuestionAnswer: s,
7278
7278
  onCurriculumComplete: o,
7279
7279
  onCustomAction: r
7280
- }), d = Y(null), g = Y(null), y = Y(null), x = Y(null), v = Y(null), T = Y(null), p = Y(null), F = Y(D?.curriculum || {
7280
+ }), d = X(null), g = X(null), y = X(null), x = X(null), I = X(null), T = X(null), p = X(null), F = X(D?.curriculum || {
7281
7281
  title: "Default Curriculum",
7282
7282
  description: "No curriculum data provided",
7283
7283
  language: "en",
7284
7284
  modules: []
7285
- }), C = Y({
7285
+ }), C = X({
7286
7286
  avatarUrl: t.avatarUrl || "/avatars/brunette.glb",
7287
7287
  avatarBody: t.avatarBody || "F",
7288
7288
  mood: t.mood || "happy",
@@ -7292,7 +7292,7 @@ const st = be(({
7292
7292
  ttsApiKey: t.ttsApiKey || null,
7293
7293
  bodyMovement: t.bodyMovement || "gesturing",
7294
7294
  movementIntensity: t.movementIntensity || 0.7,
7295
- showFullAvatar: t.showFullAvatar !== void 0 ? t.showFullAvatar : !0,
7295
+ showFullAvatar: t.showFullAvatar !== void 0 ? t.showFullAvatar : !1,
7296
7296
  animations: e,
7297
7297
  lipsyncLang: "en"
7298
7298
  });
@@ -7320,16 +7320,16 @@ const st = be(({
7320
7320
  ttsApiKey: t.ttsApiKey || null,
7321
7321
  bodyMovement: t.bodyMovement || "gesturing",
7322
7322
  movementIntensity: t.movementIntensity || 0.7,
7323
- showFullAvatar: t.showFullAvatar !== void 0 ? t.showFullAvatar : !0,
7323
+ showFullAvatar: t.showFullAvatar !== void 0 ? t.showFullAvatar : !1,
7324
7324
  animations: e,
7325
7325
  lipsyncLang: "en"
7326
7326
  };
7327
7327
  }, [D, t, e]);
7328
- const I = E(() => (F.current || { modules: [] }).modules[l.current.currentModuleIndex]?.lessons[l.current.currentLessonIndex], []), O = E(() => I()?.questions[l.current.currentQuestionIndex], [I]), B = E((b, R) => R.type === "multiple_choice" || R.type === "true_false" ? b === R.answer : R.type === "code_test" && typeof b == "object" && b !== null ? b.passed === !0 : !1, []), $ = E(() => {
7328
+ const R = E(() => (F.current || { modules: [] }).modules[l.current.currentModuleIndex]?.lessons[l.current.currentLessonIndex], []), O = E(() => R()?.questions[l.current.currentQuestionIndex], [R]), B = 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, []), $ = E(() => {
7329
7329
  l.current.lessonCompleted = !0, l.current.isQuestionMode = !1;
7330
7330
  const b = l.current.totalQuestions > 0 ? Math.round(l.current.score / l.current.totalQuestions * 100) : 100;
7331
- let R = "Congratulations! You've completed this lesson";
7332
- if (l.current.totalQuestions > 0 ? R += ` with a score of ${l.current.score} out of ${l.current.totalQuestions} (${b}%). ` : R += "! ", b >= 80 ? R += "Excellent work! You have a great understanding of this topic." : b >= 60 ? R += "Good job! You understand most of the concepts." : R += "Keep practicing! You're making progress.", c.current.onLessonComplete({
7331
+ let v = "Congratulations! You've completed this lesson";
7332
+ if (l.current.totalQuestions > 0 ? v += ` with a score of ${l.current.score} out of ${l.current.totalQuestions} (${b}%). ` : v += "! ", b >= 80 ? v += "Excellent work! You have a great understanding of this topic." : b >= 60 ? v += "Good job! You understand most of the concepts." : v += "Keep practicing! You're making progress.", c.current.onLessonComplete({
7333
7333
  moduleIndex: l.current.currentModuleIndex,
7334
7334
  lessonIndex: l.current.currentLessonIndex,
7335
7335
  score: l.current.score,
@@ -7349,25 +7349,28 @@ const st = be(({
7349
7349
  } catch {
7350
7350
  u.current.playCelebration();
7351
7351
  }
7352
- const z = F.current || { modules: [] }, L = z.modules[l.current.currentModuleIndex], H = l.current.currentLessonIndex < (L?.lessons?.length || 0) - 1, U = l.current.currentModuleIndex < (z.modules?.length || 0) - 1, w = H || U, G = C.current || { lipsyncLang: "en" };
7353
- w ? u.current.speakText(R, {
7354
- lipsyncLang: G.lipsyncLang,
7352
+ const z = F.current || { modules: [] }, L = z.modules[l.current.currentModuleIndex], H = l.current.currentLessonIndex < (L?.lessons?.length || 0) - 1, U = l.current.currentModuleIndex < (z.modules?.length || 0) - 1, w = H || U, j = C.current || { lipsyncLang: "en" };
7353
+ u.current.speakText(v, {
7354
+ lipsyncLang: j.lipsyncLang,
7355
7355
  onSpeechEnd: () => {
7356
- g.current && g.current();
7357
- }
7358
- }) : u.current.speakText(R, {
7359
- lipsyncLang: G.lipsyncLang,
7360
- onSpeechEnd: () => {
7361
- v.current && v.current();
7356
+ c.current.onCustomAction({
7357
+ type: "lessonCompleteFeedbackDone",
7358
+ moduleIndex: l.current.currentModuleIndex,
7359
+ lessonIndex: l.current.currentLessonIndex,
7360
+ score: l.current.score,
7361
+ totalQuestions: l.current.totalQuestions,
7362
+ percentage: b,
7363
+ hasNextLesson: w
7364
+ });
7362
7365
  }
7363
7366
  });
7364
7367
  }
7365
- }, [e.lessonComplete]), j = E(() => {
7368
+ }, [e.lessonComplete]), Y = E(() => {
7366
7369
  l.current.curriculumCompleted = !0;
7367
7370
  const b = F.current || { modules: [] };
7368
7371
  if (c.current.onCurriculumComplete({
7369
7372
  modules: b.modules.length,
7370
- totalLessons: b.modules.reduce((R, z) => R + z.lessons.length, 0)
7373
+ totalLessons: b.modules.reduce((v, z) => v + z.lessons.length, 0)
7371
7374
  }), u.current) {
7372
7375
  if (u.current.setMood("celebrating"), e.curriculumComplete)
7373
7376
  try {
@@ -7375,21 +7378,21 @@ const st = be(({
7375
7378
  } catch {
7376
7379
  u.current.playCelebration();
7377
7380
  }
7378
- const R = C.current || { lipsyncLang: "en" };
7379
- u.current.speakText("Amazing! You've completed the entire curriculum! You're now ready to move on to more advanced topics. Well done!", { lipsyncLang: R.lipsyncLang });
7381
+ const v = C.current || { lipsyncLang: "en" };
7382
+ 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 });
7380
7383
  }
7381
7384
  }, [e.curriculumComplete]), S = E(() => {
7382
- const b = I();
7385
+ const b = R();
7383
7386
  l.current.isQuestionMode = !0, l.current.currentQuestionIndex = 0, l.current.totalQuestions = b?.questions?.length || 0;
7384
- const R = O();
7385
- if (R && c.current.onCustomAction({
7387
+ const v = O();
7388
+ if (v && c.current.onCustomAction({
7386
7389
  type: "questionStart",
7387
7390
  moduleIndex: l.current.currentModuleIndex,
7388
7391
  lessonIndex: l.current.currentLessonIndex,
7389
7392
  questionIndex: l.current.currentQuestionIndex,
7390
7393
  totalQuestions: l.current.totalQuestions,
7391
- question: R
7392
- }), u.current && u.current.isReady && R) {
7394
+ question: v
7395
+ }), u.current && u.current.isReady && v) {
7393
7396
  if (u.current.setMood("curious"), e.questionStart)
7394
7397
  try {
7395
7398
  u.current.playAnimation(e.questionStart, !0);
@@ -7397,7 +7400,7 @@ const st = be(({
7397
7400
  console.warn("Failed to play questionStart animation:", L);
7398
7401
  }
7399
7402
  const z = C.current || { lipsyncLang: "en" };
7400
- R.type === "code_test" ? u.current.speakText(`Let's test your coding skills! Here's your first challenge: ${R.question}`, { lipsyncLang: z.lipsyncLang }) : R.type === "multiple_choice" ? u.current.speakText(`Now let me ask you some questions. Here's the first one: ${R.question}`, { lipsyncLang: z.lipsyncLang }) : R.type === "true_false" ? u.current.speakText(`Let's start with some true or false questions. First question: ${R.question}`, { lipsyncLang: z.lipsyncLang }) : u.current.speakText(`Now let me ask you some questions. Here's the first one: ${R.question}`, { lipsyncLang: z.lipsyncLang });
7403
+ v.type === "code_test" ? u.current.speakText(`Let's test your coding skills! Here's your first challenge: ${v.question}`, { lipsyncLang: z.lipsyncLang }) : v.type === "multiple_choice" ? u.current.speakText(`Now let me ask you some questions. Here's the first one: ${v.question}`, { lipsyncLang: z.lipsyncLang }) : v.type === "true_false" ? u.current.speakText(`Let's start with some true or false questions. First question: ${v.question}`, { lipsyncLang: z.lipsyncLang }) : u.current.speakText(`Now let me ask you some questions. Here's the first one: ${v.question}`, { lipsyncLang: z.lipsyncLang });
7401
7404
  } else if (u.current && u.current.isReady) {
7402
7405
  const z = C.current || { lipsyncLang: "en" };
7403
7406
  u.current.speakText("Now let me ask you some questions to test your understanding.", { lipsyncLang: z.lipsyncLang });
@@ -7405,19 +7408,19 @@ const st = be(({
7405
7408
  setTimeout(() => {
7406
7409
  T.current && T.current();
7407
7410
  }, 100);
7408
- }, [e.questionStart, I, O]), P = E(() => {
7409
- const b = I();
7411
+ }, [e.questionStart, R, O]), P = E(() => {
7412
+ const b = R();
7410
7413
  if (l.current.currentQuestionIndex < (b?.questions?.length || 0) - 1) {
7411
7414
  l.current.currentQuestionIndex += 1;
7412
- const R = O();
7413
- if (R && c.current.onCustomAction({
7415
+ const v = O();
7416
+ if (v && c.current.onCustomAction({
7414
7417
  type: "nextQuestion",
7415
7418
  moduleIndex: l.current.currentModuleIndex,
7416
7419
  lessonIndex: l.current.currentLessonIndex,
7417
7420
  questionIndex: l.current.currentQuestionIndex,
7418
7421
  totalQuestions: l.current.totalQuestions,
7419
- question: R
7420
- }), u.current && R) {
7422
+ question: v
7423
+ }), u.current && v) {
7421
7424
  if (u.current.setMood("happy"), u.current.setBodyMovement("idle"), e.nextQuestion)
7422
7425
  try {
7423
7426
  u.current.playAnimation(e.nextQuestion, !0);
@@ -7425,38 +7428,52 @@ const st = be(({
7425
7428
  console.warn("Failed to play nextQuestion animation:", L);
7426
7429
  }
7427
7430
  const z = C.current || { lipsyncLang: "en" };
7428
- R.type === "code_test" ? u.current.speakText(`Great! Now let's move on to your next coding challenge: ${R.question}`, {
7431
+ v.type === "code_test" ? u.current.speakText(`Great! Now let's move on to your next coding challenge: ${v.question}`, {
7429
7432
  lipsyncLang: z.lipsyncLang
7430
- }) : R.type === "multiple_choice" ? u.current.speakText(`Alright! Here's your next question: ${R.question}`, {
7433
+ }) : v.type === "multiple_choice" ? u.current.speakText(`Alright! Here's your next question: ${v.question}`, {
7431
7434
  lipsyncLang: z.lipsyncLang
7432
- }) : R.type === "true_false" ? u.current.speakText(`Now let's try this one: ${R.question}`, {
7435
+ }) : v.type === "true_false" ? u.current.speakText(`Now let's try this one: ${v.question}`, {
7433
7436
  lipsyncLang: z.lipsyncLang
7434
- }) : u.current.speakText(`Here's the next question: ${R.question}`, {
7437
+ }) : u.current.speakText(`Here's the next question: ${v.question}`, {
7435
7438
  lipsyncLang: z.lipsyncLang
7436
7439
  });
7437
7440
  }
7438
7441
  } else
7439
- y.current && y.current();
7440
- }, [e.nextQuestion, I, O]), W = E(() => {
7441
- const b = F.current || { modules: [] }, R = b.modules[l.current.currentModuleIndex];
7442
- l.current.currentLessonIndex < (R?.lessons?.length || 0) - 1 ? (l.current.currentLessonIndex += 1, l.current.currentQuestionIndex = 0, l.current.lessonCompleted = !1, l.current.isQuestionMode = !1, l.current.isTeaching = !1, l.current.score = 0, l.current.totalQuestions = 0, c.current.onCustomAction({
7442
+ c.current.onCustomAction({
7443
+ type: "allQuestionsComplete",
7444
+ moduleIndex: l.current.currentModuleIndex,
7445
+ lessonIndex: l.current.currentLessonIndex,
7446
+ totalQuestions: l.current.totalQuestions,
7447
+ score: l.current.score
7448
+ });
7449
+ }, [e.nextQuestion, R, O]), W = E(() => {
7450
+ const b = F.current || { modules: [] }, v = b.modules[l.current.currentModuleIndex];
7451
+ l.current.currentLessonIndex < (v?.lessons?.length || 0) - 1 ? (l.current.currentLessonIndex += 1, l.current.currentQuestionIndex = 0, l.current.lessonCompleted = !1, l.current.isQuestionMode = !1, l.current.isTeaching = !1, l.current.score = 0, l.current.totalQuestions = 0, c.current.onCustomAction({
7443
7452
  type: "lessonStart",
7444
7453
  moduleIndex: l.current.currentModuleIndex,
7445
7454
  lessonIndex: l.current.currentLessonIndex
7446
- }), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"), d.current && d.current())) : l.current.currentModuleIndex < (b.modules?.length || 0) - 1 ? (l.current.currentModuleIndex += 1, l.current.currentLessonIndex = 0, l.current.currentQuestionIndex = 0, l.current.lessonCompleted = !1, l.current.isQuestionMode = !1, l.current.isTeaching = !1, l.current.score = 0, l.current.totalQuestions = 0, c.current.onCustomAction({
7455
+ }), c.current.onLessonStart({
7456
+ moduleIndex: l.current.currentModuleIndex,
7457
+ lessonIndex: l.current.currentLessonIndex,
7458
+ lesson: R()
7459
+ }), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"))) : l.current.currentModuleIndex < (b.modules?.length || 0) - 1 ? (l.current.currentModuleIndex += 1, l.current.currentLessonIndex = 0, l.current.currentQuestionIndex = 0, l.current.lessonCompleted = !1, l.current.isQuestionMode = !1, l.current.isTeaching = !1, l.current.score = 0, l.current.totalQuestions = 0, c.current.onCustomAction({
7447
7460
  type: "lessonStart",
7448
7461
  moduleIndex: l.current.currentModuleIndex,
7449
7462
  lessonIndex: l.current.currentLessonIndex
7450
- }), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"), d.current && d.current())) : v.current && v.current();
7463
+ }), c.current.onLessonStart({
7464
+ moduleIndex: l.current.currentModuleIndex,
7465
+ lessonIndex: l.current.currentLessonIndex,
7466
+ lesson: R()
7467
+ }), u.current && (u.current.setMood("happy"), u.current.setBodyMovement("idle"))) : I.current && I.current();
7451
7468
  }, []), V = E(() => {
7452
- const b = I();
7453
- let R = null;
7469
+ const b = R();
7470
+ let v = null;
7454
7471
  if (b?.avatar_script && b?.body) {
7455
7472
  const z = b.avatar_script.trim(), L = b.body.trim(), H = z.match(/[.!?]$/) ? " " : ". ";
7456
- R = `${z}${H}${L}`;
7473
+ v = `${z}${H}${L}`;
7457
7474
  } else
7458
- R = b?.avatar_script || b?.body || null;
7459
- if (u.current && u.current.isReady && R) {
7475
+ v = b?.avatar_script || b?.body || null;
7476
+ if (u.current && u.current.isReady && v) {
7460
7477
  l.current.isTeaching = !0, l.current.isQuestionMode = !1, u.current.setMood("happy");
7461
7478
  let z = !1;
7462
7479
  if (e.teaching)
@@ -7476,22 +7493,28 @@ const st = be(({
7476
7493
  moduleIndex: l.current.currentModuleIndex,
7477
7494
  lessonIndex: l.current.currentLessonIndex,
7478
7495
  lesson: b
7479
- }), u.current.speakText(R, {
7496
+ }), u.current.speakText(v, {
7480
7497
  lipsyncLang: L.lipsyncLang,
7481
7498
  onSpeechEnd: () => {
7482
- l.current.isTeaching = !1, b.questions && b.questions.length > 0 ? T.current && T.current() : y.current && y.current();
7499
+ l.current.isTeaching = !1, c.current.onCustomAction({
7500
+ type: "teachingComplete",
7501
+ moduleIndex: l.current.currentModuleIndex,
7502
+ lessonIndex: l.current.currentLessonIndex,
7503
+ lesson: b,
7504
+ hasQuestions: b.questions && b.questions.length > 0
7505
+ });
7483
7506
  }
7484
7507
  });
7485
7508
  }
7486
- }, [e.teaching, I]), q = E((b) => {
7487
- const R = O(), z = B(b, R);
7509
+ }, [e.teaching, R]), q = E((b) => {
7510
+ const v = O(), z = B(b, v);
7488
7511
  if (z && (l.current.score += 1), c.current.onQuestionAnswer({
7489
7512
  moduleIndex: l.current.currentModuleIndex,
7490
7513
  lessonIndex: l.current.currentLessonIndex,
7491
7514
  questionIndex: l.current.currentQuestionIndex,
7492
7515
  answer: b,
7493
7516
  isCorrect: z,
7494
- question: R
7517
+ question: v
7495
7518
  }), u.current)
7496
7519
  if (z) {
7497
7520
  if (u.current.setMood("happy"), e.correct)
@@ -7501,11 +7524,18 @@ const st = be(({
7501
7524
  u.current.setBodyMovement("happy");
7502
7525
  }
7503
7526
  u.current.setBodyMovement("gesturing");
7504
- const L = R.type === "code_test" ? `Great job! Your code passed all the tests! ${R.explanation || ""}` : `Excellent! That's correct! ${R.explanation || ""}`, H = C.current || { lipsyncLang: "en" };
7527
+ const L = v.type === "code_test" ? `Great job! Your code passed all the tests! ${v.explanation || ""}` : `Excellent! That's correct! ${v.explanation || ""}`, H = C.current || { lipsyncLang: "en" };
7505
7528
  u.current.speakText(L, {
7506
7529
  lipsyncLang: H.lipsyncLang,
7507
7530
  onSpeechEnd: () => {
7508
- x.current && x.current();
7531
+ c.current.onCustomAction({
7532
+ type: "answerFeedbackComplete",
7533
+ moduleIndex: l.current.currentModuleIndex,
7534
+ lessonIndex: l.current.currentLessonIndex,
7535
+ questionIndex: l.current.currentQuestionIndex,
7536
+ isCorrect: !0,
7537
+ hasNextQuestion: l.current.currentQuestionIndex < (R()?.questions?.length || 0) - 1
7538
+ });
7509
7539
  }
7510
7540
  });
7511
7541
  } else {
@@ -7516,23 +7546,38 @@ const st = be(({
7516
7546
  u.current.setBodyMovement("idle");
7517
7547
  }
7518
7548
  u.current.setBodyMovement("gesturing");
7519
- const L = R.type === "code_test" ? `Your code didn't pass all the tests. ${R.explanation || "Try again!"}` : `Not quite right, but don't worry! ${R.explanation || ""} Let's move on to the next question.`, H = C.current || { lipsyncLang: "en" };
7549
+ const L = 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.`, H = C.current || { lipsyncLang: "en" };
7520
7550
  u.current.speakText(L, {
7521
7551
  lipsyncLang: H.lipsyncLang,
7522
7552
  onSpeechEnd: () => {
7523
- x.current && x.current();
7553
+ c.current.onCustomAction({
7554
+ type: "answerFeedbackComplete",
7555
+ moduleIndex: l.current.currentModuleIndex,
7556
+ lessonIndex: l.current.currentLessonIndex,
7557
+ questionIndex: l.current.currentQuestionIndex,
7558
+ isCorrect: !1,
7559
+ hasNextQuestion: l.current.currentQuestionIndex < (R()?.questions?.length || 0) - 1
7560
+ });
7524
7561
  }
7525
7562
  });
7526
7563
  }
7527
7564
  else
7528
- x.current && x.current();
7529
- }, [e.correct, e.incorrect, O, B]), _ = E((b) => {
7530
- const R = O();
7565
+ c.current.onCustomAction({
7566
+ type: "answerFeedbackComplete",
7567
+ moduleIndex: l.current.currentModuleIndex,
7568
+ lessonIndex: l.current.currentLessonIndex,
7569
+ questionIndex: l.current.currentQuestionIndex,
7570
+ isCorrect: z,
7571
+ hasNextQuestion: l.current.currentQuestionIndex < (R()?.questions?.length || 0) - 1,
7572
+ avatarNotReady: !0
7573
+ });
7574
+ }, [e.correct, e.incorrect, O, R, B]), _ = E((b) => {
7575
+ const v = O();
7531
7576
  if (!b || typeof b != "object") {
7532
7577
  console.error("Invalid code test result format. Expected object with {passed: boolean, ...}");
7533
7578
  return;
7534
7579
  }
7535
- if (R?.type !== "code_test") {
7580
+ if (v?.type !== "code_test") {
7536
7581
  console.warn("Current question is not a code test. Use handleAnswerSelect for other question types.");
7537
7582
  return;
7538
7583
  }
@@ -7552,19 +7597,19 @@ const st = be(({
7552
7597
  lessonIndex: l.current.currentLessonIndex,
7553
7598
  questionIndex: l.current.currentQuestionIndex,
7554
7599
  testResult: z,
7555
- question: R
7600
+ question: v
7556
7601
  }), p.current && p.current(z);
7557
7602
  }, [O, B]), le = E(() => {
7558
7603
  l.current.currentModuleIndex = 0, l.current.currentLessonIndex = 0, l.current.currentQuestionIndex = 0, l.current.isTeaching = !1, l.current.isQuestionMode = !1, l.current.lessonCompleted = !1, l.current.curriculumCompleted = !1, l.current.score = 0, l.current.totalQuestions = 0;
7559
7604
  }, []), ye = E((b) => {
7560
7605
  console.log("Avatar is ready!", b);
7561
- const R = I(), z = R?.avatar_script || R?.body;
7606
+ const v = R(), z = v?.avatar_script || v?.body;
7562
7607
  h && z && setTimeout(() => {
7563
7608
  d.current && d.current();
7564
7609
  }, 10);
7565
- }, [h, I]);
7610
+ }, [h, R]);
7566
7611
  Pe(() => {
7567
- d.current = V, g.current = W, y.current = $, x.current = P, v.current = j, T.current = S, p.current = q;
7612
+ d.current = V, g.current = W, y.current = $, x.current = P, I.current = Y, T.current = S, p.current = q;
7568
7613
  }), Re(a, () => ({
7569
7614
  // Curriculum control methods
7570
7615
  startTeaching: V,
@@ -7574,28 +7619,28 @@ const st = be(({
7574
7619
  nextQuestion: P,
7575
7620
  nextLesson: W,
7576
7621
  completeLesson: $,
7577
- completeCurriculum: j,
7622
+ completeCurriculum: Y,
7578
7623
  resetCurriculum: le,
7579
7624
  getState: () => ({ ...l.current }),
7580
7625
  getCurrentQuestion: () => O(),
7581
- getCurrentLesson: () => I(),
7626
+ getCurrentLesson: () => R(),
7582
7627
  // Direct access to avatar ref (always returns current value)
7583
7628
  getAvatarRef: () => u.current,
7584
7629
  // Convenience methods that delegate to avatar (always check current ref)
7585
- speakText: async (b, R = {}) => {
7630
+ speakText: async (b, v = {}) => {
7586
7631
  await u.current?.resumeAudioContext?.();
7587
7632
  const z = C.current || { lipsyncLang: "en" };
7588
- u.current?.speakText(b, { ...R, lipsyncLang: R.lipsyncLang || z.lipsyncLang });
7633
+ u.current?.speakText(b, { ...v, lipsyncLang: v.lipsyncLang || z.lipsyncLang });
7589
7634
  },
7590
7635
  resumeAudioContext: async () => {
7591
7636
  if (u.current?.resumeAudioContext)
7592
7637
  return await u.current.resumeAudioContext();
7593
7638
  const b = u.current?.talkingHead;
7594
7639
  if (b?.audioCtx) {
7595
- const R = b.audioCtx;
7596
- if (R.state === "suspended" || R.state === "interrupted")
7640
+ const v = b.audioCtx;
7641
+ if (v.state === "suspended" || v.state === "interrupted")
7597
7642
  try {
7598
- await R.resume(), console.log("Audio context resumed via talkingHead");
7643
+ await v.resume(), console.log("Audio context resumed via talkingHead");
7599
7644
  } catch (z) {
7600
7645
  console.warn("Failed to resume audio context:", z);
7601
7646
  }
@@ -7604,7 +7649,7 @@ const st = be(({
7604
7649
  },
7605
7650
  stopSpeaking: () => u.current?.stopSpeaking(),
7606
7651
  setMood: (b) => u.current?.setMood(b),
7607
- playAnimation: (b, R) => u.current?.playAnimation(b, R),
7652
+ playAnimation: (b, v) => u.current?.playAnimation(b, v),
7608
7653
  setBodyMovement: (b) => u.current?.setBodyMovement(b),
7609
7654
  setMovementIntensity: (b) => u.current?.setMovementIntensity(b),
7610
7655
  playRandomDance: () => u.current?.playRandomDance(),
@@ -7615,10 +7660,10 @@ const st = be(({
7615
7660
  lockAvatarPosition: () => u.current?.lockAvatarPosition(),
7616
7661
  unlockAvatarPosition: () => u.current?.unlockAvatarPosition(),
7617
7662
  // Custom action trigger
7618
- triggerCustomAction: (b, R) => {
7663
+ triggerCustomAction: (b, v) => {
7619
7664
  c.current.onCustomAction({
7620
7665
  type: b,
7621
- ...R,
7666
+ ...v,
7622
7667
  state: { ...l.current }
7623
7668
  });
7624
7669
  },
@@ -7626,7 +7671,7 @@ const st = be(({
7626
7671
  handleResize: () => u.current?.handleResize(),
7627
7672
  // Avatar readiness check (always returns current value)
7628
7673
  isAvatarReady: () => u.current?.isReady || !1
7629
- }), [V, S, q, _, P, W, $, j, le, O, I]);
7674
+ }), [V, S, q, _, P, W, $, Y, le, O, R]);
7630
7675
  const K = C.current || {
7631
7676
  avatarUrl: "/avatars/brunette.glb",
7632
7677
  avatarBody: "F",
@@ -7637,7 +7682,7 @@ const st = be(({
7637
7682
  ttsApiKey: null,
7638
7683
  bodyMovement: "gesturing",
7639
7684
  movementIntensity: 0.7,
7640
- showFullAvatar: !0,
7685
+ showFullAvatar: !1,
7641
7686
  animations: e
7642
7687
  };
7643
7688
  return /* @__PURE__ */ oe("div", { style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ oe(