@spatius/avatarkit 0.5.0 → 1.0.0

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
@@ -1,22 +1,15 @@
1
1
  # Changelog
2
2
 
3
- ## [0.5.0] - 2026-05-14
3
+ All notable changes to this project will be documented in this file.
4
4
 
5
- Initial release.
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).
6
7
 
7
- ### Features
8
- - Real-time 3D avatar rendering powered by WebGL/WebGPU + WASM.
9
- - Streaming audio-driven animation with low-latency lip sync.
10
- - SDK mode and host mode for the driving service.
11
- - Animation state callbacks (idle, speaking, fallback transitions).
12
- - Telemetry built in (PostHog).
13
- - Vite and Next.js plugins for zero-config WASM asset handling.
8
+ ## [1.0.0] - 2026-05-17
14
9
 
15
- ### Public API
16
- - `AvatarSDK` – SDK lifecycle, configuration, session token, device support.
17
- - `AvatarManager` – avatar resource loading and caching.
18
- - `Avatar` / `AvatarView` / `AvatarController` – rendering and conversation control.
19
- - Types: `Configuration`, `AudioFormat`, `ConnectionState`, `ConversationState`, `DrivingServiceMode`, `LogLevel`, `LoadProgressInfo`, `CameraConfig`, `PostProcessingConfig`, `AvatarError`.
10
+ First stable release.
20
11
 
21
- ### Audio
22
- - Mono PCM input. Supported sample rates: 8000, 16000, 22050, 24000, 32000, 44100, 48000 Hz.
12
+ - Real-time avatar rendering with WebGL and WebGPU backends.
13
+ - Audio-driven SDK mode and host-driven mode for custom animation pipelines.
14
+ - Public API: `AvatarSDK`, `AvatarView`, `AvatarController`, `AvatarManager`.
15
+ - See [README.md](README.md) for installation and usage.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # AvatarKit SDK
1
+ # @spatius/avatarkit
2
2
 
3
3
  Real-time virtual avatar rendering SDK for Web, supporting audio-driven animation and high-quality 3D rendering.
4
4
 
@@ -165,7 +165,7 @@ All environments require an **App ID** and **Session Token** for authentication.
165
165
  The App ID is used to identify your application. You can obtain your App ID by:
166
166
 
167
167
  1. **For Testing**: Use the default test App ID provided in demo repositories (paired with test Session Token, only works with publicly available test avatars like Rohan, Dr.Kellan, Priya, Josh, etc.)
168
- 2. **For Production**: Visit the [Developer Platform](https://dash.spatialreal.ai) to create your own App and avatars. You will receive your own App ID after creating an App.
168
+ 2. **For Production**: Visit the [Developer Platform](https://app.spatius.ai) to create your own App and avatars. You will receive your own App ID after creating an App.
169
169
 
170
170
  ### Session Token
171
171
 
@@ -175,7 +175,7 @@ The Session Token is required for authentication and must be obtained from your
175
175
  - The Session Token must be valid and not expired
176
176
  - In production applications, you **must** manually inject a valid Session Token obtained from your SDK provider
177
177
  - The default Session Token provided in demo repositories is **only for demonstration purposes** and can only be used with test avatars
178
- - If you want to create your own avatars and test them, please visit the [Developer Platform](https://dash.spatialreal.ai) to create your own App and generate Session Tokens
178
+ - If you want to create your own avatars and test them, please visit the [Developer Platform](https://app.spatius.ai) to create your own App and generate Session Tokens
179
179
 
180
180
  **How to Set Session Token:**
181
181
 
@@ -237,7 +237,6 @@ const configuration: Configuration = {
237
237
  sampleRate: 16000 // Supported: 8000, 16000, 22050, 24000, 32000, 44100, 48000 Hz
238
238
  // ⚠️ Must match your actual audio sample rate. Mismatched sample rate will cause playback issues.
239
239
  }
240
- // characterApiBaseUrl: 'https://custom-api.example.com' // Optional, internal debug config, can be ignored
241
240
  }
242
241
 
243
242
  await AvatarSDK.initialize('your-app-id', configuration)
@@ -690,7 +689,6 @@ button.addEventListener('click', async () => {
690
689
  - `yieldAudioData()` returns a conversationId (automatically generates if starting new session)
691
690
  - `yieldFramesData()` requires a valid conversationId parameter
692
691
  - Animation data with mismatched conversationId will be **discarded**
693
- - Use `getCurrentConversationId()` to retrieve the current active conversationId
694
692
 
695
693
  #### Common Methods (Both Modes)
696
694
 
@@ -705,13 +703,6 @@ await avatarView.controller.resume()
705
703
  // Interrupt current playback (stops and clears data)
706
704
  avatarView.controller.interrupt()
707
705
 
708
- // Clear all data and resources
709
- avatarView.controller.clear()
710
-
711
- // Get current conversation ID (for Host mode)
712
- const conversationId = avatarView.controller.getCurrentConversationId()
713
- // Returns: Current conversationId for the active audio session, or null if no active session
714
-
715
706
  // Volume control (affects only avatar audio player, not system volume)
716
707
  avatarView.controller.setVolume(0.5) // Set volume to 50% (0.0 to 1.0)
717
708
  const currentVolume = avatarView.controller.getVolume() // Get current volume (0.0 to 1.0)
@@ -742,7 +733,7 @@ avatarView.avatarTransform = { x: 0.5, y: 0, scale: 2.0 } // Right half, double
742
733
  **Important Notes:**
743
734
  - `start()` and `close()` are only available in SDK mode
744
735
  - `yieldAudioData()` and `yieldFramesData()` are only available in Host mode
745
- - `pause()`, `resume()`, `interrupt()`, `clear()`, `getCurrentConversationId()`, `setVolume()`, and `getVolume()` are available in both modes
736
+ - `pause()`, `resume()`, `interrupt()`, `setVolume()`, and `getVolume()` are available in both modes
746
737
  - The playback mode is determined when creating `AvatarView` and cannot be changed
747
738
 
748
739
  ## 🔧 Configuration
@@ -754,7 +745,6 @@ interface Configuration {
754
745
  drivingServiceMode?: DrivingServiceMode // Optional, default is 'sdk' (SDK mode)
755
746
  logLevel?: LogLevel // Optional, default is 'off' (no logs)
756
747
  audioFormat?: AudioFormat // Optional, default is { channelCount: 1, sampleRate: 16000 }
757
- characterApiBaseUrl?: string // Optional, internal debug config, can be ignored
758
748
  }
759
749
 
760
750
  interface AudioFormat {
@@ -792,7 +782,6 @@ enum LogLevel {
792
782
  - `sampleRate`: Audio sample rate in Hz (default: 16000)
793
783
  - Supported values: 8000, 16000, 22050, 24000, 32000, 44100, 48000
794
784
  - The configured sample rate will be used for both audio recording and playback
795
- - `characterApiBaseUrl`: Internal debug config, can be ignored
796
785
  - `sessionToken`: **Required for authentication**. Set separately via `AvatarSDK.setSessionToken()`, not in Configuration. See [Authentication](#-authentication) section for details
797
786
 
798
787
  ### CameraConfig
@@ -947,7 +936,7 @@ avatarView.dispose()
947
936
  - Render system and canvas elements
948
937
  - All event listeners and callbacks
949
938
  - Not properly calling `dispose()` may cause resource leaks and rendering errors
950
- - 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
939
+ - If you need to manually close connections before disposing, you can call `avatarView.controller.close()` (SDK mode) first, but it's not required as `dispose()` handles this automatically
951
940
 
952
941
  ### Memory Optimization
953
942
 
@@ -973,4 +962,4 @@ Issues and Pull Requests are welcome!
973
962
 
974
963
  For questions, please contact:
975
964
  - Email: code@spatius.net
976
- - Documentation: https://docs.spatialreal.ai
965
+ - Documentation: https://docs.spatius.ai
@@ -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-DrRoews_.js";
4
+ import { A as APP_CONFIG, l as logger, e as errorToMessage, a as logEvent } from "./index-zTpDp_Pv.js";
5
5
  class StreamingAudioPlayer {
6
6
  // Mark if AudioContext is being resumed, avoid concurrent resume requests
7
7
  constructor(options) {
@@ -1,6 +1,7 @@
1
1
  import { CharacterMeta } from '../types';
2
2
  export declare class Avatar {
3
3
  readonly id: string;
4
+ get isFromCache(): boolean;
4
5
  private characterMeta;
5
6
  private resources;
6
7
  /** Local-only field: tracks whether cached model is "standard" or "compressed". */
@@ -1,5 +1,5 @@
1
1
  import { Avatar } from './Avatar';
2
- import { ConnectionState, AvatarError, DrivingServiceMode, ConversationState, PostProcessingConfig } from '../types';
2
+ import { ConnectionState, AvatarError, DrivingServiceMode, ConversationState, AnimationType, PostProcessingConfig } from '../types';
3
3
  import { FrameRateInfo } from '../performance/FrameRateMonitor';
4
4
  export declare class AvatarController {
5
5
  private networkLayer?;
@@ -10,6 +10,8 @@ export declare class AvatarController {
10
10
  onConnectionState: ((state: ConnectionState) => void) | null;
11
11
  onConversationState: ((state: ConversationState) => void) | null;
12
12
  onError: ((error: AvatarError) => void) | null;
13
+ /** Callback for animation type changes (e.g., idle → mono in fallback mode). Aligned with iOS/Android AvatarController.onAnimationState. */
14
+ onAnimationState: ((type: AnimationType) => void) | null;
13
15
  private eventListeners;
14
16
  private readonly frameRateMonitor;
15
17
  /** Frame rate monitoring callback. Fires with aggregated metrics from a 2-second sliding window. */
@@ -22,8 +24,7 @@ export declare class AvatarController {
22
24
  private characterHandle;
23
25
  private characterId;
24
26
  private postProcessingConfig;
25
- private playbackLoopId;
26
- private playbackLoopGeneration;
27
+ private audioMonitorLoopId;
27
28
  private lastRenderedFrameIndex;
28
29
  private keyframesOffset;
29
30
  private readonly MAX_KEYFRAMES;
@@ -43,14 +44,13 @@ export declare class AvatarController {
43
44
  playbackMode?: DrivingServiceMode;
44
45
  });
45
46
  private handleVisibilityChange;
46
- private shouldReportPlaybackStats;
47
- private _getDeviceScoreProps;
48
47
  /**
49
- * Get current conversation ID
50
- * Returns the current conversation ID for the active audio session
51
- * @returns Current conversation ID, or null if no active session
48
+ * Playback time of the current audio session, in seconds.
49
+ * Resets to 0 on each new playback round. Returns 0 when not playing.
52
50
  */
53
- getCurrentConversationId(): string | null;
51
+ getAudioTime(): number;
52
+ private shouldReportPlaybackStats;
53
+ private _getDeviceScoreProps;
54
54
  /**
55
55
  * Initialize audio context (must be called in user gesture context)
56
56
  *
@@ -92,7 +92,7 @@ export declare class AvatarController {
92
92
  * Public API: accepts binary data array (protobuf encoded Message array)
93
93
  * @param keyframesDataArray - Animation keyframes binary data array (each element is a protobuf encoded Message) or empty array to trigger audio-only mode
94
94
  * @param conversationId - Conversation ID (required). If conversationId doesn't match current conversationId, keyframes will be discarded.
95
- * Use getCurrentConversationId() to get the current conversationId.
95
+ * The conversationId is returned by yieldAudioData().
96
96
  * @returns `true` if the server has sent all animation data for this conversation (end signal received), `false` otherwise.
97
97
  */
98
98
  yieldFramesData(keyframesDataArray: (Uint8Array | ArrayBuffer)[], conversationId: string): boolean;
@@ -112,14 +112,9 @@ export declare class AvatarController {
112
112
  */
113
113
  interrupt(): void;
114
114
  /**
115
- * Clear all data and resources
116
- */
117
- clear(): void;
118
- /**
119
- * Get point cloud count of the current avatar
120
- * @returns Point cloud count, or null if avatar is not loaded
115
+ * The point count of current avatar, or null if avatar is not loaded.
121
116
  */
122
- getPointCount(): number | null;
117
+ get pointCount(): number | null;
123
118
  /**
124
119
  * Set post-processing configuration
125
120
  * These parameters will be applied in real-time to animation parameters returned by the server
@@ -137,4 +132,5 @@ export declare class AvatarController {
137
132
  * @returns Current volume value (0.0 - 1.0)
138
133
  */
139
134
  getVolume(): number;
135
+ protected stopPlayback(): void;
140
136
  }
@@ -25,7 +25,6 @@ export declare class AvatarSDK {
25
25
  * Optional interface for developers, SDK includes this in telemetry logs
26
26
  */
27
27
  static setUserId(userId: string): void;
28
- static get isInitialized(): boolean;
29
28
  static get appId(): string | null;
30
29
  static get configuration(): Configuration | null;
31
30
  static get sessionToken(): string | null;
@@ -9,26 +9,23 @@ export declare class AvatarView {
9
9
  private renderSystem;
10
10
  private isInitialized;
11
11
  private cameraConfig;
12
- private renderingState;
13
- private currentKeyframes;
14
- private lastRenderedFrameIndex;
15
- private lastRealtimeProtoFrame;
16
- private idleAnimationLoopId;
17
- private realtimeAnimationLoopId;
12
+ private renderLoopId;
18
13
  private resizeObserver;
19
14
  private onWindowResize;
15
+ private onVisibilityChange;
20
16
  private frameCount;
21
17
  private lastFpsUpdate;
22
18
  private currentFPS;
23
- private transitionKeyframes;
24
- private transitionStartTime;
25
- private readonly startTransitionDurationMs;
26
- private readonly endTransitionDurationMs;
27
- private cachedIdleFirstFrame;
28
- private idleCurrentFrameIndex;
29
19
  private currentPlayingFrame;
20
+ private cachedIdleFirstFrame;
30
21
  private characterHandle;
31
22
  private characterId;
23
+ private transitionFrames;
24
+ private onTransitionFramesConsumed;
25
+ private isConversationActive;
26
+ private lastRenderedFrameIndex;
27
+ private animationHandleMap;
28
+ private activeAnimationState;
32
29
  private isPureRenderingMode;
33
30
  private _renderingEnabled;
34
31
  private avatarActiveTimer;
@@ -44,6 +41,28 @@ export declare class AvatarView {
44
41
  * Get controller (public interface)
45
42
  */
46
43
  get controller(): AvatarController;
44
+ private _exportBitmapResolve;
45
+ /**
46
+ * Exports the current rendering as a Blob (PNG).
47
+ * Returns null if the canvas is not initialized or not rendering.
48
+ * Aligned with iOS exportBitmap() / Android exportBitmap().
49
+ *
50
+ * The capture happens synchronously inside the render loop (after renderFrame)
51
+ * to work correctly with WebGL preserveDrawingBuffer:false.
52
+ */
53
+ exportBitmap(): Promise<Blob | null>;
54
+ /** @deprecated Use startRenderLoop() */
55
+ private startIdleAnimationLoop;
56
+ /**
57
+ * Render a specific idle frame by index for benchmark capture.
58
+ * Bypasses animation loop and _renderingEnabled check.
59
+ */
60
+ renderIdleFrameForBenchmark(frameIndex: number): Promise<void>;
61
+ /**
62
+ * Render a single frame from FlameParams for benchmark capture (transition / speaking).
63
+ * Bypasses animation loop and _renderingEnabled check.
64
+ */
65
+ renderFrameForBenchmark(flameParams: import('../wasm/avatarCoreAdapter').FlameParams): Promise<void>;
47
66
  /**
48
67
  * Cleanup view resources
49
68
  * Closes avatarController and cleans up all related resources
@@ -167,4 +186,31 @@ export declare class AvatarView {
167
186
  y: number;
168
187
  scale: number;
169
188
  });
189
+ /**
190
+ * Get the approximate bounding rectangle of the avatar in canvas pixel coordinates.
191
+ * Projects idle first frame positions through current view/projection matrices and transform.
192
+ * No caching is performed — each call recomputes from scratch.
193
+ *
194
+ * **Important:** The result depends on the current canvas size and `avatarTransform`.
195
+ * You must call this method again after any of the following changes to get an up-to-date result:
196
+ * - Canvas / container size changes (e.g. window resize)
197
+ * - `avatarTransform` changes (offset or scale)
198
+ *
199
+ * **Performance note:** Each call iterates ~70k splat points. Avoid calling every frame;
200
+ * call on-demand (e.g. after init, on resize, after transform change).
201
+ *
202
+ * @returns Bounding rectangle { x, y, width, height } in CSS pixels (top-left origin), or null if not ready
203
+ *
204
+ * @example
205
+ * const rect = avatarView.getBoundingRect()
206
+ * if (rect) {
207
+ * console.log(`Avatar at (${rect.x}, ${rect.y}), size ${rect.width}x${rect.height}`)
208
+ * }
209
+ */
210
+ getBoundingRect(): {
211
+ x: number;
212
+ y: number;
213
+ width: number;
214
+ height: number;
215
+ } | null;
170
216
  }