New Renderer Proposal #59
Replies: 3 comments 7 replies
-
This looks incredibly helpful, will users be able to define custom jsx elements, similar to how React defines elements? Or will you create node types with a different syntax? I.e. With classes that have a |
Beta Was this translation helpful? Give feedback.
-
The current plan for computed properties is to run the function on every read, right? I think that's where things wound up. Out of curiosity, what is the plan for conjoined properties? You mentioned them before. circ.origin(() => compOrigin());
\\ or
circ.originX(() => compX()); Is the plan for // SUPER simplified code
origin(arg: {x: number, y: number}) {
this.originX(x);
this.originY(y);
} Is your plan to keep My gut reflex is to use arrays for things like vectors, EDIT: Will arrows and pins be done with computed properties? EDITx2: Rotations are in degrees, right? EDITx3: How many shapes do you intend to implement before release? Circle and Rectangle I'm assuming, but Konva had some weird ones. |
Beta Was this translation helpful? Give feedback.
-
Do you want any help? I still have work to do on my code highlighter, but it doesn't look like I should bother building a Konva component out of it. |
Beta Was this translation helpful? Give feedback.
-
The current renderer - based on Konva - has limitations and problems that are making it increasingly harder to maintain and extend.
A lot of them cannot be fixed without heavily modifying the Konva library itself.
What follows is a proposal for a brand new renderer that would be built from the ground up with Motion Canvas in mind.
General Idea
Here's a sample scene utilizing the new renderer:
The result is the following object node:
![image](https://user-images.githubusercontent.com/64662184/187316777-55fefae5-227a-4d72-91c0-11f0a5f2f831.png)
The above example is made out of primitives, but if the element is meant to be used often, it can be simplified by creating two custom components:
Hierarchy
Just like with Konva, the scene is represented by a document object model.
Created elements are organized in a tree hierarchy.
The main difference is that any node can have children.
This is why we can use primitives such as
Rect
as containers:Creation
When using a JSX tag, the runtime will create an instance of the adequate class.
All properties defined on the tag are passed to the constructor as a single object.
This includes any possible children, which is a major difference compared to the old renderer.
This allows us to control how we want to treat the child nodes and what kind of nodes we can accept.
For instance, the
Text
primitive only accepts a single string node and treats it as its value.The following are interchangeable:
Placement
By default, nodes are placed using the following attributes:
x
- position along the x-axisy
- position along the y-axisrotation
- rotation along the z-axisscaleX
- scale along the x-axisscaleY
- scale along the y-axisThese attributes are relative to the parent node. And work the same way as in Konva.
The
position
andscale
attributes can be used as shortcuts.Additionally, it's possible to define the origin of the node using the
originX
andoriginY
attributes.Here, the main difference is that origin is relative to the size of the node.
For instance, (1, 1) would mean the upper right corner of the node.
(-1, 0) would be the middle left. etc.
origin
attribute can be used together with theOrigin
type to easily configure it:Layout
The biggest advancement is the use of the Yoga layout engine.
Any node can be marked with a dedicated
yoga
attribute to delegate control over its size and position to Yoga:These attributes cascade down, making all children of the node controlled by Yoga as well.
Children can opt-out of this by explicitly setting the
yoga
attribute tofalse
.When in control, Yoga will override the
size
andposition
attributes.This means that disabling Yoga in the middle of the animation will keep the last calculated size and position.
The following values provide more gradual control over Yoga:
yoga="content"
- only the size of the node is controlled by Yoga, position can still be manually adjusted.yoga="pop"
- the node is no longer controlled by Yoga, but the parent layout still respects it. There's a "hole" left in the parent layout as if the element was still there. Useful when we want to temporarily "pop" a node out of its parent.All attributes related to the Yoga layout can be adjusted through the
layout
attribute:When all we need is a simple container that doesn't render anything, a
Layout
node can be used for convenience.It acts as a basic node but allows us to set the layout attributes as individual JSX properties:
Properties
The approach to properties doesn't change much compared to the current version.
Each of them acts as a getter/setter/animator depending on the number of attributes passed:
As a new addition, a function can be passed as the first argument to make the value dynamic:
A more detailed discussion about this feature can be found in #58
Style Settings
The
Style
interface is the universal type used to configure how elements are rendered.It contains all properties necessary to configure a canvas:
In the case of most primitives, such as
Rect
, these properties can be configured through JSX:But more complex components can use it to make their style customizable.
For example:
Under the hood, a helper function is used to apply a style to the context:
This function can be used in custom components to make them easily customizable.
Type System
The new renderer continues to use duck typing for all of its basic types.
That is, types such as vectors, rects, and sizes are not instances of specific classes.
The shape of the object defines its type, so any object matching the following interface:
is considered a valid two-dimensional vector.
To make defining and modifying basic types easier, a set of helper functions will be provided.
For instance:
Custom components
Just like in the old renderer, custom components can be created by extending an existing Node class:
(Example of a class component in the old renderer.)
Or by creating a function component:
Unlike in React, function components are stateless.
(Example of a function component in the old renderer.)
Additional features
I omitted certain technical features, such as hit detection, events, and querying elements.
These are rather easy to implement and can be added later on, once the general shape of the renderer has been established.
Thanks for reading!
This is just a proposal and everything is subject to change, so feel free to discuss anything below.
Beta Was this translation helpful? Give feedback.
All reactions