@spatialwalk/avatarkit 1.0.0-beta.1 → 1.0.0-beta.11
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/CHANGELOG.md +185 -0
- package/README.md +450 -148
- package/dist/{StreamingAudioPlayer-C2TfYsO8.js → StreamingAudioPlayer-CLFmPod8.js} +88 -62
- package/dist/StreamingAudioPlayer-CLFmPod8.js.map +1 -0
- package/dist/animation/AnimationWebSocketClient.d.ts.map +1 -1
- package/dist/animation/utils/flameConverter.d.ts.map +1 -1
- package/dist/audio/AnimationPlayer.d.ts +4 -0
- package/dist/audio/AnimationPlayer.d.ts.map +1 -1
- package/dist/audio/StreamingAudioPlayer.d.ts +10 -0
- package/dist/audio/StreamingAudioPlayer.d.ts.map +1 -1
- package/dist/avatar_core_wasm-D4eEi7Eh.js +1666 -0
- package/dist/{avatar_core_wasm-DmkU6dYn.js.map → avatar_core_wasm-D4eEi7Eh.js.map} +1 -1
- package/dist/avatar_core_wasm.wasm +0 -0
- package/dist/config/app-config.d.ts +3 -7
- package/dist/config/app-config.d.ts.map +1 -1
- package/dist/config/constants.d.ts +19 -3
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/core/Avatar.d.ts +0 -8
- package/dist/core/Avatar.d.ts.map +1 -1
- package/dist/core/AvatarController.d.ts +50 -74
- package/dist/core/AvatarController.d.ts.map +1 -1
- package/dist/core/AvatarDownloader.d.ts +0 -5
- package/dist/core/AvatarDownloader.d.ts.map +1 -1
- package/dist/core/AvatarKit.d.ts +3 -15
- package/dist/core/AvatarKit.d.ts.map +1 -1
- package/dist/core/AvatarManager.d.ts.map +1 -1
- package/dist/core/AvatarView.d.ts +47 -46
- package/dist/core/AvatarView.d.ts.map +1 -1
- package/dist/core/NetworkLayer.d.ts +59 -0
- package/dist/core/NetworkLayer.d.ts.map +1 -0
- package/dist/index-Ck21a9C4.js +5999 -0
- package/dist/index-Ck21a9C4.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -11
- package/dist/renderer/RenderSystem.d.ts +4 -2
- package/dist/renderer/RenderSystem.d.ts.map +1 -1
- package/dist/renderer/webgl/webglRenderer.d.ts.map +1 -1
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/cls-tracker.d.ts +17 -0
- package/dist/utils/cls-tracker.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/package.json +14 -18
- package/dist/StreamingAudioPlayer-C2TfYsO8.js.map +0 -1
- package/dist/avatar_core_wasm-DmkU6dYn.js +0 -1666
- package/dist/config/region-config.d.ts +0 -17
- package/dist/config/region-config.d.ts.map +0 -1
- package/dist/generated/google/protobuf/any.d.ts +0 -145
- package/dist/generated/google/protobuf/any.d.ts.map +0 -1
- package/dist/generated/jsonapi/v1/base.d.ts +0 -140
- package/dist/generated/jsonapi/v1/base.d.ts.map +0 -1
- package/dist/generated/platform/v1/asset_groups.d.ts +0 -225
- package/dist/generated/platform/v1/asset_groups.d.ts.map +0 -1
- package/dist/generated/platform/v1/assets.d.ts +0 -149
- package/dist/generated/platform/v1/assets.d.ts.map +0 -1
- package/dist/generated/platform/v1/character.d.ts +0 -395
- package/dist/generated/platform/v1/character.d.ts.map +0 -1
- package/dist/generated/platform/v1/redeem.d.ts +0 -22
- package/dist/generated/platform/v1/redeem.d.ts.map +0 -1
- package/dist/index-DwhR9l52.js +0 -9712
- package/dist/index-DwhR9l52.js.map +0 -1
- package/dist/utils/posthog-tracker.d.ts +0 -82
- package/dist/utils/posthog-tracker.d.ts.map +0 -1
- package/dist/utils/toast.d.ts +0 -74
- package/dist/utils/toast.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# SPAvatarKit SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Real-time virtual avatar rendering SDK based on 3D Gaussian Splatting, supporting audio-driven animation rendering and high-quality 3D rendering.
|
|
4
4
|
|
|
5
|
-
## 🚀
|
|
5
|
+
## 🚀 Features
|
|
6
6
|
|
|
7
|
-
- **3D Gaussian Splatting
|
|
8
|
-
-
|
|
9
|
-
- **WebGPU/WebGL
|
|
10
|
-
- **WASM
|
|
11
|
-
- **TypeScript
|
|
12
|
-
-
|
|
7
|
+
- **3D Gaussian Splatting Rendering** - Based on the latest point cloud rendering technology, providing high-quality 3D virtual avatars
|
|
8
|
+
- **Audio-Driven Real-Time Animation Rendering** - Users provide audio data, SDK handles receiving animation data and rendering
|
|
9
|
+
- **WebGPU/WebGL Dual Rendering Backend** - Automatically selects the best rendering backend for compatibility
|
|
10
|
+
- **WASM High-Performance Computing** - Uses C++ compiled WebAssembly modules for geometric calculations
|
|
11
|
+
- **TypeScript Support** - Complete type definitions and IntelliSense
|
|
12
|
+
- **Modular Architecture** - Clear component separation, easy to integrate and extend
|
|
13
13
|
|
|
14
|
-
## 📦
|
|
14
|
+
## 📦 Installation
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
17
|
npm install @spatialwalk/avatarkit
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
## 🎯
|
|
20
|
+
## 🎯 Quick Start
|
|
21
21
|
|
|
22
|
-
###
|
|
22
|
+
### Basic Usage
|
|
23
23
|
|
|
24
24
|
```typescript
|
|
25
25
|
import {
|
|
@@ -30,150 +30,359 @@ import {
|
|
|
30
30
|
Environment
|
|
31
31
|
} from '@spatialwalk/avatarkit'
|
|
32
32
|
|
|
33
|
-
// 1.
|
|
33
|
+
// 1. Initialize SDK
|
|
34
34
|
const configuration: Configuration = {
|
|
35
35
|
environment: Environment.test,
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
await AvatarKit.initialize('your-app-id', configuration)
|
|
39
39
|
|
|
40
|
-
//
|
|
40
|
+
// Set sessionToken (if needed, call separately)
|
|
41
41
|
// AvatarKit.setSessionToken('your-session-token')
|
|
42
42
|
|
|
43
|
-
// 2.
|
|
43
|
+
// 2. Load character
|
|
44
44
|
const avatarManager = new AvatarManager()
|
|
45
45
|
const avatar = await avatarManager.load('character-id', (progress) => {
|
|
46
46
|
console.log(`Loading progress: ${progress.progress}%`)
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
// 3.
|
|
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,
|
|
52
|
+
const avatarView = new AvatarView(avatar, {
|
|
53
|
+
container: container,
|
|
54
|
+
playbackMode: 'network' // Optional, 'network' is default
|
|
55
|
+
})
|
|
52
56
|
|
|
53
|
-
// 4.
|
|
57
|
+
// 4. Start real-time communication (network mode only)
|
|
54
58
|
await avatarView.avatarController.start()
|
|
55
59
|
|
|
56
|
-
// 5.
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
avatarView.avatarController.send(audioData,
|
|
60
|
+
// 5. Send audio data (network mode)
|
|
61
|
+
// ⚠️ Important: Audio must be 16kHz mono PCM16 format
|
|
62
|
+
// If audio is Uint8Array, you can use slice().buffer to convert to ArrayBuffer
|
|
63
|
+
const audioUint8 = new Uint8Array(1024) // Example: 16kHz PCM16 audio data (512 samples = 1024 bytes)
|
|
64
|
+
const audioData = audioUint8.slice().buffer // Simplified conversion, works for ArrayBuffer and SharedArrayBuffer
|
|
65
|
+
avatarView.avatarController.send(audioData, false) // Send audio data, will automatically start playing after accumulating enough data
|
|
66
|
+
avatarView.avatarController.send(audioData, true) // end=true means immediately return animation data, no longer accumulating
|
|
62
67
|
```
|
|
63
68
|
|
|
64
|
-
###
|
|
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
|
+
})
|
|
82
|
+
|
|
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.
|
|
65
98
|
|
|
66
|
-
|
|
99
|
+
**Example Project:** [AvatarKit-Web-Demo](https://github.com/spatialwalk/AvatarKit-Web-Demo)
|
|
67
100
|
|
|
68
|
-
|
|
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
|
|
69
104
|
|
|
70
|
-
|
|
105
|
+
## 🏗️ Architecture Overview
|
|
71
106
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
+
|
|
115
|
+
### Core Components
|
|
116
|
+
|
|
117
|
+
- **AvatarKit** - SDK initialization and management
|
|
118
|
+
- **AvatarManager** - Character resource loading and management
|
|
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)
|
|
122
|
+
- **AvatarCoreAdapter** - WASM module adapter
|
|
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
|
+
|
|
140
|
+
### Data Flow
|
|
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
|
+
```
|
|
77
161
|
|
|
78
|
-
|
|
162
|
+
#### External Data Mode Flow
|
|
79
163
|
|
|
80
164
|
```
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
+
↓
|
|
174
|
+
FLAME parameters → AvatarCore.computeFrameFlatFromParams() → Splat data
|
|
175
|
+
↓
|
|
176
|
+
AvatarController (playback loop) → AvatarView.renderRealtimeFrame()
|
|
177
|
+
↓
|
|
178
|
+
RenderSystem → WebGPU/WebGL → Canvas rendering
|
|
88
179
|
```
|
|
89
180
|
|
|
90
|
-
|
|
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
|
|
91
184
|
|
|
92
|
-
|
|
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
|
|
203
|
+
|
|
204
|
+
## 📚 API Reference
|
|
93
205
|
|
|
94
206
|
### AvatarKit
|
|
95
207
|
|
|
96
|
-
SDK
|
|
208
|
+
The core management class of the SDK, responsible for initialization and global configuration.
|
|
97
209
|
|
|
98
210
|
```typescript
|
|
99
|
-
//
|
|
211
|
+
// Initialize SDK
|
|
100
212
|
await AvatarKit.initialize(appId: string, configuration: Configuration)
|
|
101
213
|
|
|
102
|
-
//
|
|
214
|
+
// Check initialization status
|
|
103
215
|
const isInitialized = AvatarKit.isInitialized
|
|
104
216
|
|
|
105
|
-
//
|
|
217
|
+
// Get initialized app ID
|
|
218
|
+
const appId = AvatarKit.appId
|
|
219
|
+
|
|
220
|
+
// Get configuration
|
|
221
|
+
const config = AvatarKit.configuration
|
|
222
|
+
|
|
223
|
+
// Set sessionToken (if needed, call separately)
|
|
224
|
+
AvatarKit.setSessionToken('your-session-token')
|
|
225
|
+
|
|
226
|
+
// Set userId (optional, for telemetry)
|
|
227
|
+
AvatarKit.setUserId('user-id')
|
|
228
|
+
|
|
229
|
+
// Get sessionToken
|
|
230
|
+
const sessionToken = AvatarKit.sessionToken
|
|
231
|
+
|
|
232
|
+
// Get userId
|
|
233
|
+
const userId = AvatarKit.userId
|
|
234
|
+
|
|
235
|
+
// Get SDK version
|
|
236
|
+
const version = AvatarKit.version
|
|
237
|
+
|
|
238
|
+
// Cleanup resources (must be called when no longer in use)
|
|
106
239
|
AvatarKit.cleanup()
|
|
107
240
|
```
|
|
108
241
|
|
|
109
242
|
### AvatarManager
|
|
110
243
|
|
|
111
|
-
|
|
244
|
+
Character resource manager, responsible for downloading, caching, and loading character data.
|
|
112
245
|
|
|
113
246
|
```typescript
|
|
114
247
|
const manager = new AvatarManager()
|
|
115
248
|
|
|
116
|
-
//
|
|
249
|
+
// Load character
|
|
117
250
|
const avatar = await manager.load(
|
|
118
251
|
characterId: string,
|
|
119
252
|
onProgress?: (progress: LoadProgressInfo) => void
|
|
120
253
|
)
|
|
121
254
|
|
|
122
|
-
//
|
|
255
|
+
// Clear cache
|
|
123
256
|
manager.clearCache()
|
|
124
257
|
```
|
|
125
258
|
|
|
126
259
|
### AvatarView
|
|
127
260
|
|
|
128
|
-
3D
|
|
261
|
+
3D rendering view (rendering layer), responsible for 3D rendering only. Internally automatically creates and manages `AvatarController`.
|
|
262
|
+
|
|
263
|
+
**⚠️ 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.
|
|
264
|
+
|
|
265
|
+
**Playback Mode Configuration:**
|
|
266
|
+
- The playback mode is fixed when creating `AvatarView` and persists throughout its lifecycle
|
|
267
|
+
- Cannot be changed after creation
|
|
129
268
|
|
|
130
269
|
```typescript
|
|
131
|
-
|
|
132
|
-
const avatarView = new AvatarView(avatar: Avatar, container?: HTMLElement)
|
|
270
|
+
import { AvatarPlaybackMode } from '@spatialwalk/avatarkit'
|
|
133
271
|
|
|
134
|
-
//
|
|
135
|
-
|
|
272
|
+
// Create view (Canvas is automatically added to container)
|
|
273
|
+
// Network mode (default)
|
|
274
|
+
const container = document.getElementById('avatar-container')
|
|
275
|
+
const avatarView = new AvatarView(avatar: Avatar, {
|
|
276
|
+
container: container,
|
|
277
|
+
playbackMode: AvatarPlaybackMode.network // Optional, default is 'network'
|
|
278
|
+
})
|
|
136
279
|
|
|
137
|
-
//
|
|
138
|
-
avatarView
|
|
139
|
-
|
|
280
|
+
// External data mode
|
|
281
|
+
const avatarView = new AvatarView(avatar: Avatar, {
|
|
282
|
+
container: container,
|
|
283
|
+
playbackMode: AvatarPlaybackMode.external
|
|
284
|
+
})
|
|
140
285
|
|
|
141
|
-
//
|
|
142
|
-
avatarView.
|
|
286
|
+
// Get playback mode
|
|
287
|
+
const mode = avatarView.playbackMode // 'network' | 'external'
|
|
143
288
|
|
|
144
|
-
//
|
|
289
|
+
// Cleanup resources (must be called before switching characters)
|
|
145
290
|
avatarView.dispose()
|
|
146
291
|
```
|
|
147
292
|
|
|
293
|
+
**Character Switching Example:**
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
// Before switching characters, must clean up old AvatarView first
|
|
297
|
+
if (currentAvatarView) {
|
|
298
|
+
currentAvatarView.dispose()
|
|
299
|
+
currentAvatarView = null
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Load new character
|
|
303
|
+
const newAvatar = await avatarManager.load('new-character-id')
|
|
304
|
+
|
|
305
|
+
// Create new AvatarView (with same or different playback mode)
|
|
306
|
+
currentAvatarView = new AvatarView(newAvatar, {
|
|
307
|
+
container: container,
|
|
308
|
+
playbackMode: AvatarPlaybackMode.network
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
// Network mode: start connection
|
|
312
|
+
if (currentAvatarView.playbackMode === AvatarPlaybackMode.network) {
|
|
313
|
+
await currentAvatarView.avatarController.start()
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
148
317
|
### AvatarController
|
|
149
318
|
|
|
150
|
-
|
|
319
|
+
Audio/animation playback controller (playback layer), manages synchronized playback of audio and animation. Automatically composes `NetworkLayer` in network mode.
|
|
320
|
+
|
|
321
|
+
**Two Usage Patterns:**
|
|
322
|
+
|
|
323
|
+
#### Network Mode Methods
|
|
151
324
|
|
|
152
325
|
```typescript
|
|
153
|
-
//
|
|
326
|
+
// Start WebSocket service
|
|
154
327
|
await avatarView.avatarController.start()
|
|
155
328
|
|
|
156
|
-
//
|
|
329
|
+
// Send audio data (SDK handles receiving animation data automatically)
|
|
157
330
|
avatarView.avatarController.send(audioData: ArrayBuffer, end: boolean)
|
|
158
|
-
// audioData:
|
|
159
|
-
//
|
|
160
|
-
//
|
|
331
|
+
// audioData: Audio data (ArrayBuffer format, must be 16kHz mono PCM16)
|
|
332
|
+
// - Sample rate: 16kHz (16000 Hz) - backend requirement
|
|
333
|
+
// - Format: PCM16 (16-bit signed integer, little-endian)
|
|
334
|
+
// - Channels: Mono (single channel)
|
|
335
|
+
// - Example: 1 second = 16000 samples × 2 bytes = 32000 bytes
|
|
336
|
+
// 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
|
|
337
|
+
// end: true - Immediately return animation data, no longer accumulating, used for ending current conversation or scenarios requiring immediate response
|
|
338
|
+
|
|
339
|
+
// Close WebSocket service
|
|
340
|
+
avatarView.avatarController.close()
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
#### External Data Mode Methods
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
// Start playback with initial audio and animation data
|
|
347
|
+
await avatarView.avatarController.play(
|
|
348
|
+
initialAudioChunks?: Array<{ data: Uint8Array, isLast: boolean }>, // Initial audio chunks (16kHz mono PCM16)
|
|
349
|
+
initialKeyframes?: any[] // Initial animation keyframes (obtained from your service)
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
// Stream additional audio chunks (after play() is called)
|
|
353
|
+
avatarView.avatarController.sendAudioChunk(
|
|
354
|
+
data: Uint8Array, // Audio chunk data
|
|
355
|
+
isLast: boolean = false // Whether this is the last chunk
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
// Stream additional animation keyframes (after play() is called)
|
|
359
|
+
avatarView.avatarController.sendKeyframes(
|
|
360
|
+
keyframes: any[] // Additional animation keyframes (obtained from your service)
|
|
361
|
+
)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Common Methods (Both Modes)
|
|
161
365
|
|
|
162
|
-
|
|
366
|
+
```typescript
|
|
367
|
+
// Interrupt current playback (stops and clears data)
|
|
163
368
|
avatarView.avatarController.interrupt()
|
|
164
369
|
|
|
165
|
-
//
|
|
166
|
-
avatarView.avatarController.
|
|
370
|
+
// Clear all data and resources
|
|
371
|
+
avatarView.avatarController.clear()
|
|
167
372
|
|
|
168
|
-
//
|
|
169
|
-
avatarView.avatarController.onConnectionState = (state: ConnectionState) => {}
|
|
373
|
+
// Set event callbacks
|
|
374
|
+
avatarView.avatarController.onConnectionState = (state: ConnectionState) => {} // Network mode only
|
|
170
375
|
avatarView.avatarController.onAvatarState = (state: AvatarState) => {}
|
|
171
376
|
avatarView.avatarController.onError = (error: Error) => {}
|
|
172
|
-
|
|
173
|
-
// 注意:不支持 sendText() 方法,调用会抛出错误
|
|
174
377
|
```
|
|
175
378
|
|
|
176
|
-
|
|
379
|
+
**Important Notes:**
|
|
380
|
+
- `start()` and `close()` are only available in network mode
|
|
381
|
+
- `play()`, `sendAudioChunk()`, and `sendKeyframes()` are only available in external data mode
|
|
382
|
+
- `interrupt()` and `clear()` are available in both modes
|
|
383
|
+
- The playback mode is determined when creating `AvatarView` and cannot be changed
|
|
384
|
+
|
|
385
|
+
## 🔧 Configuration
|
|
177
386
|
|
|
178
387
|
### Configuration
|
|
179
388
|
|
|
@@ -183,14 +392,37 @@ interface Configuration {
|
|
|
183
392
|
}
|
|
184
393
|
```
|
|
185
394
|
|
|
186
|
-
|
|
187
|
-
- `environment`:
|
|
188
|
-
- `sessionToken`:
|
|
395
|
+
**Description:**
|
|
396
|
+
- `environment`: Specifies the environment (cn/us/test), SDK will automatically use the corresponding API address and WebSocket address based on the environment
|
|
397
|
+
- `sessionToken`: Set separately via `AvatarKit.setSessionToken()`, not in Configuration
|
|
189
398
|
|
|
399
|
+
```typescript
|
|
190
400
|
enum Environment {
|
|
191
|
-
cn = 'cn', //
|
|
192
|
-
us = 'us', //
|
|
193
|
-
test = 'test' //
|
|
401
|
+
cn = 'cn', // China region
|
|
402
|
+
us = 'us', // US region
|
|
403
|
+
test = 'test' // Test environment
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### AvatarViewOptions
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
interface AvatarViewOptions {
|
|
411
|
+
playbackMode?: AvatarPlaybackMode // Playback mode, default is 'network'
|
|
412
|
+
container?: HTMLElement // Canvas container element
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**Description:**
|
|
417
|
+
- `playbackMode`: Specifies the playback mode (`'network'` or `'external'`), default is `'network'`
|
|
418
|
+
- `'network'`: SDK handles WebSocket communication, send audio via `send()`
|
|
419
|
+
- `'external'`: External components provide audio and animation data, SDK handles synchronized playback
|
|
420
|
+
- `container`: Optional container element for Canvas, if not provided, Canvas will be created but not added to DOM
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
enum AvatarPlaybackMode {
|
|
424
|
+
network = 'network', // Network mode: SDK handles WebSocket communication
|
|
425
|
+
external = 'external' // External data mode: External provides data, SDK handles playback
|
|
194
426
|
}
|
|
195
427
|
```
|
|
196
428
|
|
|
@@ -198,17 +430,17 @@ enum Environment {
|
|
|
198
430
|
|
|
199
431
|
```typescript
|
|
200
432
|
interface CameraConfig {
|
|
201
|
-
position: [number, number, number] //
|
|
202
|
-
target: [number, number, number] //
|
|
203
|
-
fov: number //
|
|
204
|
-
near: number //
|
|
205
|
-
far: number //
|
|
206
|
-
up?: [number, number, number] //
|
|
207
|
-
aspect?: number //
|
|
433
|
+
position: [number, number, number] // Camera position
|
|
434
|
+
target: [number, number, number] // Camera target
|
|
435
|
+
fov: number // Field of view angle
|
|
436
|
+
near: number // Near clipping plane
|
|
437
|
+
far: number // Far clipping plane
|
|
438
|
+
up?: [number, number, number] // Up direction
|
|
439
|
+
aspect?: number // Aspect ratio
|
|
208
440
|
}
|
|
209
441
|
```
|
|
210
442
|
|
|
211
|
-
## 📊
|
|
443
|
+
## 📊 State Management
|
|
212
444
|
|
|
213
445
|
### ConnectionState
|
|
214
446
|
|
|
@@ -225,77 +457,77 @@ enum ConnectionState {
|
|
|
225
457
|
|
|
226
458
|
```typescript
|
|
227
459
|
enum AvatarState {
|
|
228
|
-
idle = 'idle', //
|
|
229
|
-
active = 'active', //
|
|
230
|
-
playing = 'playing' //
|
|
460
|
+
idle = 'idle', // Idle state, showing breathing animation
|
|
461
|
+
active = 'active', // Active, waiting for playable content
|
|
462
|
+
playing = 'playing' // Playing
|
|
231
463
|
}
|
|
232
464
|
```
|
|
233
465
|
|
|
234
|
-
## 🎨
|
|
466
|
+
## 🎨 Rendering System
|
|
235
467
|
|
|
236
|
-
SDK
|
|
468
|
+
The SDK supports two rendering backends:
|
|
237
469
|
|
|
238
|
-
- **WebGPU** -
|
|
239
|
-
- **WebGL** -
|
|
470
|
+
- **WebGPU** - High-performance rendering for modern browsers
|
|
471
|
+
- **WebGL** - Better compatibility traditional rendering
|
|
240
472
|
|
|
241
|
-
|
|
473
|
+
The rendering system automatically selects the best backend, no manual configuration needed.
|
|
242
474
|
|
|
243
|
-
## 🔍
|
|
475
|
+
## 🔍 Debugging and Monitoring
|
|
244
476
|
|
|
245
|
-
###
|
|
477
|
+
### Logging System
|
|
246
478
|
|
|
247
|
-
SDK
|
|
479
|
+
The SDK has a built-in complete logging system, supporting different levels of log output:
|
|
248
480
|
|
|
249
481
|
```typescript
|
|
250
482
|
import { logger } from '@spatialwalk/avatarkit'
|
|
251
483
|
|
|
252
|
-
//
|
|
484
|
+
// Set log level
|
|
253
485
|
logger.setLevel('verbose') // 'basic' | 'verbose'
|
|
254
486
|
|
|
255
|
-
//
|
|
487
|
+
// Manual log output
|
|
256
488
|
logger.log('Info message')
|
|
257
489
|
logger.warn('Warning message')
|
|
258
490
|
logger.error('Error message')
|
|
259
491
|
```
|
|
260
492
|
|
|
261
|
-
###
|
|
493
|
+
### Performance Monitoring
|
|
262
494
|
|
|
263
|
-
SDK
|
|
495
|
+
The SDK provides performance monitoring interfaces to monitor rendering performance:
|
|
264
496
|
|
|
265
497
|
```typescript
|
|
266
|
-
//
|
|
498
|
+
// Get rendering performance statistics
|
|
267
499
|
const stats = avatarView.getPerformanceStats()
|
|
268
500
|
|
|
269
501
|
if (stats) {
|
|
270
|
-
console.log(
|
|
271
|
-
console.log(
|
|
272
|
-
console.log(
|
|
502
|
+
console.log(`Render time: ${stats.renderTime.toFixed(2)}ms`)
|
|
503
|
+
console.log(`Sort time: ${stats.sortTime.toFixed(2)}ms`)
|
|
504
|
+
console.log(`Rendering backend: ${stats.backend}`)
|
|
273
505
|
|
|
274
|
-
//
|
|
506
|
+
// Calculate frame rate
|
|
275
507
|
const fps = 1000 / stats.renderTime
|
|
276
|
-
console.log(
|
|
508
|
+
console.log(`Frame rate: ${fps.toFixed(2)} FPS`)
|
|
277
509
|
}
|
|
278
510
|
|
|
279
|
-
//
|
|
511
|
+
// Regular performance monitoring
|
|
280
512
|
setInterval(() => {
|
|
281
513
|
const stats = avatarView.getPerformanceStats()
|
|
282
514
|
if (stats) {
|
|
283
|
-
//
|
|
515
|
+
// Send to monitoring service or display on UI
|
|
284
516
|
console.log('Performance:', stats)
|
|
285
517
|
}
|
|
286
518
|
}, 1000)
|
|
287
519
|
```
|
|
288
520
|
|
|
289
|
-
|
|
290
|
-
- `renderTime`:
|
|
291
|
-
- `sortTime`:
|
|
292
|
-
- `backend`:
|
|
521
|
+
**Performance Statistics Description:**
|
|
522
|
+
- `renderTime`: Total rendering time (milliseconds), includes sorting and GPU rendering
|
|
523
|
+
- `sortTime`: Sorting time (milliseconds), uses Radix Sort algorithm to depth-sort point cloud
|
|
524
|
+
- `backend`: Currently used rendering backend (`'webgpu'` | `'webgl'` | `null`)
|
|
293
525
|
|
|
294
|
-
## 🚨
|
|
526
|
+
## 🚨 Error Handling
|
|
295
527
|
|
|
296
528
|
### SPAvatarError
|
|
297
529
|
|
|
298
|
-
SDK
|
|
530
|
+
The SDK uses custom error types, providing more detailed error information:
|
|
299
531
|
|
|
300
532
|
```typescript
|
|
301
533
|
import { SPAvatarError } from '@spatialwalk/avatarkit'
|
|
@@ -311,65 +543,135 @@ try {
|
|
|
311
543
|
}
|
|
312
544
|
```
|
|
313
545
|
|
|
314
|
-
###
|
|
546
|
+
### Error Callbacks
|
|
315
547
|
|
|
316
548
|
```typescript
|
|
317
549
|
avatarView.avatarController.onError = (error: Error) => {
|
|
318
550
|
console.error('AvatarController error:', error)
|
|
319
|
-
//
|
|
551
|
+
// Handle error, such as reconnection, user notification, etc.
|
|
320
552
|
}
|
|
321
553
|
```
|
|
322
554
|
|
|
323
|
-
## 🔄
|
|
555
|
+
## 🔄 Resource Management
|
|
324
556
|
|
|
325
|
-
###
|
|
557
|
+
### Lifecycle Management
|
|
558
|
+
|
|
559
|
+
#### Network Mode Lifecycle
|
|
326
560
|
|
|
327
561
|
```typescript
|
|
328
|
-
//
|
|
329
|
-
const
|
|
562
|
+
// Initialize
|
|
563
|
+
const container = document.getElementById('avatar-container')
|
|
564
|
+
const avatarView = new AvatarView(avatar, {
|
|
565
|
+
container: container,
|
|
566
|
+
playbackMode: AvatarPlaybackMode.network
|
|
567
|
+
})
|
|
330
568
|
await avatarView.avatarController.start()
|
|
331
569
|
|
|
332
|
-
//
|
|
570
|
+
// Use
|
|
333
571
|
avatarView.avatarController.send(audioData, false)
|
|
334
572
|
|
|
335
|
-
//
|
|
336
|
-
avatarView.
|
|
573
|
+
// Cleanup
|
|
574
|
+
avatarView.avatarController.close()
|
|
575
|
+
avatarView.dispose() // Automatically cleans up all resources
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
#### External Data Mode Lifecycle
|
|
579
|
+
|
|
580
|
+
```typescript
|
|
581
|
+
// Initialize
|
|
582
|
+
const container = document.getElementById('avatar-container')
|
|
583
|
+
const avatarView = new AvatarView(avatar, {
|
|
584
|
+
container: container,
|
|
585
|
+
playbackMode: AvatarPlaybackMode.external
|
|
586
|
+
})
|
|
587
|
+
|
|
588
|
+
// Use
|
|
589
|
+
const initialAudioChunks = [{ data: audioData1, isLast: false }]
|
|
590
|
+
await avatarView.avatarController.play(initialAudioChunks, initialKeyframes)
|
|
591
|
+
avatarView.avatarController.sendAudioChunk(audioChunk, false)
|
|
592
|
+
avatarView.avatarController.sendKeyframes(keyframes)
|
|
593
|
+
|
|
594
|
+
// Cleanup
|
|
595
|
+
avatarView.avatarController.clear() // Clear all data and resources
|
|
596
|
+
avatarView.dispose() // Automatically cleans up all resources
|
|
337
597
|
```
|
|
338
598
|
|
|
339
|
-
|
|
599
|
+
**⚠️ Important Notes:**
|
|
600
|
+
- SDK currently only supports one AvatarView instance at a time
|
|
601
|
+
- When switching characters, must first call `dispose()` to clean up old AvatarView, then create new instance
|
|
602
|
+
- Not properly cleaning up may cause resource leaks and rendering errors
|
|
603
|
+
- In network mode, call `close()` before `dispose()` to properly close WebSocket connections
|
|
604
|
+
- In external data mode, call `clear()` before `dispose()` to clear all playback data
|
|
605
|
+
|
|
606
|
+
### Memory Optimization
|
|
607
|
+
|
|
608
|
+
- SDK automatically manages WASM memory allocation
|
|
609
|
+
- Supports dynamic loading/unloading of character and animation resources
|
|
610
|
+
- Provides memory usage monitoring interface
|
|
611
|
+
|
|
612
|
+
### Audio Data Sending
|
|
613
|
+
|
|
614
|
+
#### Network Mode
|
|
340
615
|
|
|
341
|
-
|
|
342
|
-
- 支持角色和动画资源的动态加载/卸载
|
|
343
|
-
- 提供内存使用监控接口
|
|
616
|
+
The `send()` method receives audio data in `ArrayBuffer` format:
|
|
344
617
|
|
|
345
|
-
|
|
618
|
+
**Audio Format Requirements:**
|
|
619
|
+
- **Sample Rate**: 16kHz (16000 Hz) - **Backend requirement, must be exactly 16kHz**
|
|
620
|
+
- **Format**: PCM16 (16-bit signed integer, little-endian)
|
|
621
|
+
- **Channels**: Mono (single channel)
|
|
622
|
+
- **Data Size**: Each sample is 2 bytes, so 1 second of audio = 16000 samples × 2 bytes = 32000 bytes
|
|
346
623
|
|
|
347
|
-
|
|
624
|
+
**Usage:**
|
|
625
|
+
- `audioData`: Audio data (ArrayBuffer format, must be 16kHz mono PCM16)
|
|
626
|
+
- `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
|
|
627
|
+
- `end=true` - Immediately return animation data, no longer accumulating, used for ending current conversation or scenarios requiring immediate response
|
|
628
|
+
- **Important**: No need to wait for `end=true` to start playing, it will automatically start playing after accumulating enough audio data
|
|
629
|
+
|
|
630
|
+
#### External Data Mode
|
|
631
|
+
|
|
632
|
+
The `play()` method starts playback with initial data, then use `sendAudioChunk()` to stream additional audio:
|
|
633
|
+
|
|
634
|
+
**Audio Format Requirements:**
|
|
635
|
+
- Same as network mode: 16kHz mono PCM16 format
|
|
636
|
+
- Audio data should be provided as `Uint8Array` in chunks with `isLast` flag
|
|
637
|
+
|
|
638
|
+
**Usage:**
|
|
639
|
+
```typescript
|
|
640
|
+
// Start playback with initial audio and animation data
|
|
641
|
+
// Note: Audio and animation data should be obtained from your backend service
|
|
642
|
+
const initialAudioChunks = [
|
|
643
|
+
{ data: audioData1, isLast: false },
|
|
644
|
+
{ data: audioData2, isLast: false }
|
|
645
|
+
]
|
|
646
|
+
await avatarController.play(initialAudioChunks, initialKeyframes)
|
|
647
|
+
|
|
648
|
+
// Stream additional audio chunks
|
|
649
|
+
avatarController.sendAudioChunk(audioChunk, isLast)
|
|
650
|
+
```
|
|
348
651
|
|
|
349
|
-
|
|
350
|
-
-
|
|
351
|
-
- `
|
|
352
|
-
- `
|
|
353
|
-
- **重要**:不需要等待 `end=true` 才开始播放,积累到一定音频数据后就会自动开始播放
|
|
652
|
+
**Resampling (Both Modes):**
|
|
653
|
+
- If your audio source is at a different sample rate (e.g., 24kHz, 48kHz), you **must** resample it to 16kHz before sending
|
|
654
|
+
- For high-quality resampling, use Web Audio API's `OfflineAudioContext` with anti-aliasing filtering
|
|
655
|
+
- See example projects (`vanilla`, `react`, `vue`) for complete resampling implementation
|
|
354
656
|
|
|
355
|
-
## 🌐
|
|
657
|
+
## 🌐 Browser Compatibility
|
|
356
658
|
|
|
357
|
-
- **Chrome/Edge** 90+ (
|
|
659
|
+
- **Chrome/Edge** 90+ (WebGPU recommended)
|
|
358
660
|
- **Firefox** 90+ (WebGL)
|
|
359
661
|
- **Safari** 14+ (WebGL)
|
|
360
|
-
-
|
|
662
|
+
- **Mobile** iOS 14+, Android 8+
|
|
361
663
|
|
|
362
|
-
## 📝
|
|
664
|
+
## 📝 License
|
|
363
665
|
|
|
364
666
|
MIT License
|
|
365
667
|
|
|
366
|
-
## 🤝
|
|
668
|
+
## 🤝 Contributing
|
|
367
669
|
|
|
368
|
-
|
|
670
|
+
Issues and Pull Requests are welcome!
|
|
369
671
|
|
|
370
|
-
## 📞
|
|
672
|
+
## 📞 Support
|
|
371
673
|
|
|
372
|
-
|
|
373
|
-
-
|
|
374
|
-
-
|
|
375
|
-
- GitHub
|
|
674
|
+
For questions, please contact:
|
|
675
|
+
- Email: support@spavatar.com
|
|
676
|
+
- Documentation: https://docs.spavatar.com
|
|
677
|
+
- GitHub: https://github.com/spavatar/sdk
|