@spatialwalk/avatarkit 1.0.0-beta.44 → 1.0.0-beta.46

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,30 @@ 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.46] - 2025-12-29
9
+
10
+ ### 🐛 Bugfix
11
+ - Expose `getCharacterMeta()` method in `Avatar` class as public API
12
+
13
+ ## [1.0.0-beta.45] - 2025-12-29
14
+
15
+ ### ✨ New Features
16
+ - **Immediate Rendering on Pause** - When playback is paused, updating post-processing parameters or camera configuration will immediately re-render the current frame:
17
+ - Post-processing parameters (rotation, neck pose, jaw pose, eye blink, etc.) now apply immediately when updated during pause
18
+ - Camera configuration (position, target, FOV, etc.) now applies immediately when updated during pause
19
+ - During normal playback, these updates still apply on the next frame as before
20
+
21
+ ### 🔄 API Changes
22
+
23
+ ### 🔄 API Changes
24
+ - **AvatarView Ready Promise Replaced with Callback** - Replaced `ready: Promise<void>` property with `onFirstRendering?: () => void` callback for better async handling:
25
+ - Removed `ready` Promise property
26
+ - Added `onFirstRendering` optional callback that is called when the first frame is rendered
27
+ - Callback-based approach is more idiomatic and easier to use than Promise-based approach
28
+
29
+ ### 🗑️ Removed
30
+ - **Removed unused `seek()` method** - Removed unused and buggy `seek()` method from `StreamingAudioPlayer`
31
+
8
32
  ## [1.0.0-beta.44] - 2025-12-29
9
33
 
10
34
  ### 🔧 Performance Improvements
package/README.md CHANGED
@@ -309,7 +309,9 @@ const container = document.getElementById('avatar-container')
309
309
  const avatarView = new AvatarView(avatar, container)
310
310
 
311
311
  // Wait for first frame to render
312
- await avatarView.ready // Promise that resolves when the first frame is rendered
312
+ avatarView.onFirstRendering = () => {
313
+ // First frame rendered
314
+ }
313
315
 
314
316
  // Get or set avatar transform (position and scale)
315
317
  // Get current transform
@@ -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, e as errorToMessage, l as logEvent, a as logger } from "./index-CEqzEo-H.js";
4
+ import { A as APP_CONFIG, e as errorToMessage, l as logEvent, a as logger } from "./index-DJMm01Eu.js";
5
5
  class StreamingAudioPlayer {
6
6
  constructor(options) {
7
7
  __publicField(this, "audioContext", null);
File without changes
@@ -5,4 +5,5 @@ export declare class Avatar {
5
5
  private characterMeta;
6
6
  private resources;
7
7
  constructor(id: string, characterMeta: CharacterMeta, resources: PreloadResult);
8
+ getCharacterMeta(): CharacterMeta;
8
9
  }
@@ -53,6 +53,7 @@ export declare class AvatarController {
53
53
  private resetConversationIdState;
54
54
  private getEffectiveConversationId;
55
55
  setPostProcessingConfig(config: PostProcessingConfig | null): void;
56
+ private rerenderCurrentFrame;
56
57
  setVolume(volume: number): void;
57
58
  getVolume(): number;
58
59
  private startStreamingPlaybackInternal;
@@ -3,7 +3,7 @@ import { AvatarController } from './AvatarController';
3
3
  export declare class AvatarView {
4
4
  private readonly avatarController;
5
5
  private readonly avatar;
6
- readonly ready: Promise<void>;
6
+ onFirstRendering?: () => void;
7
7
  private canvas;
8
8
  private renderSystem;
9
9
  private isInitialized;
@@ -56,6 +56,7 @@ export declare class AvatarView {
56
56
  private startRealtimeRendering;
57
57
  private stopRealtimeRendering;
58
58
  dispose(): void;
59
+ private rerenderCurrentFrameWithNewCamera;
59
60
  private handleResize;
60
61
  get transform(): {
61
62
  x: number;
@@ -7573,7 +7573,7 @@ const _AnimationPlayer = class _AnimationPlayer {
7573
7573
  if (this.streamingPlayer) {
7574
7574
  return;
7575
7575
  }
7576
- const { StreamingAudioPlayer } = await import("./StreamingAudioPlayer-rs7ZcwVo.js");
7576
+ const { StreamingAudioPlayer } = await import("./StreamingAudioPlayer-BlY4b-HD.js");
7577
7577
  const { AvatarSDK: AvatarSDK2 } = await Promise.resolve().then(() => AvatarSDK$1);
7578
7578
  const audioFormat = AvatarSDK2.getAudioFormat();
7579
7579
  this.streamingPlayer = new StreamingAudioPlayer({
@@ -8963,7 +8963,7 @@ class AvatarSDK {
8963
8963
  }
8964
8964
  __publicField(AvatarSDK, "_isInitialized", false);
8965
8965
  __publicField(AvatarSDK, "_configuration", null);
8966
- __publicField(AvatarSDK, "_version", "1.0.0-beta.44");
8966
+ __publicField(AvatarSDK, "_version", "1.0.0-beta.46");
8967
8967
  __publicField(AvatarSDK, "_avatarCore", null);
8968
8968
  __publicField(AvatarSDK, "_dynamicSdkConfig", null);
8969
8969
  const AvatarSDK$1 = Object.freeze(Object.defineProperty({
@@ -11091,6 +11091,44 @@ class AvatarController {
11091
11091
  }
11092
11092
  setPostProcessingConfig(config) {
11093
11093
  this.postProcessingConfig = config;
11094
+ if (this.currentState === AvatarState.paused && this.isPlaying) {
11095
+ this.rerenderCurrentFrame();
11096
+ }
11097
+ }
11098
+ async rerenderCurrentFrameIfPaused() {
11099
+ if (this.currentState !== AvatarState.paused || !this.renderCallback) {
11100
+ return;
11101
+ }
11102
+ const frameIndex = this.lastRenderedFrameIndex;
11103
+ if (frameIndex < 0) {
11104
+ return;
11105
+ }
11106
+ let arrayIndex = frameIndex - this.keyframesOffset;
11107
+ if (arrayIndex < 0 || arrayIndex >= this.currentKeyframes.length) {
11108
+ if (this.currentKeyframes.length === 0) {
11109
+ return;
11110
+ }
11111
+ arrayIndex = Math.max(0, Math.min(this.currentKeyframes.length - 1, arrayIndex));
11112
+ }
11113
+ try {
11114
+ const currentFrame = this.currentKeyframes[arrayIndex];
11115
+ let wasmParams = convertProtoFlameToWasmParams(currentFrame);
11116
+ if (this.postProcessingConfig) {
11117
+ wasmParams = this.applyPostProcessingToParams(wasmParams);
11118
+ }
11119
+ const avatarCore = AvatarSDK.getAvatarCore();
11120
+ if (avatarCore) {
11121
+ const splatData = await avatarCore.computeFrameFlatFromParams(wasmParams, this.characterHandle ?? void 0);
11122
+ if (splatData) {
11123
+ this.renderCallback(splatData, frameIndex);
11124
+ }
11125
+ }
11126
+ } catch (error) {
11127
+ logger.error("[AvatarController] Failed to rerender current frame:", error instanceof Error ? error.message : String(error));
11128
+ }
11129
+ }
11130
+ async rerenderCurrentFrame() {
11131
+ await this.rerenderCurrentFrameIfPaused();
11094
11132
  }
11095
11133
  onTransitionComplete() {
11096
11134
  var _a;
@@ -13477,7 +13515,7 @@ class AvatarView {
13477
13515
  constructor(avatar, container) {
13478
13516
  __publicField(this, "avatarController");
13479
13517
  __publicField(this, "avatar");
13480
- __publicField(this, "ready");
13518
+ __publicField(this, "onFirstRendering");
13481
13519
  __publicField(this, "canvas");
13482
13520
  __publicField(this, "renderSystem", null);
13483
13521
  __publicField(this, "isInitialized", false);
@@ -13513,7 +13551,9 @@ class AvatarView {
13513
13551
  this.renderRealtimeFrame(splatData, frameIndex);
13514
13552
  });
13515
13553
  this.canvas = this.createCanvas(container);
13516
- this.ready = this.initializeView(avatar);
13554
+ this.initializeView(avatar).catch((error) => {
13555
+ logger.error("[AvatarView] Initialization failed:", error instanceof Error ? error.message : String(error));
13556
+ });
13517
13557
  this.setupControllerEventListeners();
13518
13558
  }
13519
13559
  alignFlamePair(from, to2) {
@@ -13749,6 +13789,7 @@ class AvatarView {
13749
13789
  return derivedCamera;
13750
13790
  }
13751
13791
  async renderFirstFrame() {
13792
+ var _a;
13752
13793
  if (!this.renderSystem) {
13753
13794
  throw new Error("Render system not initialized");
13754
13795
  }
@@ -13771,6 +13812,7 @@ class AvatarView {
13771
13812
  this.renderSystem.renderFrame();
13772
13813
  if (APP_CONFIG.debug)
13773
13814
  logger.log("[AvatarView] First frame rendered successfully");
13815
+ (_a = this.onFirstRendering) == null ? void 0 : _a.call(this);
13774
13816
  } else {
13775
13817
  throw new Error("Failed to compute first frame splat data");
13776
13818
  }
@@ -14143,7 +14185,16 @@ class AvatarView {
14143
14185
  this.renderSystem.updateCamera(cameraConfig);
14144
14186
  if (APP_CONFIG.debug)
14145
14187
  logger.log("[AvatarView] Applied new camera config to render system");
14188
+ if (this.avatarController.state === AvatarState.paused && this.renderingState === "speaking") {
14189
+ this.rerenderCurrentFrameWithNewCamera();
14190
+ }
14191
+ }
14192
+ }
14193
+ async rerenderCurrentFrameWithNewCamera() {
14194
+ if (this.avatarController.state !== AvatarState.paused || this.renderingState !== "speaking" || !this.renderSystem) {
14195
+ return;
14146
14196
  }
14197
+ await this.avatarController.rerenderCurrentFrameIfPaused();
14147
14198
  }
14148
14199
  handleResize() {
14149
14200
  if (this.renderSystem) {
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { b, c, f, d, j, g, C, i, D, E, k, h, L, R, S, m } from "./index-CEqzEo-H.js";
1
+ import { b, c, f, d, j, g, C, i, D, E, k, h, L, R, S, m } from "./index-DJMm01Eu.js";
2
2
  export {
3
3
  b as Avatar,
4
4
  c as AvatarController,
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@spatialwalk/avatarkit",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.44",
4
+ "version": "1.0.0-beta.46",
5
+ "packageManager": "pnpm@10.18.2",
5
6
  "description": "SPAvatar SDK - 3D Gaussian Splatting Avatar Rendering SDK",
6
7
  "author": "SPAvatar Team",
7
8
  "license": "MIT",
@@ -31,6 +32,16 @@
31
32
  "CHANGELOG.md",
32
33
  "dist"
33
34
  ],
35
+ "scripts": {
36
+ "build": "SDK_BUILD=true vite build --mode library",
37
+ "dev": "vite build --mode library --watch",
38
+ "clean": "rm -rf dist",
39
+ "typecheck": "tsc --noEmit",
40
+ "test": "cd tests && pnpm test",
41
+ "test:watch": "cd tests && pnpm run test:watch",
42
+ "test:e2e": "cd tests && pnpm run test:e2e",
43
+ "test:perf": "cd tests && pnpm run test:perf"
44
+ },
34
45
  "peerDependencies": {
35
46
  "@webgpu/types": "*"
36
47
  },
@@ -47,15 +58,5 @@
47
58
  "typescript": "^5.0.0",
48
59
  "vite": "^5.0.0",
49
60
  "vite-plugin-dts": "^4.5.4"
50
- },
51
- "scripts": {
52
- "build": "SDK_BUILD=true vite build --mode library",
53
- "dev": "vite build --mode library --watch",
54
- "clean": "rm -rf dist",
55
- "typecheck": "tsc --noEmit",
56
- "test": "cd tests && pnpm test",
57
- "test:watch": "cd tests && pnpm run test:watch",
58
- "test:e2e": "cd tests && pnpm run test:e2e",
59
- "test:perf": "cd tests && pnpm run test:perf"
60
61
  }
61
- }
62
+ }