node package manager
Easy sharing. Manage teams and permissions with one click. Create a free org »

animaxe

Animaxe, Composable Animation Library

Maybe I should explain my motivation, I like procedural graphics, graphics drawn by code. But fiddling with parameters in a compile-execute cycle is slow and does not get the best artistic results. So I want a graphical system that allows me to:

  • Alter the generation code dynamically and see the results immediately (that's why I put the examples on Codepen)
  • Fiddle with the animation meta parameters live (that's what the FRP-like bit helps with)

So the aim of Animaxe is to be a few things:

  • Make it easy to create animations that are composable.
  • Be a nicer API for the Canvas drawing API
  • Be reactive, every parameter to every animation primitive should be alterable at any time
  • Be functional, a lot of inspiration is drawn from Functional Reactive Programming, although the intention is not to be too pure
  • Be efficient
  • Be typed using Typescript

Now you can compose animations functionally. Ideal for procedural and interactive animations.

Its still very early on this project, the basic building blocks are not complete, and the repository layout is not useful for libraries to link to. However, the following is a proof-of-concept for the API feel. Maybe you want to contribute?

Being a nicer Canvas API

Instead of the procedural style of drawing that the Canvas API uses, we chain. So instead of:

ctx.fillStyle = "red";
ctx.translate(30, 45);
ctx.fillRect(0,0, 10, 10)

In Animaxe we use the Ax module as the entrace to an animation chain. We use the same identifiers as the Canvas API, so it becomes

Ax.create()
  .fillStyle("red")
  .translate([30, 45])
  .fillRect([0,0], [10,10]);

Being reactive

It's worth noting almost every argument in Animaxe can be a literal, like in the example above, OR, it can be a dynamic time varying value. The Parameter module is the entrance to time varying functions, which can also be chained together with the normal functional primitives.

For example, a fading in an out example:

Ax.create()
  .fillStyle(Parameter.rgba(255, 255, 255, Parameter.sin(Parameter.t())))
  .translate(Parameter.point(30, Parameter.sin(30).map(x => x * 50)))
  .fillRect([0,0], [10,10]); 

The animation life lifecycle

The composable building block of Animaxe is an Animation. An animation does something with the drawing context. An animation can do something indefinitely, for example this draws a red square forever:

 foreverRedSquare() {
    return Ax.create() 
        .fillStyle = "red";
        .fillRect(0,0, 10, 10);
 }

But an animation can also have a finite duration. You can turn an infinite animation into a finite animation using take(<n>):

  redSquareFor2Frames() {return foreverRedSquare().take(2);}

You can chain animations temporally using .then, which creates a new animation from the the temporal concatenation.

  redThenGreenSquareFor4Frames() {return redSquareFor2Frames().then(greenSquareFor2Frames());}

You can create an infinite length animation from a limited duration animation by using .loop(), which just repeatedly sequences the same animation end-to-end

 foreverRedAndGreenSquare() {return Ax.loop(redThenGreenSquareFor4Frames());}

These animation operators are the defining characteristics of Animaxe, which internally resolve around using Rx's onCompleted semantic to dynamically change the dataflow graph. The dynamic dataflow operators, so far, in Animaxe are:-

  • parallel (play multiple animations at the same time)
  • clone (specialised version of parallel which plays the same animation multiple times)
  • emit (spawn a new animation every frame)
  • take (limit the temporal duration of an animation)
  • then (concatinate animations temporally)
  • pipe (pass the context of one animation into another)
  • loop (create an infinite duration animation by repeatedly resequencing)
  • .if .elif .else (switch an animation based on reevaluated conditionals)

(This style is quite related to AFRP if your interested. Elm is about signals, whereas Animaxe and YAMPA are about signal transformer)

Trying it out

Clone the repo

git clone git@github.com:tomlarkworthy/animaxe.git
npm install
python -m SimpleHTTPServer & gulp watch-example1

and browse to http://localhost:8000/html/example1.html, if you modify any TS sources, the page will refresh automatically.

You can add your own examples to the examples/ directory and a gulp watch-XXX task is created automagically!

Examples

Example 1 - Basic animation compositions (source)

Example1

Example 2 - Skewing time and dynamic colors (source)

Example2

Example 3 - Particles (source) (edit on Codepen)

Example3

Example 4 - Glow filter (source)

Example4

Example 5 - UI Button (source) (edit on Codepen)

Example5

Example 6 - UI Slider (source) (edit on Codepen)

Example6

We have some examples in the test directory written in Typescript. You can use the babel preprocessor within Codepen quite well. Although it borks on some of the typescript syntax, if anyone knows a good online Typescript editor that can read type definition files I would love to hear.

API

Currently documentation is broken until typedoc can do later versions of TS. Its in constant flux changed, but you can try it here here

TODOS

Packaging

  • instructions on using save As.. then map to network resource for example editing
  • Test npm workflow
  • Test TS workflow (bower?)
  • Redo codepen examples with systemJS (SystemJS doesn't support inline script tags for transpilation)

Glow

  • different distance exponents are interesting
  • think about alpha over existing backgrounds
    • improve effeciency by calculating the glow envelope when applying it

Features

  • Reflection
  • L-systems (fold?)
  • Perlin noise
  • simulate a lazer show, XY parametric functions (Lissajous curves), intergrate with ODE solve

Engineering

  • figure out why example3 cannot have move than 1000 particles without a stack overflow
  • replace parallel with its own internal animator OR make parallel the only option
  • check for memory leaks.
  • Time travelling debugger? http://elm-lang.org/blog/time-travel-made-easy uses snapshots and fast forwards, totally doable

Refactors

  • make Animator sequence Parameters And Animation

  • change event propogation

  • Move the .pipe inside the .draw (rename draw), and remove lots of redundant pipes

  • change order of playExample parameters

  • (partial) do all of canvas API methods

    • finish that API!
    • withinClip, withinTx, (done) withinPath
    • createLinearGradient, createPattern(), createRadialGradient(), addColorStop(), isPointInPath(), measureText(), drawImage()
    • save() restore()
  • the way the tick is passed on in Animator is ugly

  • All the complex methods are implemented badly, then, emit, parallel. Maybe state machines?

API documentation

website

  • npm

Code pen example

  • sync with codepen automatically

UI controls

  • slider
    • todo: let the user pass in the source of truth, and through a callback, let the user connect the value change to the source of truth this will allow min/max without hardcoding logic in the basic slider
  • (done) button
  • knob
  • (done) Default mouse behaviour.
  • (done) relative positions and transformation aware
  • As we need global event listeners (e.g. slider needs to listen to mouse moves after the mouse has left the component) we should have a global mouse listener implemented with RxJS which local listeners map over, instead of the ropey array thing we have for global events

Random IDEAS

  • PacMan
  • mouse input, tailing glow (remember to tween between rapid movements)
  • prerendering an animation for fast playback
  • SVG path parser for withinPath
  • Matrix esq. The rain