@spatialwalk/avatarkit 1.0.0-beta.82 → 1.0.0-beta.84

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 CHANGED
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.0-beta.84] - 2026-03-03
9
+
10
+ ### 🐛 Bugfixes
11
+ - **End-Transition Continuity** - Fixed the visual jump after conversation end transition by resetting idle frame cursor when returning to `Idle` state
12
+
13
+ ## [1.0.0-beta.83] - 2026-03-03
14
+
15
+ ### 🐛 Bugfixes
16
+ - **Playback Startup Sync** - Improved startup sequencing for SDK mode playback to reduce transition/audio desync at conversation start
17
+ - **Initialization Guard** - Added explicit `appId` validation in `AvatarSDK.initialize()` to fail fast when `appId` is empty
18
+
19
+ ### 🔧 Improvements
20
+ - **Server Error Propagation** - `onError` now consistently receives `AvatarError` with server message and mapped error code for `MESSAGE_SERVER_ERROR` in SDK mode
21
+
22
+ ### 📚 Documentation
23
+ - **README Error Callback** - Added detailed `onError` callback behavior and server error code mapping documentation
24
+
8
25
  ## [1.0.0-beta.82] - 2026-02-12
9
26
 
10
27
  ### 🔧 Improvements
package/README.md CHANGED
@@ -1,14 +1,12 @@
1
1
  # AvatarKit SDK
2
2
 
3
- Real-time virtual avatar rendering SDK based on 3D Gaussian Splatting, supporting audio-driven animation rendering and high-quality 3D rendering.
3
+ Real-time virtual avatar rendering SDK for Web, supporting audio-driven animation and high-quality 3D rendering.
4
4
 
5
5
  ## 🚀 Features
6
6
 
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
7
+ - **High-Quality 3D Rendering** - GPU-accelerated avatar rendering with automatic backend selection
8
+ - **Audio-Driven Real-Time Animation** - Send audio data, SDK handles animation and rendering
9
9
  - **Multi-Avatar Support** - Support multiple avatar instances simultaneously, each with independent state and rendering
10
- - **WebGPU/WebGL Dual Rendering Backend** - Automatically selects the best rendering backend for compatibility
11
- - **WASM High-Performance Computing** - Uses C++ compiled WebAssembly modules for geometric calculations
12
10
  - **TypeScript Support** - Complete type definitions and IntelliSense
13
11
  - **Modular Architecture** - Clear component separation, easy to integrate and extend
14
12
 
@@ -65,10 +63,6 @@ The plugin automatically handles:
65
63
 
66
64
  - ✅ **Development Server**: Automatically sets the correct MIME type (`application/wasm`) for WASM files
67
65
  - ✅ **Build Time**: Automatically copies WASM files to `dist/assets/` directory
68
- - Smart Detection: Extracts referenced WASM file names (including hash) from JS glue files
69
- - Auto Matching: Ensures copied WASM files match references in JS glue files
70
- - Hash Support: Correctly handles hashed WASM files (e.g., `avatar_core_wasm-{hash}.wasm`)
71
- - ✅ **WASM JS Glue**: Automatically copies WASM JS glue files to `dist/assets/` directory
72
66
  - ✅ **Cloudflare Pages**: Automatically generates `_headers` file to ensure WASM files use the correct MIME type
73
67
  - ✅ **Vite Configuration**: Automatically configures `optimizeDeps`, `assetsInclude`, `assetsInlineLimit`, and other options
74
68
 
@@ -128,7 +122,7 @@ export default withAvatarkit({
128
122
 
129
123
  The plugin automatically handles:
130
124
 
131
- - ✅ **Emscripten Fix**: Patches `scriptDirectory` so the WASM glue file correctly resolves assets at `/_next/static/chunks/` instead of a build-time `file://` path
125
+ - ✅ **Path Fix**: Patches asset path resolution so WASM files are correctly loaded at `/_next/static/chunks/`
132
126
  - ✅ **WASM Copying**: Copies `.wasm` files into `static/chunks/` via a custom webpack plugin (client build only)
133
127
  - ✅ **Content-Type Headers**: Adds `application/wasm` response header for `/_next/static/chunks/*.wasm`
134
128
  - ✅ **Config Chaining**: Preserves your existing `webpack` and `headers` configurations
@@ -146,7 +140,7 @@ The App ID is used to identify your application. You can obtain your App ID by:
146
140
 
147
141
  ### Session Token
148
142
 
149
- The Session Token is required for WebSocket authentication and must be obtained from your SDK provider.
143
+ The Session Token is required for authentication and must be obtained from your SDK provider.
150
144
 
151
145
  **⚠️ Important Notes:**
152
146
  - The Session Token must be valid and not expired
@@ -204,7 +198,7 @@ import {
204
198
  const configuration: Configuration = {
205
199
  environment: Environment.cn,
206
200
  drivingServiceMode: DrivingServiceMode.sdk, // Optional, 'sdk' is default
207
- // - DrivingServiceMode.sdk: SDK mode - SDK handles WebSocket communication
201
+ // - DrivingServiceMode.sdk: SDK mode - SDK handles network communication
208
202
  // - DrivingServiceMode.host: Host mode - Host app provides audio and animation data
209
203
  logLevel: LogLevel.off, // Optional, 'off' is default
210
204
  // - LogLevel.off: Disable all logs
@@ -233,7 +227,7 @@ const avatar = await avatarManager.load('character-id', (progress) => {
233
227
 
234
228
  // 3. Create view (automatically creates Canvas and AvatarController)
235
229
  // The playback mode is determined by drivingServiceMode in AvatarSDK configuration
236
- // - DrivingServiceMode.sdk: SDK mode - SDK handles WebSocket communication
230
+ // - DrivingServiceMode.sdk: SDK mode - SDK handles network communication
237
231
  // - DrivingServiceMode.host: Host mode - Host app provides audio and animation data
238
232
  const container = document.getElementById('avatar-container')
239
233
  const avatarView = new AvatarView(avatar, container)
@@ -290,20 +284,12 @@ This SDK supports two usage modes:
290
284
 
291
285
  ## 🏗️ Architecture Overview
292
286
 
293
- ### Three-Layer Architecture
294
-
295
- The SDK uses a three-layer architecture for clear separation of concerns:
296
-
297
- 1. **Rendering Layer (AvatarView)** - Responsible for 3D rendering only
298
- 2. **Playback Layer (AvatarController)** - Manages audio/animation synchronization and playback
299
- 3. **Network Layer** - Handles WebSocket communication (only in SDK mode, internal implementation)
300
-
301
287
  ### Core Components
302
288
 
303
289
  - **AvatarSDK** - SDK initialization and management
304
290
  - **AvatarManager** - Avatar resource loading and management
305
- - **AvatarView** - 3D rendering view (rendering layer)
306
- - **AvatarController** - Audio/animation playback controller (playback layer)
291
+ - **AvatarView** - 3D rendering view
292
+ - **AvatarController** - Audio/animation playback controller
307
293
 
308
294
  ### Playback Modes
309
295
 
@@ -311,7 +297,7 @@ The SDK supports two playback modes, configured in `AvatarSDK.initialize()`:
311
297
 
312
298
  #### 1. SDK Mode (Default)
313
299
  - Configured via `drivingServiceMode: DrivingServiceMode.sdk` in `AvatarSDK.initialize()`
314
- - SDK handles WebSocket communication automatically
300
+ - SDK handles network communication automatically
315
301
  - Send audio data via `AvatarController.send()`
316
302
  - SDK receives animation data from backend and synchronizes playback
317
303
  - Best for: Real-time audio input scenarios
@@ -329,33 +315,27 @@ The SDK supports two playback modes, configured in `AvatarSDK.initialize()`:
329
315
 
330
316
  The SDK includes a fallback mechanism to ensure audio playback continues even when animation data is unavailable:
331
317
 
332
- - **SDK Mode Connection Failure**: If WebSocket connection fails to establish within 15 seconds, the SDK automatically enters fallback mode. In this mode, audio data can still be sent and will play normally, even though no animation data will be received from the server. This ensures that audio playback is not interrupted even when the service connection fails.
333
- - **SDK Mode Server Error**: If the server returns an error after connection is established, the SDK automatically enters audio-only mode for that session and continues playing audio independently.
318
+ - **SDK Mode Connection Failure**: If connection fails to establish within 15 seconds, the SDK automatically enters fallback mode. Audio data can still be sent and will play normally, even though no animation data will be received. This ensures audio playback is not interrupted.
319
+ - **SDK Mode Server Error**: If the server returns an error after connection is established, the SDK automatically enters audio-only mode for that session.
334
320
  - **Host Mode**: If empty animation data is provided (empty array or undefined), the SDK automatically enters audio-only mode.
335
321
  - Once in audio-only mode, any subsequent animation data for that session will be ignored, and only audio will continue playing.
336
322
  - The fallback mode is interruptible, just like normal playback mode.
337
- - Connection state callbacks (`onConnectionState`) will notify you when connection fails or times out, allowing you to handle the fallback state appropriately.
323
+ - Connection state callbacks (`onConnectionState`) will notify you when connection fails or times out.
338
324
 
339
325
  ### Data Flow
340
326
 
341
327
  #### SDK Mode Flow
342
328
 
343
329
  ```
344
- User audio input (16kHz mono PCM16)
345
-
346
- AvatarController.send()
347
-
348
- WebSocket → Backend processing
330
+ Audio input (PCM16 mono)
349
331
 
350
- Backend returns animation data (FLAME keyframes)
332
+ AvatarController.send()
351
333
 
352
- AvatarControllerAnimationPlayer
334
+ Backend processing Animation data
353
335
 
354
- FLAME parameters AvatarCore.computeFrameFlatFromParams() Splat data
336
+ SDK synchronizes audio + animation playback
355
337
 
356
- AvatarController (playback loop) AvatarView.renderRealtimeFrame()
357
-
358
- RenderSystem → WebGPU/WebGL → Canvas rendering
338
+ GPU renderingCanvas
359
339
  ```
360
340
 
361
341
  #### Host Mode Flow
@@ -363,17 +343,12 @@ RenderSystem → WebGPU/WebGL → Canvas rendering
363
343
  ```
364
344
  External data source (audio + animation)
365
345
 
366
- AvatarController.yieldAudioData(audioChunk) // Returns conversationId
367
-
368
- AvatarController.yieldFramesData(keyframesDataArray, conversationId) // keyframesDataArray: (Uint8Array | ArrayBuffer)[] - each element is a protobuf encoded Message
369
-
370
- AvatarController → AnimationPlayer (synchronized playback)
346
+ AvatarController.yieldAudioData(audioChunk) returns conversationId
347
+ AvatarController.yieldFramesData(dataArray, conversationId)
371
348
 
372
- FLAME parameters AvatarCore.computeFrameFlatFromParams() Splat data
349
+ SDK synchronizes audio + animation playback
373
350
 
374
- AvatarController (playback loop) AvatarView.renderRealtimeFrame()
375
-
376
- RenderSystem → WebGPU/WebGL → Canvas rendering
351
+ GPU renderingCanvas
377
352
  ```
378
353
 
379
354
  ### Audio Format Requirements
@@ -545,7 +520,7 @@ manager.clearAll()
545
520
 
546
521
  ### AvatarView
547
522
 
548
- 3D rendering view (rendering layer), responsible for 3D rendering only. Internally automatically creates and manages `AvatarController`.
523
+ 3D rendering view, responsible for 3D rendering only. Internally automatically creates and manages `AvatarController`.
549
524
 
550
525
  ```typescript
551
526
  constructor(avatar: Avatar, container: HTMLElement)
@@ -608,7 +583,7 @@ await currentAvatarView.controller.start()
608
583
 
609
584
  ### AvatarController
610
585
 
611
- Audio/animation playback controller (playback layer), manages synchronized playback of audio and animation. Automatically handles WebSocket communication in SDK mode.
586
+ Audio/animation playback controller, manages synchronized playback of audio and animation. Automatically handles network communication in SDK mode.
612
587
 
613
588
  **Two Usage Patterns:**
614
589
 
@@ -623,9 +598,9 @@ button.addEventListener('click', async () => {
623
598
  // Initialize audio context - MUST be in user gesture context
624
599
  await avatarView.controller.initializeAudioContext()
625
600
 
626
- // Start WebSocket service
601
+ // Start service
627
602
  await avatarView.controller.start()
628
-
603
+
629
604
  // Send audio data (must be mono PCM16 format matching configured sample rate)
630
605
  const conversationId = avatarView.controller.send(audioData: ArrayBuffer, end: boolean)
631
606
  // Returns: conversationId - Conversation ID for this conversation session
@@ -633,7 +608,7 @@ button.addEventListener('click', async () => {
633
608
  // 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
634
609
  })
635
610
 
636
- // Close WebSocket service
611
+ // Close service
637
612
  avatarView.controller.close()
638
613
  ```
639
614
 
@@ -657,7 +632,7 @@ button.addEventListener('click', async () => {
657
632
 
658
633
  // Stream animation keyframes (requires conversationId from audio data)
659
634
  avatarView.controller.yieldFramesData(
660
- keyframesDataArray: (Uint8Array | ArrayBuffer)[], // Animation keyframes binary data array (each element is a protobuf encoded Message)
635
+ keyframesDataArray: (Uint8Array | ArrayBuffer)[], // Animation keyframes binary data array
661
636
  conversationId: string // Conversation ID (required)
662
637
  )
663
638
  })
@@ -702,7 +677,7 @@ const currentVolume = avatarView.controller.getVolume() // Get current volume (
702
677
  // Set event callbacks
703
678
  avatarView.controller.onConnectionState = (state: ConnectionState) => {} // SDK mode only
704
679
  avatarView.controller.onConversationState = (state: ConversationState) => {}
705
- avatarView.controller.onError = (error: Error) => {}
680
+ avatarView.controller.onError = (error: Error) => {} // Usually AvatarError (includes code for SDK/server errors)
706
681
  ```
707
682
 
708
683
  #### Avatar Transform Methods
@@ -763,9 +738,9 @@ enum LogLevel {
763
738
  **Note:** `LogLevel.off` completely disables all logging, including error logs. Use with caution in production environments.
764
739
 
765
740
  **Description:**
766
- - `environment`: Specifies the environment (cn/intl), SDK will automatically use the corresponding API address and WebSocket address based on the environment
741
+ - `environment`: Specifies the environment (cn/intl), SDK will automatically use the corresponding server addresses based on the environment
767
742
  - `drivingServiceMode`: Specifies the driving service mode
768
- - `DrivingServiceMode.sdk` (default): SDK mode - SDK handles WebSocket communication automatically
743
+ - `DrivingServiceMode.sdk` (default): SDK mode - SDK handles network communication automatically
769
744
  - `DrivingServiceMode.host`: Host mode - Host application provides audio and animation data
770
745
  - `logLevel`: Controls the verbosity of SDK logs
771
746
  - `LogLevel.off` (default): Disable all logs
@@ -835,12 +810,7 @@ enum ConversationState {
835
810
 
836
811
  ## 🎨 Rendering System
837
812
 
838
- The SDK supports two rendering backends:
839
-
840
- - **WebGPU** - High-performance rendering for modern browsers
841
- - **WebGL** - Better compatibility for traditional rendering
842
-
843
- The rendering system automatically selects the best backend, no manual configuration needed.
813
+ The SDK automatically selects the best rendering backend for your browser, no manual configuration needed.
844
814
 
845
815
  ## 🚨 Error Handling
846
816
 
@@ -865,12 +835,26 @@ try {
865
835
  ### Error Callbacks
866
836
 
867
837
  ```typescript
838
+ import { AvatarError } from '@spatialwalk/avatarkit'
839
+
868
840
  avatarView.controller.onError = (error: Error) => {
869
- console.error('AvatarController error:', error)
870
- // Handle error, such as reconnection, user notification, etc.
841
+ if (error instanceof AvatarError) {
842
+ console.error('AvatarController error:', error.message, error.code)
843
+ return
844
+ }
845
+
846
+ console.error('AvatarController unknown error:', error)
871
847
  }
872
848
  ```
873
849
 
850
+ In SDK mode, server `MESSAGE_SERVER_ERROR` is forwarded to `onError` as `AvatarError`:
851
+ - `error.message`: server-returned error message
852
+ - `error.code` mapping:
853
+ - `401` -> `sessionTokenExpired`
854
+ - `400` -> `sessionTokenInvalid`
855
+ - `404` -> `avatarIDUnrecognized`
856
+ - other HTTP status -> original status code string (for example, `"500"`)
857
+
874
858
  ## 🔄 Resource Management
875
859
 
876
860
  ### Lifecycle Management
@@ -886,7 +870,7 @@ await avatarView.controller.start()
886
870
  // Use
887
871
  avatarView.controller.send(audioData, false)
888
872
 
889
- // Cleanup - dispose() automatically cleans up all resources including WebSocket connections
873
+ // Cleanup - dispose() automatically cleans up all resources including connections
890
874
  avatarView.dispose()
891
875
  ```
892
876
 
@@ -899,26 +883,25 @@ const avatarView = new AvatarView(avatar, container)
899
883
 
900
884
  // Use
901
885
  const conversationId = avatarView.controller.yieldAudioData(audioChunk, false)
902
- avatarView.controller.yieldFramesData(keyframesDataArray, conversationId) // keyframesDataArray: (Uint8Array | ArrayBuffer)[]
886
+ avatarView.controller.yieldFramesData(keyframesDataArray, conversationId)
903
887
 
904
888
  // Cleanup - dispose() automatically cleans up all resources including playback data
905
889
  avatarView.dispose()
906
890
  ```
907
891
 
908
- **⚠️ Important Notes:**
892
+ **⚠️ Important Notes:**
909
893
  - `dispose()` automatically cleans up all resources, including:
910
- - WebSocket connections (SDK mode)
894
+ - Network connections (SDK mode)
911
895
  - Playback data and animation resources (both modes)
912
896
  - Render system and canvas elements
913
897
  - All event listeners and callbacks
914
898
  - Not properly calling `dispose()` may cause resource leaks and rendering errors
915
- - If you need to manually close WebSocket connections or clear playback data before disposing, you can call `avatarView.controller.close()` (SDK mode) or `avatarView.controller.clear()` (both modes) first, but it's not required as `dispose()` handles this automatically
899
+ - If you need to manually close connections or clear playback data before disposing, you can call `avatarView.controller.close()` (SDK mode) or `avatarView.controller.clear()` (both modes) first, but it's not required as `dispose()` handles this automatically
916
900
 
917
901
  ### Memory Optimization
918
902
 
919
- - SDK automatically manages WASM memory allocation
903
+ - SDK automatically manages memory allocation
920
904
  - Supports dynamic loading/unloading of avatar and animation resources
921
- - Provides memory usage monitoring interface
922
905
 
923
906
  ## 🌐 Browser Compatibility
924
907
 
@@ -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-DvCy6yVA.js";
4
+ import { A as APP_CONFIG, l as logger, e as errorToMessage, a as logEvent } from "./index-BNATNpKA.js";
5
5
  class StreamingAudioPlayer {
6
6
  // Mark if AudioContext is being resumed, avoid concurrent resume requests
7
7
  constructor(options) {
File without changes
@@ -6,7 +6,7 @@ export declare class AvatarController {
6
6
  private isStartingPlayback;
7
7
  private currentConversationId;
8
8
  private reqEnd;
9
- onConnectionState: ((state: ConnectionState) => void) | null;
9
+ onConnectionState: ((state: ConnectionState, error?: Error) => void) | null;
10
10
  onConversationState: ((state: ConversationState) => void) | null;
11
11
  onError: ((error: Error) => void) | null;
12
12
  private eventListeners;
@@ -21,7 +21,7 @@ export declare class AvatarController {
21
21
  private readonly KEYFRAMES_CLEANUP_THRESHOLD;
22
22
  private lastSyncLogTime;
23
23
  private lastOutOfBoundsState;
24
- private isAudioOnlyMode;
24
+ private isFallbackMode;
25
25
  private playbackStuckCheckState;
26
26
  private readonly MAX_AUDIO_TIME_ZERO_COUNT;
27
27
  private readonly MAX_AUDIO_TIME_STUCK_COUNT;
@@ -13,16 +13,14 @@ export declare class AvatarView {
13
13
  private currentKeyframes;
14
14
  private lastRenderedFrameIndex;
15
15
  private lastRealtimeProtoFrame;
16
- private idleAnimationLoopId;
17
- private realtimeAnimationLoopId;
16
+ private renderLoopId;
17
+ private endTransitionFrames;
18
+ private isConversationActive;
18
19
  private resizeObserver;
19
20
  private onWindowResize;
20
21
  private frameCount;
21
22
  private lastFpsUpdate;
22
23
  private currentFPS;
23
- private transitionKeyframes;
24
- private transitionStartTime;
25
- private readonly startTransitionDurationMs;
26
24
  private readonly endTransitionDurationMs;
27
25
  private cachedIdleFirstFrame;
28
26
  private idleCurrentFrameIndex;