@spatialwalk/avatarkit 1.0.0-beta.9 → 1.0.0-beta.91

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.
Files changed (98) hide show
  1. package/CHANGELOG.md +701 -3
  2. package/README.md +650 -370
  3. package/dist/StreamingAudioPlayer-CGUA8-w0.js +638 -0
  4. package/dist/{avatar_core_wasm.wasm → avatar_core_wasm-9834c91c.wasm} +0 -0
  5. package/dist/avatar_core_wasm-BY3MuXDA.js +2696 -0
  6. package/dist/core/Avatar.d.ts +4 -14
  7. package/dist/core/AvatarController.d.ts +104 -111
  8. package/dist/core/AvatarManager.d.ts +32 -12
  9. package/dist/core/AvatarSDK.d.ts +58 -0
  10. package/dist/core/AvatarView.d.ts +86 -132
  11. package/dist/demo/src/main.d.ts +1 -0
  12. package/dist/index-BYr_FIpm.js +18107 -0
  13. package/dist/index.d.ts +2 -5
  14. package/dist/index.js +17 -18
  15. package/dist/next.d.ts +2 -0
  16. package/dist/performance/FrameRateMonitor.d.ts +85 -0
  17. package/dist/types/character-settings.d.ts +1 -1
  18. package/dist/types/character.d.ts +42 -16
  19. package/dist/types/index.d.ts +135 -45
  20. package/dist/vite.d.ts +19 -0
  21. package/next.d.ts +3 -0
  22. package/next.js +187 -0
  23. package/package.json +46 -16
  24. package/vite.d.ts +20 -0
  25. package/vite.js +126 -0
  26. package/dist/StreamingAudioPlayer-LW0pGK-E.js +0 -319
  27. package/dist/StreamingAudioPlayer-LW0pGK-E.js.map +0 -1
  28. package/dist/animation/AnimationWebSocketClient.d.ts +0 -50
  29. package/dist/animation/AnimationWebSocketClient.d.ts.map +0 -1
  30. package/dist/animation/utils/eventEmitter.d.ts +0 -13
  31. package/dist/animation/utils/eventEmitter.d.ts.map +0 -1
  32. package/dist/animation/utils/flameConverter.d.ts +0 -26
  33. package/dist/animation/utils/flameConverter.d.ts.map +0 -1
  34. package/dist/audio/AnimationPlayer.d.ts +0 -57
  35. package/dist/audio/AnimationPlayer.d.ts.map +0 -1
  36. package/dist/audio/StreamingAudioPlayer.d.ts +0 -123
  37. package/dist/audio/StreamingAudioPlayer.d.ts.map +0 -1
  38. package/dist/avatar_core_wasm-D4eEi7Eh.js +0 -1666
  39. package/dist/avatar_core_wasm-D4eEi7Eh.js.map +0 -1
  40. package/dist/config/app-config.d.ts +0 -44
  41. package/dist/config/app-config.d.ts.map +0 -1
  42. package/dist/config/constants.d.ts +0 -29
  43. package/dist/config/constants.d.ts.map +0 -1
  44. package/dist/config/sdk-config-loader.d.ts +0 -12
  45. package/dist/config/sdk-config-loader.d.ts.map +0 -1
  46. package/dist/core/Avatar.d.ts.map +0 -1
  47. package/dist/core/AvatarController.d.ts.map +0 -1
  48. package/dist/core/AvatarDownloader.d.ts +0 -100
  49. package/dist/core/AvatarDownloader.d.ts.map +0 -1
  50. package/dist/core/AvatarKit.d.ts +0 -66
  51. package/dist/core/AvatarKit.d.ts.map +0 -1
  52. package/dist/core/AvatarManager.d.ts.map +0 -1
  53. package/dist/core/AvatarView.d.ts.map +0 -1
  54. package/dist/core/NetworkLayer.d.ts +0 -59
  55. package/dist/core/NetworkLayer.d.ts.map +0 -1
  56. package/dist/generated/driveningress/v1/driveningress.d.ts +0 -80
  57. package/dist/generated/driveningress/v1/driveningress.d.ts.map +0 -1
  58. package/dist/generated/driveningress/v2/driveningress.d.ts +0 -81
  59. package/dist/generated/driveningress/v2/driveningress.d.ts.map +0 -1
  60. package/dist/generated/google/protobuf/struct.d.ts +0 -108
  61. package/dist/generated/google/protobuf/struct.d.ts.map +0 -1
  62. package/dist/generated/google/protobuf/timestamp.d.ts +0 -129
  63. package/dist/generated/google/protobuf/timestamp.d.ts.map +0 -1
  64. package/dist/index-8jCKHF1q.js +0 -6033
  65. package/dist/index-8jCKHF1q.js.map +0 -1
  66. package/dist/index.d.ts.map +0 -1
  67. package/dist/index.js.map +0 -1
  68. package/dist/renderer/RenderSystem.d.ts +0 -79
  69. package/dist/renderer/RenderSystem.d.ts.map +0 -1
  70. package/dist/renderer/covariance.d.ts +0 -13
  71. package/dist/renderer/covariance.d.ts.map +0 -1
  72. package/dist/renderer/renderer.d.ts +0 -8
  73. package/dist/renderer/renderer.d.ts.map +0 -1
  74. package/dist/renderer/sortSplats.d.ts +0 -12
  75. package/dist/renderer/sortSplats.d.ts.map +0 -1
  76. package/dist/renderer/webgl/reorderData.d.ts +0 -14
  77. package/dist/renderer/webgl/reorderData.d.ts.map +0 -1
  78. package/dist/renderer/webgl/webglRenderer.d.ts +0 -66
  79. package/dist/renderer/webgl/webglRenderer.d.ts.map +0 -1
  80. package/dist/renderer/webgpu/webgpuRenderer.d.ts +0 -54
  81. package/dist/renderer/webgpu/webgpuRenderer.d.ts.map +0 -1
  82. package/dist/types/character-settings.d.ts.map +0 -1
  83. package/dist/types/character.d.ts.map +0 -1
  84. package/dist/types/index.d.ts.map +0 -1
  85. package/dist/utils/animation-interpolation.d.ts +0 -17
  86. package/dist/utils/animation-interpolation.d.ts.map +0 -1
  87. package/dist/utils/cls-tracker.d.ts +0 -17
  88. package/dist/utils/cls-tracker.d.ts.map +0 -1
  89. package/dist/utils/error-utils.d.ts +0 -27
  90. package/dist/utils/error-utils.d.ts.map +0 -1
  91. package/dist/utils/logger.d.ts +0 -35
  92. package/dist/utils/logger.d.ts.map +0 -1
  93. package/dist/utils/reqId.d.ts +0 -20
  94. package/dist/utils/reqId.d.ts.map +0 -1
  95. package/dist/wasm/avatarCoreAdapter.d.ts +0 -188
  96. package/dist/wasm/avatarCoreAdapter.d.ts.map +0 -1
  97. package/dist/wasm/avatarCoreMemory.d.ts +0 -141
  98. package/dist/wasm/avatarCoreMemory.d.ts.map +0 -1
@@ -1,23 +1,13 @@
1
1
  import { CharacterMeta } from '../types';
2
- import { PreloadResult } from './AvatarDownloader';
3
2
  export declare class Avatar {
4
3
  readonly id: string;
5
4
  private characterMeta;
6
5
  private resources;
6
+ /** Local-only field: tracks whether cached model is "standard" or "compressed". */
7
+ _cachedModelType: string;
7
8
  /**
8
- * 构造函数(内部使用)
9
- * @param id 数字人 ID
10
- * @param characterMeta 角色元数据
11
- * @param resources 资源数据
12
- */
13
- constructor(id: string, characterMeta: CharacterMeta, resources: PreloadResult);
14
- /**
15
- * 获取角色元数据(内部使用)
9
+ * Get character metadata
10
+ * @returns Character metadata, including all configuration information (version, resource URLs, camera config, etc.)
16
11
  */
17
12
  getCharacterMeta(): CharacterMeta;
18
- /**
19
- * 获取资源数据(内部使用)
20
- */
21
- getResources(): PreloadResult;
22
13
  }
23
- //# sourceMappingURL=Avatar.d.ts.map
@@ -1,157 +1,150 @@
1
- import { Flame } from '../generated/driveningress/v1/driveningress';
2
1
  import { Avatar } from './Avatar';
3
- import { AnimationPlayer } from '../audio/AnimationPlayer';
4
- import { AvatarState, ConnectionState, AvatarPlaybackMode } from '../types';
2
+ import { ConnectionState, DrivingServiceMode, ConversationState, PostProcessingConfig, KeyframeData } from '../types';
3
+ import { FrameRateInfo } from '../performance/FrameRateMonitor';
5
4
  export declare class AvatarController {
6
5
  private networkLayer?;
7
- readonly playbackMode: AvatarPlaybackMode;
8
- protected avatar: Avatar;
9
- protected animationPlayer: AnimationPlayer | null;
10
- protected currentKeyframes: Flame[];
11
- protected pendingAudioChunks: Array<{
12
- data: Uint8Array;
13
- isLast: boolean;
14
- }>;
15
- protected isPlaying: boolean;
16
- protected isConnected: boolean;
17
- protected currentState: AvatarState;
6
+ private readonly playbackMode;
7
+ private isStartingPlayback;
8
+ private currentConversationId;
9
+ private reqEnd;
18
10
  onConnectionState: ((state: ConnectionState) => void) | null;
19
- onAvatarState: ((state: AvatarState) => void) | null;
11
+ onConversationState: ((state: ConversationState) => void) | null;
20
12
  onError: ((error: Error) => void) | null;
21
13
  private eventListeners;
14
+ private readonly frameRateMonitor;
15
+ /** Frame rate monitoring callback. Fires with aggregated metrics from a 2-second sliding window. */
16
+ get onFrameRateInfo(): ((info: FrameRateInfo) => void) | null;
17
+ set onFrameRateInfo(value: ((info: FrameRateInfo) => void) | null);
18
+ /** Whether frame rate monitoring is enabled. Default is false (zero overhead when disabled). */
19
+ get frameRateMonitorEnabled(): boolean;
20
+ set frameRateMonitorEnabled(value: boolean);
22
21
  private renderCallback?;
23
- private transitionCompleteCallback?;
22
+ private characterHandle;
23
+ private characterId;
24
+ private postProcessingConfig;
24
25
  private playbackLoopId;
26
+ private playbackLoopGeneration;
25
27
  private lastRenderedFrameIndex;
28
+ private keyframesOffset;
29
+ private readonly MAX_KEYFRAMES;
30
+ private readonly KEYFRAMES_CLEANUP_THRESHOLD;
31
+ private lastSyncLogTime;
32
+ private lastOutOfBoundsState;
33
+ private isFallbackMode;
34
+ private playbackStuckCheckState;
35
+ private readonly MAX_AUDIO_TIME_ZERO_COUNT;
36
+ private readonly MAX_AUDIO_TIME_STUCK_COUNT;
37
+ private readonly AUDIO_TIME_STUCK_THRESHOLD;
38
+ private hostModeMetrics;
39
+ private readonly audioBytesPerSecond;
26
40
  constructor(avatar: Avatar, options?: {
27
- playbackMode?: AvatarPlaybackMode;
41
+ playbackMode?: DrivingServiceMode;
28
42
  });
43
+ private handleVisibilityChange;
44
+ private shouldReportPlaybackStats;
45
+ private _getDeviceScoreProps;
29
46
  /**
30
- * 获取 Avatar ID(供 NetworkLayer 使用)
47
+ * Get current conversation ID
48
+ * Returns the current conversation ID for the active audio session
49
+ * @returns Current conversation ID, or null if no active session
31
50
  */
32
- getAvatarId(): string;
51
+ getCurrentConversationId(): string | null;
33
52
  /**
34
- * 获取播放状态(供 NetworkLayer 使用)
53
+ * Initialize audio context (must be called in user gesture context)
54
+ *
55
+ * This method must be called before any audio operations (send, yieldAudioData, etc.)
56
+ * to ensure AudioContext is created and initialized in a user gesture context.
57
+ *
58
+ * @example
59
+ * // In user click handler
60
+ * button.addEventListener('click', async () => {
61
+ * await avatarView.controller.initializeAudioContext()
62
+ * // Now you can safely use send() or yieldAudioData()
63
+ * })
35
64
  */
36
- getIsPlaying(): boolean;
65
+ initializeAudioContext(): Promise<void>;
37
66
  /**
38
- * 设置连接状态(供 NetworkLayer 使用)
39
- */
40
- setConnected(connected: boolean): void;
41
- /**
42
- * 获取连接状态
43
- */
44
- get connected(): boolean;
45
- /**
46
- * 获取当前状态
47
- */
48
- get state(): AvatarState;
49
- /**
50
- * 获取动画播放器实例
51
- * @internal
52
- */
53
- getAnimationPlayer(): AnimationPlayer | null;
54
- /**
55
- * 启动服务(仅网络模式)
67
+ * Start service (SDK mode only)
56
68
  */
57
69
  start(): Promise<void>;
58
70
  /**
59
- * 发送音频到服务器(仅网络模式)
60
- * 同时缓存到数据层用于播放
71
+ * Send audio to server (SDK mode only)
72
+ * Also cache to data layer for playback
73
+ * @returns conversationId - Conversation ID for this audio session
61
74
  */
62
- send(audioData: ArrayBuffer, end?: boolean): void;
75
+ send(audioData: ArrayBuffer, end?: boolean): string | null;
63
76
  /**
64
- * 关闭服务(仅网络模式)
77
+ * Close service (SDK mode only)
65
78
  */
66
79
  close(): void;
67
80
  /**
68
- * 开始播放(外部数据模式)
69
- * 必须先调用此方法,传入初始数据开始播放
70
- */
71
- play(initialAudioChunks?: Array<{
72
- data: Uint8Array;
73
- isLast: boolean;
74
- }>, initialKeyframes?: Flame[]): Promise<void>;
75
- /**
76
- * 发送音频数据(外部数据模式)
77
- * 在 play() 之后流式添加剩余音频数据
78
- */
79
- sendAudioChunk(data: Uint8Array, isLast?: boolean): void;
80
- /**
81
- * 发送动画关键帧(外部数据模式或网络模式)
82
- * 在 play() 之后流式添加剩余动画数据
83
- */
84
- sendKeyframes(keyframes: Flame[]): void;
85
- /**
86
- * 打断当前播放
81
+ * Send audio data (host mode)
82
+ * Stream additional audio data after playback()
83
+ * @returns conversationId - Conversation ID for this audio session
87
84
  */
88
- interrupt(): void;
89
- /**
90
- * 清理所有数据和资源
91
- */
92
- clear(): void;
93
- /**
94
- * 销毁控制器,清理所有回调避免内存泄漏
95
- * 应该在 AvatarView.dispose() 时调用
96
- */
97
- dispose(): void;
98
- /**
99
- * 开始流式播放(内部方法,由 NetworkLayer 或 play() 调用)
100
- */
101
- startStreamingPlayback(): Promise<void>;
102
- /**
103
- * 设置渲染回调(由 AvatarView 调用)
104
- */
105
- setRenderCallback(callback: (splatData: Float32Array, frameIndex: number) => void): void;
85
+ yieldAudioData(data: Uint8Array, isLast?: boolean): string | null;
106
86
  /**
107
- * 设置过渡完成回调(由 AvatarView 调用)
87
+ * Send animation keyframes (host mode or SDK mode)
88
+ * Stream additional animation data after playback()
89
+ *
90
+ * Public API: accepts binary data array (protobuf encoded Message array)
91
+ * @param keyframesDataArray - Animation keyframes binary data array (each element is a protobuf encoded Message) or empty array to trigger audio-only mode
92
+ * @param conversationId - Conversation ID (required). If conversationId doesn't match current conversationId, keyframes will be discarded.
93
+ * Use getCurrentConversationId() to get the current conversationId.
108
94
  */
109
- setTransitionCompleteCallback(callback: () => void): void;
95
+ yieldFramesData(keyframesDataArray: (Uint8Array | ArrayBuffer)[], conversationId: string): void;
110
96
  /**
111
- * 过渡完成通知(由 AvatarView 调用)
97
+ * Send animation keyframes (host mode)
98
+ * Stream animation keyframes data after yieldAudioData()
99
+ *
100
+ * ⚠️ **Not recommended**: Prefer using `yieldFramesData()` method, which accepts binary data (protobuf encoded Message) with better performance.
101
+ * This method is only for scenarios where you already have decoded KeyframeData arrays.
102
+ *
103
+ * Public API: accepts decoded keyframes
104
+ * @param keyframes - Animation keyframes array (KeyframeData[]) or empty array to trigger audio-only mode
105
+ * @param conversationId - Conversation ID (required). If conversationId doesn't match current conversationId, keyframes will be discarded.
106
+ * Use getCurrentConversationId() to get the current conversationId.
112
107
  */
113
- onTransitionComplete(): void;
108
+ yieldKeyframes(keyframes: KeyframeData[], conversationId: string): void;
114
109
  /**
115
- * AvatarView 提供注册内部事件的接口
116
- * @internal
110
+ * Pause playback (can be resumed later)
111
+ * Pause audio playback and stop render loop, but preserve all state (keyframes, audio buffers, etc.)
117
112
  */
118
- setupInternalEventListeners(callbacks: {
119
- onKeyframesUpdate?: (keyframes: Flame[]) => void;
120
- onStartRendering?: () => void;
121
- onStopRendering?: () => void;
122
- onInterrupt?: () => void;
123
- }): void;
113
+ pause(): void;
124
114
  /**
125
- * 开始流式播放(内部实现)
115
+ * Resume playback (from paused state)
116
+ * Resume audio playback and restart render loop
117
+ * Animation will continue from paused frame (because animation time base comes from audio, will auto-sync)
126
118
  */
127
- private startStreamingPlaybackInternal;
119
+ resume(): Promise<void>;
128
120
  /**
129
- * 播放循环:根据音频时间计算动画帧,通知渲染层渲染
121
+ * Interrupt current playback
130
122
  */
131
- private startPlaybackLoop;
132
- /**
133
- * 停止播放循环
134
- */
135
- private stopPlaybackLoop;
123
+ interrupt(): void;
136
124
  /**
137
- * 停止播放
125
+ * Clear all data and resources
138
126
  */
139
- protected stopPlayback(): void;
127
+ clear(): void;
140
128
  /**
141
- * 清理播放器
129
+ * Get point cloud count of the current avatar
130
+ * @returns Point cloud count, or null if avatar is not loaded
142
131
  */
143
- protected cleanupPlayers(): void;
132
+ getPointCount(): number | null;
144
133
  /**
145
- * 添加音频块到缓冲区
134
+ * Set post-processing configuration
135
+ * These parameters will be applied in real-time to animation parameters returned by the server
136
+ * @param config Post-processing configuration, or null to clear
146
137
  */
147
- private addAudioChunkToBuffer;
138
+ setPostProcessingConfig(config: PostProcessingConfig | null): void;
148
139
  /**
149
- * 事件系统
140
+ * Set audio playback volume
141
+ * Note: This only controls the avatar audio player volume, not the system volume
142
+ * @param volume Volume value, range from 0.0 to 1.0 (0.0 = mute, 1.0 = max volume)
150
143
  */
151
- private registerEventListener;
144
+ setVolume(volume: number): void;
152
145
  /**
153
- * 触发事件
146
+ * Get current audio playback volume
147
+ * @returns Current volume value (0.0 - 1.0)
154
148
  */
155
- protected emit(event: string, data?: any): void;
149
+ getVolume(): number;
156
150
  }
157
- //# sourceMappingURL=AvatarController.d.ts.map
@@ -3,24 +3,44 @@ import { Avatar } from './Avatar';
3
3
  export declare class AvatarManager {
4
4
  private static _instance;
5
5
  private avatarDownloader;
6
- private _templateInitialized;
6
+ private avatarCache;
7
+ /** 下载队列:FIFO 顺序 */
8
+ private downloadQueue;
9
+ /** 当前正在执行的任务 */
10
+ private currentTask;
11
+ /** 任务索引:快速查找 id 对应的任务 */
12
+ private taskIndex;
7
13
  /**
8
- * 通过全局单例来访问
14
+ * Access via global singleton
9
15
  */
10
16
  static get shared(): AvatarManager;
11
17
  /**
12
- * 加载数字人
13
- * @param id 数字人 ID
14
- * @param onProgress 进度回调
15
- * @param options 加载选项
18
+ * Load avatar
19
+ * @param id Avatar ID
20
+ * @param onProgress Progress callback
21
+ * @param useCompressedModel Use compressed model resource (~30% of original size, with minor quality degradation). Defaults to false.
16
22
  * @returns Promise<Avatar>
17
23
  */
18
- load(id: string, onProgress?: (progress: LoadProgressInfo) => void, options?: {
19
- enableMonologue?: boolean;
20
- }): Promise<Avatar>;
24
+ load(id: string, onProgress?: (progress: LoadProgressInfo) => void, useCompressedModel?: boolean): Promise<Avatar>;
21
25
  /**
22
- * 清理资源加载器缓存
26
+ * Cancel a pending or running download task
27
+ * @param id Avatar ID to cancel
28
+ * @returns true if task was found and cancelled
23
29
  */
24
- clearCache(): void;
30
+ cancelLoad(id: string): boolean;
31
+ /**
32
+ * Get cached avatar
33
+ * @param id Avatar ID
34
+ * @returns Avatar instance, or undefined if not in cache
35
+ */
36
+ retrieve(id: string): Avatar | undefined;
37
+ /**
38
+ * Clear cached avatar for specified ID
39
+ * @param id Avatar ID
40
+ */
41
+ clear(id: string): void;
42
+ /**
43
+ * Clear all avatar cache and cancel all tasks
44
+ */
45
+ clearAll(): void;
25
46
  }
26
- //# sourceMappingURL=AvatarManager.d.ts.map
@@ -0,0 +1,58 @@
1
+ import { Configuration } from '../types';
2
+ export declare class AvatarSDK {
3
+ private static _initializationState;
4
+ private static _initializingPromise;
5
+ private static _configuration;
6
+ private static readonly _version;
7
+ private static _avatarCore;
8
+ private static _dynamicSdkConfig;
9
+ private static _cachedDeviceScore;
10
+ private static _rendererBackend;
11
+ /**
12
+ * Initialize SDK
13
+ * @param appId Application ID to be included in both HTTP Headers and WebSocket Headers
14
+ * @param configuration Configuration parameters
15
+ */
16
+ static initialize(appId: string, configuration: Configuration): Promise<void>;
17
+ private static _initializeInternal;
18
+ /**
19
+ * Set sessionToken
20
+ * Developer Client -> Developer Server -> AvatarKit Server -> return sessionToken (max 1 hour validity)
21
+ * Include in WebSocket Headers for avatar WebSocket service authentication
22
+ */
23
+ static setSessionToken(token: string): void;
24
+ /**
25
+ * Set userId
26
+ * Optional interface for developers, SDK includes this in telemetry logs
27
+ */
28
+ static setUserId(userId: string): void;
29
+ static get isInitialized(): boolean;
30
+ static get appId(): string | null;
31
+ static get configuration(): Configuration | null;
32
+ static get sessionToken(): string | null;
33
+ static get userId(): string | null;
34
+ static get version(): string;
35
+ /**
36
+ * Cleanup resources
37
+ */
38
+ static cleanup(): void;
39
+ /**
40
+ * Device performance score (CPU + GPU).
41
+ * CPU: matrix multiply throughput in Web Worker (warmup 1s + measure 1s).
42
+ * GPU: WebGPU compute shader throughput (warmup 1s + measure 1s).
43
+ * Returns 0 for GPU if WebGPU is not available.
44
+ */
45
+ static deviceScore(): Promise<{
46
+ cpuScore: number;
47
+ gpuScore: number;
48
+ }>;
49
+ private static readonly CPU_SCORE_THRESHOLD;
50
+ private static readonly GPU_SCORE_THRESHOLD;
51
+ /**
52
+ * Check if the current device can run the avatar.
53
+ * Runs a ~2s benchmark, reports device info and scores to PostHog.
54
+ * Currently always returns true — thresholds will be calibrated from production data.
55
+ */
56
+ static isDeviceSupported(): Promise<boolean>;
57
+ private static _getGPURenderer;
58
+ }
@@ -1,10 +1,10 @@
1
- import { CameraConfig, RenderPerformanceStats, AvatarViewOptions, AvatarPlaybackMode } from '../types';
1
+ import { CameraConfig, KeyframeData } from '../types';
2
2
  import { Avatar } from './Avatar';
3
3
  import { AvatarController } from './AvatarController';
4
4
  export declare class AvatarView {
5
5
  private readonly avatarController;
6
- readonly playbackMode: AvatarPlaybackMode;
7
6
  private readonly avatar;
7
+ onFirstRendering?: () => void;
8
8
  private canvas;
9
9
  private renderSystem;
10
10
  private isInitialized;
@@ -17,137 +17,36 @@ export declare class AvatarView {
17
17
  private realtimeAnimationLoopId;
18
18
  private resizeObserver;
19
19
  private onWindowResize;
20
+ private frameCount;
21
+ private lastFpsUpdate;
22
+ private currentFPS;
20
23
  private transitionKeyframes;
21
24
  private transitionStartTime;
22
- private readonly transitionDurationMs;
25
+ private readonly startTransitionDurationMs;
26
+ private readonly endTransitionDurationMs;
23
27
  private cachedIdleFirstFrame;
24
28
  private idleCurrentFrameIndex;
29
+ private currentPlayingFrame;
30
+ private characterHandle;
31
+ private characterId;
32
+ private isPureRenderingMode;
33
+ private _renderingEnabled;
34
+ private avatarActiveTimer;
35
+ private readonly AVATAR_ACTIVE_INTERVAL;
25
36
  /**
26
- * 对齐两端 Flame 维度:标量统一长度,expression 取最大长度并零填充
37
+ * Constructor
38
+ * Creates a unified AvatarController, internally composes network layer based on configuration
39
+ * @param avatar - Avatar instance
40
+ * @param container - Canvas container element (required)
27
41
  */
28
- private alignFlamePair;
42
+ constructor(avatar: Avatar, container: HTMLElement);
29
43
  /**
30
- * 判断是否为空 Flame(用于跳过 isLast=true 的哨兵帧)
31
- */
32
- private isEmptyFlame;
33
- /**
34
- * 生成并对齐过渡帧,确保首尾帧与起止帧完全一致
35
- */
36
- private generateAndAlignTransitionFrames;
37
- /**
38
- * 获取缓存的 Idle 首帧,如果未缓存则获取并缓存
39
- */
40
- private getCachedIdleFirstFrame;
41
- /**
42
- * 构造函数
43
- * 创建统一的 AvatarController,内部根据配置自动组合网络层
44
- */
45
- constructor(avatar: Avatar, options?: AvatarViewOptions);
46
- /**
47
- * 获取控制器(公共接口)
44
+ * Get controller (public interface)
48
45
  */
49
46
  get controller(): AvatarController;
50
47
  /**
51
- * 创建canvas元素
52
- */
53
- private createCanvas;
54
- /**
55
- * 获取canvas元素(供外部访问)
56
- */
57
- getCanvas(): HTMLCanvasElement;
58
- /**
59
- * 初始化视图系统
60
- */
61
- private initializeView;
62
- /**
63
- * 初始化渲染系统
64
- */
65
- private initializeRenderSystem;
66
- /**
67
- * 获取默认相机配置
68
- */
69
- private getDefaultCameraConfig;
70
- /**
71
- * 根据资源解析最终的相机配置,优先使用角色设置,其次 camera.json
72
- */
73
- private resolveCameraConfig;
74
- /**
75
- * 从角色设置中推导相机配置
76
- */
77
- private deriveCameraConfigFromSettings;
78
- /**
79
- * 渲染第一帧
80
- */
81
- private renderFirstFrame;
82
- /**
83
- * 开始idle动画循环
84
- */
85
- private startIdleAnimationLoop;
86
- /**
87
- * 开始实时对话动画循环
88
- */
89
- private startRealtimeAnimationLoop;
90
- /**
91
- * 停止idle动画循环
92
- */
93
- private stopIdleAnimationLoop;
94
- /**
95
- * 停止实时对话动画循环
96
- */
97
- private stopRealtimeAnimationLoop;
98
- /**
99
- * 停止所有动画循环
100
- */
101
- private stopAllAnimationLoops;
102
- /**
103
- * 渲染实时帧(由播放层回调调用)
104
- */
105
- private renderRealtimeFrame;
106
- /**
107
- * 过渡完成回调(通知播放层启动音频)
108
- */
109
- private onTransitionComplete;
110
- /**
111
- * 状态转换方法
112
- * 统一管理状态转换,确保状态一致性
113
- */
114
- private setState;
115
- /**
116
- * 检查是否在实时播放状态(Speaking 或过渡到 Speaking)
117
- */
118
- private get isRealtimePlaying();
119
- /**
120
- * 检查是否在过渡中
121
- */
122
- private get isTransitioning();
123
- /**
124
- * 检查过渡结束后是否回到 Idle
125
- */
126
- private get endToIdleAfterTransition();
127
- /**
128
- * 处理打断
129
- * 打断时应该生成过渡动画,而不是直接跳回 Idle
130
- */
131
- private handleInterrupt;
132
- /**
133
- * 设置 AvatarController 事件监听器
134
- */
135
- private setupControllerEventListeners;
136
- /**
137
- * 准备实时渲染(生成 Idle -> Speaking 过渡)
138
- */
139
- private prepareRealtimeRendering;
140
- /**
141
- * 开始实时渲染循环
142
- */
143
- private startRealtimeRendering;
144
- /**
145
- * 停止实时对话渲染
146
- */
147
- private stopRealtimeRendering;
148
- /**
149
- * 清理视图资源
150
- * 关闭 avatarController 并清理所有相关资源
48
+ * Cleanup view resources
49
+ * Closes avatarController and cleans up all related resources
151
50
  */
152
51
  dispose(): void;
153
52
  /**
@@ -159,13 +58,68 @@ export declare class AvatarView {
159
58
  */
160
59
  updateCameraConfig(cameraConfig: CameraConfig): void;
161
60
  /**
162
- * 处理尺寸变化:通知渲染系统更新视口与投影
163
- */
164
- private handleResize;
165
- /**
166
- * 获取渲染性能统计
167
- * @returns 渲染性能统计数据,如果渲染系统未初始化则返回 null
168
- */
169
- getPerformanceStats(): RenderPerformanceStats | null;
61
+ * Render specified keyframe (pure rendering mode, no audio-animation synchronization)
62
+ * Suitable for scenarios where external application controls audio playback and animation playback
63
+ * @param keyframeData - Keyframe data
64
+ * @param enableIdleRendering - Whether to enable idle loop rendering. true: Enable idle rendering and return immediately (skip this keyframe); false: Disable idle rendering and process keyframe (default)
65
+ */
66
+ renderFlame(keyframeData: KeyframeData, enableIdleRendering?: boolean): Promise<void>;
67
+ generateTransition(options: {
68
+ from?: KeyframeData;
69
+ to?: KeyframeData;
70
+ frameCount: number;
71
+ useLinear?: boolean;
72
+ }): Promise<KeyframeData[]>;
73
+ /**
74
+ * Pause rendering loop
75
+ *
76
+ * When called:
77
+ * - Rendering loop stops (no GPU/canvas updates)
78
+ * - Audio playback continues normally
79
+ * - Animation state machine continues running
80
+ *
81
+ * Use `resumeRendering()` to resume rendering.
82
+ *
83
+ * @example
84
+ * // Stop rendering to save GPU resources (audio continues)
85
+ * avatarView.pauseRendering()
86
+ */
87
+ pauseRendering(): void;
88
+ /**
89
+ * Resume rendering loop
90
+ *
91
+ * When called:
92
+ * - Rendering loop resumes from current state
93
+ * - If in Idle state, immediately renders current frame to restore display
94
+ *
95
+ * @example
96
+ * // Resume rendering
97
+ * avatarView.resumeRendering()
98
+ */
99
+ resumeRendering(): void;
100
+ /**
101
+ * Check if rendering is currently enabled
102
+ * @returns true if rendering is enabled, false if paused
103
+ */
104
+ isRenderingEnabled(): boolean;
105
+ /**
106
+ * Get or set avatar transform in canvas
107
+ *
108
+ * @example
109
+ * // Get current transform
110
+ * const current = avatarView.transform
111
+ *
112
+ * // Set transform
113
+ * avatarView.transform = { x: 0.5, y: 0, scale: 2.0 }
114
+ */
115
+ get transform(): {
116
+ x: number;
117
+ y: number;
118
+ scale: number;
119
+ };
120
+ set transform(value: {
121
+ x: number;
122
+ y: number;
123
+ scale: number;
124
+ });
170
125
  }
171
- //# sourceMappingURL=AvatarView.d.ts.map
@@ -0,0 +1 @@
1
+ export {};