Parallel & wait
Every VideoFlow timeline is built from two primitives: $.wait(duration) pushes the flow pointer forward, and $.parallel([...]) runs multiple branches starting at the same pointer. That's the whole model — everything else is sequenced layer calls.
On this page
Sequential by default
Calls run in source order. .animate() and .fadeIn() advance the pointer by their duration — so the next call starts when the previous finishes.
title.fadeIn('500ms'); // pointer: 0 → 0.5s
$.wait('1s'); // pointer: 0.5 → 1.5s
title.fadeOut('500ms'); // pointer: 1.5 → 2sStagger with parallel
Inside each branch, $.wait() advances only that branch. The parent pointer jumps to the longest branch when parallel() returns.
const $ = new VideoFlow({ width: 512, height: 512, fps: 30, backgroundColor: '#0a0a1a' });
const lines = ['First', 'Second', 'Third', 'Fourth'].map((t, i) =>
$.addText({ text: t, fontSize: 7, fontWeight: 700, color: '#fff', position: [0.5, 0.3 + i * 0.13], opacity: 0 })
);
$.parallel(lines.map((l, i) => () => {
$.wait(`${i * 120}ms`);
l.animate({ opacity: 0, position: [0.42, 0.3 + i * 0.13] }, { opacity: 1, position: [0.5, 0.3 + i * 0.13] }, { duration: '600ms', easing: 'easeOut' });
}));
$.wait('1.5s');
return $;Overlapping with wait: false
Without parallel(), you can still overlap by setting wait: false on the longer animation. The pointer ignores it, so subsequent calls start immediately.
bg.animate({ scale: 1 }, { scale: 1.2 }, { duration: '3s', wait: false });
// 3s pulse runs in background, rest of the flow keeps its own rhythm
title.fadeIn('500ms');
$.wait('2s');
title.fadeOut('500ms');Nesting
$.parallel([...]) can be nested inside another parallel branch. Each level creates a new scope for its wait calls.
$.parallel([
() => title.fadeIn('500ms'),
() => $.parallel([
() => sub1.fadeIn('500ms'),
() => { $.wait('200ms'); sub2.fadeIn('500ms'); },
]),
]);parallel() call. If one is a backdrop effect that shouldn't block, wait: false is simpler.