import { AvatarView } from '@spatialwalk/avatarkit'// Container MUST have non-zero width and heightconst container = document.getElementById('avatar-container')!const avatarView = new AvatarView(avatar, container)
4
Initialize Audio Context
Critical:initializeAudioContext()must be called inside a user gesture handler (e.g., click, touchstart). This is a browser security requirement — calling it outside a user gesture will fail silently.
// Start WebSocket connection to AvatarKit server// Note: start() initiates the connection asynchronously.// Wait for onConnectionState === 'connected' before calling send().await avatarView.controller.start()// Wait for connection to be readyawait new Promise<void>((resolve, reject) => { avatarView.controller.onConnectionState = (state) => { if (state === ConnectionState.connected) resolve() else if (state === ConnectionState.failed) reject(new Error('Connection failed')) }})// Send audio data (PCM16, mono, matching configured sample rate)const audioData: ArrayBuffer = /* your PCM16 audio data */avatarView.controller.send(audioData, false) // Continue sending// Mark end of audio input for current conversation round// The avatar will continue playing remaining animation until finished,// then automatically return to idle (notified via onConversationState).avatarView.controller.send(lastChunk, true)
6
Cleanup
avatarView.controller.close() // Close WebSocket connectionavatarView.dispose() // Release all resources
These methods are only available when drivingServiceMode is DrivingServiceMode.sdk.
// Initialize audio (MUST be in user gesture handler)await controller.initializeAudioContext()// Connect to AvatarKit serverawait controller.start()// Send audio data — returns conversationIdconst conversationId = controller.send( audioData: ArrayBuffer, // PCM16, mono end: boolean // true = end of conversation round)// Close connectioncontroller.close()
send() behavior:
end: false — continues the current conversation round
end: true — marks the end of audio input for the current round. The avatar will continue playing remaining animation until finished, then automatically return to idle (notified via onConversationState). Sending new audio after this starts a new round and interrupts any ongoing playback
// Playback controlcontroller.pause() // Pause audio + animationcontroller.resume() // Resume playbackcontroller.interrupt() // Stop current playback, clear data// Data managementcontroller.clear() // Clear all data and resources// Conversationcontroller.getCurrentConversationId() // string | null// Volume (affects avatar audio only, not system volume)controller.volume = 0.5 // Set volume (0.0 to 1.0)controller.volume // Get current volume
enum ConversationState { idle = 'idle', // Breathing animation, waiting for input playing = 'playing', // Active conversation playback paused = 'paused', // Paused during playback}
State transitions are notified immediately when the transition starts, not when the animation completes. For example, playing is reported as soon as the transition from idle begins.
If the WebSocket connection fails within 15 seconds, the SDK automatically enters audio-only fallback mode — audio continues playing without animation. This ensures uninterrupted audio playback when the server is unreachable.
The fallback mode is interruptible like normal playback
onConnectionState reports failed when the connection times out