@spatius/avatarkit 1.3.7 → 1.3.9

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,59 @@ 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.3.9] - 2026-09-16
9
+
10
+ ### Added
11
+ - `AvatarSDK.isDeviceSupported()` now checks whether a rendering context can actually be created before running the benchmark, and returns `false` immediately when neither WebGL2 nor WebGPU is available. Previously it always returned `true`: a device whose browser had hardware acceleration switched off passed the check, loaded the avatar, and then silently failed to draw anything. The check adds no measurable cost.
12
+ - Two new `ErrorCode` values: `renderNotSupported` (no WebGL2 or WebGPU — typically hardware acceleration disabled or the GPU driver blocklisted; deterministic, tell the user rather than retry) and `renderInitFailed` (any other failure while setting up the renderer). A host that listens for errors on the view can now tell "this machine can't draw" apart from "something else went wrong".
13
+
14
+ ### Changed
15
+ - The error thrown when the WebAssembly module cannot be loaded now says which URL was tried and links to the toolchain setup page (`https://docs.spatius.ai/sdk-reference/web-sdk/toolchain`). Nearly every such failure is a build tool inlining or relocating `avatar_core_wasm.wasm`; the previous message only carried the runtime's own "both async and sync fetching of the wasm failed", which named neither the path nor the fix.
16
+ - **Behaviour change**: the SDK no longer reconnects the driving-service WebSocket on its own. Until now the Web SDK silently retried up to 5 times with exponential backoff on almost every disconnect — including abnormal closures (1006), server-initiated normal closures and server rejections it did not recognise — while the Android and iOS SDKs never retried. The server drops connections without a close frame when it intentionally ends a session, so a client cannot tell "the server ended this" from "the network dropped", and the automatic retries turned every intentional disconnect into a burst of failed connections. All three SDKs now behave the same way: on disconnect `onConnectionState` reports `disconnected` (or `failed`), the conversation ends, and the host decides whether to reconnect — typically by calling `controller.start()` again after checking the error reported via `onError`. Hosts that relied on the SDK reconnecting by itself must add that call. See ADR-0006.
17
+ - Internal telemetry only, no change to public API or runtime behaviour: metrics no longer emit a same-named log record alongside every data point. Until now each metric (`fetch_avatar_latency`, `ws_connect_latency`, `time_calibrated`, `template_resources_load_measure`, …) also wrote a log line that was ~95% repeated resource fields; the number itself lives in the metric. Where a metric needs high-cardinality detail (avatar / conversation / trace ids, failure reasons) the SDK now sends one explicit detail log record instead. **Consequence for anyone querying the log stream by these event names**: the success side of `time_calibrated`, `template_resources_load_measure` and `ws_connect_latency` no longer appears in logs at all — only failure-side records remain — so success rates for these must be computed from the metric, not from logs. `fetch_avatar_latency`, `fetch_avatar_metadata_latency` and `download_avatar_assets_latency` keep a detail record on both sides.
18
+ - Internal telemetry only, no change to public API or runtime behaviour: server error messages received over the driving connection are rate-limited per error code (first occurrence always sent, then at most one per minute per code), so a server that answers every message with an error cannot flood the pipeline.
19
+ - Internal telemetry only, no change to public API or runtime behaviour: audio send failures now record whether the audio was PCM or Opus, matching the Android and iOS SDKs.
20
+ - Internal telemetry only, no change to public API or runtime behaviour: a failure anywhere in `AvatarView` initialization — loading the character, setting up the renderer, drawing the first frame — is now reported with which stage failed and why. Until now the only trace of such a failure was a browser-console line, so a device that could not render at all showed up in our data as a perfectly healthy session that never played anything. This is the gap that produced the 2026-09-03 "avatar never appears" report.
21
+ - Internal telemetry only, no change to public API or runtime behaviour: every session now reports once whether WebGL2 and WebGPU are available on that device, so environments that cannot render can be counted by browser and OS rather than found one support ticket at a time.
22
+
23
+ - Internal telemetry only, no change to public API or runtime behaviour: failures that until now were only written to the browser console are reported as structured diagnostics — playback failing to start, the render loop stopping on an error, Opus input decoding, audio-context state changes, renderer blit, WebSocket message handling and reconnects, server error messages, and WebAssembly runtime errors. Diagnostics raised on per-frame or per-packet paths are rate-limited to one per minute per kind, with the number of suppressed occurrences attached.
24
+ - Internal telemetry only, no change to public API or runtime behaviour: server error messages received over the driving connection were never reported (the handler that would have done so was unreachable). They are now.
25
+ - Internal telemetry only, no change to public API or runtime behaviour: the SDK now records when the host tears it down — `AvatarView.dispose()`, `controller.close()` and a host-initiated `controller.interrupt()` each report what was playing at that moment, how long since the last disconnect, and the calling code — and when the avatar vanishes without any of those being called: the canvas being removed from the DOM while the view is still alive, the container collapsing to zero size, and the page being unloaded mid-playback. Until now an avatar disappearing mid-sentence looked identical in our data whether the host destroyed it, the page reloaded, or the renderer failed; this is the gap that made the 2026-09-16 "avatar vanishes while speaking" report take a week of log correlation to attribute.
26
+ - Internal telemetry only, no change to public API or runtime behaviour: an abnormal WebSocket closure (code 1006) is now reported once instead of twice, and audio-send failures after a disconnect carry the id of the connection that just dropped, so both can be matched to the server-side session log.
27
+
28
+ ### Deprecated
29
+ - `AvatarView.getCameraConfig()` and `AvatarView.updateCameraConfig()`. The camera is defined by the avatar's own settings, which the rendering baselines are calibrated against; overriding it from the host produces a view that no longer matches those baselines. Both methods still work in this release and log a one-time console warning when called; they will be removed in the next release. There is no replacement: hosts that were adjusting `fov` or the camera position through these methods should remove that code.
30
+
31
+ ### Removed
32
+ - `ErrorCode.appIDUnrecognized`, `ErrorCode.websocketClosedAbnormally` and `ErrorCode.audioOnlyInitFailed`. None of the three could ever be produced: the service has no separate signal for an unknown app ID (it surfaces as a session-token error), close code 1006 is reported as `websocketClosedUnexpected` like every other unexpected close, and the audio-only path never raised its own error. Code that switched on them can drop those branches.
33
+ - `AvatarView.playTransitionFromProtobuf()` and `AvatarView.playTransitionToIdleFromProtobuf()`. Both were superseded by `generateTransitionToFrame()` / `generateTransitionToIdle()`, which hand the transition frames back to the host to play at its own cadence; the removed methods played them internally at a fixed 25 fps and had no callers.
34
+ - `extractResourceUrls()` and the `ResourceType` enum from the character types. Neither was ever used, and the URL set they produced no longer matches the current asset schema.
35
+ - `isClockCalibrated()` from the `@spatius/avatarkit/internal-telemetry` entry, which exists only as a bridge for the companion RTC SDK; no RTC release ever used it. (`clientContextFields()` on the same entry is kept: RTC 1.1.3, still deployed, imports it.)
36
+
37
+ ### Fixed
38
+ - After a driving-service connection was closed before it finished opening (handshake failure, or the server dropping the socket before confirming the session), calling `controller.start()` again silently did nothing: the SDK still believed a connection was in progress and returned without opening a socket, raising an error or changing the connection state, and only `controller.close()` could unblock it. The pending connection attempt is now settled and the "connecting" flag cleared as soon as the socket closes, so `start()` opens a new connection as documented. This mattered little while the SDK retried on its own; now that reconnection is the host's responsibility it would have left the host with no way to recover.
39
+ - `ErrorCode.failedToDownloadAvatarAssets` is now actually raised when a required avatar asset fails to download or the download completes incomplete. Previously the raw network error (or a plain `Error`) was thrown instead, so the code existed but never reached a host.
40
+ - Internal telemetry only, no change to public API or runtime behaviour: the blank-canvas diagnostic introduced in 1.3.8 was being sent to the product-analytics channel only and never reached the log backend, so it could not be queried or alerted on. It now goes through the same path as every other diagnostic.
41
+ - Internal telemetry only, no change to public API or runtime behaviour: the blank-canvas check now reports on every view once the first frame has been sampled, with a `blank` field saying whether anything was drawn, instead of reporting only the blank case. Until now the blank-screen rate had no denominator — only failures were counted, so it could not be expressed as a rate. Matches the Android and iOS SDKs.
42
+
43
+ ## [1.3.8] - 2026-08-31
44
+
45
+ ### Added
46
+ - The SDK now checks, one second after the first frame is reported as rendered, whether the canvas actually has anything on it, and reports a diagnostic when it is completely blank. Some devices pass the capability check and still render nothing; until now that failure was silent on our side and only surfaced as a user complaint. Costs a few milliseconds once per session and never blocks the render loop.
47
+
48
+ ### Changed
49
+ - Internal telemetry only, no change to public API or runtime behaviour: diagnostics are now sent to a collection gateway instead of the storage backend directly, and the SDK no longer carries any credentials for that backend. Credentials shipped inside a redistributed SDK are readable by anyone who receives it.
50
+ - Internal telemetry only, no change to public API or runtime behaviour: collection of browser page-performance metrics is now switched off explicitly in code rather than being left to a server-side setting, so what the SDK collects is fixed by the version you install. This is unrelated to the SDK's own frame-rate monitoring.
51
+ - Internal telemetry only, no change to public API or runtime behaviour: diagnostic records now carry the session and device identifiers that the Android and iOS SDKs have always included, so a session can be followed across records. Records emitted by a companion SDK carry them too — those previously went out with no identity at all.
52
+ - Updated the bundled analytics dependency, which fixes log batches being retried indefinitely when an ad blocker drops them and batches being discarded outright on a 408. The published bundle is marginally smaller than before.
53
+
54
+ ### Removed
55
+ - Internal telemetry only, no change to public API or runtime behaviour: removed a playback-stall detector that only ever emitted one diagnostic and drove no behaviour. What it looked for is already covered by the stall and dropped-frame figures reported for every round of playback.
56
+
57
+ ### Fixed
58
+ - Internal telemetry only, no change to public API or runtime behaviour: end-to-end latency is now reported when the host application supplies the motion data, not only when the SDK connects to the driving service itself. The measurements were being taken in both cases and discarded in one of them.
59
+ - Internal telemetry only, no change to public API or runtime behaviour: the reported frame time now includes the core compute stage, which was previously left out of the total.
60
+
8
61
  ## [1.3.7] - 2026-08-17
9
62
 
10
63
  ### Fixed