Skip to main content

Logical Separation of Scene Components

A question that frequently comes up from Revideo users is how to organize your scene code to achieve good logical separation and make things readable.

Custom Generator Functions

Revideo lets you define your scene code as a generator function wrapped in makeScene2D. Here is a mininal example that displays an image for five seconds:

import {Img, makeScene2D, View2D} from '@revideo/2d';
import {waitFor} from '@revideo/core';

export default makeScene2D(function* (view) {
yield view.add(
<Img
width={'30%'}
ref={logoRef}
src={
'https://revideo-example-assets.s3.amazonaws.com/revideo-logo-white.png'
}
/>,
);

yield* waitFor(5);
});

Let's say that you additionally want to display some text:

import {Img, Txt, makeScene2D} from '@revideo/2d';
import {waitFor} from '@revideo/core';

export default makeScene2D(function* (view) {
yield view.add(
<Img
width={'30%'}
ref={logoRef}
src={
'https://revideo-example-assets.s3.amazonaws.com/revideo-logo-white.png'
}
/>,
);

yield view.add(<Txt fill="red" y={300} text={'Hello World!'} />);

yield* waitFor(5);
});

Instead of adding the text node inside your main function, you can also create a separate generator function that does so and is called within your main generator function:

import {Img, Txt, makeScene2D} from '@revideo/2d';
import {waitFor} from '@revideo/core';

export default makeScene2D(function* (view) {
yield view.add(
<Img
width={'30%'}
ref={logoRef}
src={
'https://revideo-example-assets.s3.amazonaws.com/revideo-logo-white.png'
}
/>,
);

yield addText(view, 'Hello World!');

yield* waitFor(5);
});

function* addText(view: View2D, displayText: string) {
yield view.add(<Txt fill="red" y={300} text={displayText} />);

yield* waitFor(5);
}

Especially as your scenes get more complex, it makes sense to separate different parts of them (for example, you might have your main video definition in one function and subtitling logic in another one).

Calling generator functions with yield and yield*:

When you have multiple generator functions that you want to use, it is important to mention the difference between yield and yield*:

yield will call your generator function but not wait for it to finish executing before executing the rest of your code. If you have a generator function displaySubtitles(), this will make a big difference:

Say you have the following code:

yield displaySubtitles();
// rest of your scene code, will get displayed at the same time as subtitles

This will display your subtitles along the rest of your scene code - it will not wait for all subtitles to have finished.

On the other hand, if you use yield*, the main generator function will wait for displaySubtitles() to finish executing before displaying your remaining animations:

yield * displaySubtitles(); // wait for displaySubtitles to finish
// rest of your scene code, will get displayed after subtitles

If you have two generator functions that you want to display at the same time, you can therefore call both subsequently with yield:

yield displaySubtitles();
yield displayImages();

Alternatively, you can use the all function:

yield * all(displaySubtitles(), displayImages());

If you want to display functions subsequently, you can call them subsequently with yield* or use chain:

yield * displaySubtitles();
yield * displayImages();

This yields the same result as:

yield * chain(displaySubtitles(), displayImages());

You can learn more about controlling the animation flow with functions like all and chain here.

Custom Components

You can build your own <CustomComponent/> to use in your revideo projects. A good guide for this is available in the Motion Canvas guide.

Note: In most cases, you won't have to implement a custom draw() function when building a custom component. If you do, note that draw() functions in Revideo need to be implemented as async functions, while they are synchronous in Motion Canvas.