Enable an avatar
This walks you from "I have a configured ScaiBot" to "my customer's site has a 3D avatar of it" in one sitting.
Prerequisites#
- A ScaiBot configured with at least a name, persona, and a voice (Voice Settings → enable + pick a voice_id). The avatar inherits the voice; no avatar without a voice.
- A 3D model file (GLB, GLTF, or VRM) hosted at a URL your customer's browser can reach. We don't host models; we point at one. CDNs, S3 buckets, or even your own static-asset host all work.
- A web page where you'll render the avatar (Three.js, react-three-fiber, etc.). The customer hosts the page; we don't ship a 3D client.
1. Turn the avatar on#
In the admin UI, open ScaiBot → Avatar (ScaiVatars). Pick your bot from the dropdown.
Flip Avatar enabled to on. Save the 3D model URL field. The bot is now reachable through the public avatar WebSocket; no other config is required to start testing locally (the origin allow-list will reject browsers until you fill it in, but curl and CLI clients still work).
2. Issue an embed token#
Open ScaiBot → Embed & Deploy. Pick the same bot. Generate an embed token.
Copy the token immediately — the page shows it once at creation time; the plaintext isn't retrievable later. If you lose it, revoke and re-issue.
The same token grants access to the chat widget, the voice widget, and the avatar WebSocket — one credential, three surfaces.
3. Whitelist your customer origins#
Back on the Avatar page, paste your customer's origin into Allowed origins:
- Exact:
https://customer.example.com - Wildcard subdomain:
https://*.customer.example.com
Press Add. Repeat for staging, dev, kiosk hostnames, etc. The public WebSocket will reject connections from any browser origin not on this list — curl and non-browser clients (which don't send an Origin header) bypass it.
4. Connect from your client#
The wire protocol is fully documented in Avatar API reference. Minimal example to confirm the path works end-to-end:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | |
If you get text + base64 voice + a blendshapes array back, you're connected. The voice block is PCM ready to play; the blendshapes are an array of [timecode, c0, c1, ..., c67] per frame — feed them to your 3D model's morph target weights, synced to audio playback time.
To switch from "make the avatar say this text" to "have a conversation with the avatar", change the action to send_text:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
The server passes your text through the bot's LLM with its persona + the avatar-mode rules block (no Markdown, no "see the diagram" — the LLM knows it's being spoken aloud), synthesizes the reply, and emits a response chunk the same shape as text_to_speech. The conversation history persists against the session; get_history reads it back.
For voice input, send send_voice with base64-encoded PCM or WAV. The server transcribes via ScaiInfer STT, runs the same send_text pipeline on the transcript, and ships the reply. Set response_config.include_transcription=true to get "you said: …" back on the response chunk.
5. Drive the 3D model#
A barebones Three.js + GLTF skeleton. Note how the model URL comes from the avatar_update event the server pushes right after start_session — no hardcoded URL in the client code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
The morph target order on the head mesh has to match the ARKit ordering the lipsync engine emits — most VRM and ARKit-blendshape-equipped GLTF models do this by convention. If your model uses a custom order, build a one-time index map at load time.
Next steps#
- Tune the system prompt. Avatar mode rules are appended automatically — they teach the LLM not to use Markdown (TTS would read the asterisks aloud), not to reference visual artifacts that don't exist in speech, and to know it's being shown as a 3D avatar. Add an
avatar_system_prompton the bot to give it a custom personality on the avatar surface (separate from text and voice). - Customize the idle animation. Set the
avatar_idle_animationfield to the animation name your 3D model bundles for "not speaking" loops. The WebSocket only ships speaking-time blendshapes; idle motion is your client's responsibility. - Watch the sessions panel. Tenant admins can see active and recent avatar sessions on the Avatar Settings page. Use it for debug; for production observability the standard audit log applies.