Scene Flow
Last updated
Last updated
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 for better understanding.
Generator functions are defined as a sequence of yield
s. When you first call a generator function, the first yielded value gets returned. When you call it again, the second yielded value gets returned:
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
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
.
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:
In many cases, you might want to do animate multiple things in parallel. For this, you can use flow generators like .