@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.
- package/README.md +704 -683
- package/lib/components/Avatar/index.d.ts +35 -2
- package/lib/components/Embed/index.d.ts +25 -2
- package/lib/components/InactiveOverlay/index.d.ts +15 -2
- package/lib/components/Preview/index.d.ts +18 -2
- package/lib/components/StyledTooltip/index.d.ts +16 -2
- package/lib/components/VolumeControl/index.d.ts +18 -0
- package/lib/components/WaveForm/index.d.ts +19 -2
- package/lib/components/index.d.ts +2 -3
- package/lib/constants/events.d.ts +52 -0
- package/lib/constants/greenscreen.d.ts +28 -0
- package/lib/constants/index.d.ts +6 -0
- package/lib/constants/waveform.d.ts +34 -0
- package/lib/index.css +1 -1
- package/lib/index.d.ts +25 -10
- package/lib/index.esm.js +1 -1
- package/lib/index.js +1 -1
- package/lib/index.standalone.js +1 -1
- package/lib/services/analytics.d.ts +116 -35
- package/lib/services/faceTracking.d.ts +13 -0
- package/lib/services/screenShare.d.ts +12 -0
- package/lib/services/webrtc.d.ts +29 -0
- package/lib/setupTests.d.ts +0 -1
- package/lib/stores/index.d.ts +2 -3
- package/lib/stores/middleware/featuresUpdateMiddleware.d.ts +0 -1
- package/lib/stores/selectors.d.ts +30 -0
- package/lib/stores/slices/appSlice.d.ts +2 -2
- package/lib/stores/slices/avatarSlice.d.ts +0 -1
- package/lib/stores/store.d.ts +4 -5
- package/lib/types/abstract-typing.d.ts +35 -0
- package/lib/types/analytics.d.ts +95 -0
- package/lib/types/errors.d.ts +63 -3
- package/lib/types/index.d.ts +277 -13
- package/lib/umd.d.ts +0 -1
- package/lib/utils/InactiveOverlayManager.d.ts +77 -0
- package/lib/utils/MediaCapture.d.ts +13 -0
- package/lib/utils/classnames.d.ts +50 -0
- package/lib/utils/debug.d.ts +84 -0
- package/lib/utils/domFactory.d.ts +56 -0
- package/lib/utils/greenscreen/GreenScreenProcessor.d.ts +25 -0
- package/lib/utils/greenscreen/index.d.ts +1 -0
- package/lib/utils/index.d.ts +15 -1
- package/lib/utils/mouthDetection.d.ts +33 -0
- package/lib/utils/sendCommand.d.ts +2 -0
- package/lib/utils/svg.d.ts +34 -0
- package/package.json +18 -18
- package/lib/CompanionApiProvider.d.ts +0 -16
- package/lib/components/Avatar/Avatar.d.ts +0 -13
- package/lib/components/Embed/Embed.d.ts +0 -13
- package/lib/components/InactiveOverlay/InactiveOverlay.d.ts +0 -12
- package/lib/components/Preview/Preview.d.ts +0 -9
- package/lib/components/StyledTooltip/StyledTooltip.d.ts +0 -12
- package/lib/components/WaveForm/WaveForm.d.ts +0 -16
- package/lib/hooks/index.d.ts +0 -5
- package/lib/hooks/useApp.d.ts +0 -25
- package/lib/hooks/useAvatar.d.ts +0 -65
- package/lib/hooks/useMicrophones.d.ts +0 -8
- package/lib/hooks/useWebRTC.d.ts +0 -22
- package/lib/index-legacy.d.ts +0 -23
- package/lib/index-legacy.esm.js +0 -1
- package/lib/index-legacy.js +0 -1
- package/lib/index.umd.js +0 -1
- package/lib/sdk-base-chunk.esm.js +0 -1
- package/lib/sdk-base-chunk.js +0 -1
- package/lib/sdk-base.d.ts +0 -25
- package/lib/stores/hooks.d.ts +0 -8
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@touchcastllc/napster-companion-api)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
|
|
6
|
-
>
|
|
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
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
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
|
-
##
|
|
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
|
-
###
|
|
32
|
+
### 1.1 Choose Your Setup
|
|
34
33
|
|
|
35
34
|
Pick the integration method that matches your project:
|
|
36
35
|
|
|
37
|
-
| Build Type
|
|
38
|
-
|
|
|
39
|
-
| **
|
|
40
|
-
| **
|
|
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
|
-
|
|
41
|
+
---
|
|
46
42
|
|
|
47
|
-
|
|
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
|
-
|
|
45
|
+
#### 1.2.1 For ESM Build Type (Recommended)
|
|
55
46
|
|
|
56
|
-
|
|
47
|
+
**Step 1: Install the SDK**
|
|
57
48
|
|
|
58
|
-
|
|
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
|
-
|
|
57
|
+
Install peer dependencies:
|
|
67
58
|
|
|
68
59
|
```bash
|
|
69
|
-
|
|
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
|
-
**
|
|
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/
|
|
76
|
+
import "@touchcastllc/napster-companion-api/styles";
|
|
90
77
|
```
|
|
91
78
|
|
|
92
|
-
|
|
79
|
+
**CommonJS:**
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
require("@touchcastllc/napster-companion-api/styles");
|
|
83
|
+
```
|
|
93
84
|
|
|
94
|
-
**
|
|
85
|
+
**HTML `<link>` Tag:**
|
|
95
86
|
|
|
96
87
|
```html
|
|
97
|
-
<
|
|
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
|
-
|
|
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
|
-
|
|
104
|
-
<script src="https://cdn.jsdelivr.net/npm/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
133
|
+
See the [1.4 Authentication](#14-authentication) section for details on generating auth tokens.
|
|
142
134
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
###
|
|
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://
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
//
|
|
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("/
|
|
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
|
-
##
|
|
238
|
+
## 2. Examples
|
|
220
239
|
|
|
221
|
-
|
|
240
|
+
We provide example implementations for popular frameworks and vanilla JavaScript:
|
|
222
241
|
|
|
223
|
-
###
|
|
242
|
+
### 2.1 React
|
|
224
243
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
-
|
|
249
|
+
export function CompanionWidget() {
|
|
250
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
251
|
+
const [instance, setInstance] = useState<NapsterCompanionApiInstance | null>(
|
|
252
|
+
null
|
|
253
|
+
);
|
|
233
254
|
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
307
|
+
### 2.3 Angular
|
|
253
308
|
|
|
254
309
|
```typescript
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
366
|
+
### 2.5 Advanced Configuration
|
|
274
367
|
|
|
275
|
-
|
|
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
|
-
|
|
374
|
+
avatarStyle: {
|
|
375
|
+
view: "round", // Options: "round" | "rectangle" | "silhouette"
|
|
376
|
+
},
|
|
278
377
|
|
|
279
|
-
|
|
378
|
+
features: {
|
|
379
|
+
inactiveTimeout: { enabled: true, duration: 120000, countdown: 15 },
|
|
380
|
+
showSDKLoader: { enabled: true, bgColor: "#f0f0f0" },
|
|
381
|
+
screenShare: { enabled: true },
|
|
382
|
+
},
|
|
280
383
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
384
|
+
style: {
|
|
385
|
+
borderRadius: "12px",
|
|
386
|
+
boxShadow: "0 4px 20px rgba(0,0,0,0.3)",
|
|
387
|
+
},
|
|
285
388
|
|
|
286
|
-
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
|
|
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
|
-
|
|
415
|
+
### 2.7 Custom Styling
|
|
312
416
|
|
|
313
|
-
|
|
417
|
+
#### Inline Styles
|
|
314
418
|
|
|
315
419
|
```typescript
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
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
|
-
|
|
432
|
+
```typescript
|
|
433
|
+
const instance = await NapsterCompanionApiSdk.init(token, {
|
|
434
|
+
className: "my-custom-avatar",
|
|
435
|
+
});
|
|
436
|
+
```
|
|
325
437
|
|
|
326
|
-
|
|
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
|
-
|
|
446
|
+
#### Dynamic Style Updates
|
|
329
447
|
|
|
330
448
|
```typescript
|
|
331
|
-
|
|
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
|
-
|
|
459
|
+
Customize the avatar's visual appearance using the `avatarStyle` configuration. Control the avatar's view mode, and other visual properties.
|
|
337
460
|
|
|
338
|
-
|
|
461
|
+
#### Avatar View Modes
|
|
339
462
|
|
|
340
463
|
```typescript
|
|
341
|
-
|
|
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
|
-
|
|
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
|
-
|
|
477
|
+
#### Avatar Style Example
|
|
349
478
|
|
|
350
479
|
```typescript
|
|
351
|
-
|
|
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
|
-
|
|
493
|
+
## 3. Feature Configuration
|
|
494
|
+
|
|
495
|
+
### 3.1 Core Features
|
|
357
496
|
|
|
358
|
-
|
|
497
|
+
#### Inactivity Timeout
|
|
359
498
|
|
|
360
|
-
|
|
499
|
+
Automatically disconnect the avatar after a period of user inactivity. Users receive a countdown notification before disconnection.
|
|
361
500
|
|
|
362
501
|
```typescript
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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
|
-
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
-
|
|
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
|
-
|
|
532
|
+
#### Prerequisites
|
|
533
|
+
|
|
534
|
+
Install the optional peer dependencies (only needed when face tracking is enabled):
|
|
387
535
|
|
|
388
|
-
|
|
536
|
+
```bash
|
|
537
|
+
npm install @tensorflow/tfjs @tensorflow-models/face-landmarks-detection
|
|
538
|
+
```
|
|
389
539
|
|
|
390
|
-
-
|
|
540
|
+
These libraries (~2MB) are lazy-loaded at runtime — they are not included in the main SDK bundle.
|
|
391
541
|
|
|
392
|
-
|
|
542
|
+
#### Enable & Configure
|
|
393
543
|
|
|
394
544
|
```typescript
|
|
395
|
-
|
|
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
|
-
|
|
570
|
+
```typescript
|
|
571
|
+
// Start detection (opens camera, loads model on first call)
|
|
572
|
+
await instance.startFaceTracking();
|
|
401
573
|
|
|
402
|
-
|
|
574
|
+
// Pause detection (stops camera, keeps model loaded for fast restart)
|
|
575
|
+
instance.stopFaceTracking();
|
|
403
576
|
|
|
404
|
-
|
|
577
|
+
// Restart — reuses model, only reopens camera
|
|
578
|
+
await instance.startFaceTracking();
|
|
579
|
+
```
|
|
405
580
|
|
|
406
|
-
|
|
581
|
+
#### Face Tracking Data
|
|
407
582
|
|
|
408
|
-
|
|
583
|
+
Each detection frame emits a `FaceTrackingData` object (or `null` if no face is detected):
|
|
409
584
|
|
|
410
585
|
```typescript
|
|
411
|
-
|
|
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
|
-
|
|
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
|
-
|
|
607
|
+
#### Cleanup
|
|
419
608
|
|
|
420
|
-
|
|
609
|
+
Face tracking is automatically destroyed when `instance.destroy()` is called. The model is disposed and camera tracks are stopped.
|
|
421
610
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
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
|
-
|
|
615
|
+
#### Enable & Configure
|
|
432
616
|
|
|
433
617
|
```typescript
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
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
|
-
|
|
629
|
+
#### Start & Stop
|
|
443
630
|
|
|
444
631
|
```typescript
|
|
445
|
-
//
|
|
446
|
-
|
|
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
|
-
//
|
|
459
|
-
|
|
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
|
-
//
|
|
467
|
-
|
|
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
|
-
|
|
644
|
+
#### Checking State
|
|
481
645
|
|
|
482
|
-
|
|
646
|
+
```typescript
|
|
647
|
+
// Whether screen sharing is currently active
|
|
648
|
+
instance.isScreenSharing; // boolean
|
|
483
649
|
|
|
484
|
-
|
|
650
|
+
// Whether the browser supports screen sharing AND the feature is enabled
|
|
651
|
+
instance.isScreenShareSupported; // boolean
|
|
652
|
+
```
|
|
485
653
|
|
|
486
|
-
|
|
487
|
-
import React, { useEffect, useRef, useState } from "react";
|
|
488
|
-
import { NapsterCompanionApiSdk } from "@touchcastllc/napster-companion-api";
|
|
654
|
+
#### How It Works
|
|
489
655
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
-
|
|
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
|
-
|
|
664
|
+
Screen sharing is automatically stopped when:
|
|
524
665
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
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
|
-
|
|
570
|
-
// Cleanup on unmount
|
|
571
|
-
this.widget?.destroy();
|
|
572
|
-
}
|
|
699
|
+
## 4. Event Handling
|
|
573
700
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
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
|
-
|
|
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
|
-
|
|
597
|
-
let widget = null;
|
|
724
|
+
### 5.1 Core Methods
|
|
598
725
|
|
|
599
|
-
|
|
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
|
-
|
|
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
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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
|
-
|
|
739
|
+
Make the avatar visible on screen.
|
|
631
740
|
|
|
632
|
-
```
|
|
633
|
-
|
|
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
|
-
|
|
747
|
+
Hide the avatar from screen.
|
|
679
748
|
|
|
680
749
|
```typescript
|
|
681
|
-
|
|
682
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
712
|
-
|
|
713
|
-
|
|
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
|
-
|
|
765
|
+
Cleanup and remove the SDK completely.
|
|
735
766
|
|
|
736
|
-
```
|
|
737
|
-
|
|
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
|
-
|
|
773
|
+
#### `updateStyles(styles: StyleObject): void`
|
|
786
774
|
|
|
787
|
-
|
|
775
|
+
Update container styles dynamically.
|
|
788
776
|
|
|
789
777
|
```typescript
|
|
790
|
-
|
|
778
|
+
instance.updateStyles({
|
|
779
|
+
top: "50px",
|
|
780
|
+
left: "50px",
|
|
781
|
+
opacity: "0.8",
|
|
782
|
+
});
|
|
791
783
|
```
|
|
792
784
|
|
|
793
|
-
|
|
785
|
+
#### `setPosition(position: Position): void`
|
|
794
786
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
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
|
-
|
|
796
|
+
#### `clearPosition(): void`
|
|
803
797
|
|
|
804
|
-
|
|
798
|
+
Reset position to default/configured value.
|
|
805
799
|
|
|
806
800
|
```typescript
|
|
807
|
-
|
|
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
|
-
|
|
806
|
+
#### `enableFeature(feature: string): void`
|
|
828
807
|
|
|
829
|
-
|
|
808
|
+
Enable a specific feature.
|
|
809
|
+
|
|
810
|
+
```typescript
|
|
811
|
+
instance.enableFeature("disclaimer");
|
|
812
|
+
```
|
|
830
813
|
|
|
831
|
-
|
|
814
|
+
#### `disableFeature(feature: string): void`
|
|
832
815
|
|
|
833
|
-
|
|
816
|
+
Disable a specific feature.
|
|
834
817
|
|
|
835
|
-
|
|
818
|
+
```typescript
|
|
819
|
+
instance.disableFeature("disclaimer");
|
|
820
|
+
```
|
|
836
821
|
|
|
837
|
-
|
|
822
|
+
#### `isFeatureEnabled(feature: string): boolean`
|
|
838
823
|
|
|
839
|
-
|
|
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
|
-
```
|
|
843
|
-
|
|
844
|
-
|
|
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
|
-
|
|
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
|
-
|
|
838
|
+
```typescript
|
|
839
|
+
await instance.startFaceTracking();
|
|
840
|
+
```
|
|
852
841
|
|
|
853
|
-
**
|
|
842
|
+
> **Note:** Requires `features.faceTracking.enabled = true` in the init config. Throws a `FeatureError` if not enabled.
|
|
854
843
|
|
|
855
|
-
|
|
844
|
+
#### `stopFaceTracking(): void`
|
|
856
845
|
|
|
857
|
-
|
|
846
|
+
Pause face tracking. Stops the camera and detection loop but keeps the model loaded for fast restart.
|
|
858
847
|
|
|
859
848
|
```typescript
|
|
860
|
-
|
|
849
|
+
instance.stopFaceTracking();
|
|
861
850
|
```
|
|
862
851
|
|
|
863
|
-
|
|
852
|
+
### 5.5 Screen Sharing Methods
|
|
864
853
|
|
|
865
|
-
|
|
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
|
-
|
|
858
|
+
```typescript
|
|
859
|
+
await instance.startScreenShare();
|
|
860
|
+
```
|
|
875
861
|
|
|
876
|
-
**
|
|
862
|
+
> **Note:** Requires `features.screenShare.enabled = true` in the init config. Does nothing if already sharing.
|
|
877
863
|
|
|
878
|
-
|
|
864
|
+
#### `stopScreenShare(): void`
|
|
879
865
|
|
|
880
|
-
|
|
866
|
+
Stop screen sharing. Releases the display stream and notifies the server.
|
|
881
867
|
|
|
882
|
-
|
|
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
|
-
|
|
872
|
+
#### `toggleScreenShare(): Promise<void>`
|
|
873
|
+
|
|
874
|
+
Toggle screen sharing on or off.
|
|
909
875
|
|
|
910
876
|
```typescript
|
|
911
|
-
|
|
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
|
-
|
|
882
|
+
Whether screen sharing is currently active.
|
|
920
883
|
|
|
921
|
-
|
|
884
|
+
```typescript
|
|
885
|
+
if (instance.isScreenSharing) {
|
|
886
|
+
console.log("User is sharing their screen");
|
|
887
|
+
}
|
|
888
|
+
```
|
|
922
889
|
|
|
923
|
-
|
|
924
|
-
2. Invalid API key
|
|
925
|
-
3. Incorrect companion ID
|
|
890
|
+
#### `isScreenShareSupported: boolean` _(read-only)_
|
|
926
891
|
|
|
927
|
-
**
|
|
892
|
+
Whether screen sharing is supported by the browser **and** enabled in the feature config.
|
|
928
893
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
894
|
+
```typescript
|
|
895
|
+
if (instance.isScreenShareSupported) {
|
|
896
|
+
showScreenShareButton();
|
|
897
|
+
}
|
|
898
|
+
```
|
|
933
899
|
|
|
934
|
-
|
|
900
|
+
### 5.6 Communication Methods
|
|
935
901
|
|
|
936
|
-
|
|
902
|
+
#### `sendCommand(command: { type: string; data?: object }): void`
|
|
937
903
|
|
|
938
|
-
|
|
904
|
+
Send a command to the avatar via the data channel.
|
|
939
905
|
|
|
940
|
-
|
|
906
|
+
```typescript
|
|
907
|
+
// Send a message to the avatar
|
|
908
|
+
instance.sendCommand({ type: "send_message", data: { text: "Hello, how are you?" } });
|
|
941
909
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
910
|
+
// Cancel the current response
|
|
911
|
+
instance.sendCommand({ type: "cancel" });
|
|
912
|
+
```
|
|
945
913
|
|
|
946
|
-
|
|
914
|
+
## 6. Configuration Interface
|
|
947
915
|
|
|
948
916
|
```typescript
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
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
|
-
//
|
|
960
|
-
|
|
961
|
-
|
|
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
|
-
|
|
968
|
-
|
|
969
|
-
**Error:** `Cannot find module '@touchcastllc/napster-companion-api'`
|
|
979
|
+
## 7. Troubleshooting
|
|
970
980
|
|
|
971
|
-
|
|
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
|
-
|
|
993
|
+
# If using face tracking, also install:
|
|
994
|
+
npm install @tensorflow/tfjs @tensorflow-models/face-landmarks-detection
|
|
995
|
+
```
|
|
984
996
|
|
|
985
|
-
**
|
|
997
|
+
**Problem: Invalid or expired token**
|
|
998
|
+
**Solution:**
|
|
986
999
|
|
|
987
|
-
|
|
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
|
-
|
|
1006
|
+
See the style import guide from [1.2.1 Installation & Setup](#121-for-esm-build-type-recommended)
|
|
992
1007
|
|
|
993
|
-
|
|
994
|
-
|
|
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
|
-
|
|
998
|
-
|
|
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
|
-
|
|
1022
|
+
Enable debug logging:
|
|
1006
1023
|
|
|
1007
|
-
|
|
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
|
-
|
|
1032
|
+
### 7.3 Performance Issues
|
|
1010
1033
|
|
|
1011
|
-
|
|
1034
|
+
#### Large Bundle Size
|
|
1012
1035
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
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
|
-
|
|
1028
|
-
|
|
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
|
-
##
|
|
1053
|
+
## License
|
|
1033
1054
|
|
|
1034
|
-
MIT License
|
|
1055
|
+
This project is licensed under the MIT License - see the [LICENSE](/LICENSE) file for details.
|