@spatialwalk/avatarkit 1.0.0-beta.3 → 1.0.0-beta.5

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +306 -36
  3. package/dist/{StreamingAudioPlayer-BeLlDiwE.js → StreamingAudioPlayer-8Dz_aHCW.js} +89 -58
  4. package/dist/StreamingAudioPlayer-8Dz_aHCW.js.map +1 -0
  5. package/dist/animation/AnimationWebSocketClient.d.ts.map +1 -1
  6. package/dist/audio/AnimationPlayer.d.ts +4 -0
  7. package/dist/audio/AnimationPlayer.d.ts.map +1 -1
  8. package/dist/audio/StreamingAudioPlayer.d.ts +10 -0
  9. package/dist/audio/StreamingAudioPlayer.d.ts.map +1 -1
  10. package/dist/avatar_core_wasm-D4eEi7Eh.js +1666 -0
  11. package/dist/{avatar_core_wasm-DmkU6dYn.js.map → avatar_core_wasm-D4eEi7Eh.js.map} +1 -1
  12. package/dist/avatar_core_wasm.wasm +0 -0
  13. package/dist/config/app-config.d.ts +3 -7
  14. package/dist/config/app-config.d.ts.map +1 -1
  15. package/dist/config/constants.d.ts +19 -3
  16. package/dist/config/constants.d.ts.map +1 -1
  17. package/dist/core/AvatarController.d.ts +91 -64
  18. package/dist/core/AvatarController.d.ts.map +1 -1
  19. package/dist/core/AvatarDownloader.d.ts.map +1 -1
  20. package/dist/core/AvatarKit.d.ts +6 -0
  21. package/dist/core/AvatarKit.d.ts.map +1 -1
  22. package/dist/core/AvatarManager.d.ts.map +1 -1
  23. package/dist/core/AvatarView.d.ts +28 -30
  24. package/dist/core/AvatarView.d.ts.map +1 -1
  25. package/dist/core/NetworkLayer.d.ts +59 -0
  26. package/dist/core/NetworkLayer.d.ts.map +1 -0
  27. package/dist/index-bbc7bE-q.js +5942 -0
  28. package/dist/index-bbc7bE-q.js.map +1 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +12 -11
  31. package/dist/renderer/RenderSystem.d.ts +4 -2
  32. package/dist/renderer/RenderSystem.d.ts.map +1 -1
  33. package/dist/types/index.d.ts +18 -0
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/utils/cls-tracker.d.ts +17 -0
  36. package/dist/utils/cls-tracker.d.ts.map +1 -0
  37. package/dist/utils/logger.d.ts +1 -1
  38. package/dist/utils/logger.d.ts.map +1 -1
  39. package/package.json +8 -4
  40. package/dist/StreamingAudioPlayer-BeLlDiwE.js.map +0 -1
  41. package/dist/avatar_core_wasm-DmkU6dYn.js +0 -1666
  42. package/dist/index-NmYXWJnL.js +0 -9712
  43. package/dist/index-NmYXWJnL.js.map +0 -1
  44. package/dist/utils/posthog-tracker.d.ts +0 -82
  45. package/dist/utils/posthog-tracker.d.ts.map +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,127 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0-beta.5] - 2025-11-14
9
+
10
+ ### 🐛 Bug Fixes
11
+ - Fixed missing `AvatarPlaybackMode` enum export in published package
12
+
13
+ ---
14
+
15
+ ## [1.0.0-beta.4] - 2025-11-14
16
+
17
+ ### 🔄 Updates
18
+ - Updated WASM module (avatar_core_wasm.wasm)
19
+
20
+ ---
21
+
22
+ ## [1.0.0-beta.3] - 2025-11-13
23
+
24
+ ### 🎉 Major Changes
25
+
26
+ #### Architecture Refactoring - Three-Layer Architecture
27
+ - **Rendering Layer (AvatarView)**: Pure rendering responsibility, receives rendering instructions from the playback layer
28
+ - **Playback Layer (AvatarController)**: Unified data controller responsible for audio playback and animation rendering synchronization
29
+ - **Network Layer (NetworkLayer)**: Optional network communication layer, automatically composed only in network mode
30
+
31
+ #### Dual Playback Mode Support
32
+ - **Network Mode**:
33
+ - Send audio data to server via WebSocket
34
+ - Automatically receive and play animation data returned from server
35
+ - Use `controller.start()` and `controller.send()` methods
36
+
37
+ - **External Data Mode**:
38
+ - External components fully control audio and animation data acquisition
39
+ - SDK only responsible for synchronized playback of externally provided data
40
+ - Use `controller.play()`, `controller.sendAudioChunk()` and `controller.sendKeyframes()` methods
41
+
42
+ ### ✨ New Features
43
+
44
+ - **Transition Animation Optimization**:
45
+ - Transition animation duration adjusted to 200ms
46
+ - Improved audio-animation synchronization logic, ensuring audio and animation start playing together after transition animation ends
47
+ - Optimized transition frame generation and alignment logic
48
+
49
+ - **Camera Configuration Enhancement**:
50
+ - Default transparent background, background rendering functionality removed
51
+ - Camera configuration aligned with iOS (Reversed-Z projection, near=0.01, far=100)
52
+ - Support dynamic camera configuration loading from characterSettings and camera.json
53
+
54
+ - **Audio Sample Rate Configuration**:
55
+ - Updated default audio sample rate to 16kHz (previously 24kHz) to match backend requirements
56
+ - Audio format requirement: 16kHz mono PCM16
57
+
58
+ - **Telemetry Migration**:
59
+ - Migrated from PostHog to Tencent Cloud CLS (Cloud Log Service)
60
+ - Support environment-based dynamic configuration (cn/test/us)
61
+ - Support both Token and SecretId/SecretKey authentication methods
62
+ - Aligned with iOS SDK configuration
63
+
64
+ ### 🔧 API Changes
65
+
66
+ #### Breaking Changes
67
+
68
+ - **AvatarView Constructor**:
69
+ ```typescript
70
+ // Old API
71
+ new AvatarView(avatar, container)
72
+
73
+ // New API
74
+ new AvatarView(avatar, {
75
+ container: container,
76
+ playbackMode: AvatarPlaybackMode.network // or AvatarPlaybackMode.external
77
+ })
78
+ ```
79
+
80
+ - **AvatarController Methods**:
81
+ - Network Mode: `start()` / `close()` / `send()`
82
+ - External Data Mode: `play()` / `sendAudioChunk()` / `sendKeyframes()`
83
+ - Common Methods: `interrupt()` / `clear()` / `dispose()`
84
+
85
+ - **Removed Properties**:
86
+ - `realtimeStartTime` property removed (no longer needed)
87
+
88
+ ### 🐛 Bug Fixes
89
+
90
+ - Fixed audio-animation desynchronization during transition animation
91
+ - Fixed animation freezing issue in external data mode
92
+ - Fixed audio playback speed abnormality caused by sample rate mismatch
93
+ - Fixed camera configuration priority logic
94
+ - Fixed WebSocket connection state callback timing issues
95
+
96
+ ### 📚 Documentation
97
+
98
+ - Updated README.md with detailed explanation of three-layer architecture and two playback modes
99
+ - Added audio format requirements documentation (16kHz mono PCM16)
100
+ - Updated API reference documentation and code examples
101
+ - Added architecture diagrams and flowcharts
102
+
103
+ ### 🧪 Testing
104
+
105
+ - Updated unit tests to cover new architecture
106
+ - Added unit tests for external data mode
107
+ - Updated E2E tests to use new API
108
+ - All tests passing (69 unit tests + 24 E2E tests)
109
+
110
+ ### 🔄 Internal Changes
111
+
112
+ - Refactored `AvatarController` into unified playback layer
113
+ - Extracted `NetworkLayer` as independent component
114
+ - Optimized animation playback loop and audio-animation synchronization logic
115
+ - Updated WASM module (avatar_core_wasm.wasm)
116
+ - Improved error handling and logging
117
+
118
+ ### 📦 Dependencies
119
+
120
+ - No new dependencies added
121
+ - Maintained existing dependency versions
122
+
123
+ ---
124
+
125
+ ## [1.0.0-beta.2] - Previous Version
126
+
127
+ (Previous version changelog entries...)
package/README.md CHANGED
@@ -47,51 +47,159 @@ const avatar = await avatarManager.load('character-id', (progress) => {
47
47
  })
48
48
 
49
49
  // 3. Create view (automatically creates Canvas and AvatarController)
50
+ // Network mode (default)
50
51
  const container = document.getElementById('avatar-container')
51
- const avatarView = new AvatarView(avatar, container)
52
+ const avatarView = new AvatarView(avatar, {
53
+ container: container,
54
+ playbackMode: 'network' // Optional, 'network' is default
55
+ })
52
56
 
53
- // 4. Start real-time communication
57
+ // 4. Start real-time communication (network mode only)
54
58
  await avatarView.avatarController.start()
55
59
 
56
- // 5. Send audio data
60
+ // 5. Send audio data (network mode)
61
+ // ⚠️ Important: Audio must be 16kHz mono PCM16 format
57
62
  // If audio is Uint8Array, you can use slice().buffer to convert to ArrayBuffer
58
- const audioUint8 = new Uint8Array(1024) // Example: audio data
63
+ const audioUint8 = new Uint8Array(1024) // Example: 16kHz PCM16 audio data (512 samples = 1024 bytes)
59
64
  const audioData = audioUint8.slice().buffer // Simplified conversion, works for ArrayBuffer and SharedArrayBuffer
60
65
  avatarView.avatarController.send(audioData, false) // Send audio data, will automatically start playing after accumulating enough data
61
66
  avatarView.avatarController.send(audioData, true) // end=true means immediately return animation data, no longer accumulating
62
67
  ```
63
68
 
64
- ### Complete Example
69
+ ### External Data Mode Example
70
+
71
+ ```typescript
72
+ import { AvatarPlaybackMode } from '@spatialwalk/avatarkit'
73
+
74
+ // 1-3. Same as network mode (initialize SDK, load character)
75
+
76
+ // 3. Create view with external data mode
77
+ const container = document.getElementById('avatar-container')
78
+ const avatarView = new AvatarView(avatar, {
79
+ container: container,
80
+ playbackMode: AvatarPlaybackMode.external
81
+ })
65
82
 
66
- Check the example code in the GitHub repository for the complete usage flow.
83
+ // 4. Start playback with initial data (obtained from your service)
84
+ // Note: Audio and animation data should be obtained from your backend service
85
+ const initialAudioChunks = [{ data: audioData1, isLast: false }, { data: audioData2, isLast: false }]
86
+ const initialKeyframes = animationData1 // Animation keyframes from your service
87
+
88
+ await avatarView.avatarController.play(initialAudioChunks, initialKeyframes)
89
+
90
+ // 5. Stream additional data as needed
91
+ avatarView.avatarController.sendAudioChunk(audioData3, false)
92
+ avatarView.avatarController.sendKeyframes(animationData2)
93
+ ```
94
+
95
+ ### Complete Examples
96
+
97
+ Check the example code in the GitHub repository for complete usage flows for both modes.
67
98
 
68
99
  **Example Project:** [Avatarkit-web-demo](https://github.com/spatialwalk/Avatarkit-web-demo)
69
100
 
70
- This repository contains complete examples for Vanilla JS, Vue 3, and React, demonstrating how to integrate and use SPAvatarKit SDK in different frameworks.
101
+ This repository contains complete examples for Vanilla JS, Vue 3, and React, demonstrating:
102
+ - Network mode: Real-time audio input with automatic animation data reception
103
+ - External data mode: Custom data sources with manual audio/animation data management
71
104
 
72
105
  ## 🏗️ Architecture Overview
73
106
 
107
+ ### Three-Layer Architecture
108
+
109
+ The SDK uses a three-layer architecture for clear separation of concerns:
110
+
111
+ 1. **Rendering Layer (AvatarView)** - Responsible for 3D rendering only
112
+ 2. **Playback Layer (AvatarController)** - Manages audio/animation synchronization and playback
113
+ 3. **Network Layer (NetworkLayer)** - Handles WebSocket communication (only in network mode)
114
+
74
115
  ### Core Components
75
116
 
76
117
  - **AvatarKit** - SDK initialization and management
77
118
  - **AvatarManager** - Character resource loading and management
78
- - **AvatarView** - 3D rendering view (internally contains AvatarController)
79
- - **AvatarController** - Real-time communication and data processing
119
+ - **AvatarView** - 3D rendering view (rendering layer)
120
+ - **AvatarController** - Audio/animation playback controller (playback layer)
121
+ - **NetworkLayer** - WebSocket communication (network layer, automatically composed in network mode)
80
122
  - **AvatarCoreAdapter** - WASM module adapter
81
123
 
124
+ ### Playback Modes
125
+
126
+ The SDK supports two playback modes, configured when creating `AvatarView`:
127
+
128
+ #### 1. Network Mode (Default)
129
+ - SDK handles WebSocket communication automatically
130
+ - Send audio data via `AvatarController.send()`
131
+ - SDK receives animation data from backend and synchronizes playback
132
+ - Best for: Real-time audio input scenarios
133
+
134
+ #### 2. External Data Mode
135
+ - External components manage their own network/data fetching
136
+ - External components provide both audio and animation data
137
+ - SDK only handles synchronized playback
138
+ - Best for: Custom data sources, pre-recorded content, or custom network implementations
139
+
82
140
  ### Data Flow
83
141
 
142
+ #### Network Mode Flow
143
+
144
+ ```
145
+ User audio input (16kHz mono PCM16)
146
+
147
+ AvatarController.send()
148
+
149
+ NetworkLayer → WebSocket → Backend processing
150
+
151
+ Backend returns animation data (FLAME keyframes)
152
+
153
+ NetworkLayer → AvatarController → AnimationPlayer
154
+
155
+ FLAME parameters → AvatarCore.computeFrameFlatFromParams() → Splat data
156
+
157
+ AvatarController (playback loop) → AvatarView.renderRealtimeFrame()
158
+
159
+ RenderSystem → WebGPU/WebGL → Canvas rendering
160
+ ```
161
+
162
+ #### External Data Mode Flow
163
+
84
164
  ```
85
- User audio input (16kHz mono PCM) → AvatarController → WebSocket → Backend processing
86
-
87
- Backend returns animation data (FLAME keyframes) AvatarController → AnimationPlayer
88
-
165
+ External data source (audio + animation)
166
+
167
+ AvatarController.play(initialAudio, initialKeyframes) // Start playback
168
+
169
+ AvatarController.sendAudioChunk() // Stream additional audio
170
+ AvatarController.sendKeyframes() // Stream additional animation
171
+
172
+ AvatarController → AnimationPlayer (synchronized playback)
173
+
89
174
  FLAME parameters → AvatarCore.computeFrameFlatFromParams() → Splat data
90
-
91
- Splat data RenderSystem WebGPU/WebGL → Canvas rendering
175
+
176
+ AvatarController (playback loop)AvatarView.renderRealtimeFrame()
177
+
178
+ RenderSystem → WebGPU/WebGL → Canvas rendering
92
179
  ```
93
180
 
94
- **Note:** Users need to provide audio data themselves (16kHz mono PCM), SDK handles receiving animation data and rendering.
181
+ **Note:**
182
+ - In network mode, users provide audio data, SDK handles network communication and animation data reception
183
+ - In external data mode, users provide both audio and animation data, SDK handles synchronized playback only
184
+
185
+ ### Audio Format Requirements
186
+
187
+ **⚠️ Important:** The SDK requires audio data to be in **16kHz mono PCM16** format:
188
+
189
+ - **Sample Rate**: 16kHz (16000 Hz) - This is a backend requirement
190
+ - **Channels**: Mono (single channel)
191
+ - **Format**: PCM16 (16-bit signed integer, little-endian)
192
+ - **Byte Order**: Little-endian
193
+
194
+ **Audio Data Format:**
195
+ - Each sample is 2 bytes (16-bit)
196
+ - Audio data should be provided as `ArrayBuffer` or `Uint8Array`
197
+ - For example: 1 second of audio = 16000 samples × 2 bytes = 32000 bytes
198
+
199
+ **Resampling:**
200
+ - If your audio source is at a different sample rate (e.g., 24kHz, 48kHz), you must resample it to 16kHz before sending to the SDK
201
+ - For high-quality resampling, we recommend using Web Audio API's `OfflineAudioContext` with anti-aliasing filtering
202
+ - See example projects for resampling implementation
95
203
 
96
204
  ## 📚 API Reference
97
205
 
@@ -129,20 +237,36 @@ manager.clearCache()
129
237
 
130
238
  ### AvatarView
131
239
 
132
- 3D rendering view, internally automatically creates and manages AvatarController.
240
+ 3D rendering view (rendering layer), responsible for 3D rendering only. Internally automatically creates and manages `AvatarController`.
133
241
 
134
242
  **⚠️ Important Limitation:** Currently, the SDK only supports one AvatarView instance at a time. If you need to switch characters, you must first call the `dispose()` method to clean up the current AvatarView, then create a new instance.
135
243
 
244
+ **Playback Mode Configuration:**
245
+ - The playback mode is fixed when creating `AvatarView` and persists throughout its lifecycle
246
+ - Cannot be changed after creation
247
+
136
248
  ```typescript
249
+ import { AvatarPlaybackMode } from '@spatialwalk/avatarkit'
250
+
137
251
  // Create view (Canvas is automatically added to container)
138
- const avatarView = new AvatarView(avatar: Avatar, container?: HTMLElement)
252
+ // Network mode (default)
253
+ const container = document.getElementById('avatar-container')
254
+ const avatarView = new AvatarView(avatar: Avatar, {
255
+ container: container,
256
+ playbackMode: AvatarPlaybackMode.network // Optional, default is 'network'
257
+ })
258
+
259
+ // External data mode
260
+ const avatarView = new AvatarView(avatar: Avatar, {
261
+ container: container,
262
+ playbackMode: AvatarPlaybackMode.external
263
+ })
139
264
 
140
265
  // Get Canvas element
141
266
  const canvas = avatarView.getCanvas()
142
267
 
143
- // Set background
144
- avatarView.setBackgroundImage('path/to/image.jpg')
145
- avatarView.setBackgroundOpaque(true)
268
+ // Get playback mode
269
+ const mode = avatarView.playbackMode // 'network' | 'external'
146
270
 
147
271
  // Update camera configuration
148
272
  avatarView.updateCameraConfig(cameraConfig: CameraConfig)
@@ -163,39 +287,98 @@ if (currentAvatarView) {
163
287
  // Load new character
164
288
  const newAvatar = await avatarManager.load('new-character-id')
165
289
 
166
- // Create new AvatarView
167
- currentAvatarView = new AvatarView(newAvatar, container)
168
- await currentAvatarView.avatarController.start()
290
+ // Create new AvatarView (with same or different playback mode)
291
+ currentAvatarView = new AvatarView(newAvatar, {
292
+ container: container,
293
+ playbackMode: AvatarPlaybackMode.network
294
+ })
295
+
296
+ // Network mode: start connection
297
+ if (currentAvatarView.playbackMode === AvatarPlaybackMode.network) {
298
+ await currentAvatarView.avatarController.start()
299
+ }
169
300
  ```
170
301
 
171
302
  ### AvatarController
172
303
 
173
- Real-time communication controller, handles WebSocket connections and animation data.
304
+ Audio/animation playback controller (playback layer), manages synchronized playback of audio and animation. Automatically composes `NetworkLayer` in network mode.
305
+
306
+ **Two Usage Patterns:**
307
+
308
+ #### Network Mode Methods
174
309
 
175
310
  ```typescript
176
- // Start connection
311
+ // Start WebSocket service
177
312
  await avatarView.avatarController.start()
178
313
 
179
- // Send audio data
314
+ // Send audio data (SDK handles receiving animation data automatically)
180
315
  avatarView.avatarController.send(audioData: ArrayBuffer, end: boolean)
181
- // audioData: Audio data (ArrayBuffer format)
316
+ // audioData: Audio data (ArrayBuffer format, must be 16kHz mono PCM16)
317
+ // - Sample rate: 16kHz (16000 Hz) - backend requirement
318
+ // - Format: PCM16 (16-bit signed integer, little-endian)
319
+ // - Channels: Mono (single channel)
320
+ // - Example: 1 second = 16000 samples × 2 bytes = 32000 bytes
182
321
  // end: false (default) - Normal audio data sending, server will accumulate audio data, automatically returns animation data and starts synchronized playback of animation and audio after accumulating enough data
183
322
  // end: true - Immediately return animation data, no longer accumulating, used for ending current conversation or scenarios requiring immediate response
184
323
 
185
- // Interrupt conversation
324
+ // Close WebSocket service
325
+ avatarView.avatarController.close()
326
+ ```
327
+
328
+ #### External Data Mode Methods
329
+
330
+ ```typescript
331
+ // Start playback with initial audio and animation data
332
+ await avatarView.avatarController.play(
333
+ initialAudioChunks?: Array<{ data: Uint8Array, isLast: boolean }>, // Initial audio chunks (16kHz mono PCM16)
334
+ initialKeyframes?: any[] // Initial animation keyframes (obtained from your service)
335
+ )
336
+
337
+ // Stream additional audio chunks (after play() is called)
338
+ avatarView.avatarController.sendAudioChunk(
339
+ data: Uint8Array, // Audio chunk data
340
+ isLast: boolean = false // Whether this is the last chunk
341
+ )
342
+
343
+ // Stream additional animation keyframes (after play() is called)
344
+ avatarView.avatarController.sendKeyframes(
345
+ keyframes: any[] // Additional animation keyframes (obtained from your service)
346
+ )
347
+ ```
348
+
349
+ #### Common Methods (Both Modes)
350
+
351
+ ```typescript
352
+ // Interrupt current playback (stops and clears data)
186
353
  avatarView.avatarController.interrupt()
187
354
 
188
- // Close connection
355
+ // Clear all data and resources
356
+ avatarView.avatarController.clear()
357
+
358
+ // Get connection state (network mode only)
359
+ const isConnected = avatarView.avatarController.connected
360
+
361
+ // Start service (network mode only)
362
+ await avatarView.avatarController.start()
363
+
364
+ // Close service (network mode only)
189
365
  avatarView.avatarController.close()
190
366
 
367
+ // Get current avatar state
368
+ const state = avatarView.avatarController.state
369
+
191
370
  // Set event callbacks
192
- avatarView.avatarController.onConnectionState = (state: ConnectionState) => {}
371
+ avatarView.avatarController.onConnectionState = (state: ConnectionState) => {} // Network mode only
193
372
  avatarView.avatarController.onAvatarState = (state: AvatarState) => {}
194
373
  avatarView.avatarController.onError = (error: Error) => {}
195
-
196
- // Note: sendText() method is not supported, calling it will throw an error
197
374
  ```
198
375
 
376
+ **Important Notes:**
377
+ - `start()` and `close()` are only available in network mode
378
+ - `play()`, `sendAudioChunk()`, and `sendKeyframes()` are only available in external data mode
379
+ - `interrupt()` and `clear()` are available in both modes
380
+ - The playback mode is determined when creating `AvatarView` and cannot be changed
381
+
199
382
  ## 🔧 Configuration
200
383
 
201
384
  ### Configuration
@@ -218,6 +401,28 @@ enum Environment {
218
401
  }
219
402
  ```
220
403
 
404
+ ### AvatarViewOptions
405
+
406
+ ```typescript
407
+ interface AvatarViewOptions {
408
+ playbackMode?: AvatarPlaybackMode // Playback mode, default is 'network'
409
+ container?: HTMLElement // Canvas container element
410
+ }
411
+ ```
412
+
413
+ **Description:**
414
+ - `playbackMode`: Specifies the playback mode (`'network'` or `'external'`), default is `'network'`
415
+ - `'network'`: SDK handles WebSocket communication, send audio via `send()`
416
+ - `'external'`: External components provide audio and animation data, SDK handles synchronized playback
417
+ - `container`: Optional container element for Canvas, if not provided, Canvas will be created but not added to DOM
418
+
419
+ ```typescript
420
+ enum AvatarPlaybackMode {
421
+ network = 'network', // Network mode: SDK handles WebSocket communication
422
+ external = 'external' // External data mode: External provides data, SDK handles playback
423
+ }
424
+ ```
425
+
221
426
  ### CameraConfig
222
427
 
223
428
  ```typescript
@@ -348,15 +553,43 @@ avatarView.avatarController.onError = (error: Error) => {
348
553
 
349
554
  ### Lifecycle Management
350
555
 
556
+ #### Network Mode Lifecycle
557
+
351
558
  ```typescript
352
559
  // Initialize
353
- const avatarView = new AvatarView(avatar, container)
560
+ const container = document.getElementById('avatar-container')
561
+ const avatarView = new AvatarView(avatar, {
562
+ container: container,
563
+ playbackMode: AvatarPlaybackMode.network
564
+ })
354
565
  await avatarView.avatarController.start()
355
566
 
356
567
  // Use
357
568
  avatarView.avatarController.send(audioData, false)
358
569
 
359
- // Cleanup (must be called before switching characters)
570
+ // Cleanup
571
+ avatarView.avatarController.close()
572
+ avatarView.dispose() // Automatically cleans up all resources
573
+ ```
574
+
575
+ #### External Data Mode Lifecycle
576
+
577
+ ```typescript
578
+ // Initialize
579
+ const container = document.getElementById('avatar-container')
580
+ const avatarView = new AvatarView(avatar, {
581
+ container: container,
582
+ playbackMode: AvatarPlaybackMode.external
583
+ })
584
+
585
+ // Use
586
+ const initialAudioChunks = [{ data: audioData1, isLast: false }]
587
+ await avatarView.avatarController.play(initialAudioChunks, initialKeyframes)
588
+ avatarView.avatarController.sendAudioChunk(audioChunk, false)
589
+ avatarView.avatarController.sendKeyframes(keyframes)
590
+
591
+ // Cleanup
592
+ avatarView.avatarController.clear() // Clear all data and resources
360
593
  avatarView.dispose() // Automatically cleans up all resources
361
594
  ```
362
595
 
@@ -364,6 +597,8 @@ avatarView.dispose() // Automatically cleans up all resources
364
597
  - SDK currently only supports one AvatarView instance at a time
365
598
  - When switching characters, must first call `dispose()` to clean up old AvatarView, then create new instance
366
599
  - Not properly cleaning up may cause resource leaks and rendering errors
600
+ - In network mode, call `close()` before `dispose()` to properly close WebSocket connections
601
+ - In external data mode, call `clear()` before `dispose()` to clear all playback data
367
602
 
368
603
  ### Memory Optimization
369
604
 
@@ -373,14 +608,49 @@ avatarView.dispose() // Automatically cleans up all resources
373
608
 
374
609
  ### Audio Data Sending
375
610
 
611
+ #### Network Mode
612
+
376
613
  The `send()` method receives audio data in `ArrayBuffer` format:
377
614
 
615
+ **Audio Format Requirements:**
616
+ - **Sample Rate**: 16kHz (16000 Hz) - **Backend requirement, must be exactly 16kHz**
617
+ - **Format**: PCM16 (16-bit signed integer, little-endian)
618
+ - **Channels**: Mono (single channel)
619
+ - **Data Size**: Each sample is 2 bytes, so 1 second of audio = 16000 samples × 2 bytes = 32000 bytes
620
+
378
621
  **Usage:**
379
- - `audioData`: Audio data (ArrayBuffer format)
622
+ - `audioData`: Audio data (ArrayBuffer format, must be 16kHz mono PCM16)
380
623
  - `end=false` (default) - Normal audio data sending, server will accumulate audio data, automatically returns animation data and starts synchronized playback of animation and audio after accumulating enough data
381
624
  - `end=true` - Immediately return animation data, no longer accumulating, used for ending current conversation or scenarios requiring immediate response
382
625
  - **Important**: No need to wait for `end=true` to start playing, it will automatically start playing after accumulating enough audio data
383
626
 
627
+ #### External Data Mode
628
+
629
+ The `play()` method starts playback with initial data, then use `sendAudioChunk()` to stream additional audio:
630
+
631
+ **Audio Format Requirements:**
632
+ - Same as network mode: 16kHz mono PCM16 format
633
+ - Audio data should be provided as `Uint8Array` in chunks with `isLast` flag
634
+
635
+ **Usage:**
636
+ ```typescript
637
+ // Start playback with initial audio and animation data
638
+ // Note: Audio and animation data should be obtained from your backend service
639
+ const initialAudioChunks = [
640
+ { data: audioData1, isLast: false },
641
+ { data: audioData2, isLast: false }
642
+ ]
643
+ await avatarController.play(initialAudioChunks, initialKeyframes)
644
+
645
+ // Stream additional audio chunks
646
+ avatarController.sendAudioChunk(audioChunk, isLast)
647
+ ```
648
+
649
+ **Resampling (Both Modes):**
650
+ - If your audio source is at a different sample rate (e.g., 24kHz, 48kHz), you **must** resample it to 16kHz before sending
651
+ - For high-quality resampling, use Web Audio API's `OfflineAudioContext` with anti-aliasing filtering
652
+ - See example projects (`vanilla`, `react`, `vue`) for complete resampling implementation
653
+
384
654
  ## 🌐 Browser Compatibility
385
655
 
386
656
  - **Chrome/Edge** 90+ (WebGPU recommended)