Skip to main content

GitHub Repository

One Web Direct Mode quickstart with two audio sources: bundled sample audio and optional realtime conversation.
This quickstart targets the Direct Mode path. It starts with bundled PCM audio so you can validate AvatarKit without any realtime provider key. After that works, switch the same UI to realtime conversation and connect a browser microphone to OpenAI Realtime, Gemini Live, or Doubao E2E.

Prerequisites

Realtime conversation is optional. The quickstart includes adapters for:
ProviderWhen neededDocs
OpenAI RealtimeOnly when you select Realtime conversation with VITE_REALTIME_PROVIDER=openai.OpenAI Realtime
Gemini Live APIOnly when you select Realtime conversation with VITE_REALTIME_PROVIDER=gemini.Gemini Live API
Doubao E2E RealtimeAPIOnly when you select Realtime conversation with VITE_REALTIME_PROVIDER=doubao.Doubao E2E RealtimeAPI
Azure OpenAI RealtimeNot built in; use the same adapter interface if you want Azure-hosted realtime audio.Azure realtime audio
The realtime path is for local development. Do not ship a long-lived realtime provider API key in browser code. For production, mint short-lived provider tokens from your backend or proxy provider sessions through your backend.

Run it

1

Clone the repo and enter the quickstart folder

git clone https://github.com/spatius-ai/spatius-avatar-demo.git
cd spatius-avatar-demo/direct-mode/clients/web/quickstart
2

Install dependencies

pnpm install
3

Create your .env

cp .env.example .env
Fill VITE_SPATIUS_APP_ID, VITE_SPATIUS_AVATAR_ID, and VITE_SPATIUS_SESSION_TOKEN.You can leave realtime provider values blank for the first run.
4

Run the dev server

pnpm dev
5

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.
6

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

ModeWhat it proves
Sample audioApp ID, Avatar ID, Session Token, avatar loading, Motion Server connection, PCM audio send, and local rendering.
Realtime conversationBrowser 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_ID and DOUBAO_E2E_ACCESS_TOKEN are available to the local dev server. They should not use the VITE_ 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.