Skip to Content
DocumentationAnimationsAnimation flow

Animation flow

Revideo uses generator functions to describe animations.

A generator function is a function that can return multiple values:

function* example() { yield 1; yield 2; yield 3; } const generator = example(); console.log(generator.next().value); // 1; console.log(generator.next().value); // 2; console.log(generator.next().value); // 3;

When the yield keyword is encountered, the execution of the function pauses, and resumes only when the caller requests another value. This is particularly useful when declaring animations - usually we want to change the things on the screen in incremental steps to create an illusion of movement. We also want to wait a constant amount of time between these updates so that our eyes can register what’s happening. With generators, we can update things in-between the yield keywords, and then wait for a bit whenever the function yields.

This is the fundamental idea of Revideo. yield means: “The current frame is ready, display it on the screen and come back to me later.”

With that in mind, we can make a circle flicker on the screen using the following code:

export default makeScene2D('scene', function* (view) { const circle = createRef<Circle>(); view.add(<Circle ref={circle} width={100} height={100} />); circle().fill('red'); yield; circle().fill('blue'); yield; circle().fill('red'); yield; });

Needless to say, it would be extremely cumbersome if we had to write all animations like that. Fortunately, JavaScript has another keyword for use within generators - yield*. It allows us to delegate the yielding to another generator.

For instance, we could extract the flickering code from the above example to a separate generator and delegate our scene function to it:

import {ThreadGenerator} from '@revideo/core'; export default makeScene2D('scene', function* (view) { const circle = createRef<Circle>(); view.add(<Circle ref={circle} width={100} height={100} />); yield* flicker(circle()); }); function* flicker(circle: Circle): ThreadGenerator { circle.fill('red'); yield; circle.fill('blue'); yield; circle.fill('red'); yield; }

The resulting animation is exactly the same, but now we have a reusable function that we can use whenever we need some flickering.

Revideo provides a lot of useful generators like this. You may remember this snippet:

yield * myCircle().fill('#e6a700', 1);

It animates the fill color of the circle from its current value to #e6a700 over a span of one second. As you may guess, the result of calling fill('#e6a700', 1) is another generator to which we can redirect our scene function. Generators like this are called tweens, because they animate between two values. You can read more about them in the tweening section.

Flow Generators

Another kind of generators are flow generators. They take one or more generators as their input and combine them together. We’ve mentioned the all() generator in the quickstart section, there’s a few more:

all

all(…tasks): ThreadGenerator

Run all tasks concurrently and wait for all of them to finish.

Parameters

tasks

ThreadGenerator[]

A list of tasks to run.

Returns

ThreadGenerator

Example

// current time: 0s yield* all( rect.fill('#ff0000', 2), rect.opacity(1, 1), ); // current time: 2s

View full API ↗


any

any(…tasks): ThreadGenerator

Run all tasks concurrently and wait for any of them to finish.

Parameters

tasks

ThreadGenerator[]

A list of tasks to run.

Returns

ThreadGenerator

Example

// current time: 0s yield* any( rect.fill('#ff0000', 2), rect.opacity(1, 1), ); // current time: 1s

View full API ↗


chain

chain(…tasks): ThreadGenerator

Run tasks one after another.

Parameters

tasks

…(Callback | ThreadGenerator)[]

A list of tasks to run.

Returns

ThreadGenerator

Example

// current time: 0s yield* chain( rect.fill('#ff0000', 2), rect.opacity(1, 1), ); // current time: 3s

Note that the same animation can be written as:

yield* rect.fill('#ff0000', 2), yield* rect.opacity(1, 1),

The reason chain exists is to make it easier to pass it to other flow functions. For example:

yield* all( rect.radius(20, 3), chain( rect.fill('#ff0000', 2), rect.opacity(1, 1), ), );

View full API ↗


delay

delay(time, task): ThreadGenerator

Run the given generator or callback after a specific amount of time.

Parameters

time

number

The delay in seconds

task

Callback | ThreadGenerator

The task or callback to run after the delay.

Returns

ThreadGenerator

Example

yield* delay(1, rect.fill('#ff0000', 2));

Note that the same animation can be written as:

yield* waitFor(1), yield* rect.fill('#ff0000', 2),

The reason delay exists is to make it easier to pass it to other flow functions. For example:

yield* all( rect.opacity(1, 3), delay(1, rect.fill('#ff0000', 2)); );

View full API ↗


sequence

sequence(delay, …tasks): ThreadGenerator

Start all tasks one after another with a constant delay between.

Parameters

delay

number

The delay between each of the tasks.

tasks

ThreadGenerator[]

A list of tasks to be run in a sequence.

Returns

ThreadGenerator

Remarks

The function doesn’t wait until the previous task in the sequence has finished. Once the delay has passed, the next task will start even if the previous is still running.

Example

yield* sequence( 0.1, ...rects.map(rect => rect.x(100, 1)) );

View full API ↗


loop

Call Signature

loop(factory): ThreadGenerator

Run the given generator in a loop.

Parameters

factory

LoopCallback

A function creating the generator to run. Because generators can’t be reset, a new generator is created on each iteration.

Returns

ThreadGenerator

Remarks

Each iteration waits until the previous one is completed. Because this loop never finishes it cannot be used in the main thread. Instead, use yield or threading.spawn to run the loop concurrently.

Example

Rotate the rect indefinitely:

yield loop( () => rect.rotation(0).rotation(360, 2, linear), );

Call Signature

loop(iterations, factory): ThreadGenerator

Run the given generator N times.

Parameters

iterations

number

The number of iterations.

factory

LoopCallback

A function creating the generator to run. Because generators can’t be reset, a new generator is created on each iteration.

Returns

ThreadGenerator

Remarks

Each iteration waits until the previous one is completed.

Example

const colors = [ '#ff6470', '#ffc66d', '#68abdf', '#99c47a', ]; yield* loop( colors.length, i => rect.fill(colors[i], 2), );

View full API ↗


Looping

There are many ways to animate multiple objects. Here are some examples. Try using them in the below editor.

Press play to preview the animation
import {makeScene2D, Rect} from '@revideo/2d'; import {all, waitFor, makeRef, range} from '@revideo/core'; export default makeScene2D('scene', function* (view) { const rects: Rect[] = []; // Create some rects view.add( range(5).map(i => ( <Rect ref={makeRef(rects, i)} width={100} height={100} x={-250 + 125 * i} fill="#88C0D0" radius={10} /> )), ); yield* waitFor(1); // Animate them yield* all( ...rects.map(rect => rect.position.y(100, 1).to(-100, 2).to(0, 1)), ); });

Using Array.map and all

This is one of the most elegant ways to do simple tweens, but requires nesting all to do multiple tweens on an object since the map callback must return a ThreadGenerator.

yield * all( ...rects.map(rect => // No yield or anything; we return this generator and deal with it outside rect.position.y(100, 1).to(-100, 2).to(0, 1), ), );

Using a for loop and all

This is similar to above, but uses a for loop and an array of generators.

const generators = []; for (const rect of rects) { // No yield here, just store the generators. generators.push(rect.position.y(100, 1).to(-100, 2).to(0, 1)); } // Run all of the generators. yield * all(...generators);

Using a for loop

This is a bit of a cumbersome option because you have to figure out how long it would take for the generator in the loop to complete, but is useful in some situations.

for (const rect of rects) { // Note the absence of a * after this yield yield rect.position.y(100, 1).to(-100, 2).to(0, 1); } // Wait for the duration of the above generators yield * waitFor(4);
Last updated on
© 2026 Haven Technologies, Inc.
Animation flow – Revideo