The Parallel & Wait Playbook: Mastering Complex Video Timelines
August 22, 2026 · By VideoFlowMaster the core timing primitives of VideoFlow. Learn how to use $.parallel() and $.wait() to build sophisticated, multi-layered video compositions with code.
The Parallel & Wait Playbook: Mastering Complex Video Timelines
Managing time in code-driven video often feels like a return to the dark ages of manual frame arithmetic. In most frameworks, if you want a title to appear 2.5 seconds after a background transition finishes, you're stuck calculating absolute timestamps or chaining complex promises. It’s fragile, hard to read, and even harder to refactor.
VideoFlow changes this by treating video composition as a structured flow. By mastering just two core primitives—$.wait() and $.parallel()—you can build sophisticated, multi-layered cinematic sequences without ever touching a calculator. In this playbook, we’ll explore how to move beyond sequential scripts and into high-performance video orchestration.

The Sequential Default
By default, the VideoFlow core builder API operates like a tape recorder. Every time you call a method that has a duration—like .fadeIn(), .animate(), or .fadeOut()—the internal flow pointer advances by that amount of time. Subsequent calls start exactly where the last one left off.
This makes simple "Intro -> Content -> Outro" sequences trivial to write:
const title = $.addText({ text: 'Hello World', opacity: 0 });
title.fadeIn('500ms'); // Pointer moves to 0.5s
$.wait('2s'); // Pointer moves to 2.5s
title.fadeOut('500ms'); // Pointer moves to 3.0s
But what happens when you want a background video to play throughout the entire sequence? Or when you want three different text elements to stagger their entrance? That's where the sequential model hits a wall, and where $.parallel() takes over.
Branching Out with $.parallel()
$.parallel([...]) allows you to run multiple execution branches starting from the same point in time. Each function inside the array gets its own local flow pointer. When the parallel block finishes, the master flow pointer jumps to the end of the longest branch.
Think of it as creating a multi-track timeline on the fly. This is the secret to creating the "staggered reveal" effect seen in professional motion graphics.
const lines = ['Build', 'Render', 'Deploy'].map((t, i) =>
$.addText({ text: t, position: [0.5, 0.3 + i * 0.1], opacity: 0 })
);
$.parallel(lines.map((layer, i) => () => {
$.wait(`${i * 200}ms`); // Stagger each start by 200ms
layer.fadeIn('600ms');
}));
$.wait('1s'); // Wait for the whole group to be visible
By using $.wait() inside a parallel branch, you stagger the entry without affecting the start time of the other layers in that block. This pattern is essential for building automated social-media video factories where timing needs to be dynamic based on the content length.

Background Effects with wait: false
Sometimes, you don't need a full parallel branch. If you have a long-running background effect—like a slow zoom on a background image—that shouldn't block the rest of your UI logic, you can use the wait: false option.
This tells VideoFlow to fire off the animation and immediately move the flow pointer to the next line of code, ignoring the animation's duration for flow purposes.
const bg = $.addImage({ fit: 'cover', scale: 1 }, { source: '...' });
// Background zoom starts but does NOT advance the pointer
bg.animate({ scale: 1 }, { scale: 1.2 }, { duration: '10s', wait: false });
// These calls happen while the background is still zooming
title.fadeIn('1s');
$.wait('2s');
title.fadeOut('1s');
How VideoFlow Handles This
Under the hood, VideoFlow compiles these imperative calls into a portable VideoJSON document. Because the timing logic is resolved at compile-time, the resulting JSON is resolution-agnostic and renderer-neutral.
Whether you are using @videoflow/renderer-browser for zero-cost client-side export or @videoflow/renderer-server for headless automation, the timing will be frame-accurate. This architecture is what enables the Three-Renderer Rule, allowing you to preview in the DOM at 60fps and render to MP4 using the exact same logic.
Summary: The Timing Hierarchy
To build maintainable video code, follow this hierarchy for timing:
- Sequential calls for elements that follow one another.
- wait: false for background loops or ambient effects that shouldn't block the flow.
- $.parallel() for complex, multi-layered scenes where elements need to overlap or stagger.
Ready to start building? Head over to the VideoFlow Playground to see these primitives in action, or dive into our Parallel and Wait guide for a deeper look at the implementation details. If you're building for production, don't forget to star the project on GitHub.