alexharri / animation-editor Goto Github PK
View Code? Open in Web Editor NEWWeb-based animation editor and runtime written in React, Redux, PIXI.js and HTML Canvas.
License: MIT License
Web-based animation editor and runtime written in React, Redux, PIXI.js and HTML Canvas.
License: MIT License
In After Effects, you can press certain keys to open certain properties on selected layers.
By holding Shift, properties can be toggled in and out of view.
Similar behavior would benefit this project.
Currently it's not possible to delete existing keyframes. The only way to remove keyframes right now is to merge them (drag one over the other).
The user should be able to delete selected keyframes via a keyboard shortcut (e.g. Delete, Backspace) and by right clicking the graph/track editor.
If a timeline has no keyframes left after deleting keyframes, the timeline should be deleted and then layer should be set to static.
The user should be able to mouse drag layers around the composition viewport.
Layer parenting will make this a bit more tricky.
When layer transform have been implemented (see #9) this feature can be worked on.
A layer should be able to specify a "parent layer". When specified, the child layer should follow the transform of the parent layer according to the transforms of both layers when the parent layer was specified.
Chains of parenting should be supported. E.g.
This would mean that A's transform is applied to itself and B. B's transform is then applied to itself and C. And C's transform is applied only to itself. The order in which these are applied matter.
The user should be able to move the control points of keyframes together.
If the user is dragging the controlPointRight
of a keyframe, the controlPointRight
of all selected keyframes should move according to the same move vector. The same goes for controlPointLeft
.
The opposite control points should follow reflectControlPoints
. This is determined on an individual keyframe basis rather than "all the keyframes being moved" basis. If the user toggles the reflectControlPoints
via option move, each individual keyframe should be toggled.
AE has effects for layers, Blender has modifiers for objects.
As discussed in #9, AE's effects tend to operate on pixels rather than vector objects. Since I don't expect us to support a canvas-based renderer (see #9) effects that operate on pixels will probably not be supported.
But Blender's modifier system operates on geometry rather than pixels.
Modifiers like Blender's array modifier could prove to be very useful in an SVG-like renderer.
For example, it would be really useful when creating patterns to be able to add an array modifier to create a repeating pattern.
Every layer in the comp would have an index of 0 by default, but for copies created by an array modifier the index would increase by 1 for each subsequent copy.
This index could be used to modify the layer via the Node Editor. I imagine a layer_index
node that can reference an array modifier and get the current index. This could be used change the position by adding a Vec2 that has been multiplied by an index.
In the above example, the layer would be repeated N times, and each copy would be moved 100 on the X axis.
We could also apply two array modifiers to create a two dimensional grid of items.
You see where this is going. We could rotate, scale, and transform the layer in different ways to create repeating patterns.
The array modifier is the most obviously useful example, but are there other modifiers that we can apply to this project?
I'm not sure yet.
There are some that seem promising (e.g. the curve modifier), but for a lot of them it's not immediately obvious how they could be translated from Blender to this project. It is also a question of whether the functionality introduced by a modifier should be in the form of a modifier in the first place.
The array modifier feels like it should be a modifier, but should the curve modifier be? The curve modifier feels like it should rather be a curve layer in our case, since multiple layers should be able to reference a single curve.
I'm 100% determined to add the array modifier in some form, but I have mixed opinions on other modifier.
In #9 I call them custom properties, since it's in the context of nested properties.
I don't like the name "custom properties" since it doesn't describe anything.
I definitely don't like using the name "effect", since it is heavily associated with AE and it's specific effects. And since we are not supporting AE's effects, the name may feel confusing.
I like the name "modifiers" since modifiers modify the layer that they live on. But if we add "Expression Control"-like modifiers, then they are not directly modifying the layer so the name becomes technically incorrect. I don't think this is a big issue though, especially since we may add "Expression Control"-like layers whose only purpose is to have animated controls.
So for now, we will call this concept "modifiers".
New control points were dragged as the blue arrow illustrates.
There is not enough space on the X axis (t would exceed 1) to reflect the amplitude of the left keyframe to the right. We should consider how much t is capped and adjust the value according to the that.
This is also a problem when angle-only reflecting keyframes after they have been created.
You currently have to individually shift select different keyframes if you want to move them together. Being able to drag a rect around a group of keyframes would be really helpful.
The user should be able to rect select keyframes of different timelines together.
Since the composition dimensions are dynamic, I can imagine a lot of cases where a node that just outputs the current center of the composition is useful.
For example, setting the anchor point of something as the center of the comp (maybe +/- some amount) would probably be a very common operation.
Maybe we should add Offset X and Offset Y inputs to the node?
We should allow locking the movement to an axis by holding Shift.
When moving keyframes or control points, the _yPan
and _yBounds
are set on each individual timeline being displayed in the CompositionTimeline
. The _yPan
and _yBounds
should be stored within the CompositionTimeline
' area state instead.
Strokes within Shapes should be deletable.
This should be doable via:
Currently, it's not very obvious how anchoring and origins behave for index transforms.
I imagine two separate but related properties.
The anchor should work the same as it currently does for normal layers. It offsets the rendering.
The origin should be the point around which index transformations are applied. Currently index transforms' origins are the translate of the previous index transform.
There should be two ways to define the origin.
Shapes within Shape layers should be deletable.
This should be doable via:
In AE, layer transforms are applied in a specific order (translate then scale and rotate). You can get around this with parenting (e.g. parenting to a null layer that controls rotation from an anchor point).
Replicating this behavior may be sufficient, but another option to consider is allowing users to specify multiple transforms of any type in any order.
I don't think we will pursue this option, but it's something to consider.
A few things can be wrong with expression nodes:
When any of these occur, they either fail silently or freeze up the app (until Esc is pressed).
This issue can be closed when invalid expression nodes are communicated to the user in some way and do not cause errors.
Originally a section in #29.
And one that I feel may be interesting is a "Clip content" boolean. This will be useful for showing elements positioned based on the composition width/height that can overflow.
In this example, the white rectangle fills the width and height of the composition. The blue rectangle exceeds the width of the composition (e.g. the X position is -20 and the width is the composition width + 40). The green circle's X and Y positions would be the width and height of the composition respectively.
Holding Shift should lock the moveVector
to the larger of the x and y axes.
If x > y, then y = 0 and reverse.
There are two types of potential circular dependencies.
There are valid reasons for two different layers to both reference properties of the other. This use case should work as expected. It also makes perfect sense for a layer's property to reference another of that layer's properties.
However, for layer A's transform to reference a computed value from layer B's transform and for B to do the same for A where both layers only have a single property_output
node we will have to compute one first. We will have to figure out a smart way to go about this, at least if we want to avoid recomputing the same things multiple times.
We will need to topologically sort these cross-layer dependencies somehow so that the computed value is what we want it to be when we read its value.
Circular dependencies will also have to be detected and communicated to the user. They shouldn't stop us from rendering (we can use the raw value), but they should be resolved by the user (maybe a third null layer)?
Or maybe we want to disallow cross-layer dependencies? Cross-layer dependencies can always be solved by null layers, but that solution is less convenient and perhaps not as intuitive.
We can probably start by disallowing circular cross-layer dependencies whilst allowing circular same-layer dependencies. If we detect a circular same-layer dependency we can decide to use the raw value for both and warn the user that this is what is happening.
Title says it best. If two composition layers reference the same composition, the values of the properties of the layers within those compositions will be the same if we are computing a propertyId to value map.
The user should be able to zoom and pan (on trackpad) via wheel events.
Transforms currently separate the X and Y position, but the Scale is just one property.
There should be an X and Y scale.
There are currently no checks or filters in place for circular parenting of layers.
Each shape should be able to have any amount of paths (0 included).
Paths should be draggable between shapes (similar to layer reordering). They should even be draggable between different shape layers (should probably adjust to transform(?)).
Paths should also be deletable via:
Currently if we encounter an uncaught exception, the app "crashes".
Instead, we should attempt to recover gracefully.
If neither of those works, the app should enter an "irrecoverable error" state.
Currently the entire timeline is always considered when determining its Y bounds.
Only the visible paths (according to the timeline's view bounds) should be considered.
I would like to support dynamic-length compositions. For example if we have a composition where something animates in, then transitions into an idle-ish state.
This is similar to the loop feature in AE's expressions. For example, you can play keyframes in the composition, then choose to pingpong between the 4 last keyframes of the animation until the end of the composition.
It would be lovely if compositions had no specific length and could be played indefinitely with a variety of loop-like behaviors. And via the node editor we could transform the animations via real-time input from the user.
Not entirely sure how we should choose to display non-fixed length compositions in the timeline editor. The view bounds kinda stop meaning anything when we remove the composition length. We could choose to give compositions a "reference length" that the view bounds abide by, but we would allow users to pan and zoom past them.
Users should be able to right click on the empty space in the CompositionTimeline
and create a new layer.
For this change, the only layer type supported should be rects. Other layer types are a separate issue.
Currently we don't support copy pasting in any way.
I don't believe we can (or should) make use of the native clipboard for copy-pasting layers, properties, keyframes etc. We also don't want the copied data types (e.g. when copying a layer) to be pasted as JSON or some other format in other programs/inputs.
Creating a "virtual clipboard" in memory where we store copied objects gives us much more control and flexibility over how copy paste behaves. And more interestingly, it allows us to have multiple objects in the clipboard at the same time (e.g. some text, a layer, nodes).
I imagine us separating the clipboard into a few slots.
The text clipboard (native clipboard) should not be handled specifically by us. Our custom copy paste handler should only fire if an input/textarea does not currently have focus. This allows us to copy and paste between programs.
More can be added in the future, but I see these as the current logical separation since none of these share much overlap in data types.
Currently each layer just has a flat list of properties. This is fine while layers have a fixed number of properties, but when we add support for non-transform and custom properties this should be changed.
Properties should probably be separated into three categories.
Every single layer has transform properties. Those are:
The transform is really performant to animate.
There is a better name than "native" out there, I just can't think of it right now. These are properties specific to a layer type.
For example a rect layer might have width
and height
properties while a circle layer might have a radius
property.
These are properties that can not be removed, but are not present on every layer.
These are non-layer specific properties that can be added to or removed from any layer.
In AE, these are called "Effects". They may operate on the layer (e.g. modify it visually) or exist as reference (e.g. Expression Controls).
I don't believe that we will significant support "effect like" properties because effects in AE operate on pixels rather than vector objects.
There are some that may be useful (color transforms, blurs, masks) but most effects (distort, generate, roughen edges, etc) are either way to computationally expensive to run in realtime or just don't work as well with vector objects.
I am not 100% certain that we will never support effects that operate on pixels though. If we end up with WebGL rendering support, then vector shapes can be converted to pixels and then operated on on the fly.
The reason I think that we will not go for WebGL rendering is because I expect us to support injecting arbitrary DOM nodes in our animation. This is just a rough idea in my head at the moment, but being able to render components within so-called "slices" of our animation may prove useful. This would only be possible via an SVG-like renderer.
The only custom properties I see us adding in the near future are "Expression Control" like properties that the Node Editor can hook into, but there is a big discussion to be had about other effects/modifiers that operate on the layer they are added to. That discussion will take place in another issue.
There is also the question of whether we want first-level support for "Control Layers", which exists purely for other layers to reference. This is similar to nulls in AE and empties in Blender.
For this reason, I don't think we should support custom properties to being with. Only transforms and native properties should be supported until we decide on a route for custom properties.
In the node editor, the layer_input
and layer_output
nodes should be updated to reflect the new categories.
I expect us to have the following Layer IO nodes:
layer_transform_input
and layer_transform_output
layer_property_input
and layer_property_output
(native layer properties)layer_{name for custom properties}_input
and layer_{name for custom properties}_output
The user should be able to reorder layers by dragging them around.
The errors of sub-compositions (composition layers) are currently not read and thus not displayed. Only errors in the top-level composition are read and displayed.
Most layers should contain the following properties.
I believe all of these apply to layers of type rect, oval, polygon, shape and text.
A composition should be able to include a composition via a "composition layer".
Compositions may not include circular composition layer references. E.g. if comp A includes comp B as a composition layer, comp B cannot include comp A. Same goes for A -> B -> C -> A.
The obvious properties that a composition layer should have, aside from transforms are:
And one that I feel may be interesting is a "Clip content" boolean. This will be useful for showing elements positioned based on the composition width/height that can overflow.
In this example, the white rectangle fills the width and height of the composition. The blue rectangle exceeds the width of the composition (e.g. the X position is -20 and the width is the composition width + 40). The green circle's X and Y positions would be the width and height of the composition respectively.
A new node that exposes the composition dimensions should be introduced. I imagine a node called Composition Dimensions
that has two outputs, width and height.
The user should be able to set the offset of an array modifier, which acts as a start index.
Given that count is 5, an offset of 5 would result in rendering the elements at indices:
5, 6, 7, 8, 9
An offset of -2 would result in rendering the elements at indices:
-2, -1, 0, 1, 2
Offset should be a property next to count.
Fills within Shapes should be deletable.
This should be doable via:
Graphs have a layerId
which dictates the layer that the property_input
nodes can work with. However, this node should allow any layer in the composition of the graph's layer to be selectable.
This selection should be done via the node's state (similar to propertyId
). When changed, existing pointers should be maintained if possible (e.g. if both layers have the property referenced by propertyId
).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.