@spatius/avatarkit 1.2.0-beta.2 → 1.2.0-beta.4

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,16 @@ 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.2.0-beta.4] - 2026-06-28
9
+
10
+ ### Fixed
11
+ - Avatars without body-fixation support no longer render a malformed body. Such avatars now correctly render the head only, matching pre-1.2.0-beta.3 behavior. Body-fixation avatars are unaffected.
12
+
13
+ ## [1.2.0-beta.3] - 2026-06-25
14
+
15
+ ### Added
16
+ - New `ErrorCode.unsupportedAvatarAsset`. When loading an avatar whose asset requires a newer SDK, the load now fails fast with this error (surfaced via the existing `AvatarError` / `onError` path) instead of rendering incorrectly, prompting an SDK upgrade.
17
+
8
18
  ## [1.2.0-beta.2] - 2026-06-23
9
19
 
10
20
  ### Removed
@@ -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-BnubRaUR.js";
4
+ import { A as APP_CONFIG, l as logger, e as errorToMessage, a as logEvent } from "./index-BIjiLtOM.js";
5
5
  class StreamingAudioPlayer {
6
6
  // Mark if AudioContext is being resumed, avoid concurrent resume requests
7
7
  constructor(options) {
@@ -75,7 +75,7 @@ class StreamingAudioPlayer {
75
75
  const context = event.target;
76
76
  if (context.state === "suspended" && this.isPlaying && !this.isPaused) {
77
77
  this.ensureAudioContextRunning().catch((err) => {
78
- logger.errorWithError("[StreamingAudioPlayer] Failed to auto-resume AudioContext after external suspend:", err);
78
+ logger.error("[StreamingAudioPlayer] Failed to auto-resume AudioContext after external suspend:", err);
79
79
  });
80
80
  }
81
81
  };
@@ -142,7 +142,7 @@ class StreamingAudioPlayer {
142
142
  state: this.audioContext.state
143
143
  });
144
144
  } catch (err) {
145
- logger.errorWithError("[StreamingAudioPlayer] Failed to resume AudioContext:", err);
145
+ logger.error("[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)
@@ -162,7 +162,7 @@ class StreamingAudioPlayer {
162
162
  }
163
163
  if (this.isPlaying && !this.isPaused && this.audioContext.state === "suspended") {
164
164
  this.ensureAudioContextRunning().catch((err) => {
165
- logger.errorWithError("[StreamingAudioPlayer] Failed to ensure AudioContext running in addChunk:", err);
165
+ logger.error("[StreamingAudioPlayer] Failed to ensure AudioContext running in addChunk:", err);
166
166
  });
167
167
  }
168
168
  this.audioChunks.push({ data: pcmData, isLast });
@@ -177,13 +177,13 @@ class StreamingAudioPlayer {
177
177
  this.log("[StreamingAudioPlayer] autoContinue=true, auto-resuming playback");
178
178
  this.autoContinue = false;
179
179
  this.resume().catch((err) => {
180
- logger.errorWithError("Failed to auto-resume playback:", err);
180
+ logger.error("Failed to auto-resume playback:", err);
181
181
  });
182
182
  }
183
183
  if (!this.isPlaying && this.autoStartEnabled && this.audioChunks.length > 0) {
184
184
  this.log("[StreamingAudioPlayer] Auto-starting playback from addChunk");
185
185
  this.startPlayback().catch((err) => {
186
- logger.errorWithError("[StreamingAudioPlayer] Failed to start playback from addChunk:", err);
186
+ logger.error("[StreamingAudioPlayer] Failed to start playback from addChunk:", err);
187
187
  });
188
188
  } else if (this.isPlaying && !this.isPaused) {
189
189
  this.log("[StreamingAudioPlayer] Already playing, scheduling next chunk");
@@ -195,7 +195,7 @@ class StreamingAudioPlayer {
195
195
  /**
196
196
  * Start new session (stop current and start fresh)
197
197
  */
198
- async startNewSession(audioChunks) {
198
+ async startNewSession(audioChunks, leadingSilenceMs = 0) {
199
199
  this.stop();
200
200
  this.sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
201
201
  this.audioChunks = [];
@@ -205,8 +205,14 @@ class StreamingAudioPlayer {
205
205
  this.pausedAudioContextTime = 0;
206
206
  this.autoContinue = false;
207
207
  this.log("Starting new session", {
208
- chunks: audioChunks.length
208
+ chunks: audioChunks.length,
209
+ leadingSilenceMs
209
210
  });
211
+ if (leadingSilenceMs > 0) {
212
+ const silenceSamples = Math.floor(leadingSilenceMs / 1e3 * this.sampleRate) * this.channelCount;
213
+ const silencePcm = new Uint8Array(silenceSamples * 2);
214
+ this.addChunk(silencePcm, false);
215
+ }
210
216
  for (const chunk of audioChunks) {
211
217
  this.addChunk(chunk.data, chunk.isLast);
212
218
  }
@@ -261,7 +267,7 @@ class StreamingAudioPlayer {
261
267
  }
262
268
  if (this.audioContext.state === "suspended") {
263
269
  this.ensureAudioContextRunning().catch((err) => {
264
- logger.errorWithError("[StreamingAudioPlayer] Failed to ensure AudioContext running in scheduleNextChunk:", err);
270
+ logger.error("[StreamingAudioPlayer] Failed to ensure AudioContext running in scheduleNextChunk:", err);
265
271
  });
266
272
  }
267
273
  const chunkIndex = this.scheduledChunks;
@@ -326,7 +332,7 @@ class StreamingAudioPlayer {
326
332
  activeSources: this.activeSources.size
327
333
  });
328
334
  } catch (err) {
329
- logger.errorWithError("Failed to schedule audio chunk:", err);
335
+ logger.error("Failed to schedule audio chunk:", err);
330
336
  logEvent("schedule_chunk_failed", "error", {
331
337
  session_id: this.sessionId,
332
338
  reason: err instanceof Error ? err.message : String(err)
@@ -440,7 +446,7 @@ class StreamingAudioPlayer {
440
446
  this.isPaused = true;
441
447
  if (this.audioContext.state === "running") {
442
448
  this.audioContext.suspend().catch((err) => {
443
- logger.errorWithError("Failed to suspend AudioContext:", err);
449
+ logger.error("Failed to suspend AudioContext:", err);
444
450
  this.isPaused = false;
445
451
  });
446
452
  }
@@ -462,7 +468,7 @@ class StreamingAudioPlayer {
462
468
  try {
463
469
  await this.audioContext.resume();
464
470
  } catch (err) {
465
- logger.errorWithError("Failed to resume AudioContext:", err);
471
+ logger.error("Failed to resume AudioContext:", err);
466
472
  throw err;
467
473
  }
468
474
  }
@@ -525,14 +531,16 @@ class StreamingAudioPlayer {
525
531
  * Start playback manually (for delayed start scenarios)
526
532
  * This allows starting playback after transition animation completes
527
533
  */
528
- play() {
534
+ async play() {
529
535
  if (this.isPlaying) {
530
536
  return;
531
537
  }
532
538
  this.autoStartEnabled = true;
533
- this.startPlayback().catch((err) => {
534
- logger.errorWithError("[StreamingAudioPlayer] Failed to start playback from play():", err);
535
- });
539
+ try {
540
+ await this.startPlayback();
541
+ } catch (err) {
542
+ logger.error("[StreamingAudioPlayer] Failed to start playback from play():", err);
543
+ }
536
544
  }
537
545
  /**
538
546
  * Mark playback as ended