Scene Flow
Revideo lets you define your scene through a generator function. This section will go into more detail about how this works and walk through a few examples to provide a better understanding for developers. It is also highly recommended to read through the Motion Canvas guide for better understanding.
Scenes are defined sequentiallyβ
Generator functions are defined as a sequence of yields. When you first call a generator function, the first yielded value gets returned. When you call it again, the second yielded value gets returned:
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;The fact that Revideo uses generator functions lets you define your videos in an intuitive imperative manner - When thinking about what your video should look like, you'll probably think of it as a sequence of concrete steps:
At first, a red circle should appear in the center of my video
The circle should move to the right by 200 pixels within two seconds
Then, the circle disappears from the video
Afterwards, nothing happens for one second
In Revideo, your code can be translated in a relatively straightforward way - you can read your scene code from top to bottom to understand what is happening
In many cases, you might want to do animate multiple things in parallel. For this, you can use flow generators like all.
Something that confuses many people getting started with Revideo is the difference between yield* and yield, as well as the difference between yield view.add and calling view.add without yielding.
When looking at code examples of Revideo, you might notice that they sometimes contain yield view.add and sometimes only view.add- this is not limited to view, but also to many other operations or adding to nodes other than View2D nodes.
Adding a yield in front of an operation ensures that Revideo awaits any promises associated with that operation, such as network requests or awaiting fonts to load. As an example, here is code that has a yield in front of it as it creates a promise:
In the code above, we initialize an Img node which loads an image from the internet. This creates a promise - adding a yield in front of view.add ensures that the code will continue executing only once the promise is resolved (the image is loaded).
Promises are not just caused by obvious network requests such as the one above. They might also be created if you add a text node, as Revideo will have to wait for the document.fonts.ready event to fire. If you want to be safe, you can simply yield every add call - this is a good catch-all and won't cause problems. If you don't have a yield in front of an operation that creates a promise, Revideo will also throw a warning that says Tried to access an asynchronous property before the node was ready.
Will calling yield add an extra frame to my video?β
yield add an extra frame to my video?βWe often explain Revideo by saying that every yield corresponds to a frame in your video. This is good for a rough understanding, but not 100% correct. A yield will only correspond to a frame when the yielded value is falsy. When stepping through your generator function to render a video, this is how Revideo decides if it should draw a frame or not (pseudocode):
Looking at some scene code, this is what would happen:
yield is used to pause the execution of a generator and return a single value, whereas yield* delegates to another generator function. Roughly speaking, you should yield everything that's just a single operation, while you yield* generators that produce multiple frames:
Last updated