@spatialwalk/avatarkit 1.0.0-beta.62 → 1.0.0-beta.64
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 +40 -0
- package/README.md +136 -35
- package/dist/{StreamingAudioPlayer-BWsAt_s7.js → StreamingAudioPlayer-CugAsNXV.js} +1 -1
- package/dist/avatar_core_wasm-Dv943JJl.js +2696 -0
- package/dist/avatar_core_wasm.wasm +0 -0
- package/dist/core/AvatarController.d.ts +2 -0
- package/dist/core/AvatarView.d.ts +1 -0
- package/dist/{index-Bhjn1nq3.js → index-D0sXXlqd.js} +197 -94
- package/dist/index.js +3 -3
- package/dist/types/index.d.ts +1 -1
- package/dist/utils/animation-interpolation.d.ts +4 -0
- package/dist/vanilla/vite.config.d.ts +1 -1
- package/dist/vite.d.ts +4 -0
- package/package.json +23 -14
- package/vite.d.ts +20 -0
- package/vite.js +110 -0
- package/dist/avatar_core_wasm-i0Ocpx6q.js +0 -2693
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.0-beta.64] - 2026-01-14
|
|
6
|
+
|
|
7
|
+
### ✨ New Features
|
|
8
|
+
- **Vite Plugin for WASM Configuration** - Added `avatarkitVitePlugin` to automate WASM file configuration
|
|
9
|
+
- Automatically handles WASM MIME types in dev server
|
|
10
|
+
- Copies WASM files to dist/assets/ during build
|
|
11
|
+
- Generates `_headers` file for Cloudflare Pages deployment
|
|
12
|
+
- Configures Vite's optimizeDeps, assetsInclude, and assetsInlineLimit
|
|
13
|
+
|
|
14
|
+
### 🔧 Improvements
|
|
15
|
+
- **Unified Transition Logic** - All transitions now start from the current playing frame, ensuring smooth transitions from any state (Idle, Speaking, or Transitioning)
|
|
16
|
+
- **Idle State Performance** - Optimized idle state to avoid unnecessary frame parameter fetching on every frame
|
|
17
|
+
- **Transition Animation** - Idle->Speaking uses linear interpolation, Speaking->Idle uses Bezier curve easing
|
|
18
|
+
|
|
19
|
+
### 🐛 Bugfixes
|
|
20
|
+
- Fixed vanilla demo audio context initialization issue
|
|
21
|
+
- Fixed recording button only working once in vanilla demo
|
|
22
|
+
- Fixed host mode data loading to use local files instead of API endpoint
|
|
23
|
+
|
|
24
|
+
### 📚 Documentation
|
|
25
|
+
- Added transition animation technical specification document for cross-platform alignment
|
|
26
|
+
|
|
27
|
+
## [1.0.0-beta.63] - 2026-01-14
|
|
28
|
+
|
|
29
|
+
### ✨ New Features
|
|
30
|
+
- **Audio Context Initialization API** - Added `initializeAudioContext()` method to `AvatarController`
|
|
31
|
+
- Must be called in a user gesture context (click, touchstart, etc.) before any audio operations
|
|
32
|
+
- Ensures AudioContext is created and initialized in a user gesture context, preventing browser security policy issues
|
|
33
|
+
- All audio operations (`send()`, `yieldAudioData()`, `start()`, `playback()`, etc.) now require prior initialization
|
|
34
|
+
|
|
35
|
+
### 🔧 Improvements
|
|
36
|
+
- **Initialization Flow** - Removed all lazy initialization logic for audio context
|
|
37
|
+
- Audio context initialization is now centralized in `initializeAudioContext()` method
|
|
38
|
+
- All audio operations check for initialization before proceeding
|
|
39
|
+
- Clear error messages when audio operations are attempted without initialization
|
|
40
|
+
|
|
41
|
+
### 🐛 Bugfixes
|
|
42
|
+
- **Audio Context User Gesture Requirement** - Fixed issue where AudioContext could not be properly initialized when external applications request recording permissions
|
|
43
|
+
- Audio context must now be initialized in user gesture context, ensuring browser security policies are satisfied
|
|
44
|
+
|
|
5
45
|
## [1.0.0-beta.62] - 2026-01-14
|
|
6
46
|
|
|
7
47
|
### ✨ New Features
|
package/README.md
CHANGED
|
@@ -18,8 +18,76 @@ Real-time virtual avatar rendering SDK based on 3D Gaussian Splatting, supportin
|
|
|
18
18
|
npm install @spatialwalk/avatarkit
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
## 🔧 Vite 配置(推荐)
|
|
22
|
+
|
|
23
|
+
如果你使用 Vite 作为构建工具,强烈推荐使用我们的 Vite 插件来自动处理 WASM 文件配置。插件会自动处理所有必要的配置,让你无需手动设置。
|
|
24
|
+
|
|
25
|
+
### 使用插件
|
|
26
|
+
|
|
27
|
+
在 `vite.config.ts` 中添加插件:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { defineConfig } from 'vite'
|
|
31
|
+
import { avatarkitVitePlugin } from '@spatialwalk/avatarkit/vite'
|
|
32
|
+
|
|
33
|
+
export default defineConfig({
|
|
34
|
+
plugins: [
|
|
35
|
+
avatarkitVitePlugin(), // 添加这一行即可
|
|
36
|
+
],
|
|
37
|
+
})
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 插件功能
|
|
41
|
+
|
|
42
|
+
插件会自动处理:
|
|
43
|
+
|
|
44
|
+
- ✅ **开发服务器**:自动设置 WASM 文件的正确 MIME 类型 (`application/wasm`)
|
|
45
|
+
- ✅ **构建时**:自动复制 WASM 文件到 `dist/assets/` 目录
|
|
46
|
+
- ✅ **Cloudflare Pages**:自动生成 `_headers` 文件
|
|
47
|
+
- ✅ **Vite 配置**:自动配置 `optimizeDeps`、`assetsInclude`、`assetsInlineLimit` 等选项
|
|
48
|
+
|
|
49
|
+
### 手动配置(不使用插件)
|
|
50
|
+
|
|
51
|
+
如果你不使用 Vite 插件,需要手动配置以下内容:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// vite.config.ts
|
|
55
|
+
export default defineConfig({
|
|
56
|
+
optimizeDeps: {
|
|
57
|
+
exclude: ['@spatialwalk/avatarkit'],
|
|
58
|
+
},
|
|
59
|
+
assetsInclude: ['**/*.wasm'],
|
|
60
|
+
build: {
|
|
61
|
+
assetsInlineLimit: 0,
|
|
62
|
+
rollupOptions: {
|
|
63
|
+
output: {
|
|
64
|
+
assetFileNames: (assetInfo) => {
|
|
65
|
+
if (assetInfo.name?.endsWith('.wasm')) {
|
|
66
|
+
return 'assets/[name][extname]'
|
|
67
|
+
}
|
|
68
|
+
return 'assets/[name]-[hash][extname]'
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
// 开发服务器需要手动配置中间件设置 WASM MIME 类型
|
|
74
|
+
configureServer(server) {
|
|
75
|
+
server.middlewares.use((req, res, next) => {
|
|
76
|
+
if (req.url?.endsWith('.wasm')) {
|
|
77
|
+
res.setHeader('Content-Type', 'application/wasm')
|
|
78
|
+
}
|
|
79
|
+
next()
|
|
80
|
+
})
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
21
85
|
## 🎯 Quick Start
|
|
22
86
|
|
|
87
|
+
### ⚠️ Important: Audio Context Initialization
|
|
88
|
+
|
|
89
|
+
**Before using any audio-related features, you MUST initialize the audio context in a user gesture context** (e.g., `click`, `touchstart` event handlers). This is required by browser security policies. Calling `initializeAudioContext()` outside a user gesture will fail.
|
|
90
|
+
|
|
23
91
|
### Basic Usage
|
|
24
92
|
|
|
25
93
|
```typescript
|
|
@@ -70,13 +138,21 @@ const avatar = await avatarManager.load('character-id', (progress) => {
|
|
|
70
138
|
const container = document.getElementById('avatar-container')
|
|
71
139
|
const avatarView = new AvatarView(avatar, container)
|
|
72
140
|
|
|
73
|
-
// 4.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
avatarView.
|
|
79
|
-
|
|
141
|
+
// 4. ⚠️ CRITICAL: Initialize audio context (MUST be called in user gesture context)
|
|
142
|
+
// This method MUST be called within a user gesture event handler (click, touchstart, etc.)
|
|
143
|
+
// to satisfy browser security policies. Calling it outside a user gesture will fail.
|
|
144
|
+
button.addEventListener('click', async () => {
|
|
145
|
+
// Initialize audio context - MUST be in user gesture context
|
|
146
|
+
await avatarView.controller.initializeAudioContext()
|
|
147
|
+
|
|
148
|
+
// 5. Start real-time communication (SDK mode only)
|
|
149
|
+
await avatarView.controller.start()
|
|
150
|
+
|
|
151
|
+
// 6. Send audio data (SDK mode, must be mono PCM16 format matching configured sample rate)
|
|
152
|
+
const audioData = new ArrayBuffer(1024) // Example: PCM16 audio data at configured sample rate
|
|
153
|
+
avatarView.controller.send(audioData, false) // Send audio data
|
|
154
|
+
avatarView.controller.send(audioData, true) // end=true marks the end of current conversation round
|
|
155
|
+
})
|
|
80
156
|
```
|
|
81
157
|
|
|
82
158
|
### Host Mode Example
|
|
@@ -89,10 +165,17 @@ avatarView.avatarController.send(audioData, true) // end=true marks the end of c
|
|
|
89
165
|
const container = document.getElementById('avatar-container')
|
|
90
166
|
const avatarView = new AvatarView(avatar, container)
|
|
91
167
|
|
|
92
|
-
// 4.
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
168
|
+
// 4. ⚠️ CRITICAL: Initialize audio context (MUST be called in user gesture context)
|
|
169
|
+
// This method MUST be called within a user gesture event handler (click, touchstart, etc.)
|
|
170
|
+
// to satisfy browser security policies. Calling it outside a user gesture will fail.
|
|
171
|
+
button.addEventListener('click', async () => {
|
|
172
|
+
// Initialize audio context - MUST be in user gesture context
|
|
173
|
+
await avatarView.controller.initializeAudioContext()
|
|
174
|
+
|
|
175
|
+
// 5. Host Mode Workflow:
|
|
176
|
+
// Send audio data first to get conversationId, then use it to send animation data
|
|
177
|
+
const conversationId = avatarView.controller.yieldAudioData(audioData, false)
|
|
178
|
+
avatarView.controller.yieldFramesData(animationDataArray, conversationId) // animationDataArray: (Uint8Array | ArrayBuffer)[]
|
|
96
179
|
```
|
|
97
180
|
|
|
98
181
|
### Complete Examples
|
|
@@ -350,34 +433,52 @@ Audio/animation playback controller (playback layer), manages synchronized playb
|
|
|
350
433
|
#### SDK Mode Methods
|
|
351
434
|
|
|
352
435
|
```typescript
|
|
353
|
-
//
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
//
|
|
359
|
-
|
|
360
|
-
|
|
436
|
+
// ⚠️ CRITICAL: Initialize audio context first (MUST be called in user gesture context)
|
|
437
|
+
// This method MUST be called within a user gesture event handler (click, touchstart, etc.)
|
|
438
|
+
// to satisfy browser security policies. Calling it outside a user gesture will fail.
|
|
439
|
+
// All audio operations (start, send, etc.) require prior initialization.
|
|
440
|
+
button.addEventListener('click', async () => {
|
|
441
|
+
// Initialize audio context - MUST be in user gesture context
|
|
442
|
+
await avatarView.controller.initializeAudioContext()
|
|
443
|
+
|
|
444
|
+
// Start WebSocket service
|
|
445
|
+
await avatarView.controller.start()
|
|
446
|
+
|
|
447
|
+
// Send audio data (must be 16kHz mono PCM16 format)
|
|
448
|
+
const conversationId = avatarView.controller.send(audioData: ArrayBuffer, end: boolean)
|
|
449
|
+
// Returns: conversationId - Conversation ID for this conversation session
|
|
450
|
+
// end: false (default) - Continue sending audio data for current conversation
|
|
451
|
+
// end: true - Mark the end of current conversation round. After end=true, sending new audio data will interrupt any ongoing playback from the previous conversation round
|
|
452
|
+
})
|
|
361
453
|
|
|
362
454
|
// Close WebSocket service
|
|
363
|
-
avatarView.
|
|
455
|
+
avatarView.controller.close()
|
|
364
456
|
```
|
|
365
457
|
|
|
366
458
|
#### Host Mode Methods
|
|
367
459
|
|
|
368
460
|
```typescript
|
|
369
|
-
//
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
)
|
|
374
|
-
//
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
461
|
+
// ⚠️ CRITICAL: Initialize audio context first (MUST be called in user gesture context)
|
|
462
|
+
// This method MUST be called within a user gesture event handler (click, touchstart, etc.)
|
|
463
|
+
// to satisfy browser security policies. Calling it outside a user gesture will fail.
|
|
464
|
+
// All audio operations (yieldAudioData, yieldFramesData, etc.) require prior initialization.
|
|
465
|
+
button.addEventListener('click', async () => {
|
|
466
|
+
// Initialize audio context - MUST be in user gesture context
|
|
467
|
+
await avatarView.controller.initializeAudioContext()
|
|
468
|
+
|
|
469
|
+
// Stream audio chunks (must be 16kHz mono PCM16 format)
|
|
470
|
+
const conversationId = avatarView.controller.yieldAudioData(
|
|
471
|
+
data: Uint8Array, // Audio chunk data
|
|
472
|
+
isLast: boolean = false // Whether this is the last chunk
|
|
473
|
+
)
|
|
474
|
+
// Returns: conversationId - Conversation ID for this audio session
|
|
475
|
+
|
|
476
|
+
// Stream animation keyframes (requires conversationId from audio data)
|
|
477
|
+
avatarView.controller.yieldFramesData(
|
|
478
|
+
keyframesDataArray: (Uint8Array | ArrayBuffer)[], // Animation keyframes binary data array (each element is a protobuf encoded Message)
|
|
479
|
+
conversationId: string // Conversation ID (required)
|
|
480
|
+
)
|
|
481
|
+
})
|
|
381
482
|
```
|
|
382
483
|
|
|
383
484
|
**⚠️ Important: Conversation ID (conversationId) Management**
|
|
@@ -555,17 +656,17 @@ The rendering system automatically selects the best backend, no manual configura
|
|
|
555
656
|
|
|
556
657
|
## 🚨 Error Handling
|
|
557
658
|
|
|
558
|
-
###
|
|
659
|
+
### AvatarError
|
|
559
660
|
|
|
560
661
|
The SDK uses custom error types, providing more detailed error information:
|
|
561
662
|
|
|
562
663
|
```typescript
|
|
563
|
-
import {
|
|
664
|
+
import { AvatarError } from '@spatialwalk/avatarkit'
|
|
564
665
|
|
|
565
666
|
try {
|
|
566
667
|
await avatarView.avatarController.start()
|
|
567
668
|
} catch (error) {
|
|
568
|
-
if (error instanceof
|
|
669
|
+
if (error instanceof AvatarError) {
|
|
569
670
|
console.error('SDK Error:', error.message, error.code)
|
|
570
671
|
} else {
|
|
571
672
|
console.error('Unknown error:', error)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import { A as APP_CONFIG, l as logger, e as errorToMessage, a as logEvent } from "./index-
|
|
4
|
+
import { A as APP_CONFIG, l as logger, e as errorToMessage, a as logEvent } from "./index-D0sXXlqd.js";
|
|
5
5
|
class StreamingAudioPlayer {
|
|
6
6
|
constructor(options) {
|
|
7
7
|
__publicField(this, "audioContext", null);
|