<!-- AvatarFactory Docs · https://avatarfactory.in/docs/sdk/react-native/types · Full map: https://avatarfactory.in/llms.txt -->

# Types

Every type the SDK exports, in one place — for autocomplete and type-safe config.

## Importing types

Import any type directly from the package. Use `import type` for type-only imports.

```tsx
import type {
  AvatarConfig,
  AvatarMode,
  AvatarSpeech,
  AvatarVoiceSettings,
  AvatarEventMap,
  UseAvatarResult,
  LiveContextArgs,
} from "@avatarfactory/react-native";

// Runtime values
import { AvatarRuntimeState, AvatarErrorCode } from "@avatarfactory/react-native";
```

The types match the web SDK exactly, so code that works with config or speech data can be shared between your web and mobile projects.

## AvatarMode

The four operational modes. Passed as `mode` in `AvatarConfig`.

```tsx
type AvatarMode = "player" | "tts" | "audio" | "call";
```

## AvatarConfig

The configuration object for ``. For production authenticate with `getSessionToken`; `apiKey` (test keys only, `af_test_*`) is for local development.

```tsx
type AvatarConfig = AvatarConfigBase & {
  getSessionToken?: () => Promise<string>;
  apiKey?: string; // test keys only (af_test_*); dev only
};

type AvatarConfigBase = {
  // Session wiring
  mode?: AvatarMode;
  turnTaking?: TurnTakingConfig;
  controls?: { enabled: boolean; stopSpeaking?: boolean };
  perception?: { camera?: boolean };
  transcript?: TranscriptConfig;
  statusBanner?: StatusBannerConfig;
  connectTone?: ConnectToneConfig;   // `src` is ignored on React Native
  debug?: boolean;

  // Agent definition
  avatar: {
    avatarId: string;
    layout?: Record<string, string>;   // platform-agnostic layout pairs
    systemPrompt?: string;             // identity & instructions (call mode)
    brain?: AvatarBrain;
    voiceSettings?: AvatarVoiceSettings;
    languages?: AvatarLanguages;
    greeting?: GreetingConfig;
  };
};

type AvatarBrain = {
  provider: "openai" | "anthropic" | "groq" | (string & {});
  model?: string;
  useOwnBrain?: boolean;  // bill the model to your own vendor key
};

type TurnTakingConfig = {
  mode?: "auto" | "push-to-talk";  // default "auto"
  // `spacebar` exists on the type but has no meaning on mobile.
};

type GreetingConfig = {
  enabled: boolean;
  message?: string;   // omit for the built-in line
  language?: "en" | "es" | "fr" | "de" | "hi" | "ru" | "pt" | "ja" | "it";
};

type AvatarLanguages =
  | "auto"
  | Array<"en" | "es" | "fr" | "de" | "hi" | "ru" | "pt" | "ja" | "it" | "nl">;
```

> React Native ships no **thinking indicator**, so there is no
>   `thinkingIndicator` config — read `useAvatar().isResponseSlow` and render your
>   own. `connectTone.src` is accepted but ignored; mobile always uses the
>   built-in tone.

> On mobile, use `getSessionToken` for production — never ship a **live** key, since app bundles can be inspected. The `apiKey` method is for local development only and accepts **test keys** (`af_test_*`); live keys are rejected.

## AvatarVoiceSettings

Per-session voice tuning. All fields are optional. `visimeMs` sets the viseme grouping window — visemes within this many milliseconds are merged into one mouth shape; the rest are passed to the voice engine — see your voice provider's docs for valid ranges.

```tsx
type TtsProvider = "elevenlabs" | "inworld";

type AvatarVoiceSettings = {
  provider?: TtsProvider;   // which speech engine voices the avatar
  voiceId?: string;         // a specific voice on that provider
  useOwnVoice?: boolean;    // route speech through your own account
  visimeMs?: number;        // viseme grouping window (ms); default 40
  voiceSpeed?: number;      // passed to the voice engine
  voiceStability?: number;  // passed to the voice engine
  similarityBoost?: number; // passed to the voice engine
};
```

## Transcript types

```tsx
type CaptionPosition =
  | "top-left" | "top-center" | "top-right"
  | "bottom-left" | "bottom-center" | "bottom-right";

type TranscriptConfig = {
  enabled: boolean;
  captions?: boolean;         // default true
  position?: CaptionPosition; // default "bottom-center"
  maxEntries?: number;        // default 50
};

type TranscriptEntry = {
  id: string;
  speaker: "user" | "avatar";
  text: string;
  words: { text: string; start: number; end: number }[];
  isFinal: boolean;
  turnId: number;
  createdAt: number;
};
```

## Health and notices

```tsx
type HealthService = "ingest" | "stt" | "llm" | "tts" | "downlink";
type HealthState = "ok" | "degraded" | "failed";

type ConnectionHealth = {
  services: Record<HealthService, HealthState>;
  concern: {
    scope: "network" | "device" | "service";
    service: HealthService;
    state: "degraded" | "failed";
    code?: string;
  } | null;
};

// A graceful, server-initiated message — not an error. The avatar speaks it,
// then the session closes.
type SessionNotice = {
  kind: "demo" | "plan" | "test" | (string & {});
  action?: "add_key" | "upgrade" | (string & {});
  message: string;
};
```

## AvatarSpeech

A pre-made speech clip. Used in `play()`.

```tsx
type AvatarSpeech = {
  audioChunks: string[];              // base64-encoded audio segments
  alignments: NormalizedAlignment[];  // per-character timing for lip-sync
  isGreeting?: boolean;               // mark as a greeting clip
};
```

## NormalizedAlignment

Character-level timing data that drives the lip-sync animation engine.

```tsx
type NormalizedAlignment = {
  characters: string[];                    // Individual characters (["H","e","l","l","o"])
  character_start_times_seconds: number[]; // Start time of each character in seconds
  character_end_times_seconds: number[];   // End time of each character in seconds
};
```

> Arrays are parallel — `characters[i]` starts at `character_start_times_seconds[i]` and ends at `character_end_times_seconds[i]`.

## LiveContextArgs

Argument shape for `addLiveContext()` (call mode).

```tsx
type LiveContextArgs = {
  context: string;   // non-empty, max 2000 characters
  update?: boolean;  // whether to replace the previously submitted context
};
```

## AvatarError

The error type emitted by the SDK.

```tsx
type AvatarError = {
  // --- Branch on these ---
  code: AvatarErrorCode;
  fatal: boolean; // Is the session over?
  retryable: boolean; // Would calling start() again help?

  // --- Log these; don't render them ---
  message: string; // Written for you, not your users
  source: AvatarErrorSource;
  cause?: unknown;
};
```

See [Error Handling](/docs/sdk/react-native/error-handling) for how to use `fatal` and `retryable`.

## AvatarErrorCode

Grouped by **who fixes it** — the only distinction you can act on.

```tsx
type AvatarErrorCode =
  // Your integration — you fix these in your own code.
  | "SESSION_TOKEN_FETCH_FAILED"
  | "INVALID_MODE"
  | "INVALID_INPUT"
  | "NOT_CONNECTED"
  // Your user — they must act; retrying alone won't help.
  | "MIC_PERMISSION_DENIED"
  // The service — retry, or report to us.
  | "CONNECTION_FAILED"
  | "SERVER_ERROR"
  | "SERVER_CLOSE_REQUESTED"
  | "AVATAR_LOAD_FAILED"
  | "BRAIN_ERROR"
  // Expected lifecycle.
  | "SESSION_IDLE_TIMEOUT"
  // Nothing else fit.
  | "UNKNOWN";
```

> These are deliberately coarse: they split where the remedy splits, and nowhere else. Every transport failure is one `CONNECTION_FAILED` — which socket call failed is in `message` and `cause`, so it never costs you a branch.

## AvatarErrorSource

Where an error originated.

```tsx
type AvatarErrorSource = "network" | "server" | "sdk";
```

## Avatar props

The `` component accepts these props (defined inline by the component, not a named export):

```tsx
type CameraPreviewCorner =
  "top-left" | "top-right" | "bottom-left" | "bottom-right";

type AvatarProps = {
  style?: ViewStyle;               // from "react-native"
  loader?: React.ReactNode;        // custom loading element
  errorFallback?: React.ReactNode; // custom error element

  // Overlay styling hooks
  captionStyle?: ViewStyle;        // shown when transcript.captions is on
  statusBannerStyle?: ViewStyle;   // shown when statusBanner.enabled is on

  // Camera (perception.camera only)
  cameraPreviewCorner?: CameraPreviewCorner;  // default "bottom-right"
  hideCameraPreview?: boolean;     // discouraged — capture continues either way
};
```

> Native takes `ViewStyle`, not `className`, and has no picture-in-picture
>   layout or `fit` override — both are web-only.

## AvatarEventMap

The complete event map — keys are event names, values are handler signatures.

```tsx
interface AvatarEventMap {
  start:      () => void;
  stop:       () => void;
  interrupt:  () => void;
  speaking:   () => void;
  ready:      () => void;
  error:      (error: AvatarError) => void;
  notice:     (notice: SessionNotice) => void;
  transcript: (entries: TranscriptEntry[]) => void;
  health:     (health: ConnectionHealth) => void;
}
```

`transcript` only fires when `transcript.enabled` is set.

## UseAvatarResult

The complete return type of the `useAvatar` hook.

```tsx
interface UseAvatarResult {
  // --- Paint axis: is there an avatar on screen? ---
  isReady: boolean;
  isLoading: boolean;
  isFailed: boolean;

  // --- Session axis: is there a live call? ---
  isIdle: boolean;
  isConnecting: boolean;
  isConnected: boolean;

  // --- Turn state (only meaningful while connected) ---
  isListening: boolean;
  isThinking: boolean;
  isSpeaking: boolean;
  isResponseSlow: boolean;   // this turn is dragging — render your own hint

  // --- Mute ---
  isMicMuted: boolean;
  isSpeakerMuted: boolean;
  setMicMuted: (muted: boolean) => void;
  setSpeakerMuted: (muted: boolean) => void;

  // --- Push to talk ---
  isPushToTalk: boolean;
  isTalking: boolean;
  startTalking: () => void;
  stopTalking: () => void;

  // --- Session control ---
  start(): void;
  stop(): void;
  interrupt(): void;
  stopSpeaking(): void;

  // --- Mode-specific (undefined in wrong mode) ---
  play?(job: AvatarSpeech): void;
  speakText?(sentence: string): void;
  speakAudio?(audio: ArrayBuffer | Float32Array | Blob): void;
  addLiveContext?(args: LiveContextArgs): void;

  // --- Gestures ---
  triggerAction?: (name: string) => void;
  availableActions?: string[];

  // --- Live data ---
  error: AvatarError | null;
  notice?: SessionNotice | null;
  health?: ConnectionHealth;
  transcript?: TranscriptEntry[];
  avatarId?: string;
  controls: { enabled: boolean; stopSpeaking?: boolean };

  // --- Event subscription ---
  on<E extends keyof AvatarEventMap>(event: E, handler: AvatarEventMap[E]): void;
  off<E extends keyof AvatarEventMap>(event: E, handler: AvatarEventMap[E]): void;
}
```

> `play`, `speakText`, `speakAudio`, and `addLiveContext` are marked optional (`?`) because they return `undefined` in unsupported modes. Always use optional chaining: `speakText?.("hello")`.
