@livepeer-frameworks/streamcrafter-wc 0.1.0
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/dist/cjs/components/fw-sc-advanced.js +198 -0
- package/dist/cjs/components/fw-sc-advanced.js.map +1 -0
- package/dist/cjs/components/fw-sc-compositor.js +116 -0
- package/dist/cjs/components/fw-sc-compositor.js.map +1 -0
- package/dist/cjs/components/fw-sc-layer-list.js +253 -0
- package/dist/cjs/components/fw-sc-layer-list.js.map +1 -0
- package/dist/cjs/components/fw-sc-scene-switcher.js +164 -0
- package/dist/cjs/components/fw-sc-scene-switcher.js.map +1 -0
- package/dist/cjs/components/fw-sc-volume.js +183 -0
- package/dist/cjs/components/fw-sc-volume.js.map +1 -0
- package/dist/cjs/components/fw-streamcrafter.js +508 -0
- package/dist/cjs/components/fw-streamcrafter.js.map +1 -0
- package/dist/cjs/controllers/ingest-controller-host.js +236 -0
- package/dist/cjs/controllers/ingest-controller-host.js.map +1 -0
- package/dist/cjs/define.js +25 -0
- package/dist/cjs/define.js.map +1 -0
- package/dist/cjs/icons/index.js +283 -0
- package/dist/cjs/icons/index.js.map +1 -0
- package/dist/cjs/index.js +38 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@rollup_plugin-typescript@12.3.0_rollup@4.57.1_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js +33 -0
- package/dist/cjs/node_modules/.pnpm/@rollup_plugin-typescript@12.3.0_rollup@4.57.1_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js.map +1 -0
- package/dist/cjs/styles/shared-styles.js +2019 -0
- package/dist/cjs/styles/shared-styles.js.map +1 -0
- package/dist/cjs/styles/utility-styles.js +182 -0
- package/dist/cjs/styles/utility-styles.js.map +1 -0
- package/dist/esm/components/fw-sc-advanced.js +198 -0
- package/dist/esm/components/fw-sc-advanced.js.map +1 -0
- package/dist/esm/components/fw-sc-compositor.js +116 -0
- package/dist/esm/components/fw-sc-compositor.js.map +1 -0
- package/dist/esm/components/fw-sc-layer-list.js +253 -0
- package/dist/esm/components/fw-sc-layer-list.js.map +1 -0
- package/dist/esm/components/fw-sc-scene-switcher.js +164 -0
- package/dist/esm/components/fw-sc-scene-switcher.js.map +1 -0
- package/dist/esm/components/fw-sc-volume.js +183 -0
- package/dist/esm/components/fw-sc-volume.js.map +1 -0
- package/dist/esm/components/fw-streamcrafter.js +508 -0
- package/dist/esm/components/fw-streamcrafter.js.map +1 -0
- package/dist/esm/controllers/ingest-controller-host.js +234 -0
- package/dist/esm/controllers/ingest-controller-host.js.map +1 -0
- package/dist/esm/define.js +23 -0
- package/dist/esm/define.js.map +1 -0
- package/dist/esm/icons/index.js +253 -0
- package/dist/esm/icons/index.js.map +1 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/node_modules/.pnpm/@rollup_plugin-typescript@12.3.0_rollup@4.57.1_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js +31 -0
- package/dist/esm/node_modules/.pnpm/@rollup_plugin-typescript@12.3.0_rollup@4.57.1_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js.map +1 -0
- package/dist/esm/styles/shared-styles.js +2017 -0
- package/dist/esm/styles/shared-styles.js.map +1 -0
- package/dist/esm/styles/utility-styles.js +180 -0
- package/dist/esm/styles/utility-styles.js.map +1 -0
- package/dist/fw-streamcrafter.iife.js +3121 -0
- package/dist/fw-streamcrafter.iife.js.map +1 -0
- package/dist/types/components/fw-sc-advanced.d.ts +20 -0
- package/dist/types/components/fw-sc-compositor.d.ts +19 -0
- package/dist/types/components/fw-sc-layer-list.d.ts +30 -0
- package/dist/types/components/fw-sc-scene-switcher.d.ts +23 -0
- package/dist/types/components/fw-sc-volume.d.ts +30 -0
- package/dist/types/components/fw-streamcrafter.d.ts +49 -0
- package/dist/types/controllers/ingest-controller-host.d.ts +77 -0
- package/dist/types/define.d.ts +1 -0
- package/dist/types/icons/index.d.ts +29 -0
- package/dist/types/iife-entry.d.ts +11 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/styles/shared-styles.d.ts +1 -0
- package/dist/types/styles/utility-styles.d.ts +1 -0
- package/package.json +55 -0
- package/src/components/fw-sc-advanced.ts +221 -0
- package/src/components/fw-sc-compositor.ts +162 -0
- package/src/components/fw-sc-layer-list.ts +251 -0
- package/src/components/fw-sc-scene-switcher.ts +163 -0
- package/src/components/fw-sc-volume.ts +171 -0
- package/src/components/fw-streamcrafter.ts +515 -0
- package/src/controllers/ingest-controller-host.ts +358 -0
- package/src/define.ts +23 -0
- package/src/icons/index.ts +291 -0
- package/src/iife-entry.ts +11 -0
- package/src/index.ts +15 -0
- package/src/styles/shared-styles.ts +2014 -0
- package/src/styles/utility-styles.ts +177 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <fw-sc-advanced> — Advanced/dev mode side panel.
|
|
3
|
+
* Simplified port of AdvancedPanel.tsx from streamcrafter-react.
|
|
4
|
+
*/
|
|
5
|
+
import { LitElement } from "lit";
|
|
6
|
+
import type { IngestControllerHost } from "../controllers/ingest-controller-host.js";
|
|
7
|
+
export declare class FwScAdvanced extends LitElement {
|
|
8
|
+
ic: IngestControllerHost;
|
|
9
|
+
private _activeTab;
|
|
10
|
+
static styles: import("lit").CSSResult[];
|
|
11
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
12
|
+
private _renderStats;
|
|
13
|
+
private _renderInfo;
|
|
14
|
+
private _row;
|
|
15
|
+
}
|
|
16
|
+
declare global {
|
|
17
|
+
interface HTMLElementTagNameMap {
|
|
18
|
+
"fw-sc-advanced": FwScAdvanced;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <fw-sc-compositor> — Compact floating compositor controls overlay.
|
|
3
|
+
* Port of CompositorControls.tsx from streamcrafter-react.
|
|
4
|
+
*/
|
|
5
|
+
import { LitElement } from "lit";
|
|
6
|
+
import type { IngestControllerHost } from "../controllers/ingest-controller-host.js";
|
|
7
|
+
export declare class FwScCompositor extends LitElement {
|
|
8
|
+
ic: IngestControllerHost;
|
|
9
|
+
private _tooltipText;
|
|
10
|
+
private _tooltipTarget;
|
|
11
|
+
static styles: import("lit").CSSResult[];
|
|
12
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
13
|
+
private _handleLayoutSelect;
|
|
14
|
+
}
|
|
15
|
+
declare global {
|
|
16
|
+
interface HTMLElementTagNameMap {
|
|
17
|
+
"fw-sc-compositor": FwScCompositor;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <fw-sc-layer-list> — Drag-to-reorder layer list.
|
|
3
|
+
* Port of LayerList.tsx from streamcrafter-react.
|
|
4
|
+
*/
|
|
5
|
+
import { LitElement } from "lit";
|
|
6
|
+
import type { Layer, MediaSource } from "@livepeer-frameworks/streamcrafter-core";
|
|
7
|
+
export declare class FwScLayerList extends LitElement {
|
|
8
|
+
layers: Layer[];
|
|
9
|
+
sources: MediaSource[];
|
|
10
|
+
selectedLayerId: string | null;
|
|
11
|
+
private _draggedId;
|
|
12
|
+
private _dragOverId;
|
|
13
|
+
private _editingLayerId;
|
|
14
|
+
static styles: import("lit").CSSResult[];
|
|
15
|
+
private get _sortedLayers();
|
|
16
|
+
private _getSourceLabel;
|
|
17
|
+
private _getSourceIcon;
|
|
18
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
19
|
+
private _dispatch;
|
|
20
|
+
private _handleDragStart;
|
|
21
|
+
private _handleDragOver;
|
|
22
|
+
private _handleDrop;
|
|
23
|
+
private _moveUp;
|
|
24
|
+
private _moveDown;
|
|
25
|
+
}
|
|
26
|
+
declare global {
|
|
27
|
+
interface HTMLElementTagNameMap {
|
|
28
|
+
"fw-sc-layer-list": FwScLayerList;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <fw-sc-scene-switcher> — Horizontal scene selector with transition controls.
|
|
3
|
+
* Port of SceneSwitcher.tsx from streamcrafter-react.
|
|
4
|
+
*/
|
|
5
|
+
import { LitElement } from "lit";
|
|
6
|
+
import type { Scene } from "@livepeer-frameworks/streamcrafter-core";
|
|
7
|
+
export declare class FwScSceneSwitcher extends LitElement {
|
|
8
|
+
scenes: Scene[];
|
|
9
|
+
activeSceneId: string | null;
|
|
10
|
+
showTransitionControls: boolean;
|
|
11
|
+
private _selectedTransition;
|
|
12
|
+
private _transitionDuration;
|
|
13
|
+
private _isTransitioning;
|
|
14
|
+
static styles: import("lit").CSSResult[];
|
|
15
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
16
|
+
private _handleSceneClick;
|
|
17
|
+
private _handleDelete;
|
|
18
|
+
}
|
|
19
|
+
declare global {
|
|
20
|
+
interface HTMLElementTagNameMap {
|
|
21
|
+
"fw-sc-scene-switcher": FwScSceneSwitcher;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <fw-sc-volume> — Volume slider with snap-to-100% and popup tooltip.
|
|
3
|
+
* Port of VolumeSlider.tsx from streamcrafter-react.
|
|
4
|
+
*/
|
|
5
|
+
import { LitElement } from "lit";
|
|
6
|
+
export declare class FwScVolume extends LitElement {
|
|
7
|
+
value: number;
|
|
8
|
+
min: number;
|
|
9
|
+
max: number;
|
|
10
|
+
snapThreshold: number;
|
|
11
|
+
compact: boolean;
|
|
12
|
+
private _isDragging;
|
|
13
|
+
private _popupPosition;
|
|
14
|
+
private _slider;
|
|
15
|
+
static styles: import("lit").CSSResult[];
|
|
16
|
+
private get _displayValue();
|
|
17
|
+
private get _isBoost();
|
|
18
|
+
private get _isDefault();
|
|
19
|
+
private get _accentColor();
|
|
20
|
+
private _handleChange;
|
|
21
|
+
private _handleMouseDown;
|
|
22
|
+
private _handleMouseUp;
|
|
23
|
+
private _updatePopupPosition;
|
|
24
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
25
|
+
}
|
|
26
|
+
declare global {
|
|
27
|
+
interface HTMLElementTagNameMap {
|
|
28
|
+
"fw-sc-volume": FwScVolume;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <fw-streamcrafter> — Main orchestrator for StreamCrafter Web Component.
|
|
3
|
+
* Port of StreamCrafter.tsx from streamcrafter-react.
|
|
4
|
+
*/
|
|
5
|
+
import { LitElement } from "lit";
|
|
6
|
+
import { IngestControllerHost } from "../controllers/ingest-controller-host.js";
|
|
7
|
+
import type { QualityProfile, MediaSource } from "@livepeer-frameworks/streamcrafter-core";
|
|
8
|
+
export declare class FwStreamCrafter extends LitElement {
|
|
9
|
+
whipUrl: string;
|
|
10
|
+
gatewayUrl: string;
|
|
11
|
+
streamKey: string;
|
|
12
|
+
initialProfile: QualityProfile;
|
|
13
|
+
autoStartCamera: boolean;
|
|
14
|
+
devMode: boolean;
|
|
15
|
+
debug: boolean;
|
|
16
|
+
enableCompositor: boolean;
|
|
17
|
+
private _showSettings;
|
|
18
|
+
private _showSources;
|
|
19
|
+
private _isAdvancedPanelOpen;
|
|
20
|
+
private _videoEl;
|
|
21
|
+
pc: IngestControllerHost;
|
|
22
|
+
static styles: import("lit").CSSResult[];
|
|
23
|
+
constructor();
|
|
24
|
+
connectedCallback(): void;
|
|
25
|
+
willUpdate(changed: Map<string, unknown>): void;
|
|
26
|
+
updated(changed: Map<string, unknown>): void;
|
|
27
|
+
private _initController;
|
|
28
|
+
private _syncVideoPreview;
|
|
29
|
+
startCamera(options?: Parameters<IngestControllerHost["startCamera"]>[0]): Promise<MediaSource>;
|
|
30
|
+
startScreenShare(options?: Parameters<IngestControllerHost["startScreenShare"]>[0]): Promise<MediaSource | null>;
|
|
31
|
+
startStreaming(): Promise<void>;
|
|
32
|
+
stopStreaming(): Promise<void>;
|
|
33
|
+
stopCapture(): Promise<void>;
|
|
34
|
+
removeSource(id: string): void;
|
|
35
|
+
setSourceVolume(id: string, vol: number): void;
|
|
36
|
+
setSourceMuted(id: string, m: boolean): void;
|
|
37
|
+
setPrimaryVideoSource(id: string): void;
|
|
38
|
+
setMasterVolume(vol: number): void;
|
|
39
|
+
setQualityProfile(p: QualityProfile): Promise<void>;
|
|
40
|
+
destroy(): void;
|
|
41
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
42
|
+
private _renderSourceRow;
|
|
43
|
+
private _renderSettingsPopup;
|
|
44
|
+
}
|
|
45
|
+
declare global {
|
|
46
|
+
interface HTMLElementTagNameMap {
|
|
47
|
+
"fw-streamcrafter": FwStreamCrafter;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IngestControllerHost — Lit ReactiveController wrapping IngestControllerV2.
|
|
3
|
+
* Direct port of useStreamCrafterV2.ts from streamcrafter-react.
|
|
4
|
+
*/
|
|
5
|
+
import type { ReactiveController, ReactiveControllerHost } from "lit";
|
|
6
|
+
import { IngestControllerV2, type IngestControllerConfigV2, type IngestState, type IngestStateContextV2, type IngestStats, type CaptureOptions, type ScreenCaptureOptions, type DeviceInfo, type MediaSource, type QualityProfile, type ReconnectionState, type EncoderOverrides } from "@livepeer-frameworks/streamcrafter-core";
|
|
7
|
+
export interface EncoderStats {
|
|
8
|
+
video: {
|
|
9
|
+
framesEncoded: number;
|
|
10
|
+
framesPending: number;
|
|
11
|
+
bytesEncoded: number;
|
|
12
|
+
lastFrameTime: number;
|
|
13
|
+
};
|
|
14
|
+
audio: {
|
|
15
|
+
samplesEncoded: number;
|
|
16
|
+
samplesPending: number;
|
|
17
|
+
bytesEncoded: number;
|
|
18
|
+
lastSampleTime: number;
|
|
19
|
+
};
|
|
20
|
+
timestamp: number;
|
|
21
|
+
}
|
|
22
|
+
export interface IngestControllerHostState {
|
|
23
|
+
state: IngestState;
|
|
24
|
+
stateContext: IngestStateContextV2;
|
|
25
|
+
isStreaming: boolean;
|
|
26
|
+
isCapturing: boolean;
|
|
27
|
+
isReconnecting: boolean;
|
|
28
|
+
error: string | null;
|
|
29
|
+
mediaStream: MediaStream | null;
|
|
30
|
+
sources: MediaSource[];
|
|
31
|
+
qualityProfile: QualityProfile;
|
|
32
|
+
reconnectionState: ReconnectionState | null;
|
|
33
|
+
stats: IngestStats | null;
|
|
34
|
+
useWebCodecs: boolean;
|
|
35
|
+
isWebCodecsActive: boolean;
|
|
36
|
+
isWebCodecsAvailable: boolean;
|
|
37
|
+
encoderStats: EncoderStats | null;
|
|
38
|
+
}
|
|
39
|
+
type HostElement = ReactiveControllerHost & HTMLElement;
|
|
40
|
+
export declare class IngestControllerHost implements ReactiveController {
|
|
41
|
+
host: HostElement;
|
|
42
|
+
private controller;
|
|
43
|
+
private unsubs;
|
|
44
|
+
private encoderStatsCleanup;
|
|
45
|
+
s: IngestControllerHostState;
|
|
46
|
+
constructor(host: HostElement, initialProfile?: QualityProfile);
|
|
47
|
+
initialize(config: IngestControllerConfigV2): void;
|
|
48
|
+
hostConnected(): void;
|
|
49
|
+
hostDisconnected(): void;
|
|
50
|
+
private teardown;
|
|
51
|
+
private update;
|
|
52
|
+
private subscribeToEvents;
|
|
53
|
+
private setupEncoderStatsListener;
|
|
54
|
+
private dispatchEvent;
|
|
55
|
+
startCamera(options?: CaptureOptions): Promise<MediaSource>;
|
|
56
|
+
startScreenShare(options?: ScreenCaptureOptions): Promise<MediaSource | null>;
|
|
57
|
+
addCustomSource(stream: MediaStream, label: string): MediaSource;
|
|
58
|
+
removeSource(sourceId: string): void;
|
|
59
|
+
stopCapture(): Promise<void>;
|
|
60
|
+
setSourceVolume(sourceId: string, volume: number): void;
|
|
61
|
+
setSourceMuted(sourceId: string, muted: boolean): void;
|
|
62
|
+
setSourceActive(sourceId: string, active: boolean): void;
|
|
63
|
+
setPrimaryVideoSource(sourceId: string): void;
|
|
64
|
+
setMasterVolume(volume: number): void;
|
|
65
|
+
getMasterVolume(): number;
|
|
66
|
+
setQualityProfile(profile: QualityProfile): Promise<void>;
|
|
67
|
+
startStreaming(): Promise<void>;
|
|
68
|
+
stopStreaming(): Promise<void>;
|
|
69
|
+
getDevices(): Promise<DeviceInfo[]>;
|
|
70
|
+
switchVideoDevice(deviceId: string): Promise<void>;
|
|
71
|
+
switchAudioDevice(deviceId: string): Promise<void>;
|
|
72
|
+
getStats(): Promise<IngestStats | null>;
|
|
73
|
+
setUseWebCodecs(enabled: boolean): void;
|
|
74
|
+
setEncoderOverrides(overrides: EncoderOverrides): void;
|
|
75
|
+
getController(): IngestControllerV2 | null;
|
|
76
|
+
}
|
|
77
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const cameraIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
2
|
+
export declare const monitorIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
3
|
+
export declare const micIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
4
|
+
export declare const micMutedIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
5
|
+
export declare const xIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
6
|
+
export declare const settingsIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
7
|
+
export declare const chevronsRightIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
8
|
+
export declare const chevronsLeftIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
9
|
+
export declare const eyeIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
10
|
+
export declare const eyeOffIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
11
|
+
export declare const videoIcon: (size?: number) => import("lit").TemplateResult<1>;
|
|
12
|
+
export declare const soloIcon: () => import("lit").TemplateResult<1>;
|
|
13
|
+
export declare const pipBRIcon: () => import("lit").TemplateResult<1>;
|
|
14
|
+
export declare const pipBLIcon: () => import("lit").TemplateResult<1>;
|
|
15
|
+
export declare const pipTRIcon: () => import("lit").TemplateResult<1>;
|
|
16
|
+
export declare const pipTLIcon: () => import("lit").TemplateResult<1>;
|
|
17
|
+
export declare const splitHIcon: () => import("lit").TemplateResult<1>;
|
|
18
|
+
export declare const splitVIcon: () => import("lit").TemplateResult<1>;
|
|
19
|
+
export declare const focusLIcon: () => import("lit").TemplateResult<1>;
|
|
20
|
+
export declare const focusRIcon: () => import("lit").TemplateResult<1>;
|
|
21
|
+
export declare const gridIcon: () => import("lit").TemplateResult<1>;
|
|
22
|
+
export declare const stackIcon: () => import("lit").TemplateResult<1>;
|
|
23
|
+
export declare const dualPipIcon: () => import("lit").TemplateResult<1>;
|
|
24
|
+
export declare const splitPipIcon: () => import("lit").TemplateResult<1>;
|
|
25
|
+
export declare const featuredIcon: () => import("lit").TemplateResult<1>;
|
|
26
|
+
export declare const featuredRIcon: () => import("lit").TemplateResult<1>;
|
|
27
|
+
export declare const letterboxIcon: () => import("lit").TemplateResult<1>;
|
|
28
|
+
export declare const cropIcon: () => import("lit").TemplateResult<1>;
|
|
29
|
+
export declare const stretchIcon: () => import("lit").TemplateResult<1>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IIFE entry — bundles everything and auto-registers custom elements.
|
|
3
|
+
* For CDN <script> tag consumers.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* <script src="fw-streamcrafter.iife.js"></script>
|
|
7
|
+
* <fw-streamcrafter whip-url="..."></fw-streamcrafter>
|
|
8
|
+
*/
|
|
9
|
+
import "./define.js";
|
|
10
|
+
export { FwStreamCrafter } from "./components/fw-streamcrafter.js";
|
|
11
|
+
export { IngestControllerHost } from "./controllers/ingest-controller-host.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESM entry — exports all classes and types but does NOT auto-register custom elements.
|
|
3
|
+
* Use `import '@livepeer-frameworks/streamcrafter-wc/define'` to register elements.
|
|
4
|
+
*/
|
|
5
|
+
export { FwStreamCrafter } from "./components/fw-streamcrafter.js";
|
|
6
|
+
export { FwScCompositor } from "./components/fw-sc-compositor.js";
|
|
7
|
+
export { FwScSceneSwitcher } from "./components/fw-sc-scene-switcher.js";
|
|
8
|
+
export { FwScLayerList } from "./components/fw-sc-layer-list.js";
|
|
9
|
+
export { FwScVolume } from "./components/fw-sc-volume.js";
|
|
10
|
+
export { FwScAdvanced } from "./components/fw-sc-advanced.js";
|
|
11
|
+
export { IngestControllerHost } from "./controllers/ingest-controller-host.js";
|
|
12
|
+
export type { IngestControllerHostState, EncoderStats, } from "./controllers/ingest-controller-host.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sharedStyles: import("lit").CSSResult;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const utilityStyles: import("lit").CSSResult;
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@livepeer-frameworks/streamcrafter-wc",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Lit Web Components for StreamCrafter - framework-agnostic streaming UI",
|
|
6
|
+
"main": "dist/cjs/index.cjs",
|
|
7
|
+
"module": "dist/esm/index.js",
|
|
8
|
+
"types": "dist/types/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"source": "./src/index.ts",
|
|
16
|
+
"types": "./dist/types/index.d.ts",
|
|
17
|
+
"import": "./dist/esm/index.js",
|
|
18
|
+
"require": "./dist/cjs/index.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./define": {
|
|
21
|
+
"source": "./src/define.ts",
|
|
22
|
+
"types": "./dist/types/define.d.ts",
|
|
23
|
+
"import": "./dist/esm/define.js",
|
|
24
|
+
"require": "./dist/cjs/define.cjs"
|
|
25
|
+
},
|
|
26
|
+
"./fw-streamcrafter.js": {
|
|
27
|
+
"source": "./src/iife-entry.ts",
|
|
28
|
+
"default": "./dist/fw-streamcrafter.iife.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build:css": "node scripts/generate-shared-styles.js",
|
|
33
|
+
"build:types": "tsc --noEmit false --emitDeclarationOnly --outDir dist/types",
|
|
34
|
+
"build": "pnpm run build:css && pnpm run build:types && NODE_ENV=production rollup -c",
|
|
35
|
+
"type-check": "tsc --noEmit",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"test:watch": "vitest"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@livepeer-frameworks/streamcrafter-core": "workspace:*",
|
|
41
|
+
"lit": "^3.2.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@rollup/plugin-commonjs": "^29.0.0",
|
|
45
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
46
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
47
|
+
"@rollup/plugin-typescript": "^12.1.4",
|
|
48
|
+
"rollup": "^4.57.1",
|
|
49
|
+
"tslib": "^2.8.1",
|
|
50
|
+
"typescript": "^5.9.2",
|
|
51
|
+
"vitest": "^4.0.18"
|
|
52
|
+
},
|
|
53
|
+
"author": "Livepeer FrameWorks",
|
|
54
|
+
"license": "Unlicense"
|
|
55
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <fw-sc-advanced> — Advanced/dev mode side panel.
|
|
3
|
+
* Simplified port of AdvancedPanel.tsx from streamcrafter-react.
|
|
4
|
+
*/
|
|
5
|
+
import { LitElement, html, css, nothing } from "lit";
|
|
6
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
7
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
8
|
+
import { sharedStyles } from "../styles/shared-styles.js";
|
|
9
|
+
import { utilityStyles } from "../styles/utility-styles.js";
|
|
10
|
+
import { xIcon } from "../icons/index.js";
|
|
11
|
+
import type { IngestControllerHost } from "../controllers/ingest-controller-host.js";
|
|
12
|
+
|
|
13
|
+
type TabId = "stats" | "info";
|
|
14
|
+
|
|
15
|
+
@customElement("fw-sc-advanced")
|
|
16
|
+
export class FwScAdvanced extends LitElement {
|
|
17
|
+
@property({ attribute: false }) ic!: IngestControllerHost;
|
|
18
|
+
|
|
19
|
+
@state() private _activeTab: TabId = "stats";
|
|
20
|
+
|
|
21
|
+
static styles = [
|
|
22
|
+
sharedStyles,
|
|
23
|
+
utilityStyles,
|
|
24
|
+
css`
|
|
25
|
+
:host {
|
|
26
|
+
display: block;
|
|
27
|
+
}
|
|
28
|
+
.panel {
|
|
29
|
+
width: 320px;
|
|
30
|
+
height: 100%;
|
|
31
|
+
border-left: 1px solid rgba(90, 96, 127, 0.3);
|
|
32
|
+
background: #1a1b26;
|
|
33
|
+
overflow: auto;
|
|
34
|
+
font-size: 0.75rem;
|
|
35
|
+
color: #a9b1d6;
|
|
36
|
+
}
|
|
37
|
+
.header {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: space-between;
|
|
41
|
+
padding: 0.5rem 0.75rem;
|
|
42
|
+
border-bottom: 1px solid rgba(90, 96, 127, 0.3);
|
|
43
|
+
}
|
|
44
|
+
.tabs {
|
|
45
|
+
display: flex;
|
|
46
|
+
gap: 0.5rem;
|
|
47
|
+
}
|
|
48
|
+
.tab {
|
|
49
|
+
padding: 0.25rem 0.5rem;
|
|
50
|
+
border: none;
|
|
51
|
+
background: none;
|
|
52
|
+
color: #565f89;
|
|
53
|
+
font-size: 0.6875rem;
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
cursor: pointer;
|
|
56
|
+
border-radius: 0.25rem;
|
|
57
|
+
}
|
|
58
|
+
.tab--active {
|
|
59
|
+
color: #c0caf5;
|
|
60
|
+
background: rgba(90, 96, 127, 0.2);
|
|
61
|
+
}
|
|
62
|
+
.close {
|
|
63
|
+
display: flex;
|
|
64
|
+
background: none;
|
|
65
|
+
border: none;
|
|
66
|
+
color: #565f89;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
padding: 0;
|
|
69
|
+
}
|
|
70
|
+
.close:hover {
|
|
71
|
+
color: #c0caf5;
|
|
72
|
+
}
|
|
73
|
+
.body {
|
|
74
|
+
padding: 0.75rem;
|
|
75
|
+
}
|
|
76
|
+
.section {
|
|
77
|
+
margin-bottom: 0.75rem;
|
|
78
|
+
}
|
|
79
|
+
.label {
|
|
80
|
+
font-size: 0.625rem;
|
|
81
|
+
font-weight: 600;
|
|
82
|
+
text-transform: uppercase;
|
|
83
|
+
letter-spacing: 0.05em;
|
|
84
|
+
color: #565f89;
|
|
85
|
+
margin-bottom: 0.375rem;
|
|
86
|
+
}
|
|
87
|
+
.row {
|
|
88
|
+
display: flex;
|
|
89
|
+
justify-content: space-between;
|
|
90
|
+
padding: 0.125rem 0;
|
|
91
|
+
}
|
|
92
|
+
.row-label {
|
|
93
|
+
color: #565f89;
|
|
94
|
+
}
|
|
95
|
+
.row-value {
|
|
96
|
+
color: #c0caf5;
|
|
97
|
+
font-family: ui-monospace, monospace;
|
|
98
|
+
font-variant-numeric: tabular-nums;
|
|
99
|
+
}
|
|
100
|
+
`,
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
protected render() {
|
|
104
|
+
return html`
|
|
105
|
+
<div class="panel">
|
|
106
|
+
<div class="header">
|
|
107
|
+
<div class="tabs">
|
|
108
|
+
<button
|
|
109
|
+
class=${classMap({ tab: true, "tab--active": this._activeTab === "stats" })}
|
|
110
|
+
@click=${() => {
|
|
111
|
+
this._activeTab = "stats";
|
|
112
|
+
}}
|
|
113
|
+
>
|
|
114
|
+
Stats
|
|
115
|
+
</button>
|
|
116
|
+
<button
|
|
117
|
+
class=${classMap({ tab: true, "tab--active": this._activeTab === "info" })}
|
|
118
|
+
@click=${() => {
|
|
119
|
+
this._activeTab = "info";
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
Info
|
|
123
|
+
</button>
|
|
124
|
+
</div>
|
|
125
|
+
<button
|
|
126
|
+
class="close"
|
|
127
|
+
@click=${() =>
|
|
128
|
+
this.dispatchEvent(new CustomEvent("fw-close", { bubbles: true, composed: true }))}
|
|
129
|
+
aria-label="Close panel"
|
|
130
|
+
>
|
|
131
|
+
${xIcon(14)}
|
|
132
|
+
</button>
|
|
133
|
+
</div>
|
|
134
|
+
<div class="body">
|
|
135
|
+
${this._activeTab === "stats" ? this._renderStats() : this._renderInfo()}
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private _renderStats() {
|
|
142
|
+
const s = this.ic.s;
|
|
143
|
+
const stats = s.stats;
|
|
144
|
+
return html`
|
|
145
|
+
<div class="section">
|
|
146
|
+
<div class="label">Connection</div>
|
|
147
|
+
${this._row("State", s.state)}
|
|
148
|
+
${this._row(
|
|
149
|
+
"WebCodecs",
|
|
150
|
+
s.isWebCodecsActive ? "Active" : s.useWebCodecs ? "Pending" : "Off"
|
|
151
|
+
)}
|
|
152
|
+
</div>
|
|
153
|
+
${stats
|
|
154
|
+
? html`
|
|
155
|
+
<div class="section">
|
|
156
|
+
<div class="label">WebRTC Stats</div>
|
|
157
|
+
${this._row(
|
|
158
|
+
"Video bitrate",
|
|
159
|
+
stats.video.bitrate ? `${Math.round(stats.video.bitrate / 1000)} kbps` : "—"
|
|
160
|
+
)}
|
|
161
|
+
${this._row(
|
|
162
|
+
"Audio bitrate",
|
|
163
|
+
stats.audio.bitrate ? `${Math.round(stats.audio.bitrate / 1000)} kbps` : "—"
|
|
164
|
+
)}
|
|
165
|
+
${this._row(
|
|
166
|
+
"RTT",
|
|
167
|
+
stats.connection.rtt ? `${(stats.connection.rtt * 1000).toFixed(0)} ms` : "—"
|
|
168
|
+
)}
|
|
169
|
+
${this._row(
|
|
170
|
+
"FPS",
|
|
171
|
+
stats.video.framesPerSecond ? String(stats.video.framesPerSecond) : "—"
|
|
172
|
+
)}
|
|
173
|
+
${this._row("Packets sent", String(stats.video.packetsSent))}
|
|
174
|
+
${this._row("Packets lost", String(stats.video.packetsLost))}
|
|
175
|
+
</div>
|
|
176
|
+
`
|
|
177
|
+
: nothing}
|
|
178
|
+
${s.encoderStats
|
|
179
|
+
? html`
|
|
180
|
+
<div class="section">
|
|
181
|
+
<div class="label">Encoder</div>
|
|
182
|
+
${this._row("Video frames", String(s.encoderStats.video.framesEncoded))}
|
|
183
|
+
${this._row("Video pending", String(s.encoderStats.video.framesPending))}
|
|
184
|
+
${this._row("Audio samples", String(s.encoderStats.audio.samplesEncoded))}
|
|
185
|
+
</div>
|
|
186
|
+
`
|
|
187
|
+
: nothing}
|
|
188
|
+
`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private _renderInfo() {
|
|
192
|
+
const s = this.ic.s;
|
|
193
|
+
return html`
|
|
194
|
+
<div class="section">
|
|
195
|
+
<div class="label">Configuration</div>
|
|
196
|
+
${this._row("Profile", s.qualityProfile)} ${this._row("Sources", String(s.sources.length))}
|
|
197
|
+
${this._row("WebCodecs Available", s.isWebCodecsAvailable ? "Yes" : "No")}
|
|
198
|
+
</div>
|
|
199
|
+
<div class="section">
|
|
200
|
+
<div class="label">Sources</div>
|
|
201
|
+
${s.sources.map(
|
|
202
|
+
(source) => html`
|
|
203
|
+
${this._row(source.label, `${source.type} ${source.muted ? "(muted)" : ""}`)}
|
|
204
|
+
`
|
|
205
|
+
)}
|
|
206
|
+
</div>
|
|
207
|
+
`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private _row(label: string, value: string) {
|
|
211
|
+
return html`<div class="row">
|
|
212
|
+
<span class="row-label">${label}</span><span class="row-value">${value}</span>
|
|
213
|
+
</div>`;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
declare global {
|
|
218
|
+
interface HTMLElementTagNameMap {
|
|
219
|
+
"fw-sc-advanced": FwScAdvanced;
|
|
220
|
+
}
|
|
221
|
+
}
|