npm package: @mascotte/avatar-sdk
Description: Official SDK for Mascotte Avatar - Embed AI-powered talking avatars in your applications
Author: Mascotte Labs
Latest version: 1.2.3

# Mascotte Avatar SDK

Official SDK for embedding AI-powered talking avatars in your applications.

## Table of Contents

- [Installation](#installation)
- [Quick Start](#quick-start)
- [Authentication](#authentication)
- [Discovering Avatars](#discovering-avatars)
- [Customization](#customization)
- [API Reference](#api-reference)
- [Credit System](#credit-system)
- [Webpack Configuration](#webpack-configuration)
- [Troubleshooting](#troubleshooting)

---

## Installation

```bash
npm install @mascotte/avatar-sdk
```

---

## Quick Start

### React Component

The simplest way to embed an avatar:

```tsx
import { MascotteAvatar } from "@mascotte/avatar-sdk";

function App() {
  return (
    <div style={{ width: "640px", height: "480px" }}>
      <MascotteAvatar
        mascotteApiKey="mk_live_xxxxx"
        avatarId={42}
        onReady={() => console.log("Avatar ready!")}
        onMessage={(msg) => console.log("AI response:", msg.content)}
      />
    </div>
  );
}
```

### With Ref Controls

Access avatar methods programmatically:

```tsx
import { useRef } from "react";
import { MascotteAvatar, MascotteAvatarRef } from "@mascotte/avatar-sdk";

function App() {
  const avatarRef = useRef<MascotteAvatarRef>(null);

  return (
    <div>
      <div style={{ width: "640px", height: "480px" }}>
        <MascotteAvatar
          ref={avatarRef}
          mascotteApiKey="mk_live_xxxxx"
          avatarId={42}
        />
      </div>

      <button onClick={() => avatarRef.current?.speak("Hello!")}>
        Make Avatar Speak
      </button>

      <button onClick={() => avatarRef.current?.sendMessage("Tell me a joke")}>
        Ask AI
      </button>
    </div>
  );
}
```

### Using the Hook

For more control over state and lifecycle:

```tsx
import { useMascotte } from "@mascotte/avatar-sdk";

function App() {
  const {
    containerRef,
    speak,
    sendMessage,
    isReady,
    isSpeaking,
    messages,
    state,
  } = useMascotte({
    mascotteApiKey: "mk_live_xxxxx",
    avatarId: 42,
  });

  return (
    <div>
      <div ref={containerRef} style={{ width: 640, height: 480 }} />

      <p>Status: {state} | Ready: {isReady ? "Yes" : "No"}</p>

      <button onClick={() => speak("Hello!")} disabled={!isReady}>
        Speak
      </button>

      <div>
        {messages.map((msg, i) => (
          <p key={i}><strong>{msg.type}:</strong> {msg.content}</p>
        ))}
      </div>
    </div>
  );
}
```

### Vanilla JavaScript

Use without React:

```html
<div id="avatar-container" style="width: 640px; height: 480px;"></div>

<script type="module">
  import { createMascotteClient } from "@mascotte/avatar-sdk";

  const client = createMascotteClient(
    {
      mascotteApiKey: "mk_live_xxxxx",
      avatarId: 42,
    },
    {
      onReady: () => {
        console.log("Avatar ready!");
        client.speak("Hello! Welcome to our website.");
      },
      onMessage: (msg) => console.log("AI:", msg.content),
      onError: (error) => console.error("Error:", error),
    }
  );

  const container = document.getElementById("avatar-container");
  client.connect(container);
</script>
```

---

## Authentication

### Getting Your Credentials

1. **API Key** (`mascotteApiKey`): Generate from Mascotte dashboard → Developers → API Keys tab. One key per account.
2. **Avatar ID** (`avatarId`): The ID of the avatar to load. Discover available avatars using `MascotteClient.listAvatars()`.

### Usage

```tsx
<MascotteAvatar
  mascotteApiKey="mk_live_xxxxx"  // Your account API key
  avatarId={42}                    // Which avatar to load
/>
```

All usage is billed to the API key owner's account.

### Optional: External User ID

Track usage per end-user in your own system:

```tsx
<MascotteAvatar
  mascotteApiKey="mk_live_xxxxx"
  avatarId={42}
  externalUserId="user_12345"  // Your own user identifier for analytics
/>
```

---

## Discovering Avatars

List all avatars available on your account:

```tsx
import { MascotteClient } from "@mascotte/avatar-sdk";

// Returns array of { id, name, thumbnail, shareId }
const avatars = await MascotteClient.listAvatars("mk_live_xxxxx");
console.log(avatars);
// [
//   { id: 42, name: "Sales Rep", thumbnail: "https://...", shareId: "abc123" },
//   { id: 55, name: "Support Agent", thumbnail: null, shareId: "def456" },
// ]
```

Use the `id` from the result as the `avatarId` prop.

---

## Customization

### Available Options

| Type | Options |
|------|---------|
| **Voices** | `Samantha`, `Richard`, `Emily`, `John`, `Puck` |
| **Hairs** | `Hair_Male_01`, `Hair_Male_03`, `Hair_Wavy_02`, `Hair_Straight_02`, `Pixie_cut` |
| **Avatars** | `Xiao`, `Achaya`, `African_Male`, `Asian_Female`, `Lu`, `Alex`, `Caucasian_Male` |

### Get Options Programmatically

```tsx
import { MascotteClient } from "@mascotte/avatar-sdk";

// Returns array of { name, gender } objects
MascotteClient.getAvailableVoices();

// Returns array of { name, style } objects
MascotteClient.getAvailableHairs();

// Returns array of { name, template, gender } objects
MascotteClient.getAvailableAvatars();
```

### Initial Configuration

Set customization when creating the avatar:

```tsx
<MascotteAvatar
  mascotteApiKey="mk_live_xxxxx"
  avatarId={42}
  customization={{
    voice: "Samantha",
    hair: "Hair_Wavy_02",
    avatar: "Xiao",
  }}
/>
```

### Runtime Changes

Change appearance after avatar is loaded:

```tsx
const avatarRef = useRef<MascotteAvatarRef>(null);

// Change voice
avatarRef.current?.setVoice("Richard");

// Change hair style
avatarRef.current?.setHair("Pixie_cut");

// Change avatar template
avatarRef.current?.setAvatar("Alex");
```

### Voice Configuration (Advanced)

#### Google Cloud Voices

```tsx
<MascotteAvatar
  mascotteApiKey="mk_live_xxxxx"
  avatarId={42}
  voice={{
    language: "en-US",
    voiceId: "en-GB-Chirp3-HD-Charon",
  }}
/>
```

#### ElevenLabs Custom Voices

```tsx
<MascotteAvatar
  mascotteApiKey="mk_live_xxxxx"
  avatarId={42}
  voice={{
    provider: "elevenlabs",
    elevenlabs: {
      apiKey: "YOUR_ELEVENLABS_KEY",
      voiceId: "YOUR_VOICE_ID",
    },
  }}
/>
```

---

## API Reference

### Component Props

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `mascotteApiKey` | `string` | Yes | API key from Mascotte dashboard |
| `avatarId` | `string \| number` | Yes | ID of the avatar to load |
| `externalUserId` | `string` | No | Your own user identifier for analytics |
| `customization` | `CustomizationConfig` | No | Initial voice/hair/avatar settings |
| `voice` | `VoiceConfig` | No | Voice configuration |
| `camera` | `CameraConfig` | No | Camera configuration |
| `showLoading` | `boolean` | No | Show loading indicator (default: true) |
| `debug` | `boolean` | No | Enable debug logging (default: false) |

### Event Callbacks

| Callback | Parameters | Description |
|----------|------------|-------------|
| `onConnect` | - | Connection established |
| `onDisconnect` | `reason?: string` | Connection lost |
| `onReady` | - | Avatar loaded and ready for commands |
| `onMessage` | `message: AvatarMessage` | Received AI response |
| `onSpeakStart` | `text: string` | Avatar started speaking |
| `onSpeakEnd` | - | Avatar finished speaking |
| `onError` | `error: MascotteError` | Error occurred |
| `onStateChange` | `state: ConnectionState` | Connection state changed |
| `onSessionStart` | `session: SDKSessionInfo` | SDK session started |
| `onSessionEnd` | `{ totalSeconds, creditsUsed }` | SDK session ended |
| `onCreditUpdate` | `status: CreditStatus` | Credit balance updated |
| `onLowCredits` | `balance: number` | Credits running low |

### Ref Methods

| Method | Parameters | Description |
|--------|------------|-------------|
| `speak` | `text: string` | Make avatar speak text |
| `sendMessage` | `message: string` | Send message to AI for response |
| `stopSpeaking` | - | Stop current speech |
| `setCamera` | `'head' \| 'torso' \| 'body'` | Change camera view |
| `setVoice` | `voiceName: string` | Change voice |
| `setHair` | `hairName: string` | Change hair style |
| `setAvatar` | `avatarName: string` | Change avatar template |
| `sendCommand` | `command: AvatarCommand` | Send raw command |
| `getState` | - | Get current connection state |
| `isReady` | - | Check if avatar is ready |
| `getSessionInfo` | - | Get session info |
| `getCreditStatus` | - | Get credit status |
| `reconnect` | - | Reconnect to avatar |
| `disconnect` | - | Disconnect from avatar |

### Static Methods

| Method | Parameters | Description |
|--------|------------|-------------|
| `MascotteClient.listAvatars` | `apiKey: string, backendUrl?: string` | List avatars available for your account |
| `MascotteClient.getAvailableVoices` | - | Get available voice options |
| `MascotteClient.getAvailableHairs` | - | Get available hair options |
| `MascotteClient.getAvailableAvatars` | - | Get available avatar templates |

### Connection States

| State | Description |
|-------|-------------|
| `disconnected` | Not connected |
| `connecting` | Establishing connection |
| `connected` | Connected, loading avatar |
| `ready` | Avatar loaded, ready for commands |
| `error` | Error occurred |
| `reconnecting` | Attempting to reconnect |

---

## Credit System

### How It Works

- **1 credit = 10 seconds** of streaming (6 credits per minute)
- Credits are deducted from the **API key owner's account**
- Tracking starts automatically when SDK connects
- Session ends automatically when credits are exhausted

### Monitoring Credits

```tsx
<MascotteAvatar
  mascotteApiKey="mk_live_xxxxx"
  avatarId={42}
  onSessionStart={(session) => {
    console.log("Session started:", session.sessionId);
    console.log("Initial balance:", session.creditBalance);
  }}
  onCreditUpdate={(status) => {
    console.log("Balance:", status.balance);
    console.log("Used this session:", status.sessionCreditsUsed);
  }}
  onLowCredits={(balance) => {
    alert(`Warning: Only ${balance} credits remaining!`);
  }}
  onError={(error) => {
    if (error.code === "INSUFFICIENT_CREDITS") {
      alert("Session ended: No credits remaining");
    }
  }}
/>
```

### Credit Status Object

```typescript
interface CreditStatus {
  balance: number;           // Current credit balance
  sessionSeconds: number;    // Seconds used in this session
  sessionCreditsUsed: number; // Credits used in this session
  lowCreditsWarning: boolean; // True when balance is low
}
```

---

## Webpack Configuration

### Next.js

```javascript
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: [
    "@arcware-cloud/pixelstreaming-websdk",
    "@mascotte/avatar-sdk",
  ],
  webpack: (config, { isServer }) => {
    if (isServer) {
      config.externals = config.externals || [];
      config.externals.push("@arcware-cloud/pixelstreaming-websdk");
    }
    config.module.rules.push({
      test: /\.m?js$/,
      type: "javascript/auto",
      resolve: { fullySpecified: false },
    });
    return config;
  },
};

module.exports = nextConfig;
```

## Troubleshooting

### "Module parse failed" Error

```
Module parse failed: 'import' and 'export' may appear only with 'sourceType: module'
```

**Solution:** Configure your bundler to handle ES modules. See [Webpack Configuration](#webpack-configuration).

### Avatar Not Loading

1. Verify `mascotteApiKey` is valid and not revoked
2. Verify `avatarId` belongs to your account (use `MascotteClient.listAvatars()` to check)
3. Check you have sufficient credits
4. Check browser console for detailed errors

### Connection Timeout

```tsx
<MascotteAvatar
  onError={(error) => {
    if (error.code === "TIMEOUT") {
      // Show retry option to user
    }
  }}
/>
```

### Source Map Warnings

Warnings about missing source maps from `@arcware-cloud` are harmless. The CRACO config above suppresses them.

---

## Migration from v1.1.x

If you were using `userToken` for authentication, here's what changed:

```diff
  <MascotteAvatar
    mascotteApiKey="mk_live_xxxxx"
-   userToken="consumer_jwt_token"
+   avatarId={42}
  />
```

**Key changes:**
- `userToken` is **deprecated** (still works but will be removed in a future major version)
- `avatarId` is now **required** — specifies which avatar to load at runtime
- All usage is billed to the API key owner (no separate consumer billing)
- Use `externalUserId` if you need to track per-user analytics
- Use `MascotteClient.listAvatars(apiKey)` to discover available avatars

---

## TypeScript

Full TypeScript support is included:

```typescript
import type {
  MascotteConfig,
  MascotteAvatarProps,
  CustomizationConfig,
  VoiceConfig,
  CameraConfig,
  SDKVoiceOption,
  SDKHairOption,
  SDKAvatarTemplate,
  SDKAvatarInfo,
  SDKSessionInfo,
  CreditStatus,
  AvatarMessage,
  ConnectionState,
  MascotteError,
  ErrorCode,
} from "@mascotte/avatar-sdk";
```

---

## Browser Support

- Chrome 70+
- Firefox 65+
- Safari 12+
- Edge 79+

---

## Support

- Email: support@mascotte.ai