Web / TypeScript SDK
The Web SDK is the browser-native path — pure TypeScript, no Flutter runtime. Pick the package shape that matches your stack:
@twai/core— the engine. Pure TS, no UI. Pair with your own rendering.@twai/player— the player facade. Owns a<video>element + the LiveKit room.@twai/mic— browser mic capture + STT. Opt-in.@twai/react— React hooks + components for the above.@twai/web-component— drop-in<twai-avatar>Custom Element. See Web Component.
Repo: 2waiorg/twai-web-sdk
Reference app: samples/nextjs in the toolkit.
Install
Section titled “Install”# React appnpm install @twai/core @twai/player @twai/react
# Vanilla JSnpm install @twai/core @twai/playerMinimum React integration
Section titled “Minimum React integration”import { useTwaiSession } from '@twai/react';
export function AvatarScreen() { const { videoRef, send, state } = useTwaiSession({ mintUrl: '/api/mint', // your mint proxy route avatarId: 'avt_...', voiceId: 'vc_...', });
return ( <> <video ref={videoRef} autoPlay playsInline /> {state === 'ready' && ( <button onClick={() => send('Hi!')}>Say hi</button> )} </> );}The hook calls /api/mint (your mint proxy), joins the LiveKit room, subscribes the agent tracks, attaches them to the <video> ref. send(text) publishes a user_text envelope on the lk.chat data-channel topic. state is one of connecting | ready | speaking | rateLimited | failed | disconnected.
Vanilla TypeScript (no React)
Section titled “Vanilla TypeScript (no React)”import { createEngine } from '@twai/core';import { createPlayer } from '@twai/player';
const engine = createEngine({ mintUrl: '/api/mint', avatarId: 'avt_...', voiceId: 'vc_...',});
const videoEl = document.getElementById('avatar') as HTMLVideoElement;const player = createPlayer({ engine, videoElement: videoEl });
await player.connect();await player.send('Hi!');Mint proxy — Next.js Route Handler
Section titled “Mint proxy — Next.js Route Handler”Your mint proxy is a trivial route-handler. See the Node tab in Reference integration for the exact code — the SDK calls it via the mintUrl option.
Resolve by handle (catalog hydrate)
Section titled “Resolve by handle (catalog hydrate)”import { createClient } from '@twai/core';
const client = createClient({ mintUrl: '/api/mint' });const { avatar } = await client.avatars.get('alman', 'dr-alman');console.log(avatar.displayName, avatar.avatarId);Mic input
Section titled “Mic input”import { createMic } from '@twai/mic';
const mic = createMic();await mic.start({ onTranscript: (text) => player.send(text) });Browser SpeechRecognition on Chrome/Edge/Safari 14.5+. For a server-hosted STT (Whisper etc.), configure transcribeUrl on the mic options.