Builder API
VideoFlow's builder is a thin fluent shell over a flow pointer. You add layers and animations in source order; the pointer advances automatically after each action. There's no React tree, no component model, no declarative diff — just a sequence of imperative calls that compile to JSON.
On this page
Constructor
const $ = new VideoFlow({
name: 'My video', // used as filename / metadata
width: 1920, height: 1080, // output resolution
fps: 30, // frames per second — 24, 30, 60 all work
backgroundColor: '#000', // fills under all layers
autoDetectDurations: true, // probe video/audio layers for their duration
verbose: false, // log keyframe/action push events to the console
defaults: {
easing: 'easeOut',
fontFamily: 'Inter',
},
});Adding layers
Five factory methods. Each pushes a layer onto the timeline at the current flow pointer and returns the layer instance.
| Call | Returns |
|---|---|
$.addText(props, settings?, options?) | TextLayer |
$.addImage(props, settings?, options?) | ImageLayer (settings.source) |
$.addVideo(props, settings?, options?) | VideoLayer (settings.source) |
$.addAudio(props, settings?, options?) | AudioLayer (settings.source) |
$.addCaptions(props, settings, options?) | CaptionsLayer (settings.captions) |
$.addShape(props, settings?, options?) | ShapeLayer (settings.shapeType: rectangle, ellipse, polygon, star) |
$.group(props, settings, fn, options?) | GroupLayer — children authored inside fn are composited as one. See Groups. |
Layer instance methods
| Method | Effect |
|---|---|
.animate(from, to, opts) | Push a pair of keyframes on each listed prop. |
.set(patch) | Patch static layer props — no keyframes. |
.fadeIn(duration) | Shorthand for animate({ opacity: 0 }, { opacity: 1 }, ...) |
.fadeOut(duration) | Shorthand for the opposite. |
.show() / .hide() | Toggle visibility at the current time — no interpolation. |
.remove(opts?) | End the layer at the current flow position. Pass { in: time } to defer. |
Layer factory options
The third argument to every add* / group call is an AddLayerOptions object that controls how the layer interacts with the flow pointer and the layer stack:
| Option | Default | Notes |
|---|---|---|
waitFor | 0 (visual layers); 'finish' (groups, video / audio with explicit duration) | How much the outer flow pointer advances. Pass a Time to wait that long, or 'finish' to wait for the layer's full duration. |
index | — | Z-order. Negative pushes the layer behind earlier ones; positive pulls it forward. |
Flow control
| Call | Effect |
|---|---|
$.wait(duration) | Advance the flow pointer without adding layers. |
$.parallel([fns]) | Run each fn with the same start time; advance the pointer by the longest branch. |
$.compile() | Finalise and return the VideoJSON. |
Parallel branches
Each function in $.parallel([...]) starts at the same flow-pointer time. Inside a branch, $.wait() advances only that branch — use it to stagger.
const $ = new VideoFlow({ width: 512, height: 512, fps: 30, backgroundColor: '#0b0b1f' });
const a = $.addText({ text: 'A', fontSize: 16, fontWeight: 800, color: '#ff6b6b', position: [0.25, 0.5], opacity: 0 });
const b = $.addText({ text: 'B', fontSize: 16, fontWeight: 800, color: '#4ecdc4', position: [0.5, 0.5], opacity: 0 });
const c = $.addText({ text: 'C', fontSize: 16, fontWeight: 800, color: '#45b7d1', position: [0.75, 0.5], opacity: 0 });
// All three branches share a start time — stagger each with $.wait().
$.parallel([
() => a.fadeIn('600ms'),
() => { $.wait('200ms'); b.fadeIn('600ms'); },
() => { $.wait('400ms'); c.fadeIn('600ms'); },
]);
$.wait('2s');
return $;Holding the pointer still
animate(..., { wait: false }) pushes keyframes but doesn't advance the pointer — so you can stack another animation on the same window.
const $ = new VideoFlow({ width: 512, height: 512, fps: 30, backgroundColor: '#111' });
const box = $.addText({ text: 'BG', fontSize: 40, fontWeight: 900, color: '#222', position: [0.5, 0.5] });
const label = $.addText({ text: 'Foreground', fontSize: 8, fontWeight: 700, color: '#fff', position: [0.5, 0.5], opacity: 0 });
// wait: false — the flow pointer doesn't advance while the background pulses,
// so the label fades in on top during the same window.
box.animate({ scale: 1 }, { scale: 1.15 }, { duration: '1.5s', easing: 'easeInOut', wait: false });
label.fadeIn('800ms');
$.wait('1.5s');
return $;Compiling
const json = await $.compile();
// json is plain, serialisable VideoJSON — save it, send it, render it later.Beyond compile(), the builder also exposes one-shot convenience methods that skip the intermediate JSON:
await $.renderVideo({ outputType: 'buffer' }); // → Buffer | Blob
await $.renderFrame(60); // → OffscreenCanvas | Buffer
await $.renderAudio(); // → AudioBuffer | BufferNext
- Time formats — all the shapes
durationaccepts. - Parallel & wait — worked examples of the timing primitives.