@sage-rsc/talking-head-react 1.0.72 → 1.0.74
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/README.md +450 -119
- package/dist/index.cjs +2 -2
- package/dist/index.js +88 -84
- package/package.json +1 -1
- package/src/components/SimpleTalkingAvatar.jsx +12 -0
package/README.md
CHANGED
|
@@ -1,74 +1,76 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @sage-rsc/talking-head-react
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A powerful React component library for creating interactive 3D talking avatars with realistic lip-sync, multiple text-to-speech services, and curriculum-based learning capabilities.
|
|
4
4
|
|
|
5
|
-
## Features
|
|
5
|
+
## ✨ Features
|
|
6
6
|
|
|
7
|
-
- 🎭 **3D Avatar Rendering** - Support for GLB/GLTF avatar models
|
|
8
|
-
- 🎤 **Lip-Sync** -
|
|
9
|
-
- 🔊 **
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
7
|
+
- 🎭 **3D Avatar Rendering** - Support for GLB/GLTF avatar models with full body or head-only modes
|
|
8
|
+
- 🎤 **Real-time Lip-Sync** - Automatic lip synchronization with audio using viseme-based animation
|
|
9
|
+
- 🔊 **Multiple TTS Services** - Edge TTS, ElevenLabs, Deepgram, Google Cloud, Azure, and Browser TTS
|
|
10
|
+
- 📚 **Curriculum Learning** - Built-in curriculum system with lessons, questions, and code examples
|
|
11
|
+
- 🎬 **Animation Support** - FBX animation support and code-based body movements
|
|
12
|
+
- ⏯️ **Playback Control** - Pause, resume, and stop speech functionality
|
|
13
|
+
- 🎯 **Interactive Mode** - Manual control over curriculum progression
|
|
14
|
+
- 💻 **Code IDE Integration** - Simulate code typing and execution in an IDE
|
|
15
|
+
- 🎨 **Zero UI** - Pure components, no built-in UI elements - full control over styling
|
|
14
16
|
|
|
15
|
-
## Installation
|
|
17
|
+
## 📦 Installation
|
|
16
18
|
|
|
17
19
|
```bash
|
|
18
|
-
npm install talking-head-react
|
|
20
|
+
npm install @sage-rsc/talking-head-react
|
|
19
21
|
```
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
This package requires the following peer dependencies:
|
|
23
|
+
### Peer Dependencies
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
26
|
npm install react react-dom three
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
**Requirements:**
|
|
30
|
+
- React 18.0.0+ or 19.0.0+
|
|
31
|
+
- React DOM 18.0.0+ or 19.0.0+
|
|
32
|
+
- Three.js 0.150.0+
|
|
33
|
+
|
|
34
|
+
## 🚀 Quick Start
|
|
35
|
+
|
|
36
|
+
### Simple Talking Avatar
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
The simplest way to get started - just pass text and the avatar speaks:
|
|
32
39
|
|
|
33
40
|
```jsx
|
|
34
|
-
import React, { useRef
|
|
35
|
-
import {
|
|
41
|
+
import React, { useRef } from 'react';
|
|
42
|
+
import { SimpleTalkingAvatar } from '@sage-rsc/talking-head-react';
|
|
36
43
|
|
|
37
44
|
function App() {
|
|
38
45
|
const avatarRef = useRef(null);
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Make the avatar speak
|
|
44
|
-
avatarRef.current.speakText("Hello! I'm your talking avatar.");
|
|
45
|
-
}
|
|
46
|
-
}, []);
|
|
47
|
+
const handleSpeak = () => {
|
|
48
|
+
avatarRef.current?.speakText("Hello! I'm a talking avatar.");
|
|
49
|
+
};
|
|
47
50
|
|
|
48
51
|
return (
|
|
49
52
|
<div style={{ width: '100vw', height: '100vh' }}>
|
|
50
|
-
<
|
|
53
|
+
<SimpleTalkingAvatar
|
|
51
54
|
ref={avatarRef}
|
|
52
|
-
avatarUrl="/
|
|
55
|
+
avatarUrl="/avatars/brunette.glb"
|
|
53
56
|
avatarBody="F"
|
|
54
57
|
mood="happy"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
showFullAvatar={true}
|
|
58
|
-
onReady={(talkingHead) => {
|
|
59
|
-
console.log('Avatar is ready!', talkingHead);
|
|
60
|
-
}}
|
|
58
|
+
showFullAvatar={false}
|
|
59
|
+
onReady={() => console.log('Avatar ready!')}
|
|
61
60
|
/>
|
|
61
|
+
<button onClick={handleSpeak}>Speak</button>
|
|
62
62
|
</div>
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
###
|
|
67
|
+
### Full-Featured Avatar
|
|
68
|
+
|
|
69
|
+
For advanced control with animations and custom configurations:
|
|
68
70
|
|
|
69
71
|
```jsx
|
|
70
72
|
import React, { useRef } from 'react';
|
|
71
|
-
import { TalkingHeadAvatar } from 'talking-head-react';
|
|
73
|
+
import { TalkingHeadAvatar } from '@sage-rsc/talking-head-react';
|
|
72
74
|
|
|
73
75
|
function App() {
|
|
74
76
|
const avatarRef = useRef(null);
|
|
@@ -76,61 +78,60 @@ function App() {
|
|
|
76
78
|
const animations = {
|
|
77
79
|
teaching: "/animations/Arguing.fbx",
|
|
78
80
|
correct: "/animations/Happy.fbx",
|
|
79
|
-
incorrect: "/animations/Disappointed.fbx"
|
|
80
|
-
lessonComplete: "/animations/Step.fbx"
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const handleSpeak = () => {
|
|
84
|
-
if (avatarRef.current?.isReady) {
|
|
85
|
-
// Play animation while speaking
|
|
86
|
-
avatarRef.current.playAnimation(animations.teaching, true);
|
|
87
|
-
avatarRef.current.speakText("Let me explain this concept to you.");
|
|
88
|
-
}
|
|
81
|
+
incorrect: "/animations/Disappointed.fbx"
|
|
89
82
|
};
|
|
90
83
|
|
|
91
84
|
return (
|
|
92
85
|
<div style={{ width: '100vw', height: '100vh' }}>
|
|
93
86
|
<TalkingHeadAvatar
|
|
94
87
|
ref={avatarRef}
|
|
95
|
-
avatarUrl="/
|
|
88
|
+
avatarUrl="/avatars/brunette.glb"
|
|
89
|
+
avatarBody="F"
|
|
90
|
+
mood="happy"
|
|
91
|
+
ttsService="elevenlabs"
|
|
92
|
+
ttsApiKey="your-api-key"
|
|
93
|
+
ttsVoice="21m00Tcm4TlvDq8ikWAM"
|
|
94
|
+
showFullAvatar={false}
|
|
95
|
+
bodyMovement="gesturing"
|
|
96
96
|
animations={animations}
|
|
97
97
|
onReady={() => {
|
|
98
|
-
|
|
98
|
+
avatarRef.current?.speakText("Welcome!");
|
|
99
99
|
}}
|
|
100
100
|
/>
|
|
101
|
-
<button onClick={handleSpeak}>Start Teaching</button>
|
|
102
101
|
</div>
|
|
103
102
|
);
|
|
104
103
|
}
|
|
105
104
|
```
|
|
106
105
|
|
|
107
|
-
###
|
|
106
|
+
### Curriculum Learning
|
|
107
|
+
|
|
108
|
+
Complete learning system with lessons, questions, and automatic progression:
|
|
108
109
|
|
|
109
110
|
```jsx
|
|
110
111
|
import React, { useRef } from 'react';
|
|
111
|
-
import { CurriculumLearning } from 'talking-head-react';
|
|
112
|
+
import { CurriculumLearning } from '@sage-rsc/talking-head-react';
|
|
112
113
|
|
|
113
114
|
function App() {
|
|
114
|
-
const curriculumRef = useRef(null);
|
|
115
|
-
|
|
116
115
|
const curriculumData = {
|
|
117
116
|
curriculum: {
|
|
118
|
-
title: "Introduction to
|
|
117
|
+
title: "Introduction to Programming",
|
|
118
|
+
description: "Learn the basics of programming",
|
|
119
|
+
language: "en",
|
|
119
120
|
modules: [
|
|
120
121
|
{
|
|
121
|
-
title: "Module 1",
|
|
122
|
+
title: "Module 1: Variables",
|
|
122
123
|
lessons: [
|
|
123
124
|
{
|
|
124
|
-
title: "
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
title: "JavaScript Variables",
|
|
126
|
+
avatar_script: "Let's learn about variables.",
|
|
127
|
+
body: "Variables store data values in your program.",
|
|
127
128
|
questions: [
|
|
128
129
|
{
|
|
129
130
|
type: "multiple_choice",
|
|
130
|
-
question: "
|
|
131
|
-
options: ["
|
|
132
|
-
answer: "
|
|
133
|
-
explanation: "
|
|
131
|
+
question: "Which keyword creates a constant variable?",
|
|
132
|
+
options: ["let", "const", "var"],
|
|
133
|
+
answer: "const",
|
|
134
|
+
explanation: "The 'const' keyword creates a constant variable."
|
|
134
135
|
}
|
|
135
136
|
]
|
|
136
137
|
}
|
|
@@ -140,122 +141,297 @@ function App() {
|
|
|
140
141
|
}
|
|
141
142
|
};
|
|
142
143
|
|
|
143
|
-
const animations = {
|
|
144
|
-
teaching: "/animations/Arguing.fbx",
|
|
145
|
-
correct: "/animations/Happy.fbx",
|
|
146
|
-
incorrect: "/animations/Disappointed.fbx"
|
|
147
|
-
};
|
|
148
|
-
|
|
149
144
|
const avatarConfig = {
|
|
150
|
-
avatarUrl: "/
|
|
145
|
+
avatarUrl: "/avatars/brunette.glb",
|
|
151
146
|
avatarBody: "F",
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
mood: "happy",
|
|
148
|
+
showFullAvatar: false
|
|
154
149
|
};
|
|
155
150
|
|
|
156
151
|
return (
|
|
157
152
|
<div style={{ width: '100vw', height: '100vh' }}>
|
|
158
153
|
<CurriculumLearning
|
|
159
|
-
ref={curriculumRef}
|
|
160
154
|
curriculumData={curriculumData}
|
|
161
155
|
avatarConfig={avatarConfig}
|
|
162
|
-
animations={animations}
|
|
163
156
|
autoStart={true}
|
|
164
|
-
onLessonStart={(data) => {
|
|
165
|
-
console.log('Lesson started:', data);
|
|
166
|
-
}}
|
|
167
157
|
onLessonComplete={(data) => {
|
|
168
158
|
console.log('Lesson completed:', data);
|
|
169
159
|
}}
|
|
170
|
-
onQuestionAnswer={(data) => {
|
|
171
|
-
console.log('Question answered:', data);
|
|
172
|
-
}}
|
|
173
160
|
/>
|
|
174
161
|
</div>
|
|
175
162
|
);
|
|
176
163
|
}
|
|
177
164
|
```
|
|
178
165
|
|
|
179
|
-
##
|
|
166
|
+
## 📖 Components
|
|
167
|
+
|
|
168
|
+
### SimpleTalkingAvatar
|
|
169
|
+
|
|
170
|
+
A lightweight component for simple text-to-speech scenarios. Perfect when you just need an avatar to speak text.
|
|
180
171
|
|
|
181
|
-
|
|
172
|
+
**Props:**
|
|
182
173
|
|
|
183
174
|
| Prop | Type | Default | Description |
|
|
184
175
|
|------|------|---------|-------------|
|
|
185
|
-
| `
|
|
176
|
+
| `text` | `string` | `null` | Text to speak (optional, can use `speakText` method) |
|
|
177
|
+
| `avatarUrl` | `string` | `"/avatars/brunette.glb"` | URL/path to GLB avatar file |
|
|
186
178
|
| `avatarBody` | `string` | `"F"` | Avatar body type ('M' or 'F') |
|
|
187
|
-
| `mood` | `string` | `"neutral"` | Initial mood ('happy', 'sad', 'neutral',
|
|
179
|
+
| `mood` | `string` | `"neutral"` | Initial mood ('happy', 'sad', 'neutral', 'excited') |
|
|
188
180
|
| `ttsLang` | `string` | `"en"` | Text-to-speech language code |
|
|
189
|
-
| `ttsService` | `string` | `null` | TTS service ('edge', 'elevenlabs', 'google', 'azure', 'browser') |
|
|
181
|
+
| `ttsService` | `string` | `null` | TTS service ('edge', 'elevenlabs', 'deepgram', 'google', 'azure', 'browser') |
|
|
190
182
|
| `ttsVoice` | `string` | `null` | TTS voice ID |
|
|
191
|
-
| `
|
|
183
|
+
| `ttsApiKey` | `string` | `null` | TTS API key (ElevenLabs, Deepgram, Google, or Azure |
|
|
184
|
+
| `bodyMovement` | `string` | `"idle"` | Body movement type ('idle', 'gesturing', 'dancing') |
|
|
192
185
|
| `movementIntensity` | `number` | `0.5` | Movement intensity (0-1) |
|
|
193
|
-
| `showFullAvatar` | `boolean` | `
|
|
194
|
-
| `cameraView` | `string` | `"upper"` | Camera view ('upper', 'full'
|
|
195
|
-
| `
|
|
186
|
+
| `showFullAvatar` | `boolean` | `false` | Whether to show full body avatar |
|
|
187
|
+
| `cameraView` | `string` | `"upper"` | Camera view ('upper', 'full') |
|
|
188
|
+
| `autoSpeak` | `boolean` | `false` | Automatically speak `text` prop when ready |
|
|
196
189
|
| `onReady` | `function` | `() => {}` | Callback when avatar is ready |
|
|
197
|
-
| `onLoading` | `function` | `() => {}` | Callback for loading progress |
|
|
198
190
|
| `onError` | `function` | `() => {}` | Callback for errors |
|
|
191
|
+
| `onSpeechEnd` | `function` | `() => {}` | Callback when speech ends |
|
|
199
192
|
| `className` | `string` | `""` | Additional CSS classes |
|
|
200
193
|
| `style` | `object` | `{}` | Additional inline styles |
|
|
201
194
|
|
|
202
|
-
|
|
195
|
+
**Ref Methods:**
|
|
203
196
|
|
|
204
197
|
| Method | Parameters | Description |
|
|
205
198
|
|--------|------------|-------------|
|
|
206
|
-
| `speakText(text)` | `text: string` | Make
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
210
|
-
| `
|
|
211
|
-
| `
|
|
212
|
-
| `
|
|
213
|
-
| `
|
|
214
|
-
| `
|
|
199
|
+
| `speakText(text, options)` | `text: string`, `options: object` | Make avatar speak text |
|
|
200
|
+
| `pauseSpeaking()` | - | Pause current speech |
|
|
201
|
+
| `resumeSpeaking()` | - | Resume paused speech |
|
|
202
|
+
| `stopSpeaking()` | - | Stop all speech |
|
|
203
|
+
| `resumeAudioContext()` | - | Resume audio context (for user interaction) |
|
|
204
|
+
| `isPaused()` | - | Check if currently paused |
|
|
205
|
+
| `setMood(mood)` | `mood: string` | Change avatar mood |
|
|
206
|
+
| `setBodyMovement(movement)` | `movement: string` | Change body movement |
|
|
207
|
+
| `playAnimation(name)` | `name: string` | Play FBX animation |
|
|
208
|
+
| `playReaction(type)` | `type: string` | Play reaction animation |
|
|
215
209
|
| `playCelebration()` | - | Play celebration animation |
|
|
216
210
|
| `setShowFullAvatar(show)` | `show: boolean` | Toggle full body mode |
|
|
211
|
+
| `isReady` | - | Boolean indicating if avatar is ready |
|
|
212
|
+
|
|
213
|
+
**Example:**
|
|
214
|
+
|
|
215
|
+
```jsx
|
|
216
|
+
const avatarRef = useRef(null);
|
|
217
|
+
|
|
218
|
+
// Speak text
|
|
219
|
+
avatarRef.current?.speakText("Hello world!", {
|
|
220
|
+
lipsyncLang: 'en',
|
|
221
|
+
onSpeechEnd: () => console.log('Done speaking')
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Pause/Resume
|
|
225
|
+
avatarRef.current?.pauseSpeaking();
|
|
226
|
+
avatarRef.current?.resumeSpeaking();
|
|
227
|
+
|
|
228
|
+
// Change mood
|
|
229
|
+
avatarRef.current?.setMood("happy");
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### TalkingHeadAvatar
|
|
233
|
+
|
|
234
|
+
Full-featured avatar component with advanced controls, animations, and TTS configuration.
|
|
235
|
+
|
|
236
|
+
**Props:** Same as `SimpleTalkingAvatar` plus:
|
|
237
|
+
|
|
238
|
+
| Prop | Type | Default | Description |
|
|
239
|
+
|------|------|---------|-------------|
|
|
240
|
+
| `animations` | `object` | `{}` | Object mapping animation names to FBX file paths |
|
|
241
|
+
| `onLoading` | `function` | `() => {}` | Callback for loading progress |
|
|
242
|
+
|
|
243
|
+
**Ref Methods:** Same as `SimpleTalkingAvatar` plus:
|
|
244
|
+
|
|
245
|
+
| Method | Parameters | Description |
|
|
246
|
+
|--------|------------|-------------|
|
|
247
|
+
| `setTimingAdjustment(rate)` | `rate: number` | Adjust animation timing (e.g., 1.05 for 5% slower) |
|
|
248
|
+
| `setMovementIntensity(intensity)` | `intensity: number` | Set movement intensity (0-1) |
|
|
249
|
+
| `playRandomDance()` | - | Play random dance animation |
|
|
217
250
|
| `lockAvatarPosition()` | - | Lock avatar position |
|
|
218
251
|
| `unlockAvatarPosition()` | - | Unlock avatar position |
|
|
219
252
|
|
|
220
|
-
### CurriculumLearning
|
|
253
|
+
### CurriculumLearning
|
|
254
|
+
|
|
255
|
+
Complete learning system with curriculum management, questions, and code examples.
|
|
256
|
+
|
|
257
|
+
**Props:**
|
|
221
258
|
|
|
222
259
|
| Prop | Type | Default | Description |
|
|
223
260
|
|------|------|---------|-------------|
|
|
224
|
-
| `curriculumData` | `object` | `null` | Curriculum data object |
|
|
225
|
-
| `avatarConfig` | `object` | `{}` | Avatar configuration |
|
|
261
|
+
| `curriculumData` | `object` | `null` | Curriculum data object (see structure below) |
|
|
262
|
+
| `avatarConfig` | `object` | `{}` | Avatar configuration (same as `SimpleTalkingAvatar` props) |
|
|
226
263
|
| `animations` | `object` | `{}` | Animation files mapping |
|
|
264
|
+
| `autoStart` | `boolean` | `false` | Automatically start teaching when ready |
|
|
227
265
|
| `onLessonStart` | `function` | `() => {}` | Callback when lesson starts |
|
|
228
266
|
| `onLessonComplete` | `function` | `() => {}` | Callback when lesson completes |
|
|
229
267
|
| `onQuestionAnswer` | `function` | `() => {}` | Callback when question is answered |
|
|
230
268
|
| `onCurriculumComplete` | `function` | `() => {}` | Callback when curriculum completes |
|
|
231
|
-
| `
|
|
269
|
+
| `onCustomAction` | `function` | `() => {}` | Callback for custom actions (interactive mode) |
|
|
232
270
|
|
|
233
|
-
|
|
271
|
+
**Ref Methods:**
|
|
234
272
|
|
|
235
273
|
| Method | Parameters | Description |
|
|
236
274
|
|--------|------------|-------------|
|
|
237
|
-
| `startTeaching()` | - | Start teaching
|
|
275
|
+
| `startTeaching()` | - | Start teaching current lesson |
|
|
238
276
|
| `startQuestions()` | - | Start asking questions |
|
|
239
|
-
| `handleAnswerSelect(answer)` | `answer: string/boolean` |
|
|
277
|
+
| `handleAnswerSelect(answer)` | `answer: string/boolean` | Submit answer to current question |
|
|
240
278
|
| `nextQuestion()` | - | Move to next question |
|
|
279
|
+
| `previousQuestion()` | - | Move to previous question |
|
|
241
280
|
| `nextLesson()` | - | Move to next lesson |
|
|
281
|
+
| `previousLesson()` | - | Move to previous lesson |
|
|
242
282
|
| `completeLesson()` | - | Complete current lesson |
|
|
243
283
|
| `completeCurriculum()` | - | Complete entire curriculum |
|
|
244
284
|
| `resetCurriculum()` | - | Reset curriculum to beginning |
|
|
245
285
|
| `getState()` | - | Get current curriculum state |
|
|
286
|
+
| `pauseSpeaking()` | - | Pause avatar speech |
|
|
287
|
+
| `resumeSpeaking()` | - | Resume avatar speech |
|
|
288
|
+
| `isPaused()` | - | Check if paused |
|
|
289
|
+
| `speakText(text, options)` | `text: string`, `options: object` | Make avatar speak text |
|
|
246
290
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
The package includes a TTS configuration system. You can configure TTS services in `src/config/ttsConfig.js`:
|
|
291
|
+
**Curriculum Data Structure:**
|
|
250
292
|
|
|
251
293
|
```javascript
|
|
252
|
-
|
|
294
|
+
{
|
|
295
|
+
curriculum: {
|
|
296
|
+
title: "Course Title",
|
|
297
|
+
description: "Course description",
|
|
298
|
+
language: "en",
|
|
299
|
+
modules: [
|
|
300
|
+
{
|
|
301
|
+
title: "Module Title",
|
|
302
|
+
lessons: [
|
|
303
|
+
{
|
|
304
|
+
title: "Lesson Title",
|
|
305
|
+
avatar_script: "What the avatar will say",
|
|
306
|
+
body: "Lesson content text",
|
|
307
|
+
code_example: { // Optional
|
|
308
|
+
code: "console.log('Hello');",
|
|
309
|
+
language: "javascript",
|
|
310
|
+
description: "Code example description",
|
|
311
|
+
autoRun: true,
|
|
312
|
+
typingSpeed: 50
|
|
313
|
+
},
|
|
314
|
+
questions: [ // Optional
|
|
315
|
+
{
|
|
316
|
+
type: "multiple_choice", // or "true_false" or "code_test"
|
|
317
|
+
question: "Question text?",
|
|
318
|
+
options: ["Option 1", "Option 2", "Option 3"], // For multiple_choice
|
|
319
|
+
answer: "Option 1", // or true/false for true_false
|
|
320
|
+
explanation: "Why this answer is correct"
|
|
321
|
+
}
|
|
322
|
+
]
|
|
323
|
+
}
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
```
|
|
253
330
|
|
|
254
|
-
|
|
255
|
-
|
|
331
|
+
**Interactive Mode:**
|
|
332
|
+
|
|
333
|
+
For manual control over curriculum progression:
|
|
334
|
+
|
|
335
|
+
```jsx
|
|
336
|
+
const curriculumRef = useRef(null);
|
|
337
|
+
|
|
338
|
+
// Handle custom actions
|
|
339
|
+
const handleCustomAction = (action) => {
|
|
340
|
+
switch (action.type) {
|
|
341
|
+
case 'teachingComplete':
|
|
342
|
+
// Teaching finished, enable "Start Questions" button
|
|
343
|
+
break;
|
|
344
|
+
case 'questionStart':
|
|
345
|
+
// Question started, show question UI
|
|
346
|
+
break;
|
|
347
|
+
case 'answerFeedbackComplete':
|
|
348
|
+
// Answer feedback finished, enable "Next Question" button
|
|
349
|
+
break;
|
|
350
|
+
case 'allQuestionsComplete':
|
|
351
|
+
// All questions done, enable "Complete Lesson" button
|
|
352
|
+
break;
|
|
353
|
+
case 'lessonCompleteFeedbackDone':
|
|
354
|
+
// Lesson completion feedback done, enable "Next Lesson" button
|
|
355
|
+
break;
|
|
356
|
+
case 'codeExampleReady':
|
|
357
|
+
// Code example ready, trigger IDE typing animation
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
<CurriculumLearning
|
|
363
|
+
ref={curriculumRef}
|
|
364
|
+
curriculumData={curriculumData}
|
|
365
|
+
avatarConfig={avatarConfig}
|
|
366
|
+
autoStart={false} // Manual control
|
|
367
|
+
onCustomAction={handleCustomAction}
|
|
368
|
+
/>
|
|
369
|
+
|
|
370
|
+
// Control progression manually
|
|
371
|
+
curriculumRef.current?.startTeaching();
|
|
372
|
+
curriculumRef.current?.startQuestions();
|
|
373
|
+
curriculumRef.current?.nextQuestion();
|
|
374
|
+
curriculumRef.current?.completeLesson();
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## 🎤 Text-to-Speech Services
|
|
378
|
+
|
|
379
|
+
### Edge TTS (Default)
|
|
380
|
+
|
|
381
|
+
Free, no API key required:
|
|
382
|
+
|
|
383
|
+
```jsx
|
|
384
|
+
<SimpleTalkingAvatar
|
|
385
|
+
ttsService="edge"
|
|
386
|
+
ttsVoice="en-US-AriaNeural"
|
|
387
|
+
/>
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### ElevenLabs
|
|
391
|
+
|
|
392
|
+
High-quality voices, requires API key:
|
|
393
|
+
|
|
394
|
+
```jsx
|
|
395
|
+
<SimpleTalkingAvatar
|
|
396
|
+
ttsService="elevenlabs"
|
|
397
|
+
ttsApiKey="your-api-key"
|
|
398
|
+
ttsVoice="21m00Tcm4TlvDq8ikWAM"
|
|
399
|
+
/>
|
|
256
400
|
```
|
|
257
401
|
|
|
258
|
-
|
|
402
|
+
### Deepgram
|
|
403
|
+
|
|
404
|
+
Fast, high-quality TTS, requires API key:
|
|
405
|
+
|
|
406
|
+
```jsx
|
|
407
|
+
<SimpleTalkingAvatar
|
|
408
|
+
ttsService="deepgram"
|
|
409
|
+
ttsApiKey="your-api-key"
|
|
410
|
+
ttsVoice="aura-asteria-en" // Options: aura-thalia-en, aura-asteria-en, aura-orion-en, etc.
|
|
411
|
+
/>
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Browser TTS
|
|
415
|
+
|
|
416
|
+
Uses browser's built-in speech synthesis:
|
|
417
|
+
|
|
418
|
+
```jsx
|
|
419
|
+
<SimpleTalkingAvatar
|
|
420
|
+
ttsService="browser"
|
|
421
|
+
/>
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Google Cloud / Azure
|
|
425
|
+
|
|
426
|
+
```jsx
|
|
427
|
+
<SimpleTalkingAvatar
|
|
428
|
+
ttsService="google" // or "azure"
|
|
429
|
+
ttsApiKey="your-api-key"
|
|
430
|
+
ttsVoice="en-US-Wavenet-D"
|
|
431
|
+
/>
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## 🎬 Animations
|
|
259
435
|
|
|
260
436
|
### FBX Animations
|
|
261
437
|
|
|
@@ -265,7 +441,8 @@ Provide animation mappings via the `animations` prop:
|
|
|
265
441
|
const animations = {
|
|
266
442
|
teaching: "/animations/Arguing.fbx",
|
|
267
443
|
correct: "/animations/Happy.fbx",
|
|
268
|
-
incorrect: "/animations/Disappointed.fbx"
|
|
444
|
+
incorrect: "/animations/Disappointed.fbx",
|
|
445
|
+
lessonComplete: "/animations/Step.fbx"
|
|
269
446
|
};
|
|
270
447
|
|
|
271
448
|
<TalkingHeadAvatar animations={animations} />
|
|
@@ -273,19 +450,173 @@ const animations = {
|
|
|
273
450
|
|
|
274
451
|
### Code-Based Animations
|
|
275
452
|
|
|
276
|
-
|
|
453
|
+
Built-in body movements:
|
|
277
454
|
|
|
278
455
|
- `idle` - Idle animation
|
|
279
456
|
- `gesturing` - Teaching gestures
|
|
457
|
+
- `dancing` - Dance animation
|
|
280
458
|
- `happy` - Happy mood animation
|
|
281
459
|
- `sad` - Sad mood animation
|
|
282
|
-
- `dancing` - Dance animation
|
|
283
|
-
- And more...
|
|
284
460
|
|
|
285
|
-
|
|
461
|
+
```jsx
|
|
462
|
+
avatarRef.current?.setBodyMovement("gesturing");
|
|
463
|
+
avatarRef.current?.playReaction("happy");
|
|
464
|
+
avatarRef.current?.playCelebration();
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## 📚 Question Types
|
|
468
|
+
|
|
469
|
+
### Multiple Choice
|
|
470
|
+
|
|
471
|
+
```javascript
|
|
472
|
+
{
|
|
473
|
+
type: "multiple_choice",
|
|
474
|
+
question: "What is a variable?",
|
|
475
|
+
options: ["A container", "A function", "A loop"],
|
|
476
|
+
answer: "A container",
|
|
477
|
+
explanation: "A variable is a container that stores data."
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### True/False
|
|
482
|
+
|
|
483
|
+
```javascript
|
|
484
|
+
{
|
|
485
|
+
type: "true_false",
|
|
486
|
+
question: "JavaScript is a compiled language.",
|
|
487
|
+
answer: false,
|
|
488
|
+
explanation: "JavaScript is an interpreted language."
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Code Test
|
|
493
|
+
|
|
494
|
+
```javascript
|
|
495
|
+
{
|
|
496
|
+
type: "code_test",
|
|
497
|
+
question: "Write a function that adds two numbers.",
|
|
498
|
+
testCriteria: {
|
|
499
|
+
type: "function",
|
|
500
|
+
functionName: "add",
|
|
501
|
+
testCases: [
|
|
502
|
+
{ input: [2, 3], expectedOutput: 5 },
|
|
503
|
+
{ input: [10, 20], expectedOutput: 30 }
|
|
504
|
+
]
|
|
505
|
+
},
|
|
506
|
+
explanation: "The function should return the sum of two numbers."
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
## 💻 Code Examples
|
|
511
|
+
|
|
512
|
+
Include code examples in lessons for IDE integration:
|
|
513
|
+
|
|
514
|
+
```javascript
|
|
515
|
+
{
|
|
516
|
+
title: "JavaScript Variables",
|
|
517
|
+
avatar_script: "Let's learn about variables.",
|
|
518
|
+
body: "Variables store data values.",
|
|
519
|
+
code_example: {
|
|
520
|
+
code: "let name = 'Alice';\nconst age = 25;\nconsole.log(name);",
|
|
521
|
+
language: "javascript", // "javascript", "python", "java", "html"
|
|
522
|
+
description: "Basic variable declarations",
|
|
523
|
+
autoRun: true, // Automatically run after typing
|
|
524
|
+
typingSpeed: 50 // Characters per second
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
Listen for `codeExampleReady` event in interactive mode:
|
|
530
|
+
|
|
531
|
+
```jsx
|
|
532
|
+
const handleCustomAction = (action) => {
|
|
533
|
+
if (action.type === 'codeExampleReady') {
|
|
534
|
+
// Trigger IDE typing animation
|
|
535
|
+
handleCodeExample(action.codeExample);
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
## 🎯 Use Cases
|
|
541
|
+
|
|
542
|
+
- **Educational Platforms** - Interactive learning with curriculum management
|
|
543
|
+
- **Virtual Assistants** - Conversational avatars with TTS
|
|
544
|
+
- **Code Tutorials** - Step-by-step coding lessons with IDE integration
|
|
545
|
+
- **Training Simulations** - Interactive training with questions and feedback
|
|
546
|
+
- **Presentation Tools** - Animated presentations with talking avatars
|
|
547
|
+
|
|
548
|
+
## 🔧 Configuration
|
|
549
|
+
|
|
550
|
+
### TTS Configuration
|
|
551
|
+
|
|
552
|
+
Configure default TTS service in your app:
|
|
553
|
+
|
|
554
|
+
```javascript
|
|
555
|
+
import { getActiveTTSConfig } from '@sage-rsc/talking-head-react';
|
|
556
|
+
|
|
557
|
+
const config = getActiveTTSConfig();
|
|
558
|
+
// Returns current TTS configuration
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Avatar Configuration
|
|
562
|
+
|
|
563
|
+
Common avatar settings:
|
|
564
|
+
|
|
565
|
+
```javascript
|
|
566
|
+
const avatarConfig = {
|
|
567
|
+
avatarUrl: "/avatars/brunette.glb",
|
|
568
|
+
avatarBody: "F", // "M" or "F"
|
|
569
|
+
mood: "happy",
|
|
570
|
+
ttsService: "elevenlabs",
|
|
571
|
+
ttsApiKey: "your-key",
|
|
572
|
+
ttsVoice: "voice-id",
|
|
573
|
+
showFullAvatar: false, // false = head only, true = full body
|
|
574
|
+
bodyMovement: "gesturing",
|
|
575
|
+
movementIntensity: 0.7
|
|
576
|
+
};
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
## 📝 Examples
|
|
580
|
+
|
|
581
|
+
Check the `example-*.jsx` files in the repository for complete examples:
|
|
582
|
+
|
|
583
|
+
- `example-simple-avatar.jsx` - Simple text-to-speech usage
|
|
584
|
+
- `example-interactive-mode.jsx` - Manual curriculum control
|
|
585
|
+
- `example-with-code-ide.jsx` - Code IDE integration
|
|
586
|
+
- `example-with-api-key.jsx` - TTS service configuration
|
|
587
|
+
|
|
588
|
+
## 🐛 Troubleshooting
|
|
589
|
+
|
|
590
|
+
### Audio Not Playing
|
|
591
|
+
|
|
592
|
+
If you see "Web Audio API suspended" error:
|
|
593
|
+
|
|
594
|
+
```jsx
|
|
595
|
+
// The component automatically resumes audio context on user interaction
|
|
596
|
+
// But you can also manually resume:
|
|
597
|
+
avatarRef.current?.resumeAudioContext();
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### Avatar Not Loading
|
|
601
|
+
|
|
602
|
+
- Ensure the avatar file path is correct
|
|
603
|
+
- Check browser console for loading errors
|
|
604
|
+
- Verify GLB file is valid
|
|
605
|
+
|
|
606
|
+
### Lip-Sync Not Working
|
|
607
|
+
|
|
608
|
+
- Ensure avatar model has viseme morph targets
|
|
609
|
+
- Check that `lipsyncLang` matches your TTS language
|
|
610
|
+
- Verify TTS service is working correctly
|
|
611
|
+
|
|
612
|
+
## 📄 License
|
|
286
613
|
|
|
287
614
|
MIT
|
|
288
615
|
|
|
289
|
-
## Contributing
|
|
616
|
+
## 🤝 Contributing
|
|
290
617
|
|
|
291
618
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
619
|
+
|
|
620
|
+
## 📞 Support
|
|
621
|
+
|
|
622
|
+
For issues, questions, or feature requests, please open an issue on GitHub.
|