@spatius/avatarkit 1.0.0 → 1.1.0-beta.1
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 +21 -0
- package/README.md +25 -25
- package/dist/{StreamingAudioPlayer-Cq5jTVny.js → StreamingAudioPlayer-DrHXn-YA.js} +6 -6
- package/dist/core/AvatarController.d.ts +0 -2
- package/dist/core/AvatarSDK.d.ts +16 -1
- package/dist/core/AvatarView.d.ts +32 -2
- package/dist/core/avatarViewRegistry.d.ts +9 -0
- package/dist/{index-zTpDp_Pv.js → index-CVQn5uEB.js} +3444 -433
- package/dist/index.js +11 -9
- package/dist/types/character-settings.d.ts +0 -1
- package/dist/types/index.d.ts +14 -10
- package/package.json +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,27 @@ 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.1.0-beta.1] - 2026-06-08
|
|
9
|
+
|
|
10
|
+
First 1.1 pre-release. Includes breaking changes — see below.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Render quality tiers (`standard` / `high` / `ultra`), selectable at init via the `renderQuality` configuration option or at runtime via `setRenderQuality()`.
|
|
14
|
+
- Render output resolution cap, to bound rendering cost on high-DPI displays.
|
|
15
|
+
- `Configuration.region` is now part of the public API, so consumers can target non-default regions (e.g. `cn`).
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- Unified audio playback path with automatic recovery after a fallback.
|
|
19
|
+
- Smoother RTC-mode speak→idle transition with bezier end interpolation.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- Fixed unfriendly avatar-load error messages that could expose internal request details.
|
|
23
|
+
- Fixed `Configuration.region` being stripped from the published type declarations, which prevented TypeScript consumers from setting the region.
|
|
24
|
+
|
|
25
|
+
### Breaking Changes
|
|
26
|
+
- `DrivingServiceMode` values renamed from `sdk` / `host` to `direct` / `backend`.
|
|
27
|
+
- Removed the `eyefocus` option (no longer supported in `CharacterSettings` or post-processing configuration).
|
|
28
|
+
|
|
8
29
|
## [1.0.0] - 2026-05-17
|
|
9
30
|
|
|
10
31
|
First stable release.
|
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ We provide complete example code and best practices to help you quickly integrat
|
|
|
55
55
|
|
|
56
56
|
**The demo repository includes:**
|
|
57
57
|
- ✅ Complete integration examples
|
|
58
|
-
- ✅ Usage examples for both
|
|
58
|
+
- ✅ Usage examples for both Direct mode and Backend mode
|
|
59
59
|
- ✅ Audio processing examples (PCM16, WAV, MP3, etc.)
|
|
60
60
|
- ✅ Vite configuration examples
|
|
61
61
|
- ✅ Next.js configuration examples
|
|
@@ -224,9 +224,9 @@ import {
|
|
|
224
224
|
// 1. Initialize SDK
|
|
225
225
|
|
|
226
226
|
const configuration: Configuration = {
|
|
227
|
-
drivingServiceMode: DrivingServiceMode.
|
|
228
|
-
// - DrivingServiceMode.
|
|
229
|
-
// - DrivingServiceMode.
|
|
227
|
+
drivingServiceMode: DrivingServiceMode.direct, // Optional, `direct` is default
|
|
228
|
+
// - DrivingServiceMode.direct: Direct mode - SDK handles network communication
|
|
229
|
+
// - DrivingServiceMode.backend: Backend mode - Host app provides audio and animation data
|
|
230
230
|
logLevel: LogLevel.off, // Optional, 'off' is default
|
|
231
231
|
// - LogLevel.off: Disable all logs
|
|
232
232
|
// - LogLevel.error: Only error logs
|
|
@@ -254,8 +254,8 @@ const avatar = await avatarManager.load('character-id', (progress) => {
|
|
|
254
254
|
|
|
255
255
|
// 3. Create view (automatically creates Canvas and AvatarController)
|
|
256
256
|
// The playback mode is determined by drivingServiceMode in AvatarSDK configuration
|
|
257
|
-
// - DrivingServiceMode.
|
|
258
|
-
// - DrivingServiceMode.
|
|
257
|
+
// - DrivingServiceMode.direct: Direct mode - SDK handles network communication
|
|
258
|
+
// - DrivingServiceMode.backend: Backend mode - Host app provides audio and animation data
|
|
259
259
|
const container = document.getElementById('avatar-container')
|
|
260
260
|
const avatarView = new AvatarView(avatar, container)
|
|
261
261
|
|
|
@@ -266,7 +266,7 @@ button.addEventListener('click', async () => {
|
|
|
266
266
|
// Initialize audio context - MUST be in user gesture context
|
|
267
267
|
await avatarView.controller.initializeAudioContext()
|
|
268
268
|
|
|
269
|
-
// 5. Start real-time communication (
|
|
269
|
+
// 5. Start real-time communication (Direct mode only)
|
|
270
270
|
// Note: start() initiates the WebSocket connection asynchronously.
|
|
271
271
|
// Wait for onConnectionState === 'connected' before calling send().
|
|
272
272
|
await avatarView.controller.start()
|
|
@@ -278,7 +278,7 @@ button.addEventListener('click', async () => {
|
|
|
278
278
|
}
|
|
279
279
|
})
|
|
280
280
|
|
|
281
|
-
// 7. Send audio data (
|
|
281
|
+
// 7. Send audio data (Direct mode, must be mono PCM16 format matching configured sample rate)
|
|
282
282
|
// audioData: ArrayBuffer or Uint8Array containing PCM16 (S16LE) audio samples
|
|
283
283
|
// ⚠️ Byte length MUST be even (2 bytes per sample). Odd-length data will cause server-side
|
|
284
284
|
// validation error and WebSocket disconnect.
|
|
@@ -295,9 +295,9 @@ button.addEventListener('click', async () => {
|
|
|
295
295
|
|
|
296
296
|
```typescript
|
|
297
297
|
|
|
298
|
-
// 1-3. Same as
|
|
298
|
+
// 1-3. Same as Direct mode (initialize SDK, load avatar)
|
|
299
299
|
|
|
300
|
-
// 3. Create view with
|
|
300
|
+
// 3. Create view with Backend mode
|
|
301
301
|
const container = document.getElementById('avatar-container')
|
|
302
302
|
const avatarView = new AvatarView(avatar, container)
|
|
303
303
|
|
|
@@ -317,8 +317,8 @@ button.addEventListener('click', async () => {
|
|
|
317
317
|
### Complete Examples
|
|
318
318
|
|
|
319
319
|
This SDK supports two usage modes:
|
|
320
|
-
-
|
|
321
|
-
-
|
|
320
|
+
- Direct mode: Real-time audio input with automatic animation data reception
|
|
321
|
+
- Backend mode: Custom data sources with manual audio/animation data management
|
|
322
322
|
|
|
323
323
|
## 🏗️ Architecture Overview
|
|
324
324
|
|
|
@@ -334,14 +334,14 @@ This SDK supports two usage modes:
|
|
|
334
334
|
The SDK supports two playback modes, configured in `AvatarSDK.initialize()`:
|
|
335
335
|
|
|
336
336
|
#### 1. SDK Mode (Default)
|
|
337
|
-
- Configured via `drivingServiceMode: DrivingServiceMode.
|
|
337
|
+
- Configured via `drivingServiceMode: DrivingServiceMode.direct` in `AvatarSDK.initialize()`
|
|
338
338
|
- SDK handles network communication automatically
|
|
339
339
|
- Send audio data via `AvatarController.send()`
|
|
340
340
|
- SDK receives animation data from backend and synchronizes playback
|
|
341
341
|
- Best for: Real-time audio input scenarios
|
|
342
342
|
|
|
343
343
|
#### 2. Host Mode
|
|
344
|
-
- Configured via `drivingServiceMode: DrivingServiceMode.
|
|
344
|
+
- Configured via `drivingServiceMode: DrivingServiceMode.backend` in `AvatarSDK.initialize()`
|
|
345
345
|
- Host application manages its own network/data fetching
|
|
346
346
|
- Host application provides both audio and animation data
|
|
347
347
|
- SDK only handles synchronized playback
|
|
@@ -618,13 +618,13 @@ const newAvatar = await AvatarManager.shared.load('new-character-id')
|
|
|
618
618
|
// 3. Create new AvatarView
|
|
619
619
|
currentAvatarView = new AvatarView(newAvatar, container)
|
|
620
620
|
|
|
621
|
-
// 4. Start connection if
|
|
621
|
+
// 4. Start connection if Direct mode
|
|
622
622
|
await currentAvatarView.controller.start()
|
|
623
623
|
```
|
|
624
624
|
|
|
625
625
|
### AvatarController
|
|
626
626
|
|
|
627
|
-
Audio/animation playback controller, manages synchronized playback of audio and animation. Automatically handles network communication in
|
|
627
|
+
Audio/animation playback controller, manages synchronized playback of audio and animation. Automatically handles network communication in Direct mode.
|
|
628
628
|
|
|
629
629
|
**Two Usage Patterns:**
|
|
630
630
|
|
|
@@ -708,7 +708,7 @@ avatarView.controller.setVolume(0.5) // Set volume to 50% (0.0 to 1.0)
|
|
|
708
708
|
const currentVolume = avatarView.controller.getVolume() // Get current volume (0.0 to 1.0)
|
|
709
709
|
|
|
710
710
|
// Set event callbacks
|
|
711
|
-
avatarView.controller.onConnectionState = (state: ConnectionState) => {} //
|
|
711
|
+
avatarView.controller.onConnectionState = (state: ConnectionState) => {} // Direct mode only
|
|
712
712
|
avatarView.controller.onConversationState = (state: ConversationState) => {}
|
|
713
713
|
avatarView.controller.onError = (error: AvatarError) => {} // Includes error.code for specific error type
|
|
714
714
|
```
|
|
@@ -731,8 +731,8 @@ avatarView.avatarTransform = { x: 0.5, y: 0, scale: 2.0 } // Right half, double
|
|
|
731
731
|
```
|
|
732
732
|
|
|
733
733
|
**Important Notes:**
|
|
734
|
-
- `start()` and `close()` are only available in
|
|
735
|
-
- `yieldAudioData()` and `yieldFramesData()` are only available in
|
|
734
|
+
- `start()` and `close()` are only available in Direct mode
|
|
735
|
+
- `yieldAudioData()` and `yieldFramesData()` are only available in Backend mode
|
|
736
736
|
- `pause()`, `resume()`, `interrupt()`, `setVolume()`, and `getVolume()` are available in both modes
|
|
737
737
|
- The playback mode is determined when creating `AvatarView` and cannot be changed
|
|
738
738
|
|
|
@@ -742,7 +742,7 @@ avatarView.avatarTransform = { x: 0.5, y: 0, scale: 2.0 } // Right half, double
|
|
|
742
742
|
|
|
743
743
|
```typescript
|
|
744
744
|
interface Configuration {
|
|
745
|
-
drivingServiceMode?: DrivingServiceMode // Optional, default is
|
|
745
|
+
drivingServiceMode?: DrivingServiceMode // Optional, default is `direct` (Direct mode)
|
|
746
746
|
logLevel?: LogLevel // Optional, default is 'off' (no logs)
|
|
747
747
|
audioFormat?: AudioFormat // Optional, default is { channelCount: 1, sampleRate: 16000 }
|
|
748
748
|
}
|
|
@@ -770,8 +770,8 @@ enum LogLevel {
|
|
|
770
770
|
|
|
771
771
|
**Description:**
|
|
772
772
|
- `drivingServiceMode`: Specifies the driving service mode
|
|
773
|
-
- `DrivingServiceMode.
|
|
774
|
-
- `DrivingServiceMode.
|
|
773
|
+
- `DrivingServiceMode.direct` (default): Direct mode - SDK handles network communication automatically
|
|
774
|
+
- `DrivingServiceMode.backend`: Backend mode - Host application provides audio and animation data
|
|
775
775
|
- `logLevel`: Controls the verbosity of SDK logs
|
|
776
776
|
- `LogLevel.off` (default): Disable all logs
|
|
777
777
|
- `LogLevel.error`: Only error logs
|
|
@@ -885,7 +885,7 @@ avatarView.controller.onError = (error: AvatarError) => {
|
|
|
885
885
|
| `sessionTimeout` | Session timeout | WebSocket close code 4002 |
|
|
886
886
|
| `connectionInProgress` | Connection already in progress | Duplicate `start()` call |
|
|
887
887
|
| **Playback** | | |
|
|
888
|
-
| `networkLayerNotAvailable` | Network layer not available | `send()` in
|
|
888
|
+
| `networkLayerNotAvailable` | Network layer not available | `send()` in backend mode |
|
|
889
889
|
| `playbackStartFailed` | Failed to start playback | Internal error |
|
|
890
890
|
| `playbackInitFailed` | Playback initialization failed | Internal error |
|
|
891
891
|
| `audioOnlyInitFailed` | Audio-only playback init failed | Fallback mode error |
|
|
@@ -931,12 +931,12 @@ avatarView.dispose()
|
|
|
931
931
|
|
|
932
932
|
**⚠️ Important Notes:**
|
|
933
933
|
- `dispose()` automatically cleans up all resources, including:
|
|
934
|
-
- Network connections (
|
|
934
|
+
- Network connections (Direct mode)
|
|
935
935
|
- Playback data and animation resources (both modes)
|
|
936
936
|
- Render system and canvas elements
|
|
937
937
|
- All event listeners and callbacks
|
|
938
938
|
- Not properly calling `dispose()` may cause resource leaks and rendering errors
|
|
939
|
-
- If you need to manually close connections before disposing, you can call `avatarView.controller.close()` (
|
|
939
|
+
- If you need to manually close connections before disposing, you can call `avatarView.controller.close()` (Direct mode) first, but it's not required as `dispose()` handles this automatically
|
|
940
940
|
|
|
941
941
|
### Memory Optimization
|
|
942
942
|
|
|
@@ -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-CVQn5uEB.js";
|
|
5
5
|
class StreamingAudioPlayer {
|
|
6
6
|
// Mark if AudioContext is being resumed, avoid concurrent resume requests
|
|
7
7
|
constructor(options) {
|
|
@@ -87,8 +87,8 @@ class StreamingAudioPlayer {
|
|
|
87
87
|
});
|
|
88
88
|
} catch (error) {
|
|
89
89
|
const message = errorToMessage(error);
|
|
90
|
-
logEvent("
|
|
91
|
-
|
|
90
|
+
logEvent("audio_session_init_failed", "warning", {
|
|
91
|
+
session_id: this.sessionId,
|
|
92
92
|
reason: message
|
|
93
93
|
});
|
|
94
94
|
logger.error("Failed to initialize AudioContext:", message);
|
|
@@ -144,7 +144,7 @@ class StreamingAudioPlayer {
|
|
|
144
144
|
} catch (err) {
|
|
145
145
|
logger.errorWithError("[StreamingAudioPlayer] Failed to resume AudioContext:", err);
|
|
146
146
|
logEvent("audio_context_resume_failed", "error", {
|
|
147
|
-
|
|
147
|
+
session_id: this.sessionId,
|
|
148
148
|
reason: err instanceof Error ? err.message : String(err)
|
|
149
149
|
});
|
|
150
150
|
} finally {
|
|
@@ -281,7 +281,7 @@ class StreamingAudioPlayer {
|
|
|
281
281
|
const errorMessage = "Failed to create AudioBuffer from PCM data";
|
|
282
282
|
logger.error(errorMessage);
|
|
283
283
|
logEvent("audio_buffer_creation_failed", "error", {
|
|
284
|
-
|
|
284
|
+
session_id: this.sessionId
|
|
285
285
|
});
|
|
286
286
|
return;
|
|
287
287
|
}
|
|
@@ -328,7 +328,7 @@ class StreamingAudioPlayer {
|
|
|
328
328
|
} catch (err) {
|
|
329
329
|
logger.errorWithError("Failed to schedule audio chunk:", err);
|
|
330
330
|
logEvent("schedule_chunk_failed", "error", {
|
|
331
|
-
|
|
331
|
+
session_id: this.sessionId,
|
|
332
332
|
reason: err instanceof Error ? err.message : String(err)
|
|
333
333
|
});
|
|
334
334
|
}
|
|
@@ -22,9 +22,7 @@ export declare class AvatarController {
|
|
|
22
22
|
set frameRateMonitorEnabled(value: boolean);
|
|
23
23
|
private renderCallback?;
|
|
24
24
|
private characterHandle;
|
|
25
|
-
private characterId;
|
|
26
25
|
private postProcessingConfig;
|
|
27
|
-
private audioMonitorLoopId;
|
|
28
26
|
private lastRenderedFrameIndex;
|
|
29
27
|
private keyframesOffset;
|
|
30
28
|
private readonly MAX_KEYFRAMES;
|
package/dist/core/AvatarSDK.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Configuration } from '../types';
|
|
1
|
+
import { Configuration, RenderQuality } from '../types';
|
|
2
2
|
export declare class AvatarSDK {
|
|
3
3
|
private static _initializationState;
|
|
4
4
|
private static _initializingPromise;
|
|
@@ -7,6 +7,13 @@ export declare class AvatarSDK {
|
|
|
7
7
|
private static _avatarCore;
|
|
8
8
|
private static _cachedDeviceScore;
|
|
9
9
|
private static _rendererBackend;
|
|
10
|
+
/** Render output resolution cap. Disabled by default; when enabled and the
|
|
11
|
+
* canvas backing height (css × DPR) exceeds maxHeight, the canvas is sized
|
|
12
|
+
* to maxHeight (aspect-preserving) and the browser scales it back up to
|
|
13
|
+
* the CSS box. Training material is 1080p so heights above ~1080-1440
|
|
14
|
+
* add no real visual information. */
|
|
15
|
+
static renderResolutionCapEnabled: boolean;
|
|
16
|
+
static renderResolutionMaxHeight: number;
|
|
10
17
|
/**
|
|
11
18
|
* Initialize SDK
|
|
12
19
|
* @param appId Application ID to be included in both HTTP Headers and WebSocket Headers
|
|
@@ -27,6 +34,14 @@ export declare class AvatarSDK {
|
|
|
27
34
|
static setUserId(userId: string): void;
|
|
28
35
|
static get appId(): string | null;
|
|
29
36
|
static get configuration(): Configuration | null;
|
|
37
|
+
/**
|
|
38
|
+
* Update the global render quality tier. Takes effect on the next rendered
|
|
39
|
+
* frame across all active AvatarView instances. Throws if SDK isn't initialized.
|
|
40
|
+
*/
|
|
41
|
+
static setRenderQuality(quality: RenderQuality): void;
|
|
42
|
+
/** Toggle the render output resolution cap. Takes effect on the next layout
|
|
43
|
+
* pass across all active AvatarView instances. */
|
|
44
|
+
static setRenderResolutionCap(enabled: boolean, maxHeight?: number): void;
|
|
30
45
|
static get sessionToken(): string | null;
|
|
31
46
|
static get userId(): string | null;
|
|
32
47
|
static get version(): string;
|
|
@@ -16,7 +16,7 @@ export declare class AvatarView {
|
|
|
16
16
|
private frameCount;
|
|
17
17
|
private lastFpsUpdate;
|
|
18
18
|
private currentFPS;
|
|
19
|
-
private
|
|
19
|
+
private currentFrame;
|
|
20
20
|
private cachedIdleFirstFrame;
|
|
21
21
|
private characterHandle;
|
|
22
22
|
private characterId;
|
|
@@ -41,6 +41,20 @@ export declare class AvatarView {
|
|
|
41
41
|
* Get controller (public interface)
|
|
42
42
|
*/
|
|
43
43
|
get controller(): AvatarController;
|
|
44
|
+
/**
|
|
45
|
+
* Current native render surface size in pixels (canvas backing buffer
|
|
46
|
+
* size, post-DPR).
|
|
47
|
+
*
|
|
48
|
+
* Differs from the canvas CSS size (`offsetWidth / offsetHeight`): this
|
|
49
|
+
* reflects the actual pixel buffer the WebGPU renderer is targeting after
|
|
50
|
+
* the most recent resize has been applied.
|
|
51
|
+
*
|
|
52
|
+
* Returns `{ width: 0, height: 0 }` before the canvas has been initialized.
|
|
53
|
+
*/
|
|
54
|
+
get renderSize(): {
|
|
55
|
+
width: number;
|
|
56
|
+
height: number;
|
|
57
|
+
};
|
|
44
58
|
private _exportBitmapResolve;
|
|
45
59
|
/**
|
|
46
60
|
* Exports the current rendering as a Blob (PNG).
|
|
@@ -126,7 +140,17 @@ export declare class AvatarView {
|
|
|
126
140
|
* @param options.useLinear - Use linear interpolation (default: true)
|
|
127
141
|
* @returns Array of opaque keyframe data for sequential playback
|
|
128
142
|
*/
|
|
129
|
-
|
|
143
|
+
generateTransitionToFrame(data: ArrayBuffer | Uint8Array, frameCount: number, options?: {
|
|
144
|
+
useLinear?: boolean;
|
|
145
|
+
}): Promise<unknown[]>;
|
|
146
|
+
/**
|
|
147
|
+
* RTC mode: generate `frameCount` interpolated frames from the most recently
|
|
148
|
+
* rendered frame back to the idle loop start. Caller plays them at 25fps
|
|
149
|
+
* via `renderFrame`, then hands control back with
|
|
150
|
+
* `renderFrame(undefined, true)`. Used for speaking → idle and disconnect
|
|
151
|
+
* soft transitions.
|
|
152
|
+
*/
|
|
153
|
+
generateTransitionToIdle(frameCount: number, options?: {
|
|
130
154
|
useLinear?: boolean;
|
|
131
155
|
}): Promise<unknown[]>;
|
|
132
156
|
/**
|
|
@@ -134,6 +158,12 @@ export declare class AvatarView {
|
|
|
134
158
|
* Called by renderFromProtobuf when streaming frames arrive during transition.
|
|
135
159
|
*/
|
|
136
160
|
cancelFrameSequence(): void;
|
|
161
|
+
/** 计算 canvas backing-store 像素尺寸. 默认 css × dpr;
|
|
162
|
+
* AvatarSDK.setRenderResolutionCap 启用且高度超过阈值时,
|
|
163
|
+
* 按比例缩到阈值, css 尺寸不变 (浏览器自动拉伸). */
|
|
164
|
+
private computeCappedBacking;
|
|
165
|
+
/** Registry hook: AvatarSDK.setRenderResolutionCap 调用时重算 backing size. */
|
|
166
|
+
applyResolutionCapFromSdk(): void;
|
|
137
167
|
/**
|
|
138
168
|
* Pause rendering loop
|
|
139
169
|
*
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AvatarView } from './AvatarView';
|
|
2
|
+
declare class AvatarViewRegistry {
|
|
3
|
+
private entries;
|
|
4
|
+
register(view: AvatarView): void;
|
|
5
|
+
unregister(view: AvatarView): void;
|
|
6
|
+
applyResolutionCapToAll(): void;
|
|
7
|
+
}
|
|
8
|
+
export declare const avatarViewRegistry: AvatarViewRegistry;
|
|
9
|
+
export {};
|