@sage-rsc/talking-head-react 1.0.31 → 1.0.33
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/{fbxAnimationLoader-C1sYMpqd.cjs → fbxAnimationLoader-BrjaqtTU.cjs} +1 -1
- package/dist/{fbxAnimationLoader-C0BDPJ-P.js → fbxAnimationLoader-YIg1EylY.js} +1 -1
- package/dist/{index-WXvj5jje.cjs → index-CdCA-KAp.cjs} +4 -4
- package/dist/{index-iUfJQ70v.js → index-Dd7BPF7g.js} +1159 -1148
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +5 -5
- package/src/components/CurriculumLearning.jsx +76 -29
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("./index-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("./index-CdCA-KAp.cjs");exports.CurriculumLearning=i.CurriculumLearning;exports.TalkingHeadAvatar=i.TalkingHeadAvatar;exports.TalkingHeadComponent=i.TalkingHeadComponent;exports.animations=i.animations;exports.getActiveTTSConfig=i.getActiveTTSConfig;exports.getAnimation=i.getAnimation;exports.getVoiceOptions=i.getVoiceOptions;exports.hasAnimation=i.hasAnimation;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sage-rsc/talking-head-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33",
|
|
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",
|
|
@@ -55,15 +55,15 @@
|
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@eslint/js": "^9.36.0",
|
|
58
|
-
"@types/react": "^
|
|
59
|
-
"@types/react-dom": "^
|
|
58
|
+
"@types/react": "^18.3.0",
|
|
59
|
+
"@types/react-dom": "^18.3.0",
|
|
60
60
|
"@vitejs/plugin-react": "^5.0.4",
|
|
61
61
|
"eslint": "^9.36.0",
|
|
62
62
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
63
63
|
"eslint-plugin-react-refresh": "^0.4.22",
|
|
64
64
|
"globals": "^16.4.0",
|
|
65
|
-
"react": "^
|
|
66
|
-
"react-dom": "^
|
|
65
|
+
"react": "^18.3.0",
|
|
66
|
+
"react-dom": "^18.3.0",
|
|
67
67
|
"vite": "^7.1.7"
|
|
68
68
|
}
|
|
69
69
|
}
|
|
@@ -194,15 +194,17 @@ const CurriculumLearning = forwardRef(({
|
|
|
194
194
|
if (animations.lessonComplete) {
|
|
195
195
|
try {
|
|
196
196
|
avatarRef.current.playAnimation(animations.lessonComplete, true);
|
|
197
|
-
|
|
197
|
+
} catch (error) {
|
|
198
198
|
avatarRef.current.playCelebration();
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
// Check if there's a next lesson available
|
|
202
|
+
// Check if there's a next lesson available (either in current module or next module)
|
|
203
203
|
const curriculum = curriculumRef.current || { modules: [] };
|
|
204
204
|
const currentModule = curriculum.modules[stateRef.current.currentModuleIndex];
|
|
205
|
-
const
|
|
205
|
+
const hasNextLessonInModule = stateRef.current.currentLessonIndex < (currentModule?.lessons?.length || 0) - 1;
|
|
206
|
+
const hasNextModule = stateRef.current.currentModuleIndex < (curriculum.modules?.length || 0) - 1;
|
|
207
|
+
const hasNextLesson = hasNextLessonInModule || hasNextModule;
|
|
206
208
|
|
|
207
209
|
const config = defaultAvatarConfigRef.current || { lipsyncLang: 'en' };
|
|
208
210
|
|
|
@@ -212,7 +214,7 @@ const CurriculumLearning = forwardRef(({
|
|
|
212
214
|
lipsyncLang: config.lipsyncLang,
|
|
213
215
|
onSpeechEnd: () => {
|
|
214
216
|
// Add a small delay after speech ends for natural flow
|
|
215
|
-
|
|
217
|
+
setTimeout(() => {
|
|
216
218
|
// Use ref to avoid circular dependency
|
|
217
219
|
if (nextLessonRef.current) {
|
|
218
220
|
nextLessonRef.current();
|
|
@@ -220,8 +222,8 @@ const CurriculumLearning = forwardRef(({
|
|
|
220
222
|
}, 1000);
|
|
221
223
|
}
|
|
222
224
|
});
|
|
223
|
-
|
|
224
|
-
// This is the last lesson, complete curriculum instead
|
|
225
|
+
} else {
|
|
226
|
+
// This is the last lesson in the last module, complete curriculum instead
|
|
225
227
|
avatarRef.current.speakText(feedbackMessage, {
|
|
226
228
|
lipsyncLang: config.lipsyncLang,
|
|
227
229
|
onSpeechEnd: () => {
|
|
@@ -340,7 +342,7 @@ const CurriculumLearning = forwardRef(({
|
|
|
340
342
|
if (animations.nextQuestion) {
|
|
341
343
|
try {
|
|
342
344
|
avatarRef.current.playAnimation(animations.nextQuestion, true);
|
|
343
|
-
|
|
345
|
+
} catch (error) {
|
|
344
346
|
console.warn('Failed to play nextQuestion animation:', error);
|
|
345
347
|
}
|
|
346
348
|
}
|
|
@@ -378,7 +380,12 @@ const CurriculumLearning = forwardRef(({
|
|
|
378
380
|
const nextLesson = useCallback(() => {
|
|
379
381
|
const curriculum = curriculumRef.current || { modules: [] };
|
|
380
382
|
const currentModule = curriculum.modules[stateRef.current.currentModuleIndex];
|
|
381
|
-
|
|
383
|
+
|
|
384
|
+
// Check if there's a next lesson in the current module
|
|
385
|
+
const hasNextLessonInModule = stateRef.current.currentLessonIndex < (currentModule?.lessons?.length || 0) - 1;
|
|
386
|
+
|
|
387
|
+
if (hasNextLessonInModule) {
|
|
388
|
+
// Move to next lesson in current module
|
|
382
389
|
stateRef.current.currentLessonIndex += 1;
|
|
383
390
|
stateRef.current.currentQuestionIndex = 0;
|
|
384
391
|
stateRef.current.lessonCompleted = false;
|
|
@@ -395,7 +402,7 @@ const CurriculumLearning = forwardRef(({
|
|
|
395
402
|
});
|
|
396
403
|
|
|
397
404
|
if (avatarRef.current) {
|
|
398
|
-
|
|
405
|
+
avatarRef.current.setMood("happy");
|
|
399
406
|
avatarRef.current.setBodyMovement("idle");
|
|
400
407
|
|
|
401
408
|
// Automatically start teaching the next lesson after a brief pause
|
|
@@ -406,8 +413,43 @@ const CurriculumLearning = forwardRef(({
|
|
|
406
413
|
}, 500);
|
|
407
414
|
}
|
|
408
415
|
} else {
|
|
409
|
-
|
|
410
|
-
|
|
416
|
+
// No more lessons in current module - check if there's a next module
|
|
417
|
+
const hasNextModule = stateRef.current.currentModuleIndex < (curriculum.modules?.length || 0) - 1;
|
|
418
|
+
|
|
419
|
+
if (hasNextModule) {
|
|
420
|
+
// Move to first lesson of next module
|
|
421
|
+
stateRef.current.currentModuleIndex += 1;
|
|
422
|
+
stateRef.current.currentLessonIndex = 0;
|
|
423
|
+
stateRef.current.currentQuestionIndex = 0;
|
|
424
|
+
stateRef.current.lessonCompleted = false;
|
|
425
|
+
stateRef.current.isQuestionMode = false;
|
|
426
|
+
stateRef.current.isTeaching = false;
|
|
427
|
+
stateRef.current.score = 0;
|
|
428
|
+
stateRef.current.totalQuestions = 0;
|
|
429
|
+
|
|
430
|
+
// Clear current question in UI
|
|
431
|
+
callbacksRef.current.onCustomAction({
|
|
432
|
+
type: 'lessonStart',
|
|
433
|
+
moduleIndex: stateRef.current.currentModuleIndex,
|
|
434
|
+
lessonIndex: stateRef.current.currentLessonIndex
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
if (avatarRef.current) {
|
|
438
|
+
avatarRef.current.setMood("happy");
|
|
439
|
+
avatarRef.current.setBodyMovement("idle");
|
|
440
|
+
|
|
441
|
+
// Automatically start teaching the next lesson after a brief pause
|
|
442
|
+
setTimeout(() => {
|
|
443
|
+
if (startTeachingRef.current) {
|
|
444
|
+
startTeachingRef.current();
|
|
445
|
+
}
|
|
446
|
+
}, 500);
|
|
447
|
+
}
|
|
448
|
+
} else {
|
|
449
|
+
// No more modules or lessons - complete curriculum
|
|
450
|
+
if (completeCurriculumRef.current) {
|
|
451
|
+
completeCurriculumRef.current();
|
|
452
|
+
}
|
|
411
453
|
}
|
|
412
454
|
}
|
|
413
455
|
}, []);
|
|
@@ -424,10 +466,10 @@ const CurriculumLearning = forwardRef(({
|
|
|
424
466
|
// Play animation if available (can be overridden via custom action)
|
|
425
467
|
let animationPlayed = false;
|
|
426
468
|
if (animations.teaching) {
|
|
427
|
-
|
|
469
|
+
try {
|
|
428
470
|
avatarRef.current.playAnimation(animations.teaching, true);
|
|
429
471
|
animationPlayed = true;
|
|
430
|
-
|
|
472
|
+
} catch (error) {
|
|
431
473
|
console.warn('Failed to play teaching animation:', error);
|
|
432
474
|
}
|
|
433
475
|
}
|
|
@@ -437,7 +479,6 @@ const CurriculumLearning = forwardRef(({
|
|
|
437
479
|
}
|
|
438
480
|
|
|
439
481
|
const config = defaultAvatarConfigRef.current || { lipsyncLang: 'en' };
|
|
440
|
-
avatarRef.current.speakText(currentLesson.avatar_script, { lipsyncLang: config.lipsyncLang });
|
|
441
482
|
|
|
442
483
|
callbacksRef.current.onLessonStart({
|
|
443
484
|
moduleIndex: stateRef.current.currentModuleIndex,
|
|
@@ -453,21 +494,27 @@ const CurriculumLearning = forwardRef(({
|
|
|
453
494
|
lesson: currentLesson
|
|
454
495
|
});
|
|
455
496
|
|
|
456
|
-
//
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
497
|
+
// Wait for avatar to finish speaking before moving to questions
|
|
498
|
+
avatarRef.current.speakText(currentLesson.avatar_script, {
|
|
499
|
+
lipsyncLang: config.lipsyncLang,
|
|
500
|
+
onSpeechEnd: () => {
|
|
501
|
+
stateRef.current.isTeaching = false;
|
|
502
|
+
// Add a small delay after speech ends for natural flow
|
|
503
|
+
setTimeout(() => {
|
|
504
|
+
if (currentLesson.questions && currentLesson.questions.length > 0) {
|
|
505
|
+
// Use ref to avoid circular dependency
|
|
506
|
+
if (startQuestionsRef.current) {
|
|
507
|
+
startQuestionsRef.current();
|
|
508
|
+
}
|
|
509
|
+
} else {
|
|
510
|
+
// No questions, complete the lesson using ref to avoid circular dependency
|
|
511
|
+
if (completeLessonRef.current) {
|
|
512
|
+
completeLessonRef.current();
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}, 500);
|
|
469
516
|
}
|
|
470
|
-
}
|
|
517
|
+
});
|
|
471
518
|
}
|
|
472
519
|
}, [animations.teaching, getCurrentLesson]);
|
|
473
520
|
|
|
@@ -495,7 +542,7 @@ const CurriculumLearning = forwardRef(({
|
|
|
495
542
|
if (animations.correct) {
|
|
496
543
|
try {
|
|
497
544
|
avatarRef.current.playReaction("happy");
|
|
498
|
-
|
|
545
|
+
} catch (error) {
|
|
499
546
|
avatarRef.current.setBodyMovement("happy");
|
|
500
547
|
}
|
|
501
548
|
}
|