Reference
Note, that you need to import this library to any context expect Global
Needs["AnimationFramework`"->"af`"];
Scene
af`Scene[opts___] _Scene
constructs the main object Scene, where animation is going to be rendered. It also serves the purpose of a hosting object for primitives, animations, workers and etc.
The local coordinates are limited to for the square aspect ratio, otherwise the smallest side takes is scaled to 1:

Scenes can be reused multiple times in different animations.
Options
ImageSize
By the default is Medium.
"TimeMarkers"
Sets the time markers from the Timeline
"GlobalDirectives"
Adds a provided list to the scene globally (set font size globally and etc)
Other options
The rest is inherited from Graphics. PlotRange, ImageSizeRaw, cannot be changed.
Animation Flow
All animations on the scene should follows the pattern:
- append objects
- animate
- remove objects
By design most of methods and functions of AF framework return Promise expression. In this regard, it makes sense to describe your animation flow using Asynchronous Functions:
AsyncFunction[scene, Module[{},
...
]][scene];
Supported methods
AddTo
The most important method for the animation scene or to a layer:
af`AddTo[_Scene | layer_, primitives_] _af`Private`entity
af`AddTo[_Scene | layer_, primitives_, {
prop1_String -> value1_,
...
}] _af`Private`entity
where primitives can be any 2D graphics object, or an expression, that produces graphics objects or your custom written WLJS Function that support .update method.
Mutable properties are embed using Slot expression aka
Primitive[#prop1, #prop2] ...
Basic example:
disk = af`AddTo[scene, {Red, Disk[{0,0}, 1]}];
However, it does not have any mutable properties. Here is another example
disk = af`AddTo[scene, {Red, Disk[#pos, #r]}, {
"pos" -> {0.,0.},
"r" -> 0.5
}];
On the created entity the following methods are supported
Supported methods
Update
Assigns a new value to a given property or list of properties
af`Update[scene_Scene, entity_, prop_String -> newValue_ ..]
af`Update[scene_Scene, entity_, {
prop1_String -> val1_,
...
}]
af`Update[entity_, {__Rule}]
The action will be applied immediately without easing. For example:
disk = af`AddTo[scene, {Red, Disk[#pos, #r]}, {
"pos" -> {0.,0.},
"r" -> 0.5
}];
af`Update[scene, disk, "pos"->RandomReal[{-1,1}, 2]];
Remove
Removes a single object or object from the scene or in a layer (including all children)
af`Remove[_af`Private`entity | _af`Private`runner | _af`Private`worker]
af`Remove[layer_af`Private`entity]
af`Remove[_Scene]
Remove acting on Scene does not remove the scene itself, but it disposes all objects added to it including the nested ones (layers). Use it as a fast way to clean up the scene.
Animate
It animates the transition of a property or set of properties with a given easing function on the scene
af`Animate[scene_Scene, entity_, prop_String -> value_, easing_:"CubicInOut", duration_:1] _Promise
af`Animate[scene_Scene, entity_, {
prop1_String -> value1_,
prop2_String -> value2_, ...
}, easing_:"CubicInOut", duration_:1] _Promise
where easing is function used for animating the transition:
"Linear""CubicInOut"or"Ease""QuadIn""QuadOut""LinearEuclidean"(usually used for colors)Function[{t, initial, current, target}, ...]
and duration is given in seconds.
In addition Animate can be applied to any held _Symbol:
af`Animate[scene_Scene, Hold[symbol_], newValue_, easing_:"CubicInOut", duration_:1] _Promise
or a Layer entity
af`Animate[scene_Scene, layer_, prop_String->newValue_, easing_:"CubicInOut", duration_:1] _Promise
Animate always returns Promise, which is resolved when the animation is finished, i.e.:
wait for the animation to be finished
af`Animate[scene, object, "prop"->1.0] // Await;
wait for multiple animations to be finished
{
af`Animate[scene, object1, "prop"->1.0],
af`Animate[scene, object2, "prop"->1.0],
}// Await;
For animating multiple properties of the same object - use
af`Animate[scene, object1, {"prop1"->1.0, "prop2"->3.0}]
Animation is done fully using Wolfram Kernel (no Javascript easing is involved) at the maximum available frame rate (dynamic).
For example:
scene = af`Scene[];
scene
AsyncFunction[scene, Module[{d},
d = af`AddTo[scene, {
Opacity[#o],
Translate[
Rotate[
Rectangle[{-0.5,-0.1}, {0.5,0.1}]
, #r]
, #c]
}, {
"o" -> 0.,
"r" -> 0.,
"c" -> {0,0}
}];
af`Animate[scene, d, {"o" -> 1.0,"r" -> 3.14}, "Ease", 1.0] // Await;
PauseAsync[1] // Await;
af`Animate[scene, d, {"o"->0., "r"->0}, "Ease", 1.0] // Await;
af`Remove[d];
]][scene];
Supported property types
Real,IntegerListof integers, realsListofListand etcStringwith numbers inside
In principle anything, which can be combined with multiplication and sum can work as a property value.
Strings
String interpolation is done in steps:
- exploding string into string and number-like string
- convert number-like strings into array
- interpolate a array (using easing function) between the original and target value (transformed from a string)
- compose back into a string
For example, one can easily animate the following SVG attribute
scene = af`Scene[];
scene
AsyncFunction[scene, Module[{layer},
layer = af`Layer[scene, {
SVGAttribute[#children, "style"->#style]
}, {"style" -> "filter: blur(0px)"}];
af`AddTo[layer, Table[{RandomColor[], Disk[RandomReal[{-1,1},2], 1.0]}, {10}]];
af`Animate[scene, layer, "style"->"filter: blur(100px)", "Ease", 5]//Await;
af`Remove[layer];
]][scene];
Layer
It creates an isolated group of objects (layer):
af`Layer[scene_Scene | layer_, body_] _af`Private`entity
af`Layer[scene_Scene | layer_, body_, {
prop1_String -> value1_,
...
}] _af`Private`entity
where body is defined similar to one in AddTo:
{
Opacity[0.5],
#children
}
or
{
Opacity[#opacity],
Translate[#children, #coordinates]
}
where #children is a special reserved slot to specify where to append children. You can append objects similar to Scene using AddTo expression:
layer = af`Layer[scene, {
Opacity[#opacity],
Translate[#children, #coordinates]
}, {"opacity" -> 0.5, "coordinates"->{0,0}}];
af`AddTo[layer, Table[{RandomColor[], Disk[RandomReal[{-0.2,0.2},2], 0.05]}, {10}]];
Z-ordering
To preserve z-order of your primitives, one can use Layer together with SVGGroup.
Supported methods
Loop
It create custom animation loop, which is repeated until manually removed
af`Loop[scene_Scene, entity_, property_String, function_, duration_:1] _af`Private`runner
where function should have the following form:
Function[{t, prevValue, cycleNumber},
]
Here t goes from 0 to 1 in duration seconds, and cycleNumber represents the number of rounds passed.
function is fired every frame