Skip to main content
AvatarKit UI is a shadcn-style React component package for embedding a SpatialReal avatar player into your app. It wraps AvatarKit RTC setup, LiveKit session wiring, loading and error states, and a small set of presentational primitives so you can ship an avatar surface with minimal glue code.

Usage

Use SpatialRealAvatarProvider to initialize AvatarKit and LiveKit, then compose the avatar surface with SpatialRealAvatarFrame, SpatialRealAvatarCanvas, SpatialRealAvatarLoading, SpatialRealAvatarError, and SpatialRealAvatarStatus.
import {
  SpatialRealAvatarCanvas,
  SpatialRealAvatarError,
  SpatialRealAvatarFrame,
  SpatialRealAvatarLoading,
  SpatialRealAvatarProvider,
  SpatialRealAvatarStatus,
} from '@/components/spatialreal-avatar'

export function AgentAvatar({ token, url, roomName }: {
  token: string
  url: string
  roomName: string
}) {
  return (
    <SpatialRealAvatarProvider
      appId={import.meta.env.VITE_SPATIALREAL_APP_ID}
      avatarId={import.meta.env.VITE_SPATIALREAL_AVATAR_ID}
      connection={{ token, url, roomName }}
    >
      <SpatialRealAvatarFrame className="overflow-hidden">
        <SpatialRealAvatarCanvas className="min-h-[520px]" />
        <SpatialRealAvatarLoading />
        <SpatialRealAvatarError />

        <div className="absolute inset-x-0 top-0 flex justify-end p-4">
          <SpatialRealAvatarStatus />
        </div>
      </SpatialRealAvatarFrame>
    </SpatialRealAvatarProvider>
  )
}
This is the same composition pattern used in the working Vite demo: an avatar frame for rendering, built-in overlays for loading and failure states, and context-driven controls for microphone and session UI.

Adding microphone controls with context

Use useSpatialRealAvatarContext() inside the provider tree when you want to drive UI from connection state or publish the local microphone into the avatar session.
import { useState } from 'react'

import {
  SpatialRealAvatarCanvas,
  SpatialRealAvatarError,
  SpatialRealAvatarFrame,
  SpatialRealAvatarLoading,
  SpatialRealAvatarProvider,
  SpatialRealAvatarStatus,
  useSpatialRealAvatarContext,
} from '@/components/spatialreal-avatar'

function AvatarPanel() {
  const avatar = useSpatialRealAvatarContext()
  const [pending, setPending] = useState(false)

  const toggleMicrophone = async () => {
    if (pending) return

    setPending(true)

    try {
      if (avatar.isPublishingMicrophone) {
        await avatar.stopPublishingMicrophone()
      } else {
        await avatar.startPublishingMicrophone()
      }
    } finally {
      setPending(false)
    }
  }

  return (
    <div className="grid gap-6 lg:grid-cols-[minmax(0,420px)_minmax(0,1fr)]">
      <section className="space-y-4">
        <SpatialRealAvatarFrame>
          <SpatialRealAvatarCanvas />
          <SpatialRealAvatarLoading />
          <SpatialRealAvatarError />
        </SpatialRealAvatarFrame>

        <div className="flex items-center justify-between rounded-2xl border p-3">
          <button
            disabled={!avatar.isConnected || pending}
            onClick={() => void toggleMicrophone()}
            type="button"
          >
            {avatar.isPublishingMicrophone ? 'Mute mic' : 'Enable mic'}
          </button>

          <SpatialRealAvatarStatus />
        </div>
      </section>

      <section className="rounded-3xl border p-4">
        {avatar.room
          ? 'Render your LiveKit transcript or agent UI here.'
          : 'Waiting for the LiveKit session to become available...'}
      </section>
    </div>
  )
}

export function VoiceAgentAvatar(props: {
  token: string
  url: string
  roomName: string
}) {
  return (
    <SpatialRealAvatarProvider
      appId={import.meta.env.VITE_SPATIALREAL_APP_ID}
      avatarId={import.meta.env.VITE_SPATIALREAL_AVATAR_ID}
      connection={props}
    >
      <AvatarPanel />
    </SpatialRealAvatarProvider>
  )
}
SpatialRealAvatarCanvas must render inside a container with non-zero width and height. The provider waits for the canvas container to be measurable before it starts loading the avatar.

Features

  • Render a SpatialReal avatar surface with a small set of composable shadcn-style primitives.
  • Connect AvatarKit and LiveKit through SpatialRealAvatarProvider without writing your own player wiring.
  • Show built-in loading, error, and connection status UI out of the box.
  • Access the active LiveKit room and avatar session state through useSpatialRealAvatarContext().
  • Start, stop, reconnect, disconnect, and publish microphone audio with hook-based controls.

Installation

AvatarKit UI is built on:
  • shadcn/ui conventions (local component files + Tailwind styles)
  • LiveKit Agent UI ecosystem (@livekit/components-react, @livekit/components-styles)
Before adding this AvatarKit UI component to your project, you can use this guide to setup shadcn
npx shadcn@latest init
npx shadcn@latest add https://ui.spatialreal.ai/r/spatialreal-avatar.json

API Reference

Exports

export {
  SpatialRealAvatarCanvas,
  SpatialRealAvatarError,
  SpatialRealAvatarFrame,
  SpatialRealAvatarLoading,
  SpatialRealAvatarProvider,
  SpatialRealAvatarStatus,
  useSpatialRealAvatar,
  useSpatialRealAvatarContext,
}

SpatialRealAvatarProvider

Initializes AvatarKit, connects the LiveKit-backed avatar stream, provides avatar state through React context, and renders remote room audio.
PropTypeDescription
childrenReactNodeProvider contents. All AvatarKit UI primitives that read context must be rendered inside this provider.
appIdstringYour AvatarKit app ID. Required.
avatarIdstringThe avatar identifier to load. Required.
connection{ roomName: string; token: string; url: string }LiveKit connection details for the avatar stream. Required.
enabledbooleanDefaults to true. When false, the provider does not initialize or connect the avatar.
publishMicrophonebooleanDefaults to false. When true, the provider starts publishing the local microphone after connection.
mutedbooleanMutes audio rendered by RoomAudioRenderer.
volumenumberPlayback volume passed to RoomAudioRenderer.
characterApiBaseUrlstringOptional override for the AvatarKit character API base URL.
drivingServiceModeDrivingServiceModeAvatarKit driving mode. Defaults to DrivingServiceMode.host.
environmentEnvironmentAvatarKit environment. Defaults to Environment.intl.
sdkLogLevelLogLevelAvatarKit SDK log level.
sessionTokenstringOptional AvatarKit session token to inject into AvatarSDK.
userIdstringOptional end-user identifier passed to AvatarSDK.setUserId().
playerOptionsAvatarPlayerOptionsOptions forwarded to AvatarPlayer.
onConnected(room: Room | null) => voidCalled once the avatar player connects and the LiveKit room is available.
onDisconnected() => voidCalled when the avatar player disconnects unexpectedly or returns to idle.
onAvatarError(error: Error) => voidCalled whenever avatar initialization, connection, reconnect, or microphone publishing fails.
onLoadProgress(progress: LoadProgressInfo) => voidReports avatar asset download progress from AvatarManager.shared.load().
onStateChange(status: SpatialRealAvatarConnectionStatus) => voidCalled whenever connection status changes.
onDisconnect() => voidCalled after session.end() or avatar.disconnect() completes through the provider session wrapper.

SpatialRealAvatarFrame

Visual wrapper for the avatar canvas and overlays.
PropTypeDescription
tone'default' | 'muted' | 'ghost'Visual treatment for the frame background. Defaults to 'default'.
classNamestringAdditional classes for layout and styling.
...propsHTMLAttributes<HTMLDivElement>Standard div attributes such as id, style, and event handlers.

SpatialRealAvatarCanvas

Mount target for AvatarView. The rendered avatar appears inside this div.
PropTypeDescription
minHeightCSSProperties['minHeight']Minimum canvas height. Defaults to 420.
classNamestringAdditional classes for sizing and styling.
...propsHTMLAttributes<HTMLDivElement>Standard div attributes forwarded to the canvas container.

SpatialRealAvatarLoading

Loading overlay shown while the avatar is initializing or connecting.
PropTypeDescription
childrenReactNodeOptional custom loading UI. When omitted, the default card shows current status and asset download progress.
classNamestringAdditional classes for the overlay container.
...propsHTMLAttributes<HTMLDivElement>Standard div attributes forwarded to the overlay container.

SpatialRealAvatarError

Error overlay shown when avatar setup or streaming fails.
PropTypeDescription
childrenReactNodeOptional custom error UI. When omitted, the default card displays error.message.
classNamestringAdditional classes for the overlay container.
...propsHTMLAttributes<HTMLDivElement>Standard div attributes forwarded to the overlay container.

SpatialRealAvatarStatus

Small status badge for the current avatar connection state.
PropTypeDescription
classNamestringAdditional classes for the badge.
...propsHTMLAttributes<HTMLDivElement>Standard div attributes forwarded to the badge wrapper.
Supported status labels:
  • idle
  • initializing
  • connecting
  • connected
  • disconnecting
  • error

useSpatialRealAvatar(options)

Low-level hook that powers the provider. Use it when you want to wire AvatarKit into your own context or compose a custom provider.

Options

useSpatialRealAvatar() accepts the same connection and SDK props as SpatialRealAvatarProvider, except for children, muted, volume, and onDisconnect.
const avatar = useSpatialRealAvatar({
  appId,
  avatarId,
  connection: {
    roomName,
    token,
    url,
  },
  publishMicrophone: false,
})

Return value

FieldTypeDescription
statusSpatialRealAvatarConnectionStatusCurrent lifecycle state.
isLoadingbooleantrue while status is initializing or connecting.
isConnectedbooleantrue when the avatar player is connected.
errorError | nullThe most recent connection or runtime error.
downloadProgressnumber | nullAsset download progress from 0 to 1, or null when unavailable.
isPublishingMicrophonebooleanIndicates whether the local microphone track is currently published.
micTrackTrack | undefinedThe published local microphone track, when available.
roomRoom | nullLiveKit room instance backing the avatar session.
connectionSpatialRealAvatarConnectionThe current connection config passed into the hook.
containerRef(node: HTMLDivElement | null) => voidRef callback that must be attached to the avatar canvas element.
sessionUseSessionReturnSession object from @livekit/components-react, with end() mapped to disconnect().
disconnect()() => Promise<void>Disconnects the avatar stream and resets state to idle.
reconnect()() => Promise<void>Attempts to reconnect the existing avatar player.
startPublishingMicrophone()() => Promise<void>Publishes the local microphone into the avatar session.
stopPublishingMicrophone()() => Promise<void>Stops microphone publishing.

useSpatialRealAvatarContext()

Returns the current avatar state from SpatialRealAvatarProvider.
const avatar = useSpatialRealAvatarContext()
Use this hook inside provider children to:
  • show or hide UI based on avatar.status
  • read the connected avatar.room for LiveKit chat and transcript components
  • call avatar.startPublishingMicrophone() and avatar.stopPublishingMicrophone()
  • invoke avatar.disconnect() or avatar.reconnect() from your own controls
useSpatialRealAvatarContext() throws an error if it is used outside SpatialRealAvatarProvider.