API reference

EffectsPipeline

The single public class. Hand it a MediaStream, get a MediaStream back with the effect applied. The pipeline owns its own worker, weight loading, autotune, frame transport selection, audio passthrough, and adaptive preset swaps — designed so you don’t have to wire any of that yourself.

Construction returns synchronously: pipeline.stream is wired immediately and emits the unprocessed input until the model is ready (~1–3s on cold start, depending on hardware). Use await pipeline.ready if you want to wait for the effect to actually be live before consuming the output.

const pipeline = new EffectsPipeline(inputStream, options?)

Constructor parameters

inputStream

Type: MediaStream  ·  Required

Any video stream — webcam from getUserMedia(), screen capture from getDisplayMedia(), or a captured stream from a <video> or <canvas> element via .captureStream(). Audio tracks are passed through unchanged by default; pass audio: 'drop' to strip them, or audio: 'denoise' to clean them (see Audio denoise).

options

Type: PipelineOptions  ·  Optional

Shape:

interface PipelineOptions {
  background?:        BackgroundInput              // default: 'blur'
  preset?:            PresetName | ManualPreset    // default: 'auto'
  weightsBaseUrl?:    string                       // default: cdn.longpipe.dev/.../v/0.0.4/
  audio?:             'passthrough' | 'drop' | 'denoise' | { denoise: DenoiseOptions }   // default: 'passthrough'
  enabled?:           boolean                      // default: true
  outputResolution?:  { w: number, h: number }     // default: input track size
  adaptive?:          boolean                      // default: true
  onReady?:           () => void
  onError?:           (err: PipelineError) => void
}

Each property in detail:

background BackgroundInput default 'blur'

Blur

To add a blur, you can either set background to 'blur' to use default blur settings,

{
  background:  'blur'
}

or you can specify an object

{
  background: {
    blur: {
      strength?: number //0 to 1
    }
  }
}

Image

You can set background to a url, an ImageBitmap or an <img> element

{
  background: string | HTMLImageElement | ImageBitmap
}

Video

You can also set a video background by specifying a video url, or a <video> element, which will play in a loop with each frame being set as the background as the video plays in a loop.

{
  background: string | HTMLVideoElement
}

Swappable at runtime via pipeline.setBackground(...) — no flicker, no re-init. See Backgrounds for the full input surface.

preset 'auto' | 'fast' | 'balanced' | 'quality' default 'auto'

Model size selection. 'auto' runs an init-time microbenchmark and picks the largest preset whose per-frame model cost fits the frame budget (~half a 30fps frame) on the user’s hardware; while in 'auto' mode the adaptive controller (see below) can swap up or down at runtime. Explicit choices — 'fast', 'balanced', 'quality' — are always respected and never auto-overridden. Pass a ManualPreset object to pin a specific model + dtype + resolution combination. See Presets & autotune.

weightsBaseUrl string default cdn.longpipe.dev/...

Where the SDK fetches model weight files. The default points at a public, versioned CDN (https://cdn.longpipe.dev/models/v/0.0.4/) — fine for prototyping. Override to self-host: offline use, locked-down corporate networks, or to avoid the public CDN dependency. The SDK fetches files of the form model_${preset}.bin. See Self-hosting weights.

audio 'passthrough' | 'drop' | 'denoise' | { denoise: DenoiseOptions } default 'passthrough'

Controls the output stream’s audio. 'passthrough' forwards the input’s audio tracks unmodified — useful for video-call scenarios where audio is part of the same stream. 'drop' strips audio, useful when you only care about the video (e.g., screen recording, frame export, server-side processing). 'denoise' runs the input microphone through the real-time speech denoiser — a separate AudioWorklet pipeline, independent of the video work — and outputs the cleaned track; pass { denoise: { model, postFilterBeta, gruLeak, enabled } } to configure it. See Audio denoise.

enabled boolean default true

Whether the effect is active. false makes the pipeline emit the raw input stream verbatim — no model load, no inference, no compositing. Toggle at runtime via pipeline.setEnabled(true | false) — cheap to re-enable since the worker stays alive.

outputResolution { w: number, h: number } default input track size

Dimensions of the output canvas. By default matches the input video track’s intrinsic size — preserves aspect ratio and avoids pointless rescale. Falls back to 1280×720 if the track hasn’t reported its size yet. Set explicitly to force a specific output dimension regardless of input.

adaptive boolean default true

Whether the SDK auto-adjusts the preset at runtime when conditions change. Only applies when preset: 'auto' — explicit preset choices are always respected. When enabled, downgrades to a smaller preset if framerate drops below target, and upgrades when modelMs shows consistent headroom (WebGPU only — WebGL upgrades are too expensive to swap live).

onReady () => void

Fires once after the first composited frame lands. Equivalent to await pipeline.ready resolving — pick whichever pattern fits your code. Fires exactly once per pipeline lifetime.

onError (err: PipelineError) => void

Fires for async / runtime errors after the constructor returns: weight 404, GPU context loss (webglcontextlost or device.lost), worker crashes, adaptive preset swap failures, runtime background-resolution errors. Synchronous construction errors (no input video track, transport setup throws) propagate out of new EffectsPipeline(...) directly — wrap construction in try/catch if you want one handler for both.

Properties

Methods

Preview

Show a user what a candidate effect would look like — e.g. while they browse a background menu — without changing the effect on the outgoing stream. The main output keeps its currently-applied background; a second canvas renders the candidate. The network and matte are computed once and shared between the two, so previewing adds only a second composite (not a second inference).

// 1. Attach a canvas you own. Called ONCE — control is transferred to the
//    worker, so the element can't be drawn to by the page afterward. The
//    worker sizes the backing to the output resolution; CSS-scale it for display.
pipeline.attachPreview(document.querySelector('#preview'))

// 2. Preview a candidate. `background` is the identical wide surface as the
//    main effect (keyword, URL, ImageBitmap, { color }, { blur }, …). 'none'
//    previews the no-effect (raw) option. fps throttles the preview (default 15;
//    the main output stays the priority).
await pipeline.setPreview({ background: 'https://example.com/beach.jpg', fps: 15 })

// 3. Stop previewing (the canvas freezes on its last frame — hide it in your UI).
pipeline.clearPreview()

To apply a previewed candidate to the outgoing stream, just call pipeline.setBackground(sameInput) — there’s no separate “commit” call.

The preview canvas is local display only; it is not a MediaStream and is not transmitted. On WebGPU it composites directly to your canvas; on WebGL2 it’s presented via a per-frame snapshot of the render canvas (a little more expensive, which is why preview is throttled).

Error handling

onError and pipeline.ready rejection both fire for async errors after the constructor returns:

onError does not fire for synchronous constructor errors — those propagate out of new EffectsPipeline(...) directly. Wrap in try/catch if you want a single handler for both.