@videoflow/renderer-dom
Live, scrubbable player that paints VideoJSON into a DOM host.
Classes
DomRenderer
Methods
constructor
(host: HTMLElement): DomRendererParameters
| Name | Type | Description |
|---|---|---|
host | HTMLElement |
Returns
DomRendereraddLayer
(layerJSON: LayerJSON, index?: number): Promise<void>Insert a new layer into the video at the given index (defaults to end). The new layer is constructed, initialized, and mounted into the existing `$canvas` — other layers' DOM elements are left untouched.
Parameters
| Name | Type | Description |
|---|---|---|
layerJSON | LayerJSON | The layer JSON to add. Must include a unique `id`. |
index optional | number | The insertion index in `this.layers`. Defaults to appending. |
Returns
Promise<void>compositeLayerInto
(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, layer: RuntimeBaseLayer, frame?: number): Promise<void>Rasterize a single layer (cached when possible), pipe it through the WebGL effect compositor if it declares effects, and `drawImage` the result onto `ctx`. Used by `RuntimeGroupLayer.renderFrame` to flatten each child onto the group's canvas.
Parameters
| Name | Type | Description |
|---|---|---|
ctx | CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | |
layer | RuntimeBaseLayer | |
frame optional | number |
Returns
Promise<void>destroy
(clearShadow: boolean): voidTear down the renderer: stop playback (also exits smooth-playback mode on every video layer), destroy every runtime layer (releases media elements, decoders, and `requestVideoFrameCallback` subscriptions), clear the per-layer effect canvases, dispose the rasterizer's per-layer surfaces and the WebGL effect compositor's GL context, and finally empty the shadow DOM. Pending queued mutations registered before destroy resolve to no-ops via the `destroyed` guard.
Parameters
| Name | Type | Description |
|---|---|---|
clearShadow | boolean | Whether to wipe the shadow DOM. Default `true`. Pass `false` if the host element is being removed anyway and you want to keep the last rendered frame visible until removal. |
getPropertyDefinition
(layerType: string): Record<string, PropertyDefinition> | undefinedReturn the full propertiesDefinition for a layer type.
Parameters
| Name | Type | Description |
|---|---|---|
layerType | string |
Returns
Record<string, PropertyDefinition> | undefinedgetVirtualLayerHost
(): NodeWhere group layers should park their hidden child host. We use the shadow root so renderer CSS (which is shadow-scoped) still applies to the group's children — without this, descendants would lose their `--vw` / `--project-*` context and render at the wrong scale.
Returns
NodeloadFont
(fontName: string): Promise<void>Load a Google Font and make it available to the document (and shadow DOM).
Parameters
| Name | Type | Description |
|---|---|---|
fontName | string |
Returns
Promise<void>loadVideo
(videoJSON: VideoJSON): Promise<void>Load a compiled VideoJSON into the renderer. Sets up the shadow DOM, creates runtime layers, initialises media, and renders frame 0.
Parameters
| Name | Type | Description |
|---|---|---|
videoJSON | VideoJSON | Compiled VideoJSON from VideoFlow.compile(). |
Returns
Promise<void>play
(options: { fpsCallback?: (fps: number) => void }): Promise<void>Start real-time playback from the current frame with audio sync. Renders audio to WAV, creates an `Audio` element, and advances frames inside a `requestAnimationFrame` loop while nudging the audio `playbackRate` to keep video and audio in sync. Each layer is switched into its smooth-playback path via RuntimeBaseLayer.enterSmoothPlayback at the start of the loop — for video layers this trades the per-frame `currentTime` seek for a native `<video>.play()` plus drift correction, eliminating the seek cost that otherwise dominates live-preview frame budget. The path is reverted on `stop()` / `seek()` so scrubbing stays frame-accurate.
Parameters
| Name | Type | Description |
|---|---|---|
options | { fpsCallback?: (fps: number) => void } | Optional callbacks: - `fpsCallback(fps)` — fired every animation frame with the current measured render FPS, useful for a HUD/diagnostic display. To track frame changes, set the public onFrame property. |
Returns
Promise<void>removeLayer
(id: string): Promise<void>Remove a layer from the video. Destroys the layer (releasing its media ref) and detaches its DOM element. Other layers are untouched.
Parameters
| Name | Type | Description |
|---|---|---|
id | string |
Returns
Promise<void>renderAudio
(): Promise<AudioBuffer | null>Render the full audio track as an AudioBuffer.
Returns
Promise<AudioBuffer | null>renderFrame
(frame: number, force: boolean): Promise<void>Render a specific frame to the DOM. Skips if already at that frame (unless forced), queues if a render is already in progress.
Parameters
| Name | Type | Description |
|---|---|---|
frame | number | Frame number to render. |
force | boolean | Render even if already at this frame. |
Returns
Promise<void>reorderLayers
(orderedIds: string[]): Promise<void>Reorder layers to match the given id sequence. The runtime layers and the backing `videoJSON.layers` array are reordered, and the layers' `$element`s are re-appended to `$canvas` in the new order. For layers without a `track`, DOM order drives paint order. Layers with a `track` carry an explicit z-index (`track + 1`) written in `applyProperties`, so reordering them in the array without changing their `track` only changes DOM order, not visual stacking. No media is touched.
Parameters
| Name | Type | Description |
|---|---|---|
orderedIds | string[] | The new layer order. Must contain exactly the set of currently-loaded layer ids, in any order. Extra/missing ids throw. |
Returns
Promise<void>seek
(frame: number): Promise<void>Seek to a frame. If playback is active, stops it (which exits smooth mode), renders the target frame deterministically through the seek path, then restarts playback (re-entering smooth mode). When playback is not active, the frame is decoded by the seek path directly — pixel-deterministic, the same path used by export.
Parameters
| Name | Type | Description |
|---|---|---|
frame | number |
Returns
Promise<void>stop
(): voidStop playback. Bumps the play-token (so any loop suspended in `await renderAudio()` / `requestAnimationFrame` exits without running its cleanup), tears down the `Audio` element, and reverts every layer's smooth-playback hook so the next `renderFrame` (typically from `seek()` or `currentTime =`) decodes the exact requested timestamp instead of whatever the smooth decoder happened to be presenting.
updateLayer
(id: string, patch: { animations?: Animation[]; effects?: any[]; properties?: Record<string, any>; settings?: Partial<LayerSettingsJSON>; transitionIn?: any; transitionOut?: any }): Promise<void>Apply a property / settings / animations patch to a single layer. - `settings` is shallow-merged into `layer.json.settings`. - `properties` replaces `layer.json.properties` wholesale so keys removed by the editor (e.g. via a reset-to-default) are actually cleared. Callers should pass the full post-mutation properties object. - `animations` replaces the array wholesale (same rationale — callers hold the diffing logic because per-keyframe reconciliation is cheap to do in editor state). If `settings.source` changed, the layer's media is re-initialized via `layer.initialize()` — callers should debounce rapid source swaps. If a text layer's `fontFamily` is among the patched properties, the font is loaded into the shadow DOM before the frame is re-rendered.
Parameters
| Name | Type | Description |
|---|---|---|
id | string | The layer id to patch. |
patch | { animations?: Animation[]; effects?: any[]; properties?: Record<string, any>; settings?: Partial<LayerSettingsJSON>; transitionIn?: any; transitionOut?: any } | A partial patch. Any subset of settings/properties/animations. |
Returns
Promise<void>updateVideo
(patch: { backgroundColor?: string; duration?: number; height?: number; name?: string; width?: number }): Promise<void>Patch top-level video properties (width, height, backgroundColor, name, duration). `fps` changes are not supported here — they invalidate frame numbers across the pipeline and require a full `loadVideo()`. `duration` is safe to update incrementally: it's only used as the loop bound in `play()` and the divisor in the `totalFrames` getter; layer frame numbers depend on `fps`, not `duration`. An in-flight `play()` call captures `durationSec` at start, so the new bound takes effect on the next `play()` invocation.
Parameters
| Name | Type | Description |
|---|---|---|
patch | { backgroundColor?: string; duration?: number; height?: number; name?: string; width?: number } |
Returns
Promise<void>registerEffect
(name: string, glsl: string, params: Record<string, EffectParamDefinition>): voidRegister a GLSL effect. Shares its registry with `BrowserRenderer`.
Parameters
| Name | Type | Description |
|---|---|---|
name | string | |
glsl | string | |
params | Record<string, EffectParamDefinition> |
registerTransition
(name: string, fn: TransitionFn): voidRegister a transition preset. The registry is shared with `BrowserRenderer` so a transition registered on either renderer is available in both live preview and export.
Parameters
| Name | Type | Description |
|---|---|---|
name | string | |
fn | TransitionFn |
Properties
| Name | Type | Description |
|---|---|---|
currentFrame | number | Current frame rendered. |
layerById | Map<string, RuntimeBaseLayer> | Fast id → runtime layer lookup, kept in sync with `layers`. |
layers | RuntimeBaseLayer[] | Runtime layer instances. |
onFrame | (frame: number) => void | null | Optional callback fired whenever a new frame is rendered. Set this externally to keep a UI (seek bar, time label, …) in sync with playback. |
playing | boolean | Whether playback is active. |
currentTime | | |
duration | | |
fps | | |
totalFrames | |
Type aliases
DomRendererCallback
type DomRendererCallback = (event: string, data: any) => void