@touchcastllc/napster-companion-api 1.0.0-alpha.4 → 1.0.0-alpha.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +704 -683
  2. package/lib/components/Avatar/index.d.ts +35 -2
  3. package/lib/components/Embed/index.d.ts +25 -2
  4. package/lib/components/InactiveOverlay/index.d.ts +15 -2
  5. package/lib/components/Preview/index.d.ts +18 -2
  6. package/lib/components/StyledTooltip/index.d.ts +16 -2
  7. package/lib/components/VolumeControl/index.d.ts +18 -0
  8. package/lib/components/WaveForm/index.d.ts +19 -2
  9. package/lib/components/index.d.ts +2 -3
  10. package/lib/constants/events.d.ts +52 -0
  11. package/lib/constants/greenscreen.d.ts +28 -0
  12. package/lib/constants/index.d.ts +6 -0
  13. package/lib/constants/waveform.d.ts +34 -0
  14. package/lib/index.css +1 -1
  15. package/lib/index.d.ts +25 -10
  16. package/lib/index.esm.js +1 -1
  17. package/lib/index.js +1 -1
  18. package/lib/index.standalone.js +1 -1
  19. package/lib/services/analytics.d.ts +116 -35
  20. package/lib/services/faceTracking.d.ts +13 -0
  21. package/lib/services/screenShare.d.ts +12 -0
  22. package/lib/services/webrtc.d.ts +29 -0
  23. package/lib/setupTests.d.ts +0 -1
  24. package/lib/stores/index.d.ts +2 -3
  25. package/lib/stores/middleware/featuresUpdateMiddleware.d.ts +0 -1
  26. package/lib/stores/selectors.d.ts +30 -0
  27. package/lib/stores/slices/appSlice.d.ts +2 -2
  28. package/lib/stores/slices/avatarSlice.d.ts +0 -1
  29. package/lib/stores/store.d.ts +4 -5
  30. package/lib/types/abstract-typing.d.ts +35 -0
  31. package/lib/types/analytics.d.ts +95 -0
  32. package/lib/types/errors.d.ts +63 -3
  33. package/lib/types/index.d.ts +277 -13
  34. package/lib/umd.d.ts +0 -1
  35. package/lib/utils/InactiveOverlayManager.d.ts +77 -0
  36. package/lib/utils/MediaCapture.d.ts +13 -0
  37. package/lib/utils/classnames.d.ts +50 -0
  38. package/lib/utils/debug.d.ts +84 -0
  39. package/lib/utils/domFactory.d.ts +56 -0
  40. package/lib/utils/greenscreen/GreenScreenProcessor.d.ts +25 -0
  41. package/lib/utils/greenscreen/index.d.ts +1 -0
  42. package/lib/utils/index.d.ts +15 -1
  43. package/lib/utils/mouthDetection.d.ts +33 -0
  44. package/lib/utils/sendCommand.d.ts +2 -0
  45. package/lib/utils/svg.d.ts +34 -0
  46. package/package.json +18 -18
  47. package/lib/CompanionApiProvider.d.ts +0 -16
  48. package/lib/components/Avatar/Avatar.d.ts +0 -13
  49. package/lib/components/Embed/Embed.d.ts +0 -13
  50. package/lib/components/InactiveOverlay/InactiveOverlay.d.ts +0 -12
  51. package/lib/components/Preview/Preview.d.ts +0 -9
  52. package/lib/components/StyledTooltip/StyledTooltip.d.ts +0 -12
  53. package/lib/components/WaveForm/WaveForm.d.ts +0 -16
  54. package/lib/hooks/index.d.ts +0 -5
  55. package/lib/hooks/useApp.d.ts +0 -25
  56. package/lib/hooks/useAvatar.d.ts +0 -65
  57. package/lib/hooks/useMicrophones.d.ts +0 -8
  58. package/lib/hooks/useWebRTC.d.ts +0 -22
  59. package/lib/index-legacy.d.ts +0 -23
  60. package/lib/index-legacy.esm.js +0 -1
  61. package/lib/index-legacy.js +0 -1
  62. package/lib/index.umd.js +0 -1
  63. package/lib/sdk-base-chunk.esm.js +0 -1
  64. package/lib/sdk-base-chunk.js +0 -1
  65. package/lib/sdk-base.d.ts +0 -25
  66. package/lib/stores/hooks.d.ts +0 -8
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@touchcastllc/napster-companion-api.svg)](https://www.npmjs.com/package/@touchcastllc/napster-companion-api)
4
4
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
5
 
6
- > A powerful, flexible JavaScript SDK for integrating AI-powered avatar experiences into your web application. Build with **Napster** and deliver engaging, interactive content across all major frameworks and deployment scenarios.
6
+ > Real-time conversational video AI for web applications. Embed AI companions that users can talk to face-to-face via WebRTC. Attaches to any DOM element, handles video streaming and avatar rendering, connects to Azure OpenAI for conversation.
7
7
 
8
8
  **Supported Environments:**
9
9
 
@@ -15,47 +15,38 @@
15
15
 
16
16
  **Key Capabilities:**
17
17
 
18
- - 🎯 **Multiple Build Targets**: Support for ES modules, CommonJS, UMD, and standalone bundles
19
- - 🔄 **React 16-19 Compatible**: Full support from React 16.0 through React 19.x
20
- - 🚪 **Dual Entry Points**: Modern (React 18+) and Legacy (React 16+) versions
21
- - 📦 **Tree-Shakeable**: Only import what you need for optimal bundle sizes
22
- - **Zero External Dependencies** (Standalone): Drop in a script tag and go
23
- - **Advanced Features**: Auto-play, waveform visualization, background removal, inactive timeouts, and more
24
- - 🔧 **TypeScript Support**: Full type definitions for a great developer experience
25
- - 🚀 **Production Ready**: Minified builds with source maps for debugging
18
+ - **WebRTC Video Streaming:** Real-time video with AI avatars
19
+ - **Framework Agnostic:** React, Vue, Angular, or vanilla JS
20
+ - **Zero External Dependencies:** Drop in a script tag and go
21
+ - **TypeScript Support:** Fully typed APIs
22
+ - **Tree-Shakeable:** Import only what you need
23
+ - **Screen Sharing:** Let the avatar see your screen in real time
24
+ - **Production Ready:** Minified builds with type definitions
26
25
 
27
26
  ---
28
27
 
29
- ## 2. Quick Start
28
+ ## 1. Quick Start
30
29
 
31
30
  Get up and running in minutes. Follow these four steps to integrate the SDK into your project.
32
31
 
33
- ### 2.1 Choose Your Setup
32
+ ### 1.1 Choose Your Setup
34
33
 
35
34
  Pick the integration method that matches your project:
36
35
 
37
- | Build Type | Best For | Import Path | React Included? |
38
- | --------------------------- | ----------------------------------- | -------------------------------------------- | --------------- |
39
- | **React 18+** (Bundler) | Modern React apps with Vite/Webpack | `@touchcastllc/napster-companion-api` | No (peer dep) |
40
- | **React 16/17** (Legacy) | React 16/17 apps with bundlers | `@touchcastllc/napster-companion-api/legacy` | No (peer dep) |
41
- | **UMD** (Script Tag) | Browser, bring your own React 18+ | `lib/index.umd.min.js` | No |
42
- | **Standalone** (Script Tag) | Browser, zero dependencies | `lib/index.standalone.min.js` | Yes |
43
- | **Core** (Headless) | Custom UI, framework-agnostic | `@touchcastllc/napster-companion-api/core` | No |
36
+ | Build Type | Best For | Import Path | Dependencies |
37
+ | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | -------------------- |
38
+ | **ESM** | **Recommended for most projects**<br>✅ You use a bundler (Vite, Webpack, Rollup, etc.)<br>✅ You want optimal bundle size (dependencies not bundled)<br>✅ You're using TypeScript or modern JavaScript | `@touchcastllc/napster-companion-api` | Redux Toolkit (peer) |
39
+ | **Standalone** | ✅ You want a `<script>` tag (no bundler, no external dependencies)<br>✅ You want zero external dependencies<br>✅ You don't want to manage dependencies separately<br>✅ You're okay with a slightly larger file (all dependencies included) | `lib/index.standalone.js` | All bundled |
44
40
 
45
- **Quick Links:**
41
+ ---
46
42
 
47
- - [React 18+ Example](#react-18-hooks)
48
- - [React 16/17 Example](#react-1617-class-component)
49
- - [Vue 3 Example](#vue-3)
50
- - [Vue 2 Example](#vue-2)
51
- - [Angular Example](#angular)
52
- - [Vanilla JS Example](#vanilla-js--core-no-build-tools)
43
+ ### 1.2 Installation & Setup
53
44
 
54
- ### 2.2 Installation & Import
45
+ #### 1.2.1 For ESM Build Type (Recommended)
55
46
 
56
- #### For Bundler-Based Projects
47
+ **Step 1: Install the SDK**
57
48
 
58
- **Install the package:**
49
+ Install the package:
59
50
 
60
51
  ```bash
61
52
  npm install @touchcastllc/napster-companion-api
@@ -63,117 +54,150 @@ npm install @touchcastllc/napster-companion-api
63
54
  yarn add @touchcastllc/napster-companion-api
64
55
  ```
65
56
 
66
- **Install peer dependencies:**
57
+ Install peer dependencies:
67
58
 
68
59
  ```bash
69
- # For React 18+
70
- npm install react@^18 react-dom@^18 @reduxjs/toolkit@^2 react-redux@^9
71
-
72
- # For React 16/17
73
- npm install react@^16 react-dom@^16 @reduxjs/toolkit@^2 react-redux@^8
60
+ npm install @reduxjs/toolkit
74
61
  ```
75
62
 
76
- **Import the SDK:**
63
+ **Step 2: Import the SDK**
77
64
 
78
65
  ```typescript
79
- // React 18+
80
66
  import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api";
81
-
82
- // React 16/17
83
- import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api/legacy";
84
67
  ```
85
68
 
86
- **Import CSS (required):**
69
+ **Also, import CSS Stylesheet (required):**
70
+
71
+ The SDK comes with a complete stylesheet for all components. Import it in your application:
72
+
73
+ **ESM/TypeScript:**
87
74
 
88
75
  ```typescript
89
- import "@touchcastllc/napster-companion-api/lib/index.css";
76
+ import "@touchcastllc/napster-companion-api/styles";
90
77
  ```
91
78
 
92
- #### For Browser Script Tags
79
+ **CommonJS:**
80
+
81
+ ```js
82
+ require("@touchcastllc/napster-companion-api/styles");
83
+ ```
93
84
 
94
- **Option A: Standalone (Easiest - React Included)**
85
+ **HTML `<link>` Tag:**
95
86
 
96
87
  ```html
97
- <script src="https://cdn.jsdelivr.net/npm/@touchcastllc/napster-companion-api@latest/lib/index.standalone.min.js"></script>
88
+ <link
89
+ rel="stylesheet"
90
+ href="https://cdn.jsdelivr.net/npm/@touchcastllc/napster-companion-api@latest/lib/index.css"
91
+ />
92
+ ```
93
+
94
+ **CSS `@import`:**
95
+
96
+ ```css
97
+ @import url("https://cdn.jsdelivr.net/npm/@touchcastllc/napster-companion-api@latest/lib/index.css");
98
98
  ```
99
99
 
100
- **Option B: UMD (Smaller - Bring Your Own React)**
100
+ The CSS file (`index.css`) is minified and contains all styles needed for the avatar widget, controls, tooltips, and more.
101
+
102
+ #### 1.2.2 For Standalone Build Type
103
+
104
+ **Step 1: Import the SDK**
101
105
 
102
106
  ```html
103
- <script src="https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js"></script>
104
- <script src="https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js"></script>
105
- <script src="https://cdn.jsdelivr.net/npm/@touchcastllc/napster-companion-api@latest/lib/index.umd.min.js"></script>
107
+ <!-- All dependencies bundled (easier, larger file) -->
108
+ <script src="https://cdn.jsdelivr.net/npm/@touchcastllc/napster-companion-api@latest/lib/index.standalone.js"></script>
106
109
  ```
107
110
 
108
- ### 2.3 Initialization
111
+ ---
112
+
113
+ ### 1.3 Initialization
114
+
115
+ #### 1.3.1 For ESM Build Type
109
116
 
110
117
  Initialize the SDK by calling `NapsterCompanionApiSdk.init()` with your auth token and configuration options.
111
118
 
119
+ See the [1.4 Authentication](#14-authentication) section for details on generating auth tokens.
120
+
112
121
  **Basic Example:**
113
122
 
114
123
  ```typescript
115
- import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api";
116
-
117
124
  const widget = await NapsterCompanionApiSdk.init("YOUR_AUTH_TOKEN", {
118
125
  mountContainer: "#avatar-container",
119
- position: "bottom-right",
120
- features: {
121
- waveform: { enabled: true },
122
- backgroundRemoval: { enabled: false },
123
- inactiveTimeout: { enabled: true, timeoutDuration: 60000 },
124
- },
125
126
  });
126
-
127
- // The returned widget object exposes control methods:
128
- // widget.showAvatar() - Show the avatar
129
- // widget.hideAvatar() - Hide the avatar
130
- // widget.destroy() - Destroy and unmount the widget
131
- // widget.updateStyles({...}) - Update widget styles dynamically
132
- // widget.enableFeature("waveform") - Enable a specific feature
133
- // widget.disableFeature("waveform") - Disable a specific feature
134
- // widget.updateFeatureConfig("waveform", { enabled: false }) - Update feature configuration
135
- // widget.setPosition("top-left") - Update widget position dynamically
136
- // widget.sendQuestion("Your question here") - Send a question to the avatar
137
127
  ```
138
128
 
139
- **What `init()` Returns:**
129
+ #### 1.3.2 For Standalone Build Type
130
+
131
+ Initialize the SDK by calling `window.napsterCompanionApiSDK.init()` with your auth token and configuration options.
140
132
 
141
- The `init()` method returns a widget instance with the following methods:
133
+ See the [1.4 Authentication](#14-authentication) section for details on generating auth tokens.
142
134
 
143
- | Method | Description |
144
- | ----------------------- | --------------------------------------------- |
145
- | `showAvatar()` | Shows the avatar |
146
- | `hideAvatar()` | Hides the avatar |
147
- | `destroy()` | Destroys and unmounts the widget from the DOM |
148
- | `updateStyles()` | Updates widget styles dynamically |
149
- | `enableFeature()` | Enables a specific feature |
150
- | `disableFeature()` | Disables a specific feature |
151
- | `updateFeatureConfig()` | Updates feature configuration |
152
- | `setPosition()` | Updates widget position dynamically |
153
- | `sendQuestion()` | Sends a question to the avatar |
135
+ **Step 1: Add container to your HTML**
136
+
137
+ ```html
138
+ <div id="sdk-container"></div>
139
+ ```
140
+
141
+ **Step 2: Initialize globally**
142
+
143
+ ```html
144
+ <script>
145
+ window.napsterCompanionApiSDK.init("AUTH_TOKEN", {
146
+ mountContainer: "#sdk-container",
147
+ });
148
+ </script>
149
+ ```
154
150
 
155
151
  ---
156
152
 
157
- ### 2.4 Authentication
153
+ ### 1.4 Authentication
158
154
 
159
155
  The SDK requires an **auth token** to connect to the Napster Companion API.
160
156
 
161
157
  **Important:** **Do not generate tokens in client-side code** — use a backend service to keep your API key secure.
162
158
 
163
- #### Step 1: Generate Napster API Key
159
+ #### Step 1: Generate Napster Companion API Key
164
160
 
165
- 1. Visit the [Napster API Keys page](https://app.cogcache.com/organization/keys)
161
+ 1. Visit the [Napster Companion API Keys page](https://companion-api.napster.com/admin/organization/keys)
166
162
  2. Click **Generate API key** and enter your details
167
163
  3. Store your API key securely on your backend server
168
164
 
169
165
  #### Step 2: Create Connection & Get Token (Backend)
170
166
 
171
- Create a backend API call to the Napster API to generate auth tokens:
167
+ Create a backend API call to the Napster Companion API to generate auth tokens:
168
+
169
+ **Request URL:**
170
+
171
+ ```
172
+ POST https://companion-api.napster.com/public/connections
173
+ ```
174
+
175
+ **Request Headers:**
176
+
177
+ | Header | Value |
178
+ | -------------- | ------------------- |
179
+ | `content-type` | `application/json` |
180
+ | `x-api-key` | `YOUR_API_KEY_HERE` |
181
+
182
+ **Request Body:**
172
183
 
173
- ```sh
174
- curl 'https://management-api.cogcache.com/public/connections' \
175
- -H 'accept: */*' \
176
- -H 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' \
184
+ | Field | Type | Description |
185
+ | ----------------------------------------------------------- | ------- | ------------------------------------ |
186
+ | `companionId` | string | Your Napster Companion ID |
187
+ | `providerConfig.type` | string | Provider type (e.g., `azureOpenAI`) |
188
+ | `providerConfig.voiceId` | string | Voice identifier (e.g., `alloy`) |
189
+ | `providerConfig.settings.instructions` | string | Custom instructions for the avatar |
190
+ | `providerConfig.settings.turnDetection.threshold` | number | Voice detection threshold |
191
+ | `providerConfig.settings.turnDetection.prefix_padding_ms` | number | Padding before speech detection (ms) |
192
+ | `providerConfig.settings.turnDetection.silence_duration_ms` | number | Silence duration threshold (ms) |
193
+ | `providerConfig.settings.temperature` | number | Response temperature (0-1) |
194
+ | `providerConfig.useGreenVideo` | boolean | Enable green screen background |
195
+ | `disableIdleTimeout` | boolean | Disable idle timeout |
196
+
197
+ **Example Request:**
198
+
199
+ ```bash
200
+ curl 'https://companion-api.napster.com/public/connections' \
177
201
  -H 'content-type: application/json' \
178
202
  -H 'x-api-key: YOUR_API_KEY_HERE' \
179
203
  --data-raw '{
@@ -191,7 +215,8 @@ curl 'https://management-api.cogcache.com/public/connections' \
191
215
  "temperature": 0
192
216
  },
193
217
  "useGreenVideo": true
194
- }
218
+ },
219
+ "disableIdleTimeout": false
195
220
  }'
196
221
  ```
197
222
 
@@ -200,835 +225,831 @@ curl 'https://management-api.cogcache.com/public/connections' \
200
225
  Fetch the token from your backend and pass it to the SDK:
201
226
 
202
227
  ```typescript
203
- // Client-side code
228
+ // Possible client-side code for token retrieval
204
229
  async function initializeAvatar() {
205
230
  // Fetch token from your backend
206
- const response = await fetch("/api/get-napster-token", { method: "POST" });
231
+ const response = await fetch("/your-backend-endpoint", { method: "POST" });
207
232
  const { token } = await response.json();
208
-
209
- // Initialize SDK with the token
210
- const widget = await NapsterCompanionApiSdk.init(token, {
211
- mountContainer: "#avatar-container",
212
- position: "bottom-right",
213
- });
214
233
  }
215
234
  ```
216
235
 
217
236
  ---
218
237
 
219
- ## 3. Feature Configuration
238
+ ## 2. Examples
220
239
 
221
- The SDK supports several configurable features. You can enable/disable them during initialization or update them dynamically at runtime.
240
+ We provide example implementations for popular frameworks and vanilla JavaScript:
222
241
 
223
- ### Available Features
242
+ ### 2.1 React
224
243
 
225
- | Feature | Description | Default Value |
226
- | ------------------- | ------------------------------------------- | -------------------------------------------- |
227
- | `waveform` | Display audio waveform visualization | `{ enabled: false }` |
228
- | `backgroundRemoval` | Remove avatar background for transparency | `{ enabled: false }` |
229
- | `inactiveTimeout` | Auto-hide avatar after period of inactivity | `{ enabled: false, timeoutDuration: 60000 }` |
230
- | `disclaimer` | Show disclaimer text above the avatar | `{ enabled: false, text: "" }` |
244
+ ```tsx
245
+ import React, { useEffect, useRef, useState } from "react";
246
+ import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api";
247
+ import type { NapsterCompanionApiInstance } from "@touchcastllc/napster-companion-api";
231
248
 
232
- ### Configuration During Initialization
249
+ export function CompanionWidget() {
250
+ const containerRef = useRef<HTMLDivElement>(null);
251
+ const [instance, setInstance] = useState<NapsterCompanionApiInstance | null>(
252
+ null
253
+ );
233
254
 
234
- ```typescript
235
- const widget = await NapsterCompanionApiSdk.init("YOUR_AUTH_TOKEN", {
236
- mountContainer: "#avatar-container",
237
- position: "bottom-right",
238
- features: {
239
- autoplay: { enabled: true },
240
- waveform: { enabled: true },
241
- backgroundRemoval: { enabled: false },
242
- inactiveTimeout: {
243
- enabled: true,
244
- timeoutDuration: 60000, // 60 seconds
245
- },
246
- },
247
- });
255
+ useEffect(() => {
256
+ const initSDK = async () => {
257
+ if (!containerRef.current) return;
258
+
259
+ const result = await NapsterCompanionApiSdk.init("YOUR_TOKEN", {
260
+ mountContainer: containerRef.current,
261
+ position: "bottom-right",
262
+ });
263
+ setInstance(result);
264
+ };
265
+
266
+ initSDK();
267
+
268
+ return () => {
269
+ instance?.destroy();
270
+ };
271
+ }, []);
272
+
273
+ return <div ref={containerRef} style={{ width: "100%", height: "100%" }} />;
274
+ }
248
275
  ```
249
276
 
250
- ### Dynamic Feature Updates
277
+ ### 2.2 Vue 3
278
+
279
+ ```html
280
+ <template>
281
+ <div ref="containerRef"></div>
282
+ </template>
283
+
284
+ <script setup lang="ts">
285
+ import { onMounted, onUnmounted, ref } from "vue";
286
+ import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api";
287
+ import type { NapsterCompanionApiInstance } from "@touchcastllc/napster-companion-api";
288
+
289
+ const containerRef = ref<HTMLElement>();
290
+ let instance: NapsterCompanionApiInstance | null = null;
291
+
292
+ onMounted(async () => {
293
+ if (!containerRef.value) return;
294
+
295
+ instance = await NapsterCompanionApiSdk.init("YOUR_TOKEN", {
296
+ mountContainer: containerRef.value,
297
+ position: "bottom-right",
298
+ });
299
+ });
300
+
301
+ onUnmounted(() => {
302
+ instance?.destroy();
303
+ });
304
+ </script>
305
+ ```
251
306
 
252
- Update feature configuration after initialization:
307
+ ### 2.3 Angular
253
308
 
254
309
  ```typescript
255
- // Enable/disable a single feature
256
- widget.enableFeature("waveform");
257
- widget.disableFeature("waveform");
258
-
259
- // Update feature configuration
260
- widget.updateFeatureConfig({
261
- autoplay: { enabled: true },
262
- inactiveTimeout: {
263
- enabled: true,
264
- timeoutDuration: 30000, // 30 seconds
265
- },
266
- });
310
+ import {
311
+ Component,
312
+ OnInit,
313
+ OnDestroy,
314
+ ElementRef,
315
+ ViewChild,
316
+ } from "@angular/core";
317
+ import {
318
+ NapsterCompanionApiSdk,
319
+ NapsterCompanionApiInstance,
320
+ } from "@touchcastllc/napster-companion-api";
321
+
322
+ @Component({
323
+ selector: "app-companion",
324
+ template: "<div #containerRef></div>",
325
+ })
326
+ export class CompanionComponent implements OnInit, OnDestroy {
327
+ @ViewChild("containerRef") containerRef!: ElementRef<HTMLDivElement>;
328
+ private instance: NapsterCompanionApiInstance | null = null;
329
+
330
+ async ngOnInit() {
331
+ this.instance = await NapsterCompanionApiSdk.init("YOUR_TOKEN", {
332
+ mountContainer: this.containerRef.nativeElement,
333
+ position: "bottom-right",
334
+ });
335
+ }
336
+
337
+ ngOnDestroy() {
338
+ this.instance?.destroy();
339
+ }
340
+ }
267
341
  ```
268
342
 
269
- ---
343
+ ### 2.4 Vanilla JavaScript/TypeScript
270
344
 
271
- ## 4. API Reference
345
+ ```html
346
+ <div id="sdk-container"></div>
347
+ <script src="https://cdn.jsdelivr.net/npm/@touchcastllc/napster-companion-api@latest/lib/index.standalone.js"></script>
348
+ <script>
349
+ const sdk = window.napsterCompanionApiSDK;
350
+
351
+ sdk
352
+ .init("YOUR_TOKEN", {
353
+ mountContainer: "#sdk-container",
354
+ position: "bottom-right",
355
+ })
356
+ .then(instance => {
357
+ // Control the avatar
358
+ instance.showAvatar();
359
+
360
+ // Hide after 10 seconds
361
+ setTimeout(() => instance.hideAvatar(), 10000);
362
+ });
363
+ </script>
364
+ ```
272
365
 
273
- ### Initialization
366
+ ### 2.5 Advanced Configuration
274
367
 
275
- #### `NapsterCompanionApiSdk.init(token, options)`
368
+ ```typescript
369
+ async function initAdvancedAvatar() {
370
+ const instance = await NapsterCompanionApiSdk.init("YOUR_TOKEN", {
371
+ mountContainer: "#avatar-container",
372
+ position: "bottom-right",
276
373
 
277
- Initialize and mount the avatar widget.
374
+ avatarStyle: {
375
+ view: "round", // Options: "round" | "rectangle" | "silhouette"
376
+ },
278
377
 
279
- **Parameters:**
378
+ features: {
379
+ inactiveTimeout: { enabled: true, duration: 120000, countdown: 15 },
380
+ showSDKLoader: { enabled: true, bgColor: "#f0f0f0" },
381
+ screenShare: { enabled: true },
382
+ },
280
383
 
281
- | Parameter | Type | Required | Description |
282
- | --------- | --------------------------- | -------- | ---------------------------- |
283
- | `token` | `string` | Yes | Auth token from your backend |
284
- | `options` | `NapsterCompanionApiConfig` | Yes | Configuration object |
384
+ style: {
385
+ borderRadius: "12px",
386
+ boxShadow: "0 4px 20px rgba(0,0,0,0.3)",
387
+ },
285
388
 
286
- **`NapsterCompanionApiConfig` Interface:**
389
+ onReady: () => console.log("Avatar ready!"),
390
+ onError: error => console.error("Error:", error),
391
+ onAvatarReady: ready => console.log("Avatar loaded:", ready),
392
+ });
393
+
394
+ return instance;
395
+ }
396
+ ```
397
+
398
+ ### 2.6 Dynamic Feature Control
287
399
 
288
400
  ```typescript
289
- interface NapsterCompanionApiConfig {
290
- mountContainer: string | HTMLElement; // CSS selector or DOM element
291
- position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
292
- features?: {
293
- autoplay?: { enabled: boolean };
294
- waveform?: { enabled: boolean };
295
- backgroundRemoval?: { enabled: boolean };
296
- inactiveTimeout?: { enabled: boolean; timeoutDuration?: number };
297
- };
298
- styles?: {
299
- width?: string;
300
- height?: string;
301
- zIndex?: number;
302
- };
303
- onReady?: () => void;
304
- onError?: (error: Error) => void;
305
- onData?: (data: EventMessage) => void;
306
- onAvatarReady?: () => void;
307
- onDestroy?: () => void;
401
+ async function controlFeatures() {
402
+ const instance = await NapsterCompanionApiSdk.init("YOUR_TOKEN", {
403
+ mountContainer: "#avatar-container",
404
+ });
405
+
406
+ // Change position dynamically
407
+ document.getElementById("move-avatar")?.addEventListener("click", () => {
408
+ instance.setPosition("top-left");
409
+ });
410
+
411
+ return instance;
308
412
  }
309
413
  ```
310
414
 
311
- **Returns:** `Promise<NapsterCompanionApiInstance>`
415
+ ### 2.7 Custom Styling
312
416
 
313
- **Example:**
417
+ #### Inline Styles
314
418
 
315
419
  ```typescript
316
- const widget = await NapsterCompanionApiSdk.init("YOUR_TOKEN", {
317
- mountContainer: "#avatar-container",
318
- position: "bottom-right",
420
+ const instance = await NapsterCompanionApiSdk.init(token, {
421
+ style: {
422
+ border: "2px solid #00ff00",
423
+ borderRadius: "8px",
424
+ boxShadow: "0 2px 10px rgba(0,0,0,0.2)",
425
+ background: "rgba(255,255,255,0.95)",
426
+ },
319
427
  });
320
428
  ```
321
429
 
322
- ---
430
+ #### CSS Classes
323
431
 
324
- ### Widget Instance Methods
432
+ ```typescript
433
+ const instance = await NapsterCompanionApiSdk.init(token, {
434
+ className: "my-custom-avatar",
435
+ });
436
+ ```
325
437
 
326
- #### `widget.showAvatar()`
438
+ ```css
439
+ .my-custom-avatar {
440
+ border: 2px solid #007acc;
441
+ border-radius: 12px;
442
+ backdrop-filter: blur(10px);
443
+ }
444
+ ```
327
445
 
328
- Shows the avatar widget.
446
+ #### Dynamic Style Updates
329
447
 
330
448
  ```typescript
331
- widget.showAvatar();
449
+ // Update styles after initialization
450
+ instance.updateStyles({
451
+ opacity: "0.9",
452
+ transform: "scale(1.1)",
453
+ transition: "all 0.3s ease",
454
+ });
332
455
  ```
333
456
 
334
- ---
457
+ ### 2.8 Avatar Style Configuration
335
458
 
336
- #### `widget.hideAvatar()`
459
+ Customize the avatar's visual appearance using the `avatarStyle` configuration. Control the avatar's view mode, and other visual properties.
337
460
 
338
- Hides the avatar widget.
461
+ #### Avatar View Modes
339
462
 
340
463
  ```typescript
341
- widget.hideAvatar();
464
+ const instance = await NapsterCompanionApiSdk.init(token, {
465
+ avatarStyle: {
466
+ view: "round", // Options: "round" | "rectangle" | "silhouette"
467
+ },
468
+ });
342
469
  ```
343
470
 
344
- ---
471
+ **Available View Modes:**
345
472
 
346
- #### `widget.destroy()`
473
+ - `"round"` (default) - Circular avatar with rounded appearance
474
+ - `"rectangle"` - Rectangular container, ideal for custom styling
475
+ - `"silhouette"` - Full view without background styling. (**Note: works only with green screen feature enabled in [Create Connection](#step-2-create-connection--get-token-backend) API**)
347
476
 
348
- Destroys and unmounts the widget from the DOM. Call this during cleanup.
477
+ #### Avatar Style Example
349
478
 
350
479
  ```typescript
351
- widget.destroy();
480
+ const instance = await NapsterCompanionApiSdk.init(token, {
481
+ avatarStyle: {
482
+ view: "rectangle",
483
+ },
484
+ style: {
485
+ borderRadius: "16px", // Works well with rectangle
486
+ boxShadow: "0 8px 32px rgba(0,0,0,0.2)",
487
+ },
488
+ });
352
489
  ```
353
490
 
354
491
  ---
355
492
 
356
- #### `widget.updateStyles(styles)`
493
+ ## 3. Feature Configuration
494
+
495
+ ### 3.1 Core Features
357
496
 
358
- Update widget styling dynamically.
497
+ #### Inactivity Timeout
359
498
 
360
- **Parameters:**
499
+ Automatically disconnect the avatar after a period of user inactivity. Users receive a countdown notification before disconnection.
361
500
 
362
501
  ```typescript
363
- interface React.CSSProperties {
364
- width?: string;
365
- height?: string;
366
- zIndex?: number;
367
- position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
368
- }
502
+ const instance = await NapsterCompanionApiSdk.init(token, {
503
+ features: {
504
+ inactiveTimeout: {
505
+ enabled: true,
506
+ duration: 60000, // 60 seconds (max: 180000ms)
507
+ countdown: 10, // 10 second countdown (max: 60s)
508
+ },
509
+ },
510
+ });
369
511
  ```
370
512
 
371
- **Example:**
513
+ #### SDK Loading Screen
514
+
515
+ Display a loading screen while the avatar assets are being loaded. Customize the background color to match your application's design.
372
516
 
373
517
  ```typescript
374
- widget.updateStyles({
375
- width: "400px",
376
- height: "600px",
377
- zIndex: 1000,
378
- position: "top-right",
518
+ const instance = await NapsterCompanionApiSdk.init(token, {
519
+ features: {
520
+ showSDKLoader: {
521
+ enabled: true,
522
+ bgColor: "#ffffff", // Optional background color
523
+ },
524
+ },
379
525
  });
380
526
  ```
381
527
 
382
- ---
528
+ ### 3.2 Face Tracking
383
529
 
384
- #### `widget.enableFeature(featureName)`
530
+ Real-time face detection using TensorFlow.js + MediaPipe Face Mesh. Detects the user's face via their camera, extracts 468 facial landmarks, and determines talking state via mouth-opening ratio. Fully client-side — no backend involved.
385
531
 
386
- Enable a specific feature.
532
+ #### Prerequisites
533
+
534
+ Install the optional peer dependencies (only needed when face tracking is enabled):
387
535
 
388
- **Parameters:**
536
+ ```bash
537
+ npm install @tensorflow/tfjs @tensorflow-models/face-landmarks-detection
538
+ ```
389
539
 
390
- - `featureName`: `"autoplay" | "waveform" | "backgroundRemoval" | "inactiveTimeout"`
540
+ These libraries (~2MB) are lazy-loaded at runtime they are not included in the main SDK bundle.
391
541
 
392
- **Example:**
542
+ #### Enable & Configure
393
543
 
394
544
  ```typescript
395
- widget.enableFeature("waveform");
545
+ const instance = await NapsterCompanionApiSdk.init(token, {
546
+ features: {
547
+ faceTracking: {
548
+ enabled: true,
549
+ fps: 15, // Detection rate: 1–30 FPS (default: 15)
550
+ talkingThreshold: 0.015, // Mouth opening ratio threshold (default: 0.015)
551
+ },
552
+ },
553
+ onFaceTrackingData: (data) => {
554
+ if (data) {
555
+ console.log("Talking:", data.isTalking);
556
+ console.log("Landmarks:", data.landmarks.length); // 468
557
+ console.log("Mouth:", data.mouthLandmarks);
558
+ } else {
559
+ console.log("No face detected");
560
+ }
561
+ },
562
+ onFaceTrackingError: (error) => {
563
+ console.error("Face tracking error:", error.message);
564
+ },
565
+ });
396
566
  ```
397
567
 
398
- ---
568
+ #### Start & Stop
399
569
 
400
- #### `widget.disableFeature(featureName)`
570
+ ```typescript
571
+ // Start detection (opens camera, loads model on first call)
572
+ await instance.startFaceTracking();
401
573
 
402
- Disable a specific feature.
574
+ // Pause detection (stops camera, keeps model loaded for fast restart)
575
+ instance.stopFaceTracking();
403
576
 
404
- **Parameters:**
577
+ // Restart — reuses model, only reopens camera
578
+ await instance.startFaceTracking();
579
+ ```
405
580
 
406
- - `featureName`: `"autoplay" | "waveform" | "backgroundRemoval" | "inactiveTimeout"`
581
+ #### Face Tracking Data
407
582
 
408
- **Example:**
583
+ Each detection frame emits a `FaceTrackingData` object (or `null` if no face is detected):
409
584
 
410
585
  ```typescript
411
- widget.disableFeature("autoplay");
586
+ interface FaceTrackingData {
587
+ landmarks: Array<{ x: number; y: number; z: number }>; // 468 points, 0–1 normalized
588
+ mouthLandmarks: {
589
+ topLip: { x: number; y: number };
590
+ bottomLip: { x: number; y: number };
591
+ leftCorner: { x: number; y: number };
592
+ rightCorner: { x: number; y: number };
593
+ } | null;
594
+ isTalking: boolean; // smoothed mouth-opening ratio > threshold
595
+ }
412
596
  ```
413
597
 
414
- ---
598
+ #### Error Codes
415
599
 
416
- #### `widget.updateFeatureConfig(config)`
600
+ | Code | When |
601
+ | -------------------------- | ----------------------------------------- |
602
+ | `CAMERA_PERMISSION_DENIED` | User denied camera access |
603
+ | `CAMERA_NOT_FOUND` | No camera available |
604
+ | `MODEL_LOAD_FAILED` | TensorFlow.js / MediaPipe failed to load |
605
+ | `DETECTION_FAILED` | Runtime detection error |
417
606
 
418
- Update multiple feature configurations at once.
607
+ #### Cleanup
419
608
 
420
- **Parameters:**
609
+ Face tracking is automatically destroyed when `instance.destroy()` is called. The model is disposed and camera tracks are stopped.
421
610
 
422
- ```typescript
423
- interface FeatureConfig {
424
- autoplay?: { enabled: boolean };
425
- waveform?: { enabled: boolean };
426
- backgroundRemoval?: { enabled: boolean };
427
- inactiveTimeout?: { enabled: boolean; timeoutDuration?: number };
428
- }
429
- ```
611
+ ### 3.3 Screen Sharing
612
+
613
+ Share the user's screen with the avatar in real time. The SDK captures the display at 1 FPS, renders each frame onto an internal canvas, and streams the canvas track over WebRTC so the avatar can "see" what the user sees. Fully browser-based — no plugins or extensions required.
430
614
 
431
- **Example:**
615
+ #### Enable & Configure
432
616
 
433
617
  ```typescript
434
- widget.updateFeatureConfig({
435
- autoplay: { enabled: true },
436
- inactiveTimeout: { enabled: true, timeoutDuration: 45000 },
618
+ const instance = await NapsterCompanionApiSdk.init(token, {
619
+ features: {
620
+ screenShare: {
621
+ enabled: true,
622
+ },
623
+ },
437
624
  });
438
625
  ```
439
626
 
440
- ---
627
+ > **Note:** `features.screenShare.enabled` must be `true` for the screen share controls to appear and for `isScreenShareSupported` to return `true`.
441
628
 
442
- ### Type Definitions
629
+ #### Start & Stop
443
630
 
444
631
  ```typescript
445
- // Main initialization options
446
- interface NapsterCompanionApiConfig {
447
- mountContainer: string | HTMLElement;
448
- position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
449
- features?: FeatureConfig;
450
- styles?: React.CSSProperties;
451
- onReady?: () => void;
452
- onError?: (error: Error) => void;
453
- onData?: (data: EventMessage) => void;
454
- onAvatarReady?: () => void;
455
- onDestroy?: () => void;
456
- }
632
+ // Start sharing (opens browser's screen picker)
633
+ await instance.startScreenShare();
457
634
 
458
- // Feature configuration
459
- interface FeatureConfig {
460
- autoplay?: { enabled: boolean };
461
- waveform?: { enabled: boolean };
462
- backgroundRemoval?: { enabled: boolean };
463
- inactiveTimeout?: { enabled: boolean; timeoutDuration?: number };
464
- }
635
+ // Stop sharing
636
+ instance.stopScreenShare();
465
637
 
466
- // Widget instance returned by init()
467
- interface NapsterCompanionApiInstance {
468
- showAvatar(): void;
469
- hideAvatar(): void;
470
- destroy(): void;
471
- updateStyles(styles: React.CSSProperties): void;
472
- enableFeature(feature: string): void;
473
- disableFeature(feature: string): void;
474
- updateFeatureConfig(config: FeatureConfig): void;
475
- }
638
+ // Or toggle on/off
639
+ await instance.toggleScreenShare();
476
640
  ```
477
641
 
478
- ---
642
+ The SDK sends `start_video` / `stop_video` commands to the avatar server automatically. If the user stops sharing via the browser's native "Stop sharing" button, the SDK detects this and cleans up.
479
643
 
480
- ## 5. Usage Examples
644
+ #### Checking State
481
645
 
482
- Framework-specific, copy-paste-ready snippets demonstrating proper lifecycle management.
646
+ ```typescript
647
+ // Whether screen sharing is currently active
648
+ instance.isScreenSharing; // boolean
483
649
 
484
- ### React 18+ (Hooks)
650
+ // Whether the browser supports screen sharing AND the feature is enabled
651
+ instance.isScreenShareSupported; // boolean
652
+ ```
485
653
 
486
- ```tsx
487
- import React, { useEffect, useRef, useState } from "react";
488
- import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api";
654
+ #### How It Works
489
655
 
490
- export function AvatarWidget() {
491
- const containerRef = useRef(null);
492
- const [widget, setWidget] = useState(null);
656
+ 1. **`getDisplayMedia`** captures the user's screen at max 1 FPS, 1280×720.
657
+ 2. **`MediaCapture`** renders each frame onto a hidden `<canvas>` via a Web Worker timer.
658
+ 3. **`canvas.captureStream(1)`** produces a video track that is added to the WebRTC peer connection at setup time.
659
+ 4. When the user starts sharing, frames begin flowing on the already-connected track and the SDK sends `start_video` through the data channel.
660
+ 5. When the user stops sharing, the display stream tracks are stopped and `stop_video` is sent.
493
661
 
494
- useEffect(() => {
495
- let mounted = true;
496
-
497
- async function initialize() {
498
- try {
499
- // Fetch token from your backend
500
- const response = await fetch("/api/get-napster-token", {
501
- method: "POST",
502
- });
503
- const { token } = await response.json();
504
-
505
- // Initialize widget
506
- const instance = await NapsterCompanionApiSdk.init(token, {
507
- mountContainer: containerRef.current,
508
- position: "bottom-right",
509
- features: {
510
- autoplay: { enabled: true },
511
- waveform: { enabled: true },
512
- },
513
- });
514
-
515
- if (mounted) {
516
- setWidget(instance);
517
- }
518
- } catch (error) {
519
- console.error("Failed to initialize avatar:", error);
520
- }
521
- }
662
+ #### Cleanup
522
663
 
523
- initialize();
664
+ Screen sharing is automatically stopped when:
524
665
 
525
- // Cleanup on unmount
526
- return () => {
527
- mounted = false;
528
- widget?.destroy();
529
- };
530
- }, []);
666
+ - The user calls `instance.destroy()`
667
+ - The WebRTC connection closes (network failure, session end)
668
+ - The user clicks the browser's native "Stop sharing" button
531
669
 
532
- return <div ref={containerRef} style={{ width: "100%", height: "100%" }} />;
533
- }
534
- ```
670
+ ### 3.4 Position & Layout
535
671
 
536
- ---
672
+ Customize the avatar's position on the screen using predefined positions or custom styles. Also you can override the position using style properties.
537
673
 
538
- ### React 16/17 (Class Component)
674
+ ```typescript
675
+ const instance = await NapsterCompanionApiSdk.init(token, {
676
+ mountContainer: "#my-container", // CSS selector or HTMLElement
677
+ position: "bottom-right", // Predefined positions
678
+ // Apply custom inline styles to override default SDK styles, will be added to root container
679
+ style: {
680
+ top: "20px",
681
+ left: "20px",
682
+ zIndex: "1000",
683
+ },
684
+ // Apply CSS class name to override default SDK styles, will be added to root container
685
+ className: "my-custom-class",
686
+ });
687
+ ```
539
688
 
540
- ```tsx
541
- import React from "react";
542
- import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api/legacy";
543
-
544
- export class AvatarWidget extends React.Component {
545
- containerRef = React.createRef();
546
- widget = null;
547
-
548
- async componentDidMount() {
549
- try {
550
- // Fetch token from your backend
551
- const response = await fetch("/api/get-napster-token", {
552
- method: "POST",
553
- });
554
- const { token } = await response.json();
689
+ **Available Positions:**
555
690
 
556
- // Initialize widget
557
- this.widget = await NapsterCompanionApiSdk.init(token, {
558
- mountContainer: this.containerRef.current,
559
- position: "bottom-right",
560
- features: {
561
- autoplay: { enabled: true },
562
- },
563
- });
564
- } catch (error) {
565
- console.error("Failed to initialize avatar:", error);
566
- }
567
- }
691
+ - `"bottom-right"` (default)
692
+ - `"bottom-left"`
693
+ - `"bottom-center"`
694
+ - `"top-right"`
695
+ - `"top-left"`
696
+ - `"top-center"`
697
+ - `"center"`
568
698
 
569
- componentWillUnmount() {
570
- // Cleanup on unmount
571
- this.widget?.destroy();
572
- }
699
+ ## 4. Event Handling
573
700
 
574
- render() {
575
- return (
576
- <div ref={this.containerRef} style={{ width: "100%", height: "100%" }} />
577
- );
578
- }
579
- }
701
+ The SDK provides several event callbacks for monitoring status and handling errors.
702
+
703
+ ```typescript
704
+ const instance = await NapsterCompanionApiSdk.init(token, {
705
+ // Fires when the SDK is initialized and ready to use
706
+ onReady: () => console.log("SDK ready!"),
707
+ // Fires on any SDK error
708
+ onError: error => console.error("SDK error:", error),
709
+ // Fires when the avatar is fully loaded and ready
710
+ onAvatarReady: isReady => console.log("Avatar ready:", isReady),
711
+ // Fires when user inactivity status changes
712
+ onInactivityStatusChange: isInactive => console.log("Inactive:", isInactive),
713
+ // Fires when the SDK is destroyed
714
+ onDestroy: () => console.log("SDK destroyed"),
715
+ // Fires when data is received from the WEBRTC data channel
716
+ onData: data => console.log("Data received:", data),
717
+ });
580
718
  ```
581
719
 
582
720
  ---
583
721
 
584
- ### Vue 3
585
-
586
- ```html
587
- <template>
588
- <div ref="containerRef" style="width: 100%; height: 100%;"></div>
589
- </template>
590
-
591
- <script setup>
592
- import { ref, onMounted, onBeforeUnmount } from "vue";
593
- import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api";
594
- import "@touchcastllc/napster-companion-api/lib/index.css";
722
+ ## 5. API Reference
595
723
 
596
- const containerRef = ref(null);
597
- let widget = null;
724
+ ### 5.1 Core Methods
598
725
 
599
- onMounted(async () => {
600
- try {
601
- // Fetch token from your backend
602
- const response = await fetch("/api/get-napster-token", {
603
- method: "POST",
604
- });
605
- const { token } = await response.json();
726
+ #### `init(token: string, config?: NapsterCompanionApiConfig): Promise<NapsterCompanionApiInstance>`
606
727
 
607
- // Initialize widget
608
- widget = await NapsterCompanionApiSdk.init(token, {
609
- mountContainer: containerRef.value,
610
- position: "bottom-right",
611
- features: {
612
- autoplay: { enabled: true },
613
- waveform: { enabled: true },
614
- },
615
- });
616
- } catch (error) {
617
- console.error("Failed to initialize avatar:", error);
618
- }
619
- });
728
+ Initialize the SDK with authentication token and configuration.
620
729
 
621
- onBeforeUnmount(() => {
622
- // Cleanup on unmount
623
- widget?.destroy();
624
- });
625
- </script>
730
+ ```typescript
731
+ const instance = await NapsterCompanionApiSdk.init("YOUR_TOKEN", {
732
+ mountContainer: "#avatar-container",
733
+ position: "bottom-right",
734
+ });
626
735
  ```
627
736
 
628
- ---
737
+ #### `showAvatar(): void`
629
738
 
630
- ### Vue 2
739
+ Make the avatar visible on screen.
631
740
 
632
- ```html
633
- <template>
634
- <div ref="container" style="width: 100%; height: 100%;"></div>
635
- </template>
636
-
637
- <script>
638
- import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api";
639
- import "@touchcastllc/napster-companion-api/lib/index.css";
640
-
641
- export default {
642
- name: "AvatarWidget",
643
- data() {
644
- return {
645
- widget: null,
646
- };
647
- },
648
- async mounted() {
649
- try {
650
- // Fetch token from your backend
651
- const response = await fetch("/api/get-napster-token", {
652
- method: "POST",
653
- });
654
- const { token } = await response.json();
655
-
656
- // Initialize widget
657
- this.widget = await NapsterCompanionApiSdk.init(token, {
658
- mountContainer: this.$refs.container,
659
- position: "bottom-right",
660
- features: {
661
- autoplay: { enabled: true },
662
- },
663
- });
664
- } catch (error) {
665
- console.error("Failed to initialize avatar:", error);
666
- }
667
- },
668
- beforeDestroy() {
669
- // Cleanup on unmount
670
- this.widget?.destroy();
671
- },
672
- };
673
- </script>
741
+ ```typescript
742
+ instance.showAvatar();
674
743
  ```
675
744
 
676
- ---
745
+ #### `hideAvatar(): void`
677
746
 
678
- ### Angular
747
+ Hide the avatar from screen.
679
748
 
680
749
  ```typescript
681
- import {
682
- Component,
683
- OnInit,
684
- OnDestroy,
685
- ElementRef,
686
- ViewChild,
687
- } from "@angular/core";
688
- import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api";
750
+ instance.hideAvatar();
751
+ ```
689
752
 
690
- @Component({
691
- selector: "app-avatar-widget",
692
- template: ` <div #container style="width: 100%; height: 100%;"></div> `,
693
- styles: [
694
- `
695
- @import "@touchcastllc/napster-companion-api/lib/index.css";
696
- `,
697
- ],
698
- })
699
- export class AvatarWidgetComponent implements OnInit, OnDestroy {
700
- @ViewChild("container", { static: true }) container!: ElementRef;
701
- private widget: any = null;
753
+ #### `avatarIsVisible(): boolean`
702
754
 
703
- async ngOnInit() {
704
- try {
705
- // Fetch token from your backend
706
- const response = await fetch("/api/get-napster-token", {
707
- method: "POST",
708
- });
709
- const { token } = await response.json();
755
+ Check if the avatar is currently visible.
710
756
 
711
- // Initialize widget
712
- this.widget = await NapsterCompanionApiSdk.init(token, {
713
- mountContainer: this.container.nativeElement,
714
- position: "bottom-right",
715
- features: {
716
- autoplay: { enabled: true },
717
- waveform: { enabled: true },
718
- },
719
- });
720
- } catch (error) {
721
- console.error("Failed to initialize avatar:", error);
722
- }
723
- }
724
-
725
- ngOnDestroy() {
726
- // Cleanup on unmount
727
- this.widget?.destroy();
728
- }
757
+ ```typescript
758
+ if (instance.avatarIsVisible()) {
759
+ console.log("Avatar is visible");
729
760
  }
730
761
  ```
731
762
 
732
- ---
763
+ #### `destroy(): void`
733
764
 
734
- ### Vanilla JS / Core (No Build Tools)
765
+ Cleanup and remove the SDK completely.
735
766
 
736
- ```html
737
- <!DOCTYPE html>
738
- <html lang="en">
739
- <head>
740
- <meta charset="UTF-8" />
741
- <title>Napster Avatar SDK</title>
742
- </head>
743
- <body>
744
- <div id="avatar-container"></div>
745
-
746
- <script src="https://cdn.jsdelivr.net/npm/@touchcastllc/napster-companion-api@latest/lib/index.standalone.min.js"></script>
747
- <script>
748
- (async function () {
749
- try {
750
- // Fetch token from your backend
751
- const response = await fetch("/api/get-napster-token", {
752
- method: "POST",
753
- });
754
- const { token } = await response.json();
755
-
756
- // Initialize widget
757
- const widget = await window.NapsterCompanionApiSdk.init(token, {
758
- mountContainer: "#avatar-container",
759
- position: "bottom-right",
760
- features: {
761
- autoplay: { enabled: true },
762
- waveform: { enabled: true },
763
- },
764
- });
765
-
766
- // Widget controls
767
- // widget.showAvatar();
768
- // widget.hideAvatar();
769
- // widget.destroy();
770
- } catch (error) {
771
- console.error("Failed to initialize avatar:", error);
772
- }
773
- })();
774
- </script>
775
- </body>
776
- </html>
767
+ ```typescript
768
+ instance.destroy();
777
769
  ```
778
770
 
779
- ---
780
-
781
- ## 6. Styling & Customization
782
-
783
- ### CSS Import Path
771
+ ### 5.2 Styling & Position Methods
784
772
 
785
- Always import the SDK's CSS file to ensure proper styling:
773
+ #### `updateStyles(styles: StyleObject): void`
786
774
 
787
- **For Bundler Projects:**
775
+ Update container styles dynamically.
788
776
 
789
777
  ```typescript
790
- import "@touchcastllc/napster-companion-api/lib/index.css";
778
+ instance.updateStyles({
779
+ top: "50px",
780
+ left: "50px",
781
+ opacity: "0.8",
782
+ });
791
783
  ```
792
784
 
793
- **For Browser Script Tags:**
785
+ #### `setPosition(position: Position): void`
794
786
 
795
- ```html
796
- <link
797
- rel="stylesheet"
798
- href="https://cdn.jsdelivr.net/npm/@touchcastllc/napster-companion-api@latest/lib/index.css"
799
- />
787
+ Change avatar position on screen.
788
+
789
+ ```typescript
790
+ instance.setPosition("top-left");
791
+ // or using enum
792
+ import { Position } from "@touchcastllc/napster-companion-api";
793
+ instance.setPosition(Position.TOP_LEFT);
800
794
  ```
801
795
 
802
- ### Custom Container Styling
796
+ #### `clearPosition(): void`
803
797
 
804
- You can customize the avatar container's size, position, and z-index:
798
+ Reset position to default/configured value.
805
799
 
806
800
  ```typescript
807
- const widget = await NapsterCompanionApiSdk.init("YOUR_TOKEN", {
808
- mountContainer: "#avatar-container",
809
- position: "bottom-right",
810
- styles: {
811
- width: "400px",
812
- height: "600px",
813
- zIndex: 9999,
814
- },
815
- });
816
-
817
- // Update styles dynamically
818
- widget.updateStyles({
819
- width: "500px",
820
- height: "700px",
821
- position: "top-right",
822
- });
801
+ instance.clearPosition();
823
802
  ```
824
803
 
825
- ---
804
+ ### 5.3 Feature Control Methods
826
805
 
827
- ## 7. Troubleshooting
806
+ #### `enableFeature(feature: string): void`
828
807
 
829
- Common integration errors and their quick resolutions.
808
+ Enable a specific feature.
809
+
810
+ ```typescript
811
+ instance.enableFeature("disclaimer");
812
+ ```
830
813
 
831
- ### React Version Mismatch
814
+ #### `disableFeature(feature: string): void`
832
815
 
833
- **Error:** `Error: Invalid hook call` or `React version mismatch`
816
+ Disable a specific feature.
834
817
 
835
- **Cause:** Using the wrong SDK entry point for your React version.
818
+ ```typescript
819
+ instance.disableFeature("disclaimer");
820
+ ```
836
821
 
837
- **Solution:**
822
+ #### `isFeatureEnabled(feature: string): boolean`
838
823
 
839
- - For React 18+, use: `import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api";`
840
- - For React 16/17, use: `import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api/legacy";`
824
+ Check if a feature is currently enabled.
841
825
 
842
- ```bash
843
- # Check your React version
844
- npm list react
826
+ ```typescript
827
+ if (instance.isFeatureEnabled("disclaimer")) {
828
+ console.log("Disclaimer is enabled");
829
+ }
845
830
  ```
846
831
 
847
- ---
832
+ ### 5.4 Face Tracking Methods
833
+
834
+ #### `startFaceTracking(): Promise<void>`
848
835
 
849
- ### Missing CSS Styles
836
+ Start face tracking. Opens the user's camera and begins the detection loop. The model is loaded on the first call and reused on subsequent calls.
850
837
 
851
- **Error:** Widget appears unstyled or invisible
838
+ ```typescript
839
+ await instance.startFaceTracking();
840
+ ```
852
841
 
853
- **Cause:** CSS file not imported.
842
+ > **Note:** Requires `features.faceTracking.enabled = true` in the init config. Throws a `FeatureError` if not enabled.
854
843
 
855
- **Solution:**
844
+ #### `stopFaceTracking(): void`
856
845
 
857
- Add the CSS import:
846
+ Pause face tracking. Stops the camera and detection loop but keeps the model loaded for fast restart.
858
847
 
859
848
  ```typescript
860
- import "@touchcastllc/napster-companion-api/lib/index.css";
849
+ instance.stopFaceTracking();
861
850
  ```
862
851
 
863
- For HTML script tags:
852
+ ### 5.5 Screen Sharing Methods
864
853
 
865
- ```html
866
- <link
867
- rel="stylesheet"
868
- href="https://cdn.jsdelivr.net/npm/@touchcastllc/napster-companion-api@latest/lib/index.css"
869
- />
870
- ```
854
+ #### `startScreenShare(): Promise<void>`
871
855
 
872
- ---
856
+ Start screen sharing. Opens the browser's screen picker and begins streaming frames to the avatar.
873
857
 
874
- ### CORS Errors
858
+ ```typescript
859
+ await instance.startScreenShare();
860
+ ```
875
861
 
876
- **Error:** `Cross-Origin Request Blocked` when fetching token
862
+ > **Note:** Requires `features.screenShare.enabled = true` in the init config. Does nothing if already sharing.
877
863
 
878
- **Cause:** Making token generation API calls from the browser.
864
+ #### `stopScreenShare(): void`
879
865
 
880
- **Solution:**
866
+ Stop screen sharing. Releases the display stream and notifies the server.
881
867
 
882
- **Never generate tokens in client-side code.** Create a backend endpoint:
883
-
884
- ```javascript
885
- // Backend (Node.js/Express)
886
- app.post("/api/get-napster-token", async (req, res) => {
887
- const response = await fetch(
888
- "https://management-api.cogcache.com/public/connections",
889
- {
890
- method: "POST",
891
- headers: {
892
- "Content-Type": "application/json",
893
- "x-api-key": process.env.NAPSTER_API_KEY,
894
- },
895
- body: JSON.stringify({
896
- companionId: process.env.COMPANION_ID,
897
- providerConfig: {
898
- /* your config */
899
- },
900
- }),
901
- }
902
- );
903
- const data = await response.json();
904
- res.json({ token: data.token });
905
- });
868
+ ```typescript
869
+ instance.stopScreenShare();
906
870
  ```
907
871
 
908
- Then fetch from your backend in the client:
872
+ #### `toggleScreenShare(): Promise<void>`
873
+
874
+ Toggle screen sharing on or off.
909
875
 
910
876
  ```typescript
911
- const response = await fetch("/api/get-napster-token", { method: "POST" });
912
- const { token } = await response.json();
877
+ await instance.toggleScreenShare();
913
878
  ```
914
879
 
915
- ---
916
-
917
- ### Authentication / Token Issues
880
+ #### `isScreenSharing: boolean` _(read-only)_
918
881
 
919
- **Error:** `401 Unauthorized` or `Invalid token`
882
+ Whether screen sharing is currently active.
920
883
 
921
- **Possible Causes:**
884
+ ```typescript
885
+ if (instance.isScreenSharing) {
886
+ console.log("User is sharing their screen");
887
+ }
888
+ ```
922
889
 
923
- 1. Token expired
924
- 2. Invalid API key
925
- 3. Incorrect companion ID
890
+ #### `isScreenShareSupported: boolean` _(read-only)_
926
891
 
927
- **Solution:**
892
+ Whether screen sharing is supported by the browser **and** enabled in the feature config.
928
893
 
929
- 1. **Verify your API key** at [Napster API Keys page](https://app.cogcache.com/organization/keys)
930
- 2. **Check token expiration** - generate a fresh token
931
- 3. **Verify companion ID** matches your configuration
932
- 4. **Ensure backend endpoint** is working:
894
+ ```typescript
895
+ if (instance.isScreenShareSupported) {
896
+ showScreenShareButton();
897
+ }
898
+ ```
933
899
 
934
- ---
900
+ ### 5.6 Communication Methods
935
901
 
936
- ### Widget Not Mounting
902
+ #### `sendCommand(command: { type: string; data?: object }): void`
937
903
 
938
- **Error:** Container element not found or widget doesn't appear
904
+ Send a command to the avatar via the data channel.
939
905
 
940
- **Possible Causes:**
906
+ ```typescript
907
+ // Send a message to the avatar
908
+ instance.sendCommand({ type: "send_message", data: { text: "Hello, how are you?" } });
941
909
 
942
- 1. Container element doesn't exist
943
- 2. Invalid CSS selector
944
- 3. Container rendered after initialization
910
+ // Cancel the current response
911
+ instance.sendCommand({ type: "cancel" });
912
+ ```
945
913
 
946
- **Solution:**
914
+ ## 6. Configuration Interface
947
915
 
948
916
  ```typescript
949
- // Good: Wait for DOM element
950
- useEffect(() => {
951
- const container = document.querySelector("#avatar-container");
952
- if (container) {
953
- NapsterCompanionApiSdk.init(token, {
954
- mountContainer: container, // Use DOM element directly
955
- });
956
- }
957
- }, []);
917
+ interface NapsterCompanionApiConfig {
918
+ // Container mounting
919
+ mountContainer?: HTMLElement | string | null;
920
+
921
+ // Positioning
922
+ position?:
923
+ | "bottom-right"
924
+ | "bottom-left"
925
+ | "bottom-center"
926
+ | "top-right"
927
+ | "top-left"
928
+ | "top-center"
929
+ | "center";
930
+
931
+ // Styling
932
+ style?: StyleObject;
933
+ className?: string;
934
+ avatarStyle?: {
935
+ view: "round" | "rectangle" | "silhouette";
936
+ borderWidth?: string;
937
+ borderColor?: string;
938
+ borderStyle?: string;
939
+ };
958
940
 
959
- // ❌ Bad: Container may not exist yet
960
- const widget = NapsterCompanionApiSdk.init(token, {
961
- mountContainer: "#avatar-container",
962
- });
941
+ // Features
942
+ features?: {
943
+ backgroundRemoval?: { enabled: boolean };
944
+ inactiveTimeout?: {
945
+ enabled: boolean;
946
+ duration?: number; // max: 180000ms
947
+ countdown?: number; // max: 60s
948
+ };
949
+ disclaimer?: { enabled: boolean; text?: string };
950
+ showSDKLoader?: { enabled: boolean; bgColor?: string };
951
+ screenShare?: {
952
+ enabled: boolean;
953
+ };
954
+ faceTracking?: {
955
+ enabled: boolean;
956
+ fps?: number; // 1–30, default 15
957
+ talkingThreshold?: number; // default 0.015
958
+ };
959
+ };
960
+
961
+ // Configuration
962
+ debug?: boolean;
963
+
964
+ // Event callbacks
965
+ onReady?: () => void;
966
+ onError?: (error: Error) => void;
967
+ onData?: (data: EventMessage) => void;
968
+ onAvatarReady?: (isReady?: boolean) => void;
969
+ onInactivityStatusChange?: (isInactive: boolean) => void;
970
+ onDestroy?: () => void;
971
+ onFeaturesUpdate?: (features: FeatureConfig) => void;
972
+ onFaceTrackingData?: (data: FaceTrackingData | null) => void;
973
+ onFaceTrackingError?: (error: Error) => void;
974
+ }
963
975
  ```
964
976
 
965
977
  ---
966
978
 
967
- ### Module Not Found
968
-
969
- **Error:** `Cannot find module '@touchcastllc/napster-companion-api'`
979
+ ## 7. Troubleshooting
970
980
 
971
- **Cause:** Package not installed.
981
+ ### 7.1 Common Issues
972
982
 
983
+ **Problem: "Module not found" Error**
973
984
  **Solution:**
974
985
 
975
986
  ```bash
987
+ # Ensure package is installed
976
988
  npm install @touchcastllc/napster-companion-api
977
- # or
978
- yarn add @touchcastllc/napster-companion-api
979
- ```
980
989
 
981
- ---
990
+ # Install peer dependencies
991
+ npm install @reduxjs/toolkit
982
992
 
983
- ### Peer Dependency Warnings
993
+ # If using face tracking, also install:
994
+ npm install @tensorflow/tfjs @tensorflow-models/face-landmarks-detection
995
+ ```
984
996
 
985
- **Warning:** `ERESOLVE unable to resolve dependency tree`
997
+ **Problem: Invalid or expired token**
998
+ **Solution:**
986
999
 
987
- **Cause:** Missing or incompatible peer dependencies.
1000
+ - Generate new token from backend API
1001
+ - Ensure token is passed correctly to `init()`
988
1002
 
1003
+ **Problem: Avatar appears unstyled**
989
1004
  **Solution:**
990
1005
 
991
- Install all required peer dependencies:
1006
+ See the style import guide from [1.2.1 Installation & Setup](#121-for-esm-build-type-recommended)
992
1007
 
993
- ```bash
994
- # For React 18+
995
- npm install react@^18 react-dom@^18 @reduxjs/toolkit@^2 react-redux@^9
1008
+ **Problem:** `mountContainer` element doesn't exist
1009
+ **Solution:**
996
1010
 
997
- # For React 16/17
998
- npm install react@^16 react-dom@^16 @reduxjs/toolkit@^2 react-redux@^8
1011
+ ```typescript
1012
+ // Wait for DOM to load
1013
+ document.addEventListener("DOMContentLoaded", async () => {
1014
+ const instance = await NapsterCompanionApiSdk.init(token, {
1015
+ mountContainer: "#avatar-container", // Ensure element exists
1016
+ });
1017
+ });
999
1018
  ```
1000
1019
 
1001
- ---
1002
-
1003
- ### TypeScript Errors
1020
+ ### 7.2 Debug Mode
1004
1021
 
1005
- **Error:** `Cannot find type definitions`
1022
+ Enable debug logging:
1006
1023
 
1007
- **Cause:** TypeScript can't locate type definitions.
1024
+ ```typescript
1025
+ const instance = await NapsterCompanionApiSdk.init(token, {
1026
+ debug: true, // Enable debug logs
1027
+ onError: error => console.error("SDK Error:", error),
1028
+ onData: data => console.log("SDK Data:", data),
1029
+ });
1030
+ ```
1008
1031
 
1009
- **Solution:**
1032
+ ### 7.3 Performance Issues
1010
1033
 
1011
- The SDK includes TypeScript definitions. Ensure your `tsconfig.json` includes:
1034
+ #### Large Bundle Size
1012
1035
 
1013
- ```json
1014
- {
1015
- "compilerOptions": {
1016
- "moduleResolution": "node",
1017
- "esModuleInterop": true,
1018
- "skipLibCheck": true
1019
- }
1020
- }
1021
- ```
1036
+ - Use ESM build instead of standalone
1037
+ - Import only needed features
1038
+ - Enable tree-shaking in bundler
1022
1039
 
1023
- ---
1024
-
1025
- ## 📚 Additional Resources
1040
+ #### Memory Leaks
1026
1041
 
1027
- - **API Keys**: [Generate API Keys](https://app.cogcache.com/organization/keys)
1028
- - **npm**: [@touchcastllc/napster-companion-api](https://www.npmjs.com/package/@touchcastllc/napster-companion-api)
1042
+ ```typescript
1043
+ // Always cleanup when done
1044
+ useEffect(() => {
1045
+ return () => {
1046
+ instance?.destroy();
1047
+ };
1048
+ }, [instance]);
1049
+ ```
1029
1050
 
1030
1051
  ---
1031
1052
 
1032
- ## 📝 License
1053
+ ## License
1033
1054
 
1034
- MIT License. See [LICENSE](LICENSE) file for details.
1055
+ This project is licensed under the MIT License - see the [LICENSE](/LICENSE) file for details.