StreamCrafter — Vanilla JS
Installation
Section titled “Installation”npm install @livepeer-frameworks/streamcrafter-coreimport "@livepeer-frameworks/streamcrafter-core/streamcrafter.css";createStreamCrafter()
Section titled “createStreamCrafter()”The primary API for vanilla and headless usage. Returns a property-based facade with queries, mutations, and subscriptions.
import { createStreamCrafter } from "@livepeer-frameworks/streamcrafter-core";import "@livepeer-frameworks/streamcrafter-core/streamcrafter.css";
const studio = createStreamCrafter({ target: "#studio-container", whipUrl: "https://edge-ingest.frameworks.network/webrtc/stream-key", profile: "broadcast", debug: true,});
// Read state (queries)studio.state; // "idle"studio.streaming; // falsestudio.sources; // []studio.profile; // "broadcast"
// Change state (mutations)await studio.startCamera();await studio.startScreenShare({ audio: true });await studio.goLive();
// React to changes (subscriptions)const unsub = studio.reactiveState.on("streaming", (isLive) => { goLiveBtn.textContent = isLive ? "Stop" : "Go Live";});
// Cleanupstudio.destroy();Use gatewayUrl + streamKey only when the resolve request runs in the publisher’s browser or
device. For backend or encoder-side publishing, prefer the dashboard DNS ingest URL directly.
Queries (Read State)
Section titled “Queries (Read State)”All queries are synchronous getters on the instance.
| Property | Type | Description |
|---|---|---|
state | IngestState | Current lifecycle state |
streaming | boolean | Whether currently live |
capturing | boolean | Whether media is captured |
reconnecting | boolean | Whether reconnecting |
sources | MediaSource[] | Active media sources |
primaryVideo | MediaSource | null | Primary video source |
masterVolume | number | Master volume (0-1) |
profile | QualityProfile | Current quality profile |
compositorEnabled | boolean | Whether compositor is active |
webCodecsActive | boolean | Whether WebCodecs encoder is active |
Mutations (Change State)
Section titled “Mutations (Change State)”| Mutation | Signature | Description |
|---|---|---|
startCamera(opts?) | (opts?) => Promise<MediaSource> | Add camera source |
startScreenShare(opts?) | (opts?) => Promise<MediaSource | null> | Add screen share source |
goLive() | () => Promise<void> | Start streaming |
stop() | () => Promise<void> | Stop streaming |
removeSource(id) | (id: string) => void | Remove a source |
setSourceVolume(id, vol) | (id, number) => void | Set source volume |
setSourceMuted(id, muted) | (id, boolean) => void | Mute/unmute source |
setSourceActive(id, active) | (id, boolean) => void | Set active source |
setPrimaryVideo(id) | (id: string) => void | Set primary video |
profile = | set profile(p) | Change quality profile |
masterVolume = | set masterVolume(v) | Set master volume |
theme = | set theme(t) | Switch theme preset |
setEncoderOverrides(o) | (overrides) => void | Override encoder settings |
destroy() | () => void | Cleanup and tear down |
Subscriptions — Events
Section titled “Subscriptions — Events”Event-based subscriptions using on(event, listener). Returns an unsubscribe function.
const unsub = studio.on("stateChange", ({ state, context }) => { console.log("New state:", state);});unsub();| Event | Payload | Description |
|---|---|---|
stateChange | { state, context } | Lifecycle state transition |
sourceAdded | { source } | New source added |
sourceRemoved | { sourceId } | Source removed |
sourceUpdated | { source, changes } | Source properties changed |
qualityChanged | { profile, previousProfile } | Quality profile changed |
statsUpdate | IngestStats | Streaming statistics update |
deviceChange | { devices } | Available devices changed |
error | { error, recoverable } | Error occurred |
reconnectionAttempt | { attempt, maxAttempts } | Reconnection attempt started |
reconnectionSuccess | void | Reconnection succeeded |
reconnectionFailed | { error } | All reconnection attempts failed |
webCodecsActive | { active } | WebCodecs encoder state changed |
Subscriptions — Reactive State
Section titled “Subscriptions — Reactive State”Per-property reactive subscriptions with immediate invocation. The callback fires immediately with the current value, then on every change.
const unsub = studio.reactiveState.on("streaming", (isLive) => { goLiveBtn.textContent = isLive ? "Stop" : "Go Live";});
const unsub2 = studio.reactiveState.on("sources", (sources) => { sourceList.innerHTML = sources.map((s) => `<li>${s.label}</li>`).join("");});
// Read current value without subscribingconst isLive = studio.reactiveState.get("streaming");| Property | Type | Trigger Events |
|---|---|---|
state | IngestState | stateChange |
stateContext | IngestStateContextV2 | stateChange |
streaming | boolean | stateChange |
capturing | boolean | stateChange |
reconnecting | boolean | stateChange |
sources | MediaSource[] | sourceAdded, sourceRemoved, sourceUpdated |
primaryVideo | MediaSource | null | sourceUpdated |
masterVolume | number | stateChange |
profile | QualityProfile | qualityChanged |
error | string | null | error, stateChange |
compositorEnabled | boolean | stateChange |
webCodecsActive | boolean | webCodecsActive |
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
target | string | HTMLElement | — | Container element or selector |
whipUrl | string | — | Direct WHIP ingest endpoint |
gatewayUrl | string | — | Gateway GraphQL endpoint for resolver-backed ingest environments |
streamKey | string | — | Stream key used with gatewayUrl |
profile | string | "broadcast" | Quality preset name |
theme | string | "default" | Theme preset |
locale | string | "en" | UI language |
keyMap | KeyMap | — | Custom hotkey bindings |
reconnection | ReconnectionConfig | { enabled: true } | Reconnection settings |
debug | boolean | false | Debug logging |
enableCompositor | boolean | true | Enable compositor |
useWebCodecs | boolean | auto | WebCodecs encoder (auto-enabled on Chromium) |
Headless Mode
Section titled “Headless Mode”Omit target to run without any UI — useful for building entirely custom interfaces:
const studio = createStreamCrafter({ whipUrl: "https://edge-ingest.frameworks.network/webrtc/key", profile: "broadcast",});
// No UI rendered — control everything programmaticallyawait studio.startCamera();const stream = studio.mediaStream;myVideoElement.srcObject = stream;
studio.reactiveState.on("state", (s) => updateUI(s));await studio.goLive();Advanced Controls
Section titled “Advanced Controls”The vanilla facade already exposes advanced operations directly:
// Device enumerationconst devices = await studio.devices;
// Compositorawait studio.enableCompositor({ renderer: "webgl" });
// Statsconst stats = await studio.stats;