Direct Mode for Web is the simplest way to put a Spatius avatar in a browser app. @spatius/avatarkit connects directly to Motion Server, sends avatar speech audio, and renders motion locally — no agent worker or relay backend needed beyond a Session Token endpoint.
Required: The SDK uses WASM files that need special build configuration. Configure your build tool before initializing the SDK, or .wasm requests will fail.
Vite
Next.js
Add the official plugin to vite.config.ts:
vite.config.ts
import { defineConfig } from 'vite'import { avatarkitVitePlugin } from '@spatius/avatarkit/vite'export default defineConfig({ plugins: [ avatarkitVitePlugin(), ],})
What the plugin handles
Dev server: serves .wasm files with the correct MIME type
Build: copies WASM files to dist/assets/
Cloudflare Pages: generates a _headers file
Vite options: configures optimizeDeps, assetsInclude, assetsInlineLimit
import { AvatarManager } from '@spatius/avatarkit'const avatar = await AvatarManager.shared.load('your-avatar-id', (progress) => { // progress.progress is in 0..1; multiply by 100 to render as a percentage. const percent = Math.round((progress.progress ?? 0) * 100) console.log(`Loading: ${percent}%`)})
3
Mount the view
import { AvatarView } from '@spatius/avatarkit'// Container must have non-zero width and height.const container = document.getElementById('avatar-container')!const avatarView = new AvatarView(avatar, container)
4
Initialize audio (inside a user gesture)
initializeAudioContext() must be called inside a user-gesture handler (a click, touchstart, or similar listener). Browsers reject AudioContext creation outside user gestures and the call fails silently.
import { ConnectionState } from '@spatius/avatarkit'await avatarView.controller.start()await new Promise<void>((resolve, reject) => { avatarView.controller.onConnectionState = (state) => { if (state === ConnectionState.connected) resolve() else if (state === ConnectionState.failed) reject(new Error('Connection failed')) }})// Stream PCM16 mono audio at the configured sample rate (default 16 kHz)avatarView.controller.send(audioChunk, /* end */ false)// Mark end of the conversation roundavatarView.controller.send(lastChunk, /* end */ true)
For full API signatures, types, audio format details, lifecycle management, error codes, browser compatibility, and common issues, see Web SDK Reference.