> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spatialreal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API Reference

> Complete API documentation for AvatarKit Web SDK

## Quick Reference

| Class              | Purpose            | Key Methods                                   |
| ------------------ | ------------------ | --------------------------------------------- |
| `AvatarSDK`        | SDK initialization | `initialize()`, `setSessionToken()`           |
| `AvatarManager`    | Avatar loading     | `load()`                                      |
| `AvatarView`       | 3D rendering       | `onFirstRendering`, `dispose()`               |
| `AvatarController` | Communication      | `start()`, `send()`, `pause()`, `interrupt()` |

<Warning>
  **Important:** App ID and Session Token are paired and must be used together. Each App ID corresponds to a specific list of avatars that can be driven. You must obtain both App ID and Session Token from the [SpatialReal Studio](https://app.spatialreal.ai).
</Warning>

```typescript theme={null}
export class AvatarSDK
```

***

## AvatarSDK

Main entry point for SDK initialization and global configuration.

```typescript theme={null}
import { AvatarSDK, Environment } from '@spatialwalk/avatarkit'
```

### Static Properties

| Property        | Type             | Description                |
| --------------- | ---------------- | -------------------------- |
| `isInitialized` | `boolean`        | Whether SDK is initialized |
| `appId`         | `string \| null` | Current App ID             |
| `configuration` | `Configuration`  | Current SDK configuration  |
| `sessionToken`  | `string \| null` | Current session token      |
| `userId`        | `string \| null` | Current user ID            |
| `version`       | `string`         | SDK version                |

### Static Methods

#### initialize(appId, configuration)

Initialize the SDK. Must be called before any other operations.

```typescript theme={null}
await AvatarSDK.initialize('your-app-id', {
  environment: Environment.cn,  // or Environment.intl
  drivingServiceMode: DrivingServiceMode.sdk,  // Optional, default: sdk
  logLevel: LogLevel.warning,  // Optional, default: off
  audioFormat: {  // Optional
    channelCount: 1,
    sampleRate: 16000,
  },
})
```

#### setSessionToken(token)

Set session token for authentication. **Only required for SDK Mode** (server-driven animation).

```typescript theme={null}
AvatarSDK.setSessionToken('your-session-token')
```

**Important:**

* **Only needed for SDK Mode** - not required for Host Mode or RTC Mode
* Token must be obtained from your backend server
* Token has max 24 hours validity
* Token must be paired with App ID

#### setUserId(userId)

Set user ID for logging and analytics.

```typescript theme={null}
AvatarSDK.setUserId('user-123')
```

#### cleanup()

Release all SDK resources. Call when SDK is no longer needed.

```typescript theme={null}
AvatarSDK.cleanup()
```

***

## AvatarManager

Handles avatar loading and caching.

```typescript theme={null}
import { AvatarManager } from '@spatialwalk/avatarkit'
```

### Static Properties

| Property | Type            | Description        |
| -------- | --------------- | ------------------ |
| `shared` | `AvatarManager` | Singleton instance |

### Instance Methods

#### load(id, onProgress?)

Load an avatar by ID.

```typescript theme={null}
const avatar = await AvatarManager.shared.load('avatar-id', (progress) => {
  switch (progress.type) {
    case 'downloading':
      console.log(`Loading: ${progress.progress}%`)
      break
    case 'completed':
      console.log('Load complete')
      break
    case 'failed':
      console.error('Load failed:', progress.error)
      break
  }
})
```

**Parameters:**

| Parameter    | Type                                   | Description       |
| ------------ | -------------------------------------- | ----------------- |
| `id`         | `string`                               | Avatar ID         |
| `onProgress` | `(progress: LoadProgressInfo) => void` | Progress callback |

**Returns:** `Promise<Avatar | null>`

#### clearAll()

Clear all cached avatar resources.

```typescript theme={null}
AvatarManager.shared.clearAll()
```

***

## AvatarView

3D rendering view that displays the avatar.

```typescript theme={null}
import { AvatarView } from '@spatialwalk/avatarkit'
```

### Constructor

```typescript theme={null}
const avatarView = new AvatarView(avatar, container)
```

| Parameter   | Type          | Description                                     |
| ----------- | ------------- | ----------------------------------------------- |
| `avatar`    | `Avatar`      | Loaded avatar object                            |
| `container` | `HTMLElement` | Container element (canvas auto-fills container) |

<Warning>
  **⚠️ Important:** The container element MUST have non-zero width and height. The canvas will automatically fill the container size.
</Warning>

### Instance Properties

| Property           | Type               | Description                       |
| ------------------ | ------------------ | --------------------------------- |
| `controller`       | `AvatarController` | Communication controller          |
| `onFirstRendering` | `() => void`       | Callback when first frame renders |
| `avatarTransform`  | `{ x, y, scale }`  | Avatar position and scale         |

### Instance Methods

#### dispose()

Clean up view resources. Call when view is no longer needed.

```typescript theme={null}
avatarView.dispose()
```

***

## AvatarController

Handles real-time communication with the avatar service.

```typescript theme={null}
// Accessed via AvatarView
const controller = avatarView.controller
```

### Instance Properties

| Property            | Type                | Description                |
| ------------------- | ------------------- | -------------------------- |
| `connectionState`   | `ConnectionState`   | Current connection state   |
| `conversationState` | `ConversationState` | Current conversation state |

### Event Callbacks

```typescript theme={null}
// Connection state changes
controller.onConnectionState = (state: ConnectionState) => {
  // 'disconnected' | 'connecting' | 'connected' | 'failed'
}

// Conversation state changes
controller.onConversationState = (state: ConversationState) => {
  // 'idle' | 'playing' | 'pausing'
}

// Error handling
controller.onError = (error: AvatarError) => {
  console.error('Error:', error.code, error.message)
}
```

### Instance Methods

#### initializeAudioContext()

Initialize audio context. **MUST be called in user gesture context.**

```typescript theme={null}
button.addEventListener('click', async () => {
  await controller.initializeAudioContext()
})
```

#### start()

Connect to the avatar service. SDK mode only.

```typescript theme={null}
await controller.start()
```

#### send(audioData, end)

Send audio data to server. SDK mode only.

```typescript theme={null}
// Send audio data (continue)
controller.send(audioData, false)

// Send final audio data (end conversation)
controller.send(audioData, true)
```

| Parameter   | Type          | Description                                                                       |
| ----------- | ------------- | --------------------------------------------------------------------------------- |
| `audioData` | `ArrayBuffer` | PCM16 (S16LE) mono audio data. Byte length **must** be even (2 bytes per sample). |
| `end`       | `boolean`     | Whether this is the final chunk                                                   |

<Warning>
  Audio data byte length must be even (2 bytes per sample). Odd-length data will cause a server-side validation error and WebSocket disconnect.
</Warning>

**Returns:** `string` - Conversation ID

#### close()

Close service connection. SDK mode only.

```typescript theme={null}
controller.close()
```

### Host Mode Methods

For Host Mode (`DrivingServiceMode.host`) only:

#### yieldAudioData(audioData, end)

Provide audio data in Host Mode.

```typescript theme={null}
const conversationId = controller.yieldAudioData(audioData, false)
```

#### yieldFramesData(frames, conversationId)

Provide animation frames in Host Mode.

```typescript theme={null}
controller.yieldFramesData(animationDataArray, conversationId)
```

### Common Methods (Both Modes)

#### pause()

Pause current playback.

```typescript theme={null}
controller.pause()
```

#### resume()

Resume paused playback.

```typescript theme={null}
await controller.resume()
```

#### interrupt()

Interrupt current playback and clear data.

```typescript theme={null}
controller.interrupt()
```

#### clear()

Clear all data and resources.

```typescript theme={null}
controller.clear()
```

#### getCurrentConversationId()

Get the current active conversation ID.

```typescript theme={null}
const conversationId = controller.getCurrentConversationId()
// Returns: string | null
```

#### volume

Playback volume property (avatar audio only, not system volume). Range: 0.0 to 1.0.

```typescript theme={null}
controller.volume = 0.5              // Set to 50%
const currentVolume = controller.volume  // Get current volume
```

***

## Types and Enums

### Configuration

```typescript theme={null}
interface Configuration {
  environment: Environment
  drivingServiceMode?: DrivingServiceMode  // Default: 'sdk'
  logLevel?: LogLevel                       // Default: 'off'
  audioFormat?: AudioFormat                 // Default: { channelCount: 1, sampleRate: 16000 }
}
```

### Environment

```typescript theme={null}
enum Environment {
  cn = 'cn',      // China region
  intl = 'intl'   // International region
}
```

### DrivingServiceMode

```typescript theme={null}
enum DrivingServiceMode {
  sdk = 'sdk',    // SDK handles WebSocket communication
  host = 'host'   // Host provides audio and animation data
}
```

### LogLevel

```typescript theme={null}
enum LogLevel {
  off = 'off',
  error = 'error',
  warning = 'warning',
  all = 'all'
}
```

### ConnectionState

```typescript theme={null}
enum ConnectionState {
  disconnected = 'disconnected',
  connecting = 'connecting',
  connected = 'connected',
  failed = 'failed'
}
```

### ConversationState

```typescript theme={null}
enum ConversationState {
  idle = 'idle',        // Breathing animation
  playing = 'playing',  // Active conversation
  paused = 'paused'     // Paused during playback
}
```

### LoadProgressInfo

```typescript theme={null}
type LoadProgressInfo = {
  type: 'downloading' | 'completed' | 'failed'
  progress?: number  // 0-100
  error?: Error
}
```

### AudioFormat

```typescript theme={null}
interface AudioFormat {
  channelCount: 1  // Fixed to mono
  sampleRate: number  // 8000 | 16000 | 22050 | 24000 | 32000 | 44100 | 48000
}
```

***

## Error Codes

| Code                           | Description                                 | Recovery                                                         |
| ------------------------------ | ------------------------------------------- | ---------------------------------------------------------------- |
| `appIDUnrecognized`            | App ID not recognized.                      | Verify your app ID in the dashboard.                             |
| `sessionTokenInvalid`          | Session token is invalid or appId mismatch. | Verify token generation on your server.                          |
| `sessionTokenExpired`          | Session token has expired.                  | Request a new token from your server.                            |
| `insufficientBalance`          | Account balance is insufficient.            | Top up your account in the dashboard.                            |
| `sessionTimeout`               | Session timed out.                          | Reconnect by calling `start()` again.                            |
| `concurrentLimitExceeded`      | Concurrent connection limit exceeded.       | Close other active sessions.                                     |
| `avatarIDUnrecognized`         | Avatar ID not found.                        | Check the avatar ID exists and is published.                     |
| `failedToFetchAvatarMetadata`  | Failed to fetch avatar metadata.            | Check network connectivity and retry.                            |
| `failedToDownloadAvatarAssets` | Failed to download avatar assets.           | Check network connectivity and retry.                            |
| `websocketError`               | WebSocket connection error.                 | Check network and retry.                                         |
| `websocketClosedAbnormally`    | WebSocket closed abnormally.                | Retry connection.                                                |
| `serverError`                  | Server-side error.                          | Check the error message for details.                             |
| `audioContextNotInitialized`   | Audio context not initialized.              | Call `initializeAudioContext()` in a user gesture handler first. |

***

## Complete Usage Example

```typescript theme={null}
import {
  AvatarSDK,
  AvatarManager,
  AvatarView,
  Environment,
  ConnectionState,
  ConversationState,
} from '@spatialwalk/avatarkit'

class AvatarApp {
  private avatarView: AvatarView | null = null

  async init(appId: string, sessionToken: string, avatarId: string, container: HTMLElement) {
    // Initialize SDK
    await AvatarSDK.initialize(appId, { environment: Environment.cn })
    AvatarSDK.setSessionToken(sessionToken)

    // Load avatar
    const avatar = await AvatarManager.shared.load(avatarId)
    if (!avatar) throw new Error('Failed to load avatar')

    // Create view
    this.avatarView = new AvatarView(avatar, container)
    this.avatarView.onFirstRendering = () => {
      console.log('First frame rendered')
    }

    // Set up handlers
    this.avatarView.controller.onConnectionState = (state) => {
      console.log('Connection:', state)
    }
    this.avatarView.controller.onConversationState = (state) => {
      console.log('Conversation:', state)
    }
    this.avatarView.controller.onError = (error) => {
      console.error('Error:', error)
    }
  }

  // Must be called in user gesture context
  async start() {
    await this.avatarView?.controller.initializeAudioContext()
    await this.avatarView?.controller.start()
  }

  send(audioData: ArrayBuffer, isEnd: boolean) {
    this.avatarView?.controller.send(audioData, isEnd)
  }

  interrupt() {
    this.avatarView?.controller.interrupt()
  }

  dispose() {
    this.avatarView?.controller.close()
    this.avatarView?.dispose()
    this.avatarView = null
  }
}
```
