VideoFlowcodeGitHubTry itCoreRenderersReact Video EditorPlaygroundExamplesDocscodeGitHubTry it
Getting started
InstallationQuick startCore conceptsYour first video
Builder
Builder APITime formatsParallel & wait
Layers
TextImageVideoAudioCaptionsShapeGroups
Animation
Animate & keyframesEasing functionsTransitionsEffects
Renderers
Browser rendererServer rendererDOM preview
React Video Editor
QuickstartThemingUploadsCustom panelsHooks & commandsKeyboard shortcuts
API reference
Overview@videoflow/core@videoflow/renderer-browser@videoflow/renderer-server@videoflow/renderer-dom@videoflow/react-video-editor

Quick start

Five minimal scenes, each one a complete VideoFlow composition. Press play on any preview to see it run, switch to VideoJSON to inspect the compiled output, or open it in the playground to fork it. By the end you'll have seen a layer, an animation, a parallel timeline, a transition, and a multi-element scene — enough to start building.

The contract. Every snippet uses the same conventions: build with const $ = new VideoFlow({...}), push layers via $.addText / $.addImage / $.addShape / …, and end with return $ so the sandbox can compile it. Positions are [x, y] as fractions of the project (0..1); sizes default to em, where 1em is 1% of the project width.

1. A single layer

The smallest useful composition: one text layer that fades in. You never write keyframes by hand — .fadeIn() pushes them for you, and the flow pointer auto-advances by the duration.

const $ = new VideoFlow({
  width: 1280, height: 720, fps: 30,
  backgroundColor: '#0f0f23',
});

$.addText({
  text: 'Hello, VideoFlow',
  fontSize: 4,
  fontWeight: 700,
  color: '#ffffff',
  textAlign: 'center',
}).fadeIn('600ms');

$.wait('1.2s');

return $;
Compiling00:00

2. Animate any property

Every layer property is animatable. .animate(from, to, opts) pushes a pair of keyframes and advances the flow pointer by duration. Easings are strings — linear, easeIn, easeOut, easeInOut, or step. See the easing guide for details.

const $ = new VideoFlow({
  width: 1280, height: 720, fps: 30,
  backgroundColor: '#0a0a1a',
});

const title = $.addText({
  text: 'Spring in',
  fontSize: 5,
  fontWeight: 800,
  color: '#ffffff',
  textAlign: 'center',
});

title.animate(
  { scale: 0.6, opacity: 0, position: [0.5, 0.55] },
  { scale: 1,   opacity: 1, position: [0.5, 0.50] },
  { duration: '700ms', easing: 'easeOut' },
);

$.wait('800ms');
title.fadeOut('400ms');

return $;
Compiling00:00

3. Run things in parallel

$.parallel([...]) takes an array of functions. Each one runs on its own branch from the current flow position; after the block, the pointer advances to the end of the longest branch.

const $ = new VideoFlow({
  width: 1280, height: 720, fps: 30,
  backgroundColor: '#11131a',
});

const left = $.addText({
  text: 'Left',
  fontSize: 4,
  color: '#7dd3fc',
  textAlign: 'center',
  position: [0.30, 0.5],
  opacity: 0,
});

const right = $.addText({
  text: 'Right',
  fontSize: 4,
  color: '#fca5a5',
  textAlign: 'center',
  position: [0.70, 0.5],
  opacity: 0,
});

$.parallel([
  () => left.animate(
    { opacity: 0, position: [0.20, 0.5] },
    { opacity: 1, position: [0.30, 0.5] },
    { duration: '600ms', easing: 'easeOut' },
  ),
  () => right.animate(
    { opacity: 0, position: [0.80, 0.5] },
    { opacity: 1, position: [0.70, 0.5] },
    { duration: '600ms', easing: 'easeOut' },
  ),
]);

$.wait('700ms');

return $;
Compiling00:00

4. Transitions between layers

transitionIn and transitionOut live in a layer's settings (the second argument to addText) and reference a registered preset by name. The renderer ships fade, slideUp, slideLeft, zoom, overshootPop, blurResolve, and more — see Transitions.

const $ = new VideoFlow({
  width: 1280, height: 720, fps: 30,
  backgroundColor: '#0b1020',
});

const first = $.addText(
  { text: 'First', fontSize: 5, color: '#fef3c7', textAlign: 'center' },
  {
    transitionIn:  { transition: 'fade',      duration: '300ms' },
    transitionOut: { transition: 'slideLeft', duration: '400ms' },
  },
);
$.wait('900ms');
first.remove();

const second = $.addText(
  { text: 'Second', fontSize: 5, color: '#bae6fd', textAlign: 'center' },
  {
    transitionIn:  { transition: 'zoom', duration: '400ms' },
    transitionOut: { transition: 'fade', duration: '300ms' },
  },
);
$.wait('900ms');
second.remove();

return $;
Compiling00:00

5. A real scene

Putting it together: a coloured backdrop shape that scales in, a title that rides on top of it, then a punch-line that lands after the title settles. Both title and backdrop start on the same frame via $.parallel.

const $ = new VideoFlow({
  width: 1280, height: 720, fps: 30,
  backgroundColor: '#0f172a',
});

const bar = $.addShape(
  {
    fill: '#7c3aed',
    width: 120, height: 18,
    position: [0.5, 0.42],
    rotation: -6,
    opacity: 0,
    scale: 0,
  },
  { shapeType: 'rectangle' },
);

const title = $.addText({
  text: 'Code',
  fontSize: 6,
  fontWeight: 800,
  color: '#ffffff',
  textAlign: 'center',
  position: [0.5, 0.42],
  opacity: 0,
});

$.parallel([
  () => bar.animate(
    { scale: 0, opacity: 0 },
    { scale: 1, opacity: 0.9 },
    { duration: '500ms', easing: 'easeOut' },
  ),
  () => title.animate(
    { opacity: 0, position: [0.5, 0.48] },
    { opacity: 1, position: [0.5, 0.42] },
    { duration: '600ms', easing: 'easeOut' },
  ),
]);

$.wait('300ms');

$.addText({
  text: 'pixels.',
  fontSize: 9,
  fontWeight: 900,
  color: '#facc15',
  textAlign: 'center',
  position: [0.5, 0.65],
  opacity: 0,
  scale: 0.7,
}).animate(
  { opacity: 0, scale: 0.7 },
  { opacity: 1, scale: 1 },
  { duration: '450ms', easing: 'easeOut' },
);

$.wait('1.2s');

return $;
Compiling00:00

Where to next

VideoFlow

Open-source toolkit for composing videos from code.

Product

CoreRenderersReact Video EditorPlayground

Learn

DocsAPI referenceExamplesvs. Remotionvs. FFmpeg

Project

GitHubLicenseContact

Legal

TermsPrivacy
© 2026 VideoFlow. Apache-2.0 core.