Scene hierarchy
Scenes are collections of nodes displayed in your animation. They’re organized in a tree hierarchy, with the scene view at its root. This concept is similar to the Document Object Model used to represent HTML and XML documents.
Here’s an example of a simple scene hierarchy together with its object representation:
view.add(
<>
<Circle />
<Layout>
<Rect />
<Txt>Hi</Txt>
</Layout>
</>,
);Each node is an instance of a class extending the base Node class. To
make the code more readable, Revideo uses a custom
JSX runtime. This way, instead
of instantiating the nodes ourselves, we can write an XML-like markup. Note that
Revideo does not use React itself, only JSX. There’s no virtual DOM or
reconciliation and the JSX tags are mapped directly to Node instances. These two
code snippets are equivalent:
// JSX
view.add(
<>
<Circle />
<Layout>
<Rect />
<Txt>Hi</Txt>
</Layout>
</>,
);// No JSX
view.add([
new Circle({}),
new Layout({
children: [
// highlight-start
new Rect({}),
new Txt({text: 'Hi'}),
],
}),
]);Modifying the hierarchy
After the hierarchy has been created, it’s still possible to add, remove, and
rearrange nodes at any time. The Node class contains the
children and
parent properties that can be used to
traverse the tree. But in order to modify it, it’s recommended to use the
following helper methods:
Node.add
add(
node):this
Add the given node(s) as the children of this node.
Parameters
node
A node or an array of nodes to append.
Returns
this
Remarks
The nodes will be appended at the end of the children list.
Example
const node = <Layout />;
node.add(<Rect />);
node.add(<Circle />);Result:
Node.insert
insert(
node,index?):this
Insert the given node(s) at the specified index in the children list.
Parameters
node
A node or an array of nodes to insert.
index?
number = 0
An index at which to insert the node(s).
Returns
this
Example
const node = (
<Layout>
<Rect />
<Circle />
</Layout>
);
node.insert(<Txt />, 1);Result:
Node.remove
remove():
this
Remove this node from the tree.
Returns
this
Node.reparent
reparent(
newParent):void
Change the parent of this node while keeping the absolute transform.
Parameters
newParent
Node
The new parent of this node.
Returns
void
Remarks
After performing this operation, the node will stay in the same place visually, but its parent will be changed.
Node.moveUp
moveUp():
this
Move the node up in relation to its siblings.
Returns
this
Remarks
The node will exchange places with the sibling right above it (if any) and from then on will be rendered on top of it.
Node.moveDown
moveDown():
this
Move the node down in relation to its siblings.
Returns
this
Remarks
The node will exchange places with the sibling right below it (if any) and from then on will be rendered under it.
Node.moveToTop
moveToTop():
this
Move the node to the top in relation to its siblings.
Returns
this
Remarks
The node will be placed at the end of the children list and from then on will be rendered on top of all of its siblings.
Node.moveToBottom
moveToBottom():
this
Move the node to the bottom in relation to its siblings.
Returns
this
Remarks
The node will be placed at the beginning of the children list and from then on will be rendered below all of its siblings.
Node.moveTo
moveTo(
index):this
Move the node to the provided position relative to its siblings.
Parameters
index
number
The index to move the node to.
Returns
this
Remarks
If the node is getting moved to a lower position, it will be placed below the sibling that’s currently at the provided index (if any). If the node is getting moved to a higher position, it will be placed above the sibling that’s currently at the provided index (if any).
Node.moveAbove
moveAbove(
node,directlyAbove?):this
Move the node above the provided node in the parent’s layout.
Parameters
node
Node
The sibling node below which to move.
directlyAbove?
boolean = false
Whether the node should be positioned directly above the sibling. When true, will move the node even if it is already positioned above the sibling.
Returns
this
Remarks
The node will be moved above the provided node and from then on will be rendered on top of it. By default, if the node is already positioned higher than the sibling node, it will not get moved.
Node.moveBelow
moveBelow(
node,directlyBelow?):this
Move the node below the provided node in the parent’s layout.
Parameters
node
Node
The sibling node below which to move.
directlyBelow?
boolean = false
Whether the node should be positioned directly below the sibling. When true, will move the node even if it is already positioned below the sibling.
Returns
this
Remarks
The node will be moved below the provided node and from then on will be rendered below it. By default, if the node is already positioned lower than the sibling node, it will not get moved.
Node.removeChildren
removeChildren():
void
Remove all children of this node.
Returns
void
Querying the hierarchy
Sometimes it can be useful to traverse the hierarchy and find some specific nodes. In this documentation, we’ll be referring to this process as querying. Consider the following animation:
import {makeScene2D, Layout, Txt, Circle, Rect, is} from '@revideo/2d';
import {all} from '@revideo/core';
export default makeScene2D('scene', function* (view) {
view.add(
<Layout layout gap={20} alignItems={'center'}>
<Txt fill={'white'}>Example</Txt>
<Rect fill={'#f3303f'} padding={20} gap={20}>
<Txt fill={'white'}>42</Txt>
<Circle size={60} fill={'#FFC66D'} />
<Txt fill={'white'}>!!!</Txt>
</Rect>
</Layout>,
);
const texts = view.findAll(is(Txt));
yield* all(...texts.map(text => text.fill('#FFC66D', 1).back(1)));
});It contains multiple text nodes whose color oscillates between white and yellow.
To achieve that, we used view.findAll(is(Txt)) to search through all
descendants of the view node and select only those of type Txt. The first
argument passed to the findAll method is a
so-called predicate. It’s a function that takes a node and returns true if
it’s a node we’re looking for.
For instance, if we wanted to find all nodes whose scale x is greater than 1,
we could write:
const wideNodes = view.findAll(node => node.scale.x() > 1);Knowing this, we could try to find all nodes of type Txt as follows:
const texts = view.findAll(node => node instanceof Txt);But Revideo comes with a helpful utility function called
is that can create this predicate for us:
import {is} from '@revideo/2d';
// ...
const texts = view.findAll(is(Txt));These can be used with any JavaScript function that accepts a predicate. The
findAll method has been implemented to traverse all descendants of a node, but
if we wanted to query only the direct children, we could retrieve the
children array and call the built-in
filter method with our predicate:
const textChildren = someParent.children().filter(is(Txt));There are a few other methods that can be used to query the hierarchy depending on your needs:
Node.findAll
Call Signature
findAll<
T>(predicate):T[]
Find all descendants of this node that match the given predicate.
Type Parameters
T
T extends Node
Parameters
predicate
(node) => node is T
A function that returns true if the node matches.
Returns
T[]
Call Signature
findAll<
T>(predicate):T[]
Find all descendants of this node that match the given predicate.
Type Parameters
T
T extends Node = Node
Parameters
predicate
(node) => boolean
A function that returns true if the node matches.
Returns
T[]
Node.findFirst
Call Signature
findFirst<
T>(predicate):T|null
Find the first descendant of this node that matches the given predicate.
Type Parameters
T
T extends Node
Parameters
predicate
(node) => node is T
A function that returns true if the node matches.
Returns
T | null
Call Signature
findFirst<
T>(predicate):T|null
Find the first descendant of this node that matches the given predicate.
Type Parameters
T
T extends Node = Node
Parameters
predicate
(node) => boolean
A function that returns true if the node matches.
Returns
T | null
Node.findLast
Call Signature
findLast<
T>(predicate):T|null
Find the last descendant of this node that matches the given predicate.
Type Parameters
T
T extends Node
Parameters
predicate
(node) => node is T
A function that returns true if the node matches.
Returns
T | null
Call Signature
findLast<
T>(predicate):T|null
Find the last descendant of this node that matches the given predicate.
Type Parameters
T
T extends Node = Node
Parameters
predicate
(node) => boolean
A function that returns true if the node matches.
Returns
T | null
Node.findAncestor
Call Signature
findAncestor<
T>(predicate):T|null
Find the closest ancestor of this node that matches the given predicate.
Type Parameters
T
T extends Node
Parameters
predicate
(node) => node is T
A function that returns true if the node matches.
Returns
T | null
Call Signature
findAncestor<
T>(predicate):T|null
Find the closest ancestor of this node that matches the given predicate.
Type Parameters
T
T extends Node = Node
Parameters
predicate
(node) => boolean
A function that returns true if the node matches.
Returns
T | null