spatius_avatarkit 1.3.8
spatius_avatarkit: ^1.3.8 copied to clipboard
AvatarKit — real-time, audio-driven avatar rendering SDK for Flutter.
Changelog #
All notable changes to this project will be documented in this file.
1.3.8 - 2026-10-03 #
Bridges the Android 1.3.6 and iOS 1.3.6 native SDKs. Rolls up everything from the
1.3.8 beta line.
Added #
AvatarWidget(audioFormat:): the audio format is now set per view instead of once for the whole process inAvatarSDK.initialize(). Two views in one process can run different sample rates. Defaults to 16 kHz PCM as before;inputAudioFormat,opusBitrateandopusUplinkEnabledmove with it and keep their meaning.AvatarController.setAudioFormat({sampleRate, inputAudioFormat, opusBitrate, opusUplinkEnabled}): change the audio format of a live view without tearing the SDK down. Every parameter is optional (null= keep the current value). Whatever field changes, the call interrupts whatever is playing and, inDrivingServiceMode.direct, disconnects; callstart()again and feed audio in the new format. SwitchinginputAudioFormattoAudioCodec.opuspins the sample rate at 48000; switching back to PCM keeps the current rate unless asampleRateis passed in the same call. Accepted sample rates are 8000, 16000, 22050, 24000, 32000, 44100 and 48000; an unsupported rate, or asampleRatepaired with Opus input, is logged natively and leaves the format untouched. Same API on the Web, Android and iOS SDKs.AvatarController.audioFormat(): reads the format currently in effect for the view, after the native SDK's normalization.AudioFormat.toJson()/AudioFormat.fromJson(), andAudioFormatnow has value equality.- Custom animations. An avatar can carry named animation clips authored alongside it,
and the host can play them on demand:
controller.playCustomAnimation(name)starts a clip,controller.getCustomAnimationNames()lists the clips that loaded and can be played, andcontroller.onCustomAnimationStatefires with the clip name when one starts. Clips are downloaded with the avatar and prepared when the view is created, so playback starts at once and needs no driving-service connection. A clip behaves like a spoken round:onConversationStatereportsplayingand returns toidlewhen it ends,interrupt()/pause()/resume()apply, and a clip started while speech or another clip is playing takes over (reported asidlethenplaying, like any interrupted round). There is no separate completion callback: to loop or chain clips, callplayCustomAnimationagain from theidlecallback. An unknown name is logged natively and ignored; it does not reachonError. Same API on the native SDKs. Configuration.extraParams(Map<String, String>, default empty): application-defined metadata the native SDK sends unchanged in the session handshake when it connects to the driving service. It is not used when requesting or setting a session token, andAvatarSDK.configuration()returns it. Same field on the Web, Android and iOS SDKs.
Changed #
- Breaking:
AnimationType.monois renamedAnimationType.fallback, following the same rename in the native SDKs. It is the valueonAnimationStatewould report while the SDK plays its locally generated animation because no server animation arrived. No alias is kept: locally generated animation is not enabled in current native releases, so no host receives this value today. - Both native SDKs updated to
1.3.6. Neither reports telemetry to PostHog any more (the dependency is gone from the Android POM and the iOS binary); internal events continue through the existing OpenTelemetry channel.
Fixed (native) #
- With Opus uplink enabled (the default in Direct Mode), a round whose connection dropped
while a chunk was still being encoded went silent — no sound, no motion, no fallback.
Both SDKs now fall back to audio-only playback with locally generated animation, as
they already did when the connection was down at
send()time. - Android: resizing the avatar view at the moment it was being removed (for example a
PlatformViewbeing rebuilt) could crash the app with a nativeSIGSEGVinside the system Vulkan library. A size change that arrives while the view is being torn down is now dropped. - Android: a round started from inside the
onConversationState(idle)callback right afterinterrupt()was discarded. Android and iOS: when a fallback round ends while the avatar is showing the idle loop, the loop no longer jumps back to its first frame.
Removed #
- Breaking:
Configuration.audioFormat. Pass the format toAvatarWidget(audioFormat:)instead (see Added above). No deprecation shim is kept: the native SDKs removed the field in the same way and the plugin has no process-wide format left to forward it to.AvatarSDK.configuration()no longer returns an audio format. - The test-only
AvatarSDK.setAudioFormatForTesting(); tests create anAvatarWidgetwith the format they need.
Deprecated #
- The
audioFormatparameter ofAvatarController.yieldAudioData()stays deprecated and ignored; the message now points atAvatarWidget.audioFormat/setAudioFormat.
1.3.8-beta.2 - 2026-09-22 #
Bridges the Android 1.3.6-beta.2 and iOS 1.3.6-beta.2 native SDKs.
Added #
- Custom animations. An avatar can carry named animation clips authored alongside it,
and the host can play them on demand:
controller.playCustomAnimation(name)starts a clip,controller.getCustomAnimationNames()lists the clips that loaded and can be played, andcontroller.onCustomAnimationStatefires with the clip name when one starts. Clips are downloaded with the avatar and prepared when the view is created, so playback starts at once and needs no driving-service connection. A clip behaves like a spoken round:onConversationStatereportsplayingand returns toidlewhen it ends,interrupt()/pause()/resume()apply, and a clip started while speech or another clip is playing takes over (reported asidlethenplaying, like any interrupted round). There is no separate completion callback: to loop or chain clips, callplayCustomAnimationagain from theidlecallback. An unknown name is logged natively and ignored; it does not reachonError. Same API on the native SDKs.
Changed #
- Breaking:
AnimationType.monois renamedAnimationType.fallback, following the same rename in the native SDKs. It is the valueonAnimationStatewould report while the SDK plays its locally generated animation because no server animation arrived. No alias is kept: locally generated animation is not enabled in current native releases, so no host receives this value today.
Fixed (native) #
- Android: a round started from inside the
onConversationState(idle)callback right afterinterrupt()was discarded. Android and iOS: when a fallback round ends while the avatar is showing the idle loop, the loop no longer jumps back to its first frame.
1.3.8-beta.1 - 2026-09-21 #
Bridges the Android 1.3.6-beta.1 and iOS 1.3.6-beta.1 native SDKs.
Added #
AvatarWidget(audioFormat:): the audio format is now set per view instead of once for the whole process inAvatarSDK.initialize(). Two views in one process can run different sample rates. Defaults to 16 kHz PCM as before;inputAudioFormat,opusBitrateandopusUplinkEnabledmove with it and keep their meaning.AvatarController.setAudioFormat({sampleRate, inputAudioFormat, opusBitrate, opusUplinkEnabled}): change the audio format of a live view without tearing the SDK down. Every parameter is optional (null= keep the current value). Whatever field changes, the call interrupts whatever is playing and, inDrivingServiceMode.direct, disconnects; callstart()again and feed audio in the new format. SwitchinginputAudioFormattoAudioCodec.opuspins the sample rate at 48000; switching back to PCM keeps the current rate unless asampleRateis passed in the same call. Accepted sample rates are 8000, 16000, 22050, 24000, 32000, 44100 and 48000; an unsupported rate, or asampleRatepaired with Opus input, is logged natively and leaves the format untouched. Same API on the Web, Android and iOS SDKs.AvatarController.audioFormat(): reads the format currently in effect for the view, after the native SDK's normalization.AudioFormat.toJson()/AudioFormat.fromJson(), andAudioFormatnow has value equality.
Changed #
- Both native SDKs updated to
1.3.6-beta.1. Highlights: with Opus uplink enabled (the default in Direct Mode), a round whose connection dropped while a chunk was still being encoded went silent — no sound, no motion, no fallback; both SDKs now fall back to audio-only playback with locally generated animation, as they already did when the connection was down atsend()time. Neither SDK reports telemetry to PostHog any more (the dependency is gone from the Android POM and the iOS binary); internal events continue through the existing OpenTelemetry channel.
Removed #
- Breaking:
Configuration.audioFormat. Pass the format toAvatarWidget(audioFormat:)instead (see Added above). No deprecation shim is kept: the native SDKs removed the field in the same way and the plugin has no process-wide format left to forward it to.AvatarSDK.configuration()no longer returns an audio format. - The test-only
AvatarSDK.setAudioFormatForTesting(); tests create anAvatarWidgetwith the format they need.
Deprecated #
- The
audioFormatparameter ofAvatarController.yieldAudioData()stays deprecated and ignored; the message now points atAvatarWidget.audioFormat/setAudioFormat.
1.3.7 - 2026-09-18 #
Bridges the Android 1.3.5 and iOS 1.3.5 native SDKs.
Added #
AvatarError.renderNotSupportedandAvatarError.renderInitFailedare now delivered toonError. The first means this device cannot render the avatar at all (Android: no usable Vulkan instance / physical device / logical device; iOS: no Metal device) and is deterministic — tell the user rather than retry. The second covers any other failure while setting up the renderer. Until now a renderer that failed to initialize was only logged natively: the host saw a view that never drew anything and received no callback.
Changed #
- Both native SDKs updated to
1.3.5. Highlights: the Android SDK fixes an ANR where destroying the avatar view froze the app's main thread until Android killed it — which on Flutter is triggered by ordinaryPlatformViewdisposal, so any Flutter app that navigates away from an avatar screen was exposed; the iOS SDK applies the same bounded-wait rule preventively. Both also report far more about renderer failures, host teardown and blank frames.
Removed #
- Breaking:
AvatarError.appIDUnrecognized. The native SDKs never produced it — the service has no separate signal for an unknown app ID, which surfaces as a session-token error instead. Code that switches exhaustively overAvatarErrormust drop this case.
1.3.6 - 2026-09-01 #
Packaging fix only. The plugin's own API and both native SDKs are unchanged from
1.3.5 (Android 1.3.4 / iOS 1.3.4).
Fixed #
- The published package no longer contains the iOS
AvatarKit.xcframework. It was bundled by mistake in1.3.4and1.3.5, which made those downloads roughly 60 MB larger than necessary — the framework is fetched from its own release duringpod install, so the copy inside the package was never used. The package is back to about 5 MB.
1.3.5 - 2026-08-31 #
Bridges the Android 1.3.4 and iOS 1.3.4 native SDKs. No changes to the plugin's own API.
Changed #
- Both native SDKs now send their diagnostics to a collection gateway instead of the storage backend directly, and no longer carry any credentials for that backend.
- Both native SDKs now check, one second after the first frame is reported as rendered, whether anything was actually drawn, and report a diagnostic when the view is completely blank.
- Updated the analytics dependency bundled by both native SDKs.
Fixed #
- 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. Applies to both platforms.
1.3.4 - 2026-08-22 #
Bridges the Android 1.3.3 and iOS 1.3.3 native SDKs. No changes to the plugin's own API.
Fixed #
- Fixed the SDK continuing to send audio under an already-finished conversation id in direct mode (Android). After
send(audio, end: true), feeding new audio while that round had not started playing yet reused the same conversation id on the wire, so the driving service received new audio on a request it had already been told was over. A new round now always starts under a fresh id, whether or not the previous one had begun playing. iOS was not affected. - The timestamp prefix on session and request ids is now generated in UTC on Android, matching the other platforms.
- Internal telemetry only, no change to public API or runtime behaviour: the connection identifier is now attached automatically to the diagnostic events and traces both native SDKs report; playback records additionally carry the rendering SDK's own version; loading and connection timings are now reported for failed attempts as well; and HTTP request duration buckets were widened to match the other platforms.
1.3.3 - 2026-08-08 #
Bridges the Android 1.3.2 and iOS 1.3.2 native SDKs. Rolls up everything from the 1.3.3 beta line.
Known issues #
- On some Android devices (Huawei and Mediatek/Mali GPUs are the ones reported), tearing down and rebuilding the avatar view in quick succession can abort the app with
java.lang.IllegalStateException: Image is already closed. This is a Flutter engine bug in how platform views hand images to the rasterizer (flutter/flutter#175267), not something this plugin can guard against — it affects any plugin that renders through a platform view. The engine fix (flutter/flutter#185125, merged 2026-04-29) makes the failure non-fatal, but has not landed in a stable release yet; it is expected in the 3.47 line. Until then, avoid mounting and unmountingAvatarWidgetin a tight loop.
Added #
- Opus audio support.
AudioFormat.inputAudioFormat(AudioCodec.pcmdefault, orAudioCodec.opus) declares the format the host feeds into the SDK viasend/yieldAudioData;opusinput is decoded back to PCM16 for local rendering and forwarded upstream as-is in direct mode.AudioFormat.opusBitratetunes the target bitrate. Only effective in direct mode. AvatarError.invalidAudioInputis now reported when audio handed to the SDK does not matchAudioFormat.inputAudioFormat— for example Opus input that is neither Ogg Opus nor a bare Opus packet, is stereo, or changes shape mid-conversation.
Changed #
- The direct-mode uplink now compresses audio to Opus by default (
AudioFormat.opusUplinkEnabled, previously off). It cuts the upload to roughly 1/8 at the cost of client-side encoding, which matters most on the mobile networks where stalls actually happen. PassopusUplinkEnabled: falseto keep the raw PCM uplink. Unchanged for host mode (no uplink) and foropusinput (already compressed). If the configuredsampleRateis not one of 8000/16000/24000/48000, the SDK logs a warning and falls back to a raw PCM uplink. Configuration.regionnow defaults to automatic selection (kDefaultRegionis'auto'): when left unset, the SDK picks the closest serving region at initialization, and reuses the cached choice on later launches. Passing an explicitregioncontinues to force that region, unchanged. If automatic selection can't be reached, the SDK falls back to a default region and continues initializing.initializewith a missingappIDnow fails fast, surfacing missing configuration immediately during local development. The accompanying message points to https://app.spatius.ai/ to obtain an app ID.
Deprecated #
- The per-call
audioFormatparameter ofAvatarController.yieldAudioDatais deprecated and now ignored; the audio format comes fromConfiguration.audioFormatpassed toinitialize. It will be removed in a future release.
1.3.3-beta.1 - 2026-07-31 #
Bridges the Android 1.3.2-beta.1 and iOS 1.3.1-beta.1 native SDKs.
Added #
- Opus audio support.
AudioFormat.inputAudioFormat(AudioCodec.pcmdefault, orAudioCodec.opus) declares the format the host feeds into the SDK viasend/yieldAudioData;opusinput is decoded back to PCM16 for local rendering and forwarded upstream as-is in direct mode.AudioFormat.opusUplinkEnabled(defaultfalse) opts the direct-mode uplink into Opus compression (roughly 1/8 the upload, at the cost of client-side encoding), andAudioFormat.opusBitratetunes the target bitrate. Only effective in direct mode. AvatarError.invalidAudioInputis now reported when audio handed to the SDK does not matchAudioFormat.inputAudioFormat— for example Opus input that is neither Ogg Opus nor a bare Opus packet, is stereo, or changes shape mid-conversation.
Changed #
Configuration.regionnow defaults to automatic selection (kDefaultRegionis'auto'): when left unset, the SDK picks the closest serving region at initialization. Passing an explicitregioncontinues to force that region, unchanged. If automatic selection can't be reached, the SDK falls back to a default region and continues initializing.- When
opusUplinkEnabledistruebut the configuredsampleRateis not Opus-compatible (8000/16000/24000/48000),initializelogs a warning and automatically falls back to a raw PCM uplink instead of silently failing. initializewith a missingappIDnow fails fast, surfacing missing configuration immediately during local development. The accompanying message points to https://app.spatius.ai/ to obtain an app ID.
Deprecated #
- The per-call
audioFormatparameter ofAvatarController.yieldAudioDatais deprecated and now ignored; the audio format comes fromConfiguration.audioFormatpassed toinitialize. It will be removed in a future release.
1.3.2 - 2026-07-13 #
Bridges the Android 1.3.1 native SDK. No Dart API changes.
Fixed #
- On Android, native libraries are now aligned to a 16 KB memory page size, ensuring compatibility with 16 KB page-size devices and meeting Google Play's upload requirement (effective Nov 1, 2025) for apps targeting Android 15+.
1.3.1 - 2026-07-05 #
Documentation-only release. No code or native dependency changes since 1.3.0.
Changed #
- Cleaned up the package README shown on pub.dev and fixed the documentation link.
1.3.0 - 2026-07-05 #
Bridges the v1.3.0 native SDKs. No breaking Dart API changes.
Changed #
- Native dependencies bumped to v1.3.0
(Android
ai.spatius:avatarkit:1.3.0, iOS xcframework v1.3.0).
Added #
- Avatars are now automatically classified as body-fixation or non-body-fixation and loaded on the matching path, driven by the asset's compatibility flags (handled by the native SDKs).
- Loading an avatar whose asset requires a newer SDK now fails fast with an incompatible-asset error instead of rendering incorrectly, prompting an SDK upgrade.
1.2.0 - 2026-06-28 #
First stable 1.2 release. No Dart API changes since 1.2.0-beta.1; this release
bumps the native SDKs to v1.2.0 for playback and asset-loading reliability fixes.
Changed #
- Native dependencies bumped to v1.2.0
(Android
ai.spatius:avatarkit:1.2.0, iOS xcframework v1.2.0).
Fixed #
- Fixed a crash that could occur when audio playback was interrupted by the system (e.g. an incoming phone call). Such interruptions are now handled gracefully instead of crashing the app.
- Fixed local avatar assets with absent or null optional fields (such as
transform) being wrongly rejected when derived. Such assets now load correctly.
1.2.0-beta.1 - 2026-06-20 #
Aligns the public API with native iOS / Android SDK v1.2.0-beta.1.
Added #
FrameStarvationModeenum (audioIndependent/strictSync) andAvatarController.setFrameStarvationMode(FrameStarvationMode mode)— choose how playback behaves when animation frames can't keep up with audio.audioIndependent(default) keeps audio playing while animation catches up;strictSyncpauses audio until frames arrive, keeping audio and animation strictly in sync.AvatarController.onPlaybackStall—void Function(bool stalled)?callback that fires when audio is paused/resumed due to frame starvation (only instrictSync).AvatarError.incompatibleAvatarAsset— thrown when a local asset is in an unsupported (legacy) format.
Changed #
- Native dependencies bumped to v1.2.0-beta.1
(Android
ai.spatius:avatarkit:1.2.0-beta.1, iOS xcframework v1.2.0-beta.1).
1.1.0-beta.1 - 2026-06-09 #
Aligns the public API with native iOS / Android SDK v1.1.0-beta.2.
Added #
RenderQualityenum (standard/high/ultra) andConfiguration({RenderQuality renderQuality = RenderQuality.ultra})to set render quality at initialization.AvatarSDK.setRenderQuality(RenderQuality quality)— change render quality at runtime.AvatarSDK.setRenderResolutionCap({required bool enabled, int maxHeight = 1440})— cap internal render resolution height to bound GPU/bandwidth cost.AvatarController.renderSize()→Size— current drawable size in pixels.AvatarController.getBoundingRect()→Rect?— rendered avatar bounds.AvatarError.invalidAvatarMetadataandAvatarError.invalidAnimationData.
Changed #
- Native dependencies bumped to v1.1.0-beta.2
(Android
ai.spatius:avatarkit:1.1.0-beta.2, iOS xcframework v1.1.0-beta.1).
Breaking #
DrivingServiceModevalues renamed:sdk→direct,host→backend. UpdateConfiguration(drivingServiceMode: ...)call sites accordingly.
1.0.0 - 2026-05-20 #
First stable release.
- Flutter plugin bridging native AvatarKit (Android
ai.spatius:avatarkit:1.0.0, iOS xcframework v1.0.0). - Public API:
AvatarSDK,AvatarManager,AvatarWidget,AvatarController. - Real-time avatar rendering with audio-driven and host-driven modes.
- See README.md for installation and usage.
Pre-1.0 beta history archived at docs/history/CHANGELOG-pre-1.0.md.