GitHub Repository
One Web Direct Mode quickstart with two audio sources: bundled sample audio and optional realtime conversation.
Prerequisites
- Node.js 18+
- pnpm
- Spatius credentials. See Credentials for what each value is and where to get it.
VITE_SPATIUS_APP_ID— from Spatius StudioVITE_SPATIUS_AVATAR_ID— from the Avatar LibraryVITE_SPATIUS_SESSION_TOKEN— see Session token API
| Provider | When needed | Docs |
|---|---|---|
| OpenAI Realtime | Only when you select Realtime conversation with VITE_REALTIME_PROVIDER=openai. | OpenAI Realtime |
| Gemini Live API | Only when you select Realtime conversation with VITE_REALTIME_PROVIDER=gemini. | Gemini Live API |
| Doubao E2E RealtimeAPI | Only when you select Realtime conversation with VITE_REALTIME_PROVIDER=doubao. | Doubao E2E RealtimeAPI |
| Azure OpenAI Realtime | Not built in; use the same adapter interface if you want Azure-hosted realtime audio. | Azure realtime audio |
Run it
Create your .env
VITE_SPATIUS_APP_ID, VITE_SPATIUS_AVATAR_ID, and VITE_SPATIUS_SESSION_TOKEN.You can leave realtime provider values blank for the first run.Validate sample audio first
Open
http://localhost:3000, keep Sample audio selected, then click Connect avatar and Send sample audio. The avatar should load, connect to Motion Server, and play the bundled PCM audio with lip sync.Optional: try realtime conversation
Set
VITE_REALTIME_PROVIDER to openai, gemini, or doubao, fill the matching provider values in .env, then restart pnpm dev.For Doubao, fill DOUBAO_E2E_APP_ID and DOUBAO_E2E_ACCESS_TOKEN without the VITE_ prefix. The quickstart’s local Vite proxy reads those values server-side because the browser cannot set Doubao’s required WebSocket headers safely.In the UI, select Realtime conversation, click Connect all, then hold Hold to talk while speaking. Release the button to send your turn.What this validates
| Mode | What it proves |
|---|---|
| Sample audio | App ID, Avatar ID, Session Token, avatar loading, Motion Server connection, PCM audio send, and local rendering. |
| Realtime conversation | Browser microphone capture, realtime provider connection, provider response audio, resampling into AvatarKit’s audio format, and Direct Mode rendering. |
Troubleshooting
- AvatarKit fails before sample audio plays: refresh
VITE_SPATIUS_SESSION_TOKEN. Direct Mode Session Tokens are short-lived and must match the App ID and region used by the client. - Sample audio works but realtime does not connect: the AvatarKit path is valid. Check the selected provider key, model name, quota, and realtime access for your provider account.
- Gemini closes with
1008: Your project has been denied access: the API key is valid enough to open the WebSocket, but the Google Cloud or AI Studio project does not have Live API access for that model. - Doubao fails before the realtime session is ready: confirm
DOUBAO_E2E_APP_IDandDOUBAO_E2E_ACCESS_TOKENare available to the local dev server. They should not use theVITE_prefix because the browser should never receive the Access Token. - The browser asks for microphone permission: allow microphone access for the local dev origin, then click Hold to talk again.
Next steps
Direct Mode guide
Full Web SDK integration with your own audio source.
Browse all demos
Multi-framework Web references plus iOS, Android, Flutter, Backend Mode, and LiveKit examples.

