@touchcastllc/napster-companion-api 1.0.0-alpha.34 → 1.0.0-alpha.36
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 +227 -2
- package/lib/components/Avatar/index.d.ts +4 -0
- package/lib/components/Embed/index.d.ts +4 -0
- package/lib/components/WaveForm/index.d.ts +3 -0
- package/lib/constants/events.d.ts +3 -1
- package/lib/index.d.ts +4 -0
- package/lib/index.esm.js +1 -1
- package/lib/index.js +1 -1
- package/lib/index.standalone.js +1 -1
- package/lib/services/screenShare.d.ts +12 -0
- package/lib/services/webrtc.d.ts +2 -0
- package/lib/types/index.d.ts +23 -1
- package/lib/utils/MediaCapture.d.ts +13 -0
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/svg.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
- **Zero External Dependencies:** Drop in a script tag and go
|
|
21
21
|
- **TypeScript Support:** Fully typed APIs
|
|
22
22
|
- **Tree-Shakeable:** Import only what you need
|
|
23
|
+
- **Screen Sharing:** Let the avatar see your screen in real time
|
|
23
24
|
- **Production Ready:** Minified builds with type definitions
|
|
24
25
|
|
|
25
26
|
---
|
|
@@ -377,6 +378,7 @@ async function initAdvancedAvatar() {
|
|
|
377
378
|
features: {
|
|
378
379
|
inactiveTimeout: { enabled: true, duration: 120000, countdown: 15 },
|
|
379
380
|
showSDKLoader: { enabled: true, bgColor: "#f0f0f0" },
|
|
381
|
+
screenShare: { enabled: true },
|
|
380
382
|
},
|
|
381
383
|
|
|
382
384
|
style: {
|
|
@@ -523,7 +525,149 @@ const instance = await NapsterCompanionApiSdk.init(token, {
|
|
|
523
525
|
});
|
|
524
526
|
```
|
|
525
527
|
|
|
526
|
-
### 3.2
|
|
528
|
+
### 3.2 Face Tracking
|
|
529
|
+
|
|
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.
|
|
531
|
+
|
|
532
|
+
#### Prerequisites
|
|
533
|
+
|
|
534
|
+
Install the optional peer dependencies (only needed when face tracking is enabled):
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
npm install @tensorflow/tfjs @tensorflow-models/face-landmarks-detection
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
These libraries (~2MB) are lazy-loaded at runtime — they are not included in the main SDK bundle.
|
|
541
|
+
|
|
542
|
+
#### Enable & Configure
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
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
|
+
});
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
#### Start & Stop
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
// Start detection (opens camera, loads model on first call)
|
|
572
|
+
await instance.startFaceTracking();
|
|
573
|
+
|
|
574
|
+
// Pause detection (stops camera, keeps model loaded for fast restart)
|
|
575
|
+
instance.stopFaceTracking();
|
|
576
|
+
|
|
577
|
+
// Restart — reuses model, only reopens camera
|
|
578
|
+
await instance.startFaceTracking();
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
#### Face Tracking Data
|
|
582
|
+
|
|
583
|
+
Each detection frame emits a `FaceTrackingData` object (or `null` if no face is detected):
|
|
584
|
+
|
|
585
|
+
```typescript
|
|
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
|
+
}
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
#### Error Codes
|
|
599
|
+
|
|
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 |
|
|
606
|
+
|
|
607
|
+
#### Cleanup
|
|
608
|
+
|
|
609
|
+
Face tracking is automatically destroyed when `instance.destroy()` is called. The model is disposed and camera tracks are stopped.
|
|
610
|
+
|
|
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.
|
|
614
|
+
|
|
615
|
+
#### Enable & Configure
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
const instance = await NapsterCompanionApiSdk.init(token, {
|
|
619
|
+
features: {
|
|
620
|
+
screenShare: {
|
|
621
|
+
enabled: true,
|
|
622
|
+
},
|
|
623
|
+
},
|
|
624
|
+
});
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
> **Note:** `features.screenShare.enabled` must be `true` for the screen share controls to appear and for `isScreenShareSupported` to return `true`.
|
|
628
|
+
|
|
629
|
+
#### Start & Stop
|
|
630
|
+
|
|
631
|
+
```typescript
|
|
632
|
+
// Start sharing (opens browser's screen picker)
|
|
633
|
+
await instance.startScreenShare();
|
|
634
|
+
|
|
635
|
+
// Stop sharing
|
|
636
|
+
instance.stopScreenShare();
|
|
637
|
+
|
|
638
|
+
// Or toggle on/off
|
|
639
|
+
await instance.toggleScreenShare();
|
|
640
|
+
```
|
|
641
|
+
|
|
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.
|
|
643
|
+
|
|
644
|
+
#### Checking State
|
|
645
|
+
|
|
646
|
+
```typescript
|
|
647
|
+
// Whether screen sharing is currently active
|
|
648
|
+
instance.isScreenSharing; // boolean
|
|
649
|
+
|
|
650
|
+
// Whether the browser supports screen sharing AND the feature is enabled
|
|
651
|
+
instance.isScreenShareSupported; // boolean
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
#### How It Works
|
|
655
|
+
|
|
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.
|
|
661
|
+
|
|
662
|
+
#### Cleanup
|
|
663
|
+
|
|
664
|
+
Screen sharing is automatically stopped when:
|
|
665
|
+
|
|
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
|
|
669
|
+
|
|
670
|
+
### 3.4 Position & Layout
|
|
527
671
|
|
|
528
672
|
Customize the avatar's position on the screen using predefined positions or custom styles. Also you can override the position using style properties.
|
|
529
673
|
|
|
@@ -685,7 +829,75 @@ if (instance.isFeatureEnabled("disclaimer")) {
|
|
|
685
829
|
}
|
|
686
830
|
```
|
|
687
831
|
|
|
688
|
-
### 5.4
|
|
832
|
+
### 5.4 Face Tracking Methods
|
|
833
|
+
|
|
834
|
+
#### `startFaceTracking(): Promise<void>`
|
|
835
|
+
|
|
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.
|
|
837
|
+
|
|
838
|
+
```typescript
|
|
839
|
+
await instance.startFaceTracking();
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
> **Note:** Requires `features.faceTracking.enabled = true` in the init config. Throws a `FeatureError` if not enabled.
|
|
843
|
+
|
|
844
|
+
#### `stopFaceTracking(): void`
|
|
845
|
+
|
|
846
|
+
Pause face tracking. Stops the camera and detection loop but keeps the model loaded for fast restart.
|
|
847
|
+
|
|
848
|
+
```typescript
|
|
849
|
+
instance.stopFaceTracking();
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
### 5.5 Screen Sharing Methods
|
|
853
|
+
|
|
854
|
+
#### `startScreenShare(): Promise<void>`
|
|
855
|
+
|
|
856
|
+
Start screen sharing. Opens the browser's screen picker and begins streaming frames to the avatar.
|
|
857
|
+
|
|
858
|
+
```typescript
|
|
859
|
+
await instance.startScreenShare();
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
> **Note:** Requires `features.screenShare.enabled = true` in the init config. Does nothing if already sharing.
|
|
863
|
+
|
|
864
|
+
#### `stopScreenShare(): void`
|
|
865
|
+
|
|
866
|
+
Stop screen sharing. Releases the display stream and notifies the server.
|
|
867
|
+
|
|
868
|
+
```typescript
|
|
869
|
+
instance.stopScreenShare();
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
#### `toggleScreenShare(): Promise<void>`
|
|
873
|
+
|
|
874
|
+
Toggle screen sharing on or off.
|
|
875
|
+
|
|
876
|
+
```typescript
|
|
877
|
+
await instance.toggleScreenShare();
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
#### `isScreenSharing: boolean` _(read-only)_
|
|
881
|
+
|
|
882
|
+
Whether screen sharing is currently active.
|
|
883
|
+
|
|
884
|
+
```typescript
|
|
885
|
+
if (instance.isScreenSharing) {
|
|
886
|
+
console.log("User is sharing their screen");
|
|
887
|
+
}
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
#### `isScreenShareSupported: boolean` _(read-only)_
|
|
891
|
+
|
|
892
|
+
Whether screen sharing is supported by the browser **and** enabled in the feature config.
|
|
893
|
+
|
|
894
|
+
```typescript
|
|
895
|
+
if (instance.isScreenShareSupported) {
|
|
896
|
+
showScreenShareButton();
|
|
897
|
+
}
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
### 5.6 Communication Methods
|
|
689
901
|
|
|
690
902
|
#### `sendCommand(command: { type: string; data?: object }): void`
|
|
691
903
|
|
|
@@ -736,6 +948,14 @@ interface NapsterCompanionApiConfig {
|
|
|
736
948
|
};
|
|
737
949
|
disclaimer?: { enabled: boolean; text?: string };
|
|
738
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
|
+
};
|
|
739
959
|
};
|
|
740
960
|
|
|
741
961
|
// Configuration
|
|
@@ -749,6 +969,8 @@ interface NapsterCompanionApiConfig {
|
|
|
749
969
|
onInactivityStatusChange?: (isInactive: boolean) => void;
|
|
750
970
|
onDestroy?: () => void;
|
|
751
971
|
onFeaturesUpdate?: (features: FeatureConfig) => void;
|
|
972
|
+
onFaceTrackingData?: (data: FaceTrackingData | null) => void;
|
|
973
|
+
onFaceTrackingError?: (error: Error) => void;
|
|
752
974
|
}
|
|
753
975
|
```
|
|
754
976
|
|
|
@@ -767,6 +989,9 @@ npm install @touchcastllc/napster-companion-api
|
|
|
767
989
|
|
|
768
990
|
# Install peer dependencies
|
|
769
991
|
npm install @reduxjs/toolkit
|
|
992
|
+
|
|
993
|
+
# If using face tracking, also install:
|
|
994
|
+
npm install @tensorflow/tfjs @tensorflow-models/face-landmarks-detection
|
|
770
995
|
```
|
|
771
996
|
|
|
772
997
|
**Problem: Invalid or expired token**
|
|
@@ -10,6 +10,9 @@ export interface AvatarOptions {
|
|
|
10
10
|
onError?: (error: Error) => void;
|
|
11
11
|
onInactivityStatusChange?: (isInactive: boolean) => void;
|
|
12
12
|
features?: Partial<FeatureConfig>;
|
|
13
|
+
onScreenShareToggle?: () => void;
|
|
14
|
+
isScreenSharing?: boolean;
|
|
15
|
+
isScreenShareSupported?: boolean;
|
|
13
16
|
}
|
|
14
17
|
export interface StreamsUpdate {
|
|
15
18
|
videoStream?: MediaStream | null;
|
|
@@ -22,6 +25,7 @@ export interface AvatarController extends BaseController<AvatarOptions> {
|
|
|
22
25
|
updateFeatures: (features: Partial<FeatureConfig>) => void;
|
|
23
26
|
setAvatarReady: (ready: boolean) => void;
|
|
24
27
|
handleMessage: (data: EventMessage) => void;
|
|
28
|
+
updateScreenShareState: (isSharing: boolean) => void;
|
|
25
29
|
}
|
|
26
30
|
/**
|
|
27
31
|
* Vanilla Avatar implementation.
|
|
@@ -10,10 +10,14 @@ export interface EmbedOptions {
|
|
|
10
10
|
onError?: (error: Error) => void;
|
|
11
11
|
onInactivityStatusChange?: (isInactive: boolean) => void;
|
|
12
12
|
features?: Partial<FeatureConfig>;
|
|
13
|
+
onScreenShareToggle?: () => void;
|
|
14
|
+
isScreenSharing?: boolean;
|
|
15
|
+
isScreenShareSupported?: boolean;
|
|
13
16
|
}
|
|
14
17
|
export interface EmbedController extends BaseController<EmbedOptions> {
|
|
15
18
|
updateStreams: (streams: StreamsUpdate) => void;
|
|
16
19
|
handleMessage: (data: EventMessage) => void;
|
|
20
|
+
updateScreenShareState: (isSharing: boolean) => void;
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
23
|
* Vanilla Embed implementation that renders a simple live container with Avatar
|
|
@@ -11,6 +11,9 @@ export interface WaveFormOptions {
|
|
|
11
11
|
onStopTalking?: () => void;
|
|
12
12
|
features?: Partial<NapsterCompanionApiConfig["features"]>;
|
|
13
13
|
onVolumeChange?: (volume: number) => void;
|
|
14
|
+
onScreenShareToggle?: () => void;
|
|
15
|
+
isScreenSharing?: boolean;
|
|
16
|
+
isScreenShareSupported?: boolean;
|
|
14
17
|
}
|
|
15
18
|
export type WaveFormController = BaseController<WaveFormOptions>;
|
|
16
19
|
export declare function createWaveForm(mount: HTMLElement, options: WaveFormOptions): WaveFormController;
|
|
@@ -46,5 +46,7 @@ export declare enum WebSocketMessageType {
|
|
|
46
46
|
export declare enum DataChannelMessageType {
|
|
47
47
|
SEND_MESSAGE = "send_message",
|
|
48
48
|
CANCEL = "cancel",
|
|
49
|
-
SET_SETTINGS = "set_settings"
|
|
49
|
+
SET_SETTINGS = "set_settings",
|
|
50
|
+
START_VIDEO = "start_video",
|
|
51
|
+
STOP_VIDEO = "stop_video"
|
|
50
52
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -11,11 +11,15 @@ declare class NapsterCompanionApiSdkVanilla implements NapsterCompanionApiSDK {
|
|
|
11
11
|
private rootEl;
|
|
12
12
|
private embed;
|
|
13
13
|
private webrtcController;
|
|
14
|
+
private screenShareController;
|
|
14
15
|
private faceTrackingController;
|
|
15
16
|
private config;
|
|
16
17
|
private isInitialized;
|
|
18
|
+
private unloadHandler;
|
|
17
19
|
static getInstance(): NapsterCompanionApiSdkVanilla;
|
|
20
|
+
constructor();
|
|
18
21
|
private renderApp;
|
|
22
|
+
private handleScreenShareToggle;
|
|
19
23
|
private initializeWebRTC;
|
|
20
24
|
private destroyWebRTC;
|
|
21
25
|
private destroyInstance;
|