@sage-rsc/talking-head-react 1.9.1 → 1.9.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sage-rsc/talking-head-react",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "description": "A reusable React component for 3D talking avatars with lip-sync and text-to-speech",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -654,15 +654,31 @@ const SimpleTalkingAvatar = forwardRef(({
654
654
  const isStillSpeaking = checkStillSpeaking();
655
655
 
656
656
  if (isStillSpeaking) {
657
- // Queue is empty but still speaking, reset queue and continue playing animations IMMEDIATELY
658
- animationQueueRef.current = [];
659
- playedAnimationsRef.current = [];
660
- // Continue immediately - no delay for continuous playback
661
- if (checkStillSpeaking()) {
662
- // Continue playing animations recursively
663
- playRandomAnimation(groupName, disablePositionLock, onFinished);
657
+ // Queue is empty but still speaking, check if there are animations available before resetting
658
+ // CRITICAL: Check if animations exist before recursively calling to prevent infinite recursion
659
+ const availableAnimations = getAllAnimationsFromGroup(groupName);
660
+
661
+ if (availableAnimations.length > 0) {
662
+ // Reset queue and continue playing animations IMMEDIATELY
663
+ animationQueueRef.current = [];
664
+ playedAnimationsRef.current = [];
665
+ // Continue immediately - no delay for continuous playback
666
+ if (checkStillSpeaking()) {
667
+ // Continue playing animations recursively
668
+ playRandomAnimation(groupName, disablePositionLock, onFinished);
669
+ } else {
670
+ // Speech ended - stop animation and return to idle pose
671
+ isSpeakingRef.current = false;
672
+ currentAnimationGroupRef.current = null;
673
+
674
+ // CRITICAL: Stop current animation to return to idle pose
675
+ if (talkingHeadRef.current) {
676
+ talkingHeadRef.current.stopAnimation();
677
+ }
678
+ }
664
679
  } else {
665
- // Speech ended - stop animation and return to idle pose
680
+ // No animations available - stop to prevent infinite recursion
681
+ console.log(`🎬 No animations available for group "${groupName}", stopping animations`);
666
682
  isSpeakingRef.current = false;
667
683
  currentAnimationGroupRef.current = null;
668
684
 
@@ -670,11 +686,15 @@ const SimpleTalkingAvatar = forwardRef(({
670
686
  if (talkingHeadRef.current) {
671
687
  talkingHeadRef.current.stopAnimation();
672
688
  }
689
+
690
+ if (onFinished) {
691
+ onFinished();
692
+ }
673
693
  }
674
694
  }
675
695
  }
676
696
  return null;
677
- }, [getNextAnimation, getAnimationName]);
697
+ }, [getNextAnimation, getAnimationName, getAllAnimationsFromGroup]);
678
698
 
679
699
  // Helper function to restart idle animations when speech ends
680
700
  // Must be defined AFTER playRandomAnimation to avoid circular dependency
@@ -1037,7 +1057,7 @@ const SimpleTalkingAvatar = forwardRef(({
1037
1057
  idleAnimationIntervalRef.current = null;
1038
1058
  }
1039
1059
  };
1040
- }, [isReady, autoIdleGroup, playRandomAnimation, isSpeakingRef]);
1060
+ }, [isReady, autoIdleGroup, playRandomAnimation]);
1041
1061
 
1042
1062
  // Auto-speak text when ready and autoSpeak is true
1043
1063
  useEffect(() => {