@sage-rsc/talking-head-react 1.8.2 → 1.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3 -3
- package/dist/index.js +62 -62
- package/package.json +1 -1
- package/src/lib/talkinghead.mjs +18 -9
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs as Pe, jsx as ae } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef as Ke, useRef as V, useState as pe, useEffect as Se, useCallback as U, useImperativeHandle as
|
|
2
|
+
import { forwardRef as Ke, useRef as V, useState as pe, useEffect as Se, useCallback as U, useImperativeHandle as $e, useLayoutEffect as pt } from "react";
|
|
3
3
|
import * as b from "three";
|
|
4
4
|
import { OrbitControls as gt } from "three/addons/controls/OrbitControls.js";
|
|
5
5
|
import { GLTFLoader as yt } from "three/addons/loaders/GLTFLoader.js";
|
|
@@ -5200,9 +5200,9 @@ class nt {
|
|
|
5200
5200
|
eyeLookOutRight: [null, 0],
|
|
5201
5201
|
eyeContact: [0]
|
|
5202
5202
|
}
|
|
5203
|
-
})))), e > 2 * this.animFrameDur && (e = 2 * this.animFrameDur), (this.viewName !== "full" || this.isAvatarOnly) && (t = this.mtRandomized[Math.floor(Math.random() * this.mtRandomized.length)], o = this.mtAvatar[t], o.needsUpdate || Object.assign(o, { base: (this.mood.baseline[t] || 0) + (1 + a / 255) * Math.random() / 5, needsUpdate: !0 })), this.updatePoseBase(this.animClock), this.mixer && (this.mixer.update(e / 1e3 * this.mixer.timeScale), this.currentFBXActionForCallback && this.
|
|
5204
|
-
const r = this.currentFBXActionForCallback.time,
|
|
5205
|
-
(r
|
|
5203
|
+
})))), e > 2 * this.animFrameDur && (e = 2 * this.animFrameDur), (this.viewName !== "full" || this.isAvatarOnly) && (t = this.mtRandomized[Math.floor(Math.random() * this.mtRandomized.length)], o = this.mtAvatar[t], o.needsUpdate || Object.assign(o, { base: (this.mood.baseline[t] || 0) + (1 + a / 255) * Math.random() / 5, needsUpdate: !0 })), this.updatePoseBase(this.animClock), this.mixer && (this.mixer.update(e / 1e3 * this.mixer.timeScale), this.currentFBXActionForCallback && this.currentFBXActionClipDuration)) {
|
|
5204
|
+
const r = this.currentFBXActionForCallback, h = r.time, d = this.currentFBXActionClipDuration;
|
|
5205
|
+
(!r.isRunning() || h >= d - 0.1 || r.getEffectiveTimeScale() === 0 && h > 0) && (console.log(`🎬 Manual check: Animation finished (time: ${h.toFixed(3)}/${d.toFixed(3)}, running: ${r.isRunning()})`), this.currentFBXActionCallback && (this.currentFBXActionCallback(), this.currentFBXActionCallback = null), this.currentFBXActionForCallback = null, this.currentFBXActionStartTime = null, this.currentFBXActionClipDuration = null);
|
|
5206
5206
|
}
|
|
5207
5207
|
if (this.updatePoseDelta(), (this.isSpeaking || this.isListening) && u ? a > this.volumeMax ? (this.volumeHeadBase = 0.05, Math.random() > 0.6 && (this.volumeHeadTarget = -0.05 - Math.random() / 15), this.volumeMax = a) : (this.volumeMax *= 0.92, this.volumeHeadTarget = this.volumeHeadBase - 0.9 * (this.volumeHeadBase - this.volumeHeadTarget)) : (this.volumeHeadTarget = 0, this.volumeMax = 0), t = this.volumeHeadTarget - this.volumeHeadCurrent, o = Math.abs(t), o > 1e-4 && (i = o * (this.volumeHeadEasing(Math.min(1, this.volumeHeadVelocity * e / 1e3 / o) / 2 + 0.5) - 0.5), this.volumeHeadCurrent += Math.sign(t) * Math.min(o, i)), Math.abs(this.volumeHeadCurrent) > 1e-4 && (ue.setFromAxisAngle(Bt, this.volumeHeadCurrent), this.objectNeck.quaternion.multiply(ue)), at.setFromObject(this.armature), this.objectLeftToeBase.getWorldPosition(Ue), Ue.sub(this.armature.position), this.objectRightToeBase.getWorldPosition(Xe), Xe.sub(this.armature.position), this.objectHips.position.y -= at.min.y / 2, this.objectHips.position.x -= (Ue.x + Xe.x) / 4, this.objectHips.position.z -= (Ue.z + Xe.z) / 2, this.dynamicbones.update(e), this.fbxAnimationLoader && this.fbxAnimationLoader.update(), this.opt.update && this.opt.update(e), this.updateMorphTargets(e), this.isAvatarOnly)
|
|
5208
5208
|
this.stats && this.stats.end();
|
|
@@ -6449,15 +6449,15 @@ class nt {
|
|
|
6449
6449
|
this.poseBase.props[h[0]] = h[1].clone(), this.poseTarget.props[h[0]] = h[1].clone(), this.poseTarget.props[h[0]].t = 0, this.poseTarget.props[h[0]].d = 1e3;
|
|
6450
6450
|
}), this.mixer || (this.mixer = new b.AnimationMixer(this.armature)), this.animationFinishedCallback = a;
|
|
6451
6451
|
const c = () => {
|
|
6452
|
-
this.animationFinishedCallback && (this.animationFinishedCallback(), this.animationFinishedCallback = null)
|
|
6452
|
+
console.log(`🎬 Mixer 'finished' event fired for animation: ${n}`), this.animationFinishedCallback && (this.animationFinishedCallback(), this.animationFinishedCallback = null);
|
|
6453
6453
|
}, r = this.mixer.clipAction(u.clip);
|
|
6454
6454
|
if (t <= 0)
|
|
6455
|
-
r.setLoop(b.LoopOnce, 1);
|
|
6455
|
+
r.setLoop(b.LoopOnce, 1), console.log(`🎬 Setting animation to LoopOnce, duration: ${u.clip.duration.toFixed(3)}s`);
|
|
6456
6456
|
else {
|
|
6457
6457
|
const h = Math.ceil(t / u.clip.duration);
|
|
6458
6458
|
r.setLoop(b.LoopRepeat, h);
|
|
6459
6459
|
}
|
|
6460
|
-
if (r.clampWhenFinished = !0, this.mixer.addEventListener("finished", c, { once: !0 }), this.currentFBXActionForCallback = r, this.currentFBXActionCallback = c, this.currentFBXActionClipDuration = u.clip.duration, this.currentFBXActionStartTime = null, this.currentFBXAction && this.currentFBXAction.isRunning()) {
|
|
6460
|
+
if (r.clampWhenFinished = !0, r.time = 0, this.mixer.addEventListener("finished", c, { once: !0 }), this.currentFBXActionForCallback = r, this.currentFBXActionCallback = c, this.currentFBXActionClipDuration = u.clip.duration, this.currentFBXActionStartTime = null, this.currentFBXAction && this.currentFBXAction.isRunning()) {
|
|
6461
6461
|
this.currentFBXAction.fadeOut(0.3), setTimeout(() => {
|
|
6462
6462
|
this.currentFBXAction = r, this.currentFBXActionForCallback = r, this.currentFBXActionCallback = c, this.currentFBXActionClipDuration = u.clip.duration, this.currentFBXActionStartTime = this.mixer.time;
|
|
6463
6463
|
try {
|
|
@@ -6842,7 +6842,7 @@ const Ze = {
|
|
|
6842
6842
|
// Male, English - Powerful
|
|
6843
6843
|
}
|
|
6844
6844
|
};
|
|
6845
|
-
function
|
|
6845
|
+
function Je() {
|
|
6846
6846
|
return {
|
|
6847
6847
|
service: "elevenlabs",
|
|
6848
6848
|
endpoint: Ze.endpoint,
|
|
@@ -6852,7 +6852,7 @@ function $e() {
|
|
|
6852
6852
|
};
|
|
6853
6853
|
}
|
|
6854
6854
|
function qt() {
|
|
6855
|
-
const Z =
|
|
6855
|
+
const Z = Je(), n = [];
|
|
6856
6856
|
return Object.entries(Z.voices).forEach(([e, t]) => {
|
|
6857
6857
|
n.push({
|
|
6858
6858
|
value: t,
|
|
@@ -6888,7 +6888,7 @@ const ct = Ke(({
|
|
|
6888
6888
|
}, [me]), Se(() => {
|
|
6889
6889
|
D.current = l;
|
|
6890
6890
|
}, [l]);
|
|
6891
|
-
const ye =
|
|
6891
|
+
const ye = Je(), Re = o || ye.service;
|
|
6892
6892
|
let he;
|
|
6893
6893
|
Re === "browser" ? he = {
|
|
6894
6894
|
service: "browser",
|
|
@@ -7118,7 +7118,7 @@ const ct = Ke(({
|
|
|
7118
7118
|
}, [x]), ke = U(() => {
|
|
7119
7119
|
m.current && m.current.onResize && m.current.onResize();
|
|
7120
7120
|
}, []);
|
|
7121
|
-
return
|
|
7121
|
+
return $e(k, () => ({
|
|
7122
7122
|
speakText: Y,
|
|
7123
7123
|
stopSpeaking: K,
|
|
7124
7124
|
pauseSpeaking: q,
|
|
@@ -7249,7 +7249,7 @@ const Ot = Ke(({
|
|
|
7249
7249
|
style: s = {},
|
|
7250
7250
|
avatarConfig: i = {}
|
|
7251
7251
|
}, a) => {
|
|
7252
|
-
const u = V(null), l = V(null), [c, r] = pe(!0), [h, d] = pe(null), [g, R] = pe(!1), x =
|
|
7252
|
+
const u = V(null), l = V(null), [c, r] = pe(!0), [h, d] = pe(null), [g, R] = pe(!1), x = Je(), k = i.ttsService || x.service, G = k === "browser" ? {
|
|
7253
7253
|
endpoint: "",
|
|
7254
7254
|
apiKey: null,
|
|
7255
7255
|
defaultVoice: "Google US English"
|
|
@@ -7376,7 +7376,7 @@ const Ot = Ke(({
|
|
|
7376
7376
|
} else
|
|
7377
7377
|
console.warn("Animation system not available or animation not found:", I);
|
|
7378
7378
|
}, []);
|
|
7379
|
-
return
|
|
7379
|
+
return $e(a, () => ({
|
|
7380
7380
|
speakText: y,
|
|
7381
7381
|
stopSpeaking: P,
|
|
7382
7382
|
setMood: L,
|
|
@@ -7615,12 +7615,12 @@ const Nt = Ke(({
|
|
|
7615
7615
|
} catch {
|
|
7616
7616
|
}
|
|
7617
7617
|
if (typeof m.auto == "string") {
|
|
7618
|
-
const H = m.auto,
|
|
7618
|
+
const H = m.auto, $ = {
|
|
7619
7619
|
talking: `${H}/talking`,
|
|
7620
7620
|
idle: `${H}/idle`
|
|
7621
7621
|
}, W = C(e);
|
|
7622
|
-
|
|
7623
|
-
const ie = await lt(
|
|
7622
|
+
$[`${W}_talking`] = `${H}/${W}/talking`, $[`${W}_idle`] = `${H}/${W}/idle`, $.shared_talking = `${H}/shared/talking`, $.shared_idle = `${H}/shared/idle`;
|
|
7623
|
+
const ie = await lt($, e);
|
|
7624
7624
|
if (!Object.values(ie).some((j) => Array.isArray(j) && j.length > 0) && w) {
|
|
7625
7625
|
O(w);
|
|
7626
7626
|
return;
|
|
@@ -7631,22 +7631,22 @@ const Nt = Ke(({
|
|
|
7631
7631
|
shared: {}
|
|
7632
7632
|
}
|
|
7633
7633
|
};
|
|
7634
|
-
Object.entries(ie).forEach(([j,
|
|
7634
|
+
Object.entries(ie).forEach(([j, J]) => {
|
|
7635
7635
|
if (j.includes("_")) {
|
|
7636
7636
|
const [ee, ...ge] = j.split("_"), de = ge.join("_");
|
|
7637
|
-
ee === "shared" ? (ce._genderSpecific.shared[de] || (ce._genderSpecific.shared[de] = []), ce._genderSpecific.shared[de].push(
|
|
7637
|
+
ee === "shared" ? (ce._genderSpecific.shared[de] || (ce._genderSpecific.shared[de] = []), ce._genderSpecific.shared[de].push(...J)) : ee === W && (ce._genderSpecific[W][de] || (ce._genderSpecific[W][de] = []), ce._genderSpecific[W][de].push(...J));
|
|
7638
7638
|
} else
|
|
7639
|
-
ce[j] =
|
|
7639
|
+
ce[j] = J;
|
|
7640
7640
|
}), w && (w._genderSpecific && Object.keys(w._genderSpecific).forEach((j) => {
|
|
7641
|
-
ce._genderSpecific[j] || (ce._genderSpecific[j] = {}), Object.entries(w._genderSpecific[j]).forEach(([
|
|
7642
|
-
ce._genderSpecific[j][
|
|
7641
|
+
ce._genderSpecific[j] || (ce._genderSpecific[j] = {}), Object.entries(w._genderSpecific[j]).forEach(([J, ee]) => {
|
|
7642
|
+
ce._genderSpecific[j][J] || (ce._genderSpecific[j][J] = ee);
|
|
7643
7643
|
});
|
|
7644
|
-
}), Object.entries(w).forEach(([j,
|
|
7645
|
-
j !== "_genderSpecific" && !ce[j] && (ce[j] =
|
|
7644
|
+
}), Object.entries(w).forEach(([j, J]) => {
|
|
7645
|
+
j !== "_genderSpecific" && !ce[j] && (ce[j] = J);
|
|
7646
7646
|
})), O(ce);
|
|
7647
7647
|
} else if (typeof m.auto == "object") {
|
|
7648
|
-
const H = await lt(m.auto, e),
|
|
7649
|
-
O(
|
|
7648
|
+
const H = await lt(m.auto, e), $ = Object.values(H).some((W) => Array.isArray(W) && W.length > 0);
|
|
7649
|
+
O(!$ && w ? w : H);
|
|
7650
7650
|
}
|
|
7651
7651
|
} catch (w) {
|
|
7652
7652
|
if (console.error("Failed to auto-discover animations:", w), m.manifest)
|
|
@@ -7665,7 +7665,7 @@ const Nt = Ke(({
|
|
|
7665
7665
|
}, [m, e, C]), Se(() => {
|
|
7666
7666
|
M.current = c;
|
|
7667
7667
|
}, [c]);
|
|
7668
|
-
const X =
|
|
7668
|
+
const X = Je(), ne = s || X.service;
|
|
7669
7669
|
let se;
|
|
7670
7670
|
ne === "browser" ? se = {
|
|
7671
7671
|
service: "browser",
|
|
@@ -7739,8 +7739,8 @@ const Nt = Ke(({
|
|
|
7739
7739
|
return [];
|
|
7740
7740
|
let w = null;
|
|
7741
7741
|
if (T._genderSpecific) {
|
|
7742
|
-
const H = C(e),
|
|
7743
|
-
if (
|
|
7742
|
+
const H = C(e), $ = T._genderSpecific[H];
|
|
7743
|
+
if ($ && $[S] && Array.isArray($[S]) && $[S].length > 0 && (w = $[S]), !w && T._genderSpecific.shared && T._genderSpecific.shared[S]) {
|
|
7744
7744
|
const W = T._genderSpecific.shared[S];
|
|
7745
7745
|
Array.isArray(W) && W.length > 0 && (w = W);
|
|
7746
7746
|
}
|
|
@@ -7753,8 +7753,8 @@ const Nt = Ke(({
|
|
|
7753
7753
|
}, [T, e, C]), He = U((S) => {
|
|
7754
7754
|
const w = [...S];
|
|
7755
7755
|
for (let H = w.length - 1; H > 0; H--) {
|
|
7756
|
-
const
|
|
7757
|
-
[w[H], w[
|
|
7756
|
+
const $ = Math.floor(Math.random() * (H + 1));
|
|
7757
|
+
[w[H], w[$]] = [w[$], w[H]];
|
|
7758
7758
|
}
|
|
7759
7759
|
return w;
|
|
7760
7760
|
}, []), we = U((S) => {
|
|
@@ -7769,10 +7769,10 @@ const Nt = Ke(({
|
|
|
7769
7769
|
}, [Be, He]), We = U((S) => S ? S.split("/").pop().replace(".fbx", "").replace(/[-_]/g, " ") : "Unknown", []), Oe = U((S, w = !1, H = null) => {
|
|
7770
7770
|
if (!f.current || !K.current || q.current !== S)
|
|
7771
7771
|
return null;
|
|
7772
|
-
const
|
|
7773
|
-
if (
|
|
7772
|
+
const $ = we(S);
|
|
7773
|
+
if ($)
|
|
7774
7774
|
try {
|
|
7775
|
-
const W = We(
|
|
7775
|
+
const W = We($);
|
|
7776
7776
|
console.log(`🎬 Playing animation: "${W}"`);
|
|
7777
7777
|
const ie = () => {
|
|
7778
7778
|
console.log("🎬 Animation finished, checking if should continue...");
|
|
@@ -7783,11 +7783,11 @@ const Nt = Ke(({
|
|
|
7783
7783
|
return console.log("🎬 isSpeakingRef is false, stopping animations"), !1;
|
|
7784
7784
|
if (q.current !== S)
|
|
7785
7785
|
return console.log(`🎬 Animation group mismatch (${q.current} !== ${S}), stopping animations`), !1;
|
|
7786
|
-
const j = f.current,
|
|
7786
|
+
const j = f.current, J = j.isAudioPlaying === !0, ee = j.audioPlaylist && j.audioPlaylist.length > 0, ge = j.speechQueue && j.speechQueue.length > 0, de = j.isSpeaking === !0, Ge = de || J || ee || ge;
|
|
7787
7787
|
return console.log("🎬 Still speaking check:", {
|
|
7788
7788
|
isSpeakingRef: K.current,
|
|
7789
7789
|
isTalkingHeadSpeaking: de,
|
|
7790
|
-
hasAudioPlaying:
|
|
7790
|
+
hasAudioPlaying: J,
|
|
7791
7791
|
hasAudioInPlaylist: ee,
|
|
7792
7792
|
hasItemsInQueue: ge,
|
|
7793
7793
|
shouldContinue: Ge
|
|
@@ -7797,7 +7797,7 @@ const Nt = Ke(({
|
|
|
7797
7797
|
le() ? (console.log("🎬 Playing next animation..."), Oe(S, w, H)) : (console.log("🎬 Speech ended, stopping animations"), K.current = !1, q.current = null, H && H());
|
|
7798
7798
|
})) : (console.log("🎬 Speech has ended, stopping animations"), K.current = !1, q.current = null, H && H());
|
|
7799
7799
|
};
|
|
7800
|
-
return f.current.playAnimation(
|
|
7800
|
+
return f.current.playAnimation($, null, 0, 0, 0.01, w, ie), $;
|
|
7801
7801
|
} catch (W) {
|
|
7802
7802
|
return console.error("Failed to play animation:", W), null;
|
|
7803
7803
|
}
|
|
@@ -7805,8 +7805,8 @@ const Nt = Ke(({
|
|
|
7805
7805
|
const W = () => {
|
|
7806
7806
|
if (!f.current || !K.current || q.current !== S)
|
|
7807
7807
|
return !1;
|
|
7808
|
-
const le = f.current, ce = le.isAudioPlaying === !0, j = le.audioPlaylist && le.audioPlaylist.length > 0,
|
|
7809
|
-
return le.isSpeaking === !0 || ce || j ||
|
|
7808
|
+
const le = f.current, ce = le.isAudioPlaying === !0, j = le.audioPlaylist && le.audioPlaylist.length > 0, J = le.speechQueue && le.speechQueue.length > 0;
|
|
7809
|
+
return le.isSpeaking === !0 || ce || j || J;
|
|
7810
7810
|
};
|
|
7811
7811
|
W() && (Ie.current = [], fe.current = [], W() ? Oe(S, w, H) : (K.current = !1, q.current = null));
|
|
7812
7812
|
}
|
|
@@ -7823,8 +7823,8 @@ const Nt = Ke(({
|
|
|
7823
7823
|
console.warn("Error in onSpeechStart callback:", ie);
|
|
7824
7824
|
}
|
|
7825
7825
|
Q.current = { remainingText: null, originalText: null, options: null }, _.current = [], I.current = { text: S, options: w }, F.current && (clearInterval(F.current), F.current = null), v(!1), B.current = !1, te.current = !1;
|
|
7826
|
-
const
|
|
7827
|
-
_.current =
|
|
7826
|
+
const $ = S.split(/[.!?]+/).filter((ie) => ie.trim().length > 0);
|
|
7827
|
+
_.current = $, et.current = 0;
|
|
7828
7828
|
const W = {
|
|
7829
7829
|
lipsyncLang: w.lipsyncLang || "en"
|
|
7830
7830
|
};
|
|
@@ -7833,11 +7833,11 @@ const Nt = Ke(({
|
|
|
7833
7833
|
let le = 0;
|
|
7834
7834
|
const ce = 1200;
|
|
7835
7835
|
F.current && (clearInterval(F.current), F.current = null);
|
|
7836
|
-
const j = { current: !1 },
|
|
7836
|
+
const j = { current: !1 }, J = setInterval(() => {
|
|
7837
7837
|
if (le++, B.current)
|
|
7838
7838
|
return;
|
|
7839
7839
|
if (le > ce) {
|
|
7840
|
-
if (
|
|
7840
|
+
if (J && (clearInterval(J), F.current = null), !j.current && !B.current) {
|
|
7841
7841
|
j.current = !0, K.current = !1, q.current = null, Ie.current = [], fe.current = [], f.current && (f.current.isSpeaking = !1);
|
|
7842
7842
|
try {
|
|
7843
7843
|
w.onSpeechEnd && w.onSpeechEnd(), x();
|
|
@@ -7852,7 +7852,7 @@ const Nt = Ke(({
|
|
|
7852
7852
|
const Te = f.current;
|
|
7853
7853
|
if (!Te)
|
|
7854
7854
|
return;
|
|
7855
|
-
!B.current && (!Te.speechQueue || Te.speechQueue.length === 0) && (!Te.audioPlaylist || Te.audioPlaylist.length === 0) && Te.isAudioPlaying === !1 && Te.isSpeaking === !1 && !j.current && !B.current && (j.current = !0,
|
|
7855
|
+
!B.current && (!Te.speechQueue || Te.speechQueue.length === 0) && (!Te.audioPlaylist || Te.audioPlaylist.length === 0) && Te.isAudioPlaying === !1 && Te.isSpeaking === !1 && !j.current && !B.current && (j.current = !0, J && (clearInterval(J), F.current = null), K.current = !1, q.current = null, Ie.current = [], fe.current = [], te.current = !0, Te && (Te.isSpeaking = !1), setTimeout(() => {
|
|
7856
7856
|
try {
|
|
7857
7857
|
w.onSpeechEnd && w.onSpeechEnd(), x(), setTimeout(() => {
|
|
7858
7858
|
te.current = !1;
|
|
@@ -7863,7 +7863,7 @@ const Nt = Ke(({
|
|
|
7863
7863
|
}, 100));
|
|
7864
7864
|
}, 200);
|
|
7865
7865
|
}, 50);
|
|
7866
|
-
F.current =
|
|
7866
|
+
F.current = J;
|
|
7867
7867
|
}
|
|
7868
7868
|
try {
|
|
7869
7869
|
f.current.speakText(S, W);
|
|
@@ -7892,12 +7892,12 @@ const Nt = Ke(({
|
|
|
7892
7892
|
const S = f.current.isSpeaking || !1, w = [...f.current.audioPlaylist || []], H = [...f.current.speechQueue || []];
|
|
7893
7893
|
if (S || w.length > 0 || H.length > 0) {
|
|
7894
7894
|
F.current && (clearInterval(F.current), F.current = null);
|
|
7895
|
-
const
|
|
7895
|
+
const $ = _.current;
|
|
7896
7896
|
let W = [];
|
|
7897
7897
|
const ie = f.current.isAudioPlaying || !1;
|
|
7898
|
-
if (
|
|
7899
|
-
const ee = w.length + H.length, ge = ie ? 1 : 0, de =
|
|
7900
|
-
Ge <
|
|
7898
|
+
if ($.length > 0) {
|
|
7899
|
+
const ee = w.length + H.length, ge = ie ? 1 : 0, de = $.length - ee - ge, Ge = ie ? de : de + ge;
|
|
7900
|
+
Ge < $.length && (W = $.slice(Ge));
|
|
7901
7901
|
} else
|
|
7902
7902
|
w.length > 0 && w.forEach((ee) => {
|
|
7903
7903
|
if (ee.text)
|
|
@@ -7922,8 +7922,8 @@ const Nt = Ke(({
|
|
|
7922
7922
|
};
|
|
7923
7923
|
const j = f.current.isAudioPlaying || !1 ? [...f.current.speechQueue || []] : null;
|
|
7924
7924
|
f.current.speechQueue.length = 0;
|
|
7925
|
-
const
|
|
7926
|
-
f.current.isSpeaking = !1, K.current = !1, q.current = null,
|
|
7925
|
+
const J = f.current.pauseSpeaking();
|
|
7926
|
+
f.current.isSpeaking = !1, K.current = !1, q.current = null, J && J.audio && j ? (ke.current = J, ke.current.savedSpeechQueue = j) : ke.current = J, v(!0), B.current = !0;
|
|
7927
7927
|
}
|
|
7928
7928
|
} catch (S) {
|
|
7929
7929
|
console.warn("Error pausing speech:", S);
|
|
@@ -7937,14 +7937,14 @@ const Nt = Ke(({
|
|
|
7937
7937
|
if (ie && (q.current = ie), ke.current.savedSpeechQueue && (f.current.speechQueue.length = 0, f.current.speechQueue.push(...ke.current.savedSpeechQueue)), f.current.isSpeaking = !0, f.current) {
|
|
7938
7938
|
const le = f.current;
|
|
7939
7939
|
let ce = 0;
|
|
7940
|
-
const j = 1200,
|
|
7940
|
+
const j = 1200, J = { current: !1 };
|
|
7941
7941
|
F.current && (clearInterval(F.current), F.current = null);
|
|
7942
7942
|
const ee = setInterval(() => {
|
|
7943
7943
|
if (ce++, B.current)
|
|
7944
7944
|
return;
|
|
7945
7945
|
if (ce > j) {
|
|
7946
|
-
if (ee && (clearInterval(ee), F.current = null),
|
|
7947
|
-
|
|
7946
|
+
if (ee && (clearInterval(ee), F.current = null), !J.current && !B.current) {
|
|
7947
|
+
J.current = !0, K.current = !1, q.current = null, Ie.current = [], fe.current = [], f.current && (f.current.isSpeaking = !1);
|
|
7948
7948
|
try {
|
|
7949
7949
|
W.onSpeechEnd && W.onSpeechEnd(), x();
|
|
7950
7950
|
} catch (Me) {
|
|
@@ -7954,10 +7954,10 @@ const Nt = Ke(({
|
|
|
7954
7954
|
return;
|
|
7955
7955
|
}
|
|
7956
7956
|
const ge = !le.speechQueue || le.speechQueue.length === 0, de = !le.audioPlaylist || le.audioPlaylist.length === 0, Ge = le.isAudioPlaying === !1;
|
|
7957
|
-
le && !B.current && ge && de && Ge && le.isSpeaking === !1 &&
|
|
7957
|
+
le && !B.current && ge && de && Ge && le.isSpeaking === !1 && !J.current && !B.current && setTimeout(() => {
|
|
7958
7958
|
const Me = f.current;
|
|
7959
7959
|
if (!Me) return;
|
|
7960
|
-
!B.current && (!Me.speechQueue || Me.speechQueue.length === 0) && (!Me.audioPlaylist || Me.audioPlaylist.length === 0) && Me.isAudioPlaying === !1 && Me.isSpeaking === !1 &&
|
|
7960
|
+
!B.current && (!Me.speechQueue || Me.speechQueue.length === 0) && (!Me.audioPlaylist || Me.audioPlaylist.length === 0) && Me.isAudioPlaying === !1 && Me.isSpeaking === !1 && !J.current && !B.current && (J.current = !0, ee && (clearInterval(ee), F.current = null), K.current = !1, q.current = null, Ie.current = [], fe.current = [], te.current = !0, Me && (Me.isSpeaking = !1), setTimeout(() => {
|
|
7961
7961
|
try {
|
|
7962
7962
|
W.onSpeechEnd && W.onSpeechEnd(), x(), setTimeout(() => {
|
|
7963
7963
|
te.current = !1;
|
|
@@ -7973,8 +7973,8 @@ const Nt = Ke(({
|
|
|
7973
7973
|
await f.current.playAudio(!1, ke.current), ie && !W.skipAnimation && (Ie.current = [], fe.current = [], Oe(ie)), ke.current = null;
|
|
7974
7974
|
return;
|
|
7975
7975
|
}
|
|
7976
|
-
const S = Q.current?.remainingText, w = Q.current?.originalText || I.current?.text, H = Q.current?.options || I.current?.options || {},
|
|
7977
|
-
|
|
7976
|
+
const S = Q.current?.remainingText, w = Q.current?.originalText || I.current?.text, H = Q.current?.options || I.current?.options || {}, $ = S || w;
|
|
7977
|
+
$ && Ve($, H), ke.current = null;
|
|
7978
7978
|
} catch (S) {
|
|
7979
7979
|
console.warn("Error resuming speech:", S), v(!1), B.current = !1, ke.current = null;
|
|
7980
7980
|
}
|
|
@@ -7988,7 +7988,7 @@ const Nt = Ke(({
|
|
|
7988
7988
|
}
|
|
7989
7989
|
}
|
|
7990
7990
|
}, [x]);
|
|
7991
|
-
return
|
|
7991
|
+
return $e(P, () => ({
|
|
7992
7992
|
speakText: Ve,
|
|
7993
7993
|
pauseSpeaking: tt,
|
|
7994
7994
|
resumeSpeaking: ht,
|
|
@@ -8537,7 +8537,7 @@ const Ut = Ke(({
|
|
|
8537
8537
|
}, [u, y]);
|
|
8538
8538
|
pt(() => {
|
|
8539
8539
|
d.current = Q, g.current = B, R.current = f, x.current = F, k.current = M, G.current = I, m.current = _;
|
|
8540
|
-
}),
|
|
8540
|
+
}), $e(l, () => ({
|
|
8541
8541
|
// Curriculum control methods
|
|
8542
8542
|
startTeaching: Q,
|
|
8543
8543
|
startQuestions: I,
|
|
@@ -9029,7 +9029,7 @@ const ut = {
|
|
|
9029
9029
|
duration: 5e3,
|
|
9030
9030
|
description: "Excited, energetic movement"
|
|
9031
9031
|
}
|
|
9032
|
-
}, Kt = (Z) => ut[Z] || null,
|
|
9032
|
+
}, Kt = (Z) => ut[Z] || null, $t = (Z) => ut.hasOwnProperty(Z);
|
|
9033
9033
|
export {
|
|
9034
9034
|
_t as AnimationSelector,
|
|
9035
9035
|
Ut as CurriculumLearning,
|
|
@@ -9037,8 +9037,8 @@ export {
|
|
|
9037
9037
|
ct as TalkingHeadAvatar,
|
|
9038
9038
|
Ot as TalkingHeadComponent,
|
|
9039
9039
|
ut as animations,
|
|
9040
|
-
|
|
9040
|
+
Je as getActiveTTSConfig,
|
|
9041
9041
|
Kt as getAnimation,
|
|
9042
9042
|
qt as getVoiceOptions,
|
|
9043
|
-
|
|
9043
|
+
$t as hasAnimation
|
|
9044
9044
|
};
|
package/package.json
CHANGED
package/src/lib/talkinghead.mjs
CHANGED
|
@@ -3174,15 +3174,20 @@ class TalkingHead {
|
|
|
3174
3174
|
|
|
3175
3175
|
// Manually check if current FBX animation has finished (backup to mixer 'finished' event)
|
|
3176
3176
|
// This ensures the callback fires reliably even if the mixer event doesn't
|
|
3177
|
-
if (this.currentFBXActionForCallback && this.
|
|
3178
|
-
const
|
|
3177
|
+
if (this.currentFBXActionForCallback && this.currentFBXActionClipDuration) {
|
|
3178
|
+
const action = this.currentFBXActionForCallback;
|
|
3179
|
+
const actionTime = action.time;
|
|
3179
3180
|
const clipDuration = this.currentFBXActionClipDuration;
|
|
3180
3181
|
|
|
3181
|
-
//
|
|
3182
|
-
//
|
|
3183
|
-
|
|
3184
|
-
|
|
3182
|
+
// Check if animation is no longer running (finished or stopped)
|
|
3183
|
+
// For LoopOnce with clampWhenFinished, the action stops when it reaches the end
|
|
3184
|
+
const isFinished = !action.isRunning() ||
|
|
3185
|
+
(actionTime >= clipDuration - 0.1) ||
|
|
3186
|
+
(action.getEffectiveTimeScale() === 0 && actionTime > 0);
|
|
3187
|
+
|
|
3188
|
+
if (isFinished) {
|
|
3185
3189
|
// Animation finished - call callback manually
|
|
3190
|
+
console.log(`🎬 Manual check: Animation finished (time: ${actionTime.toFixed(3)}/${clipDuration.toFixed(3)}, running: ${action.isRunning()})`);
|
|
3186
3191
|
if (this.currentFBXActionCallback) {
|
|
3187
3192
|
this.currentFBXActionCallback();
|
|
3188
3193
|
this.currentFBXActionCallback = null;
|
|
@@ -5570,25 +5575,29 @@ class TalkingHead {
|
|
|
5570
5575
|
|
|
5571
5576
|
// Create handler that calls callback before stopping
|
|
5572
5577
|
const finishedHandler = () => {
|
|
5578
|
+
console.log(`🎬 Mixer 'finished' event fired for animation: ${url}`);
|
|
5573
5579
|
if (this.animationFinishedCallback) {
|
|
5574
5580
|
this.animationFinishedCallback();
|
|
5575
5581
|
this.animationFinishedCallback = null;
|
|
5576
5582
|
}
|
|
5577
|
-
|
|
5583
|
+
// Don't call stopAnimation() here - let the callback handle continuation
|
|
5584
|
+
// The callback will decide whether to play next animation or stop
|
|
5578
5585
|
};
|
|
5579
|
-
|
|
5586
|
+
|
|
5580
5587
|
// Play action with error handling
|
|
5581
5588
|
// If dur is 0 or negative, play animation once (use clip's natural duration)
|
|
5582
5589
|
const action = this.mixer.clipAction(item.clip);
|
|
5583
5590
|
if (dur <= 0) {
|
|
5584
5591
|
// Play once - use LoopOnce to ensure finished event fires
|
|
5585
5592
|
action.setLoop( THREE.LoopOnce, 1 );
|
|
5593
|
+
console.log(`🎬 Setting animation to LoopOnce, duration: ${item.clip.duration.toFixed(3)}s`);
|
|
5586
5594
|
} else {
|
|
5587
5595
|
// Play for specified duration
|
|
5588
5596
|
const repeat = Math.ceil(dur / item.clip.duration);
|
|
5589
|
-
|
|
5597
|
+
action.setLoop( THREE.LoopRepeat, repeat );
|
|
5590
5598
|
}
|
|
5591
5599
|
action.clampWhenFinished = true;
|
|
5600
|
+
action.time = 0; // Reset to start
|
|
5592
5601
|
|
|
5593
5602
|
// Set up callback to check when animation finishes
|
|
5594
5603
|
// Use both mixer 'finished' event and manual time checking for reliability
|