Installing Animations

To use Animatron you’ll need some animations to work with.

Animations are just collections of .png files or spritesheets (like the ones used in videogames).

When using image collections, it gathers them from named folders, using the folder name as the animation identifier.

The default directory to store animations is: user://assets/animations where user:// depends on the system you’re on:

  • Linux: ~/.local/share/animatron/

  • macOS: ~/Library/Application Support/

  • Windows: %APPDATA%\

For example, on Linux, having a collection of .png images in this directory ~/.local/share/animatron/assets/animations/whatever/ would allow us to create an actor with:

/load whatever
/create myactor whatever

This works with symlinks as well (shortcuts), so you don’t need to have the actual folders in that path.

If you want to use images that are in other directories, you can change the assets path with:

/assets/path path/to/your/custom/directory

We strongly recommend using your own animations, but you can find some of ours in this link.

Loading Animations (Assets)

Assets are anything that Animatron can load from disc. Animations are image assets that are loaded into the program.

In this tutorial we’ll learn how to load assets into Animatron.

Read how to install animations if you haven’t already.

We’ll assume that the parent folder for our animations is: /home/me/animations. We’ll imagine that our animations directory tree looks something like this:

animations
├── foo-jump
│   ├── 0001.png
│   ├── 0002.png
│   ├── 0003.png
│   ├── 0004.png
│   ├── 0005.png
│   ├── 0006.png
│   ├── 0007.png
│   └── ...
├── mama
│   ├── 00001.png
│   ├── 00002.png
│   ├── 00003.png
│   ├── 00004.png
│   └── ...
└── ...

To load the animation called foo-jump, first we need to tell Animatron where it can find it by setting the path to the image assets parent folder.

(assets-path-set! "/home/me/animations")

Then we can load it by name

(define-animation foo-jump)

Nothing seems to happen, because we just loaded the animation. To play it we need to create an actor

Creating Actors

We call actor the object playing an animation. We need to give the actor a name so we can send commands to it later. A name can be anything starting with a letter followed by an arbitrary number of letters, numbers and hyphens (-). Other symbols are not allowed.

Create a caracter named foo which will play our foo-jump animation.

(define-actor foo foo-jump)
Warning
Names are case-sensitive; this means that foo is different from Foo and FOO.

Controlling stuff with commands

A command is message we send to objects in Animatron in order to change something. Most of the commands we’ll use will modify actors' behaviour or appearance. There are commands for non-actors as well.

An actor command always has the same structure: (COMMAND-NAME ACTOR-NAME ARGUMENTS).

For example, let’s double the playback speed of the animation played by an actor named foo:

(speed! foo 2)  ; normal speed is 1

A command ending with an exclamation mark (!) usually means that the command is changing something in the system.

Some actor commands don’t have arguments:

(stop! foo)

Commands with no arguments at all are usually to get info from the system —note the lack of exclamation mark (!):

(list-actors)   ; prints a message in the console

For the full list of commands see the cheat sheet.

Routines

A routine is an action that happens repeatedly every given time. This allows us to automate stuff while we code other things.

To define a routine we need to give it a name, how many times we want it to repeat, how much time it must wait between calls, and a function telling it what to do.

(define-routine bar (1)
                3 (2)
                1.5 (3)
                (lambda (tick) (4)
                  (angle! foo (* tick 10)))) (5)
  1. define a routine named bar.

  2. number of repetitions.

  3. interval between each repetition, in seconds.

  4. function definition: takes one argument which counts how many times the function has been called by the routine. The word lambda means it’s an anonymous function (only called by the routine).

  5. function body: what to do every time the routine calls the function. In this case, it sets the angle of an actor named foo to a value obtained by multiplying the current tick count (how many times the function has been called until now) by 10 degrees.

Infinite Routines

To let a routine run forever, set the value of repeats to INF.

(define-routine bar INF 0.3 (lambda (t) (rotate! foo 5)))

Stop the routine at any time using its name:

(routine-stop! bar)

Receiving OSC

Animatron can be controlled using OSC messages on port 56101.

Some of its commands are already mapped to OSC. To see a full list of existing messages, use:

(list-osc-commands)

For example, if we have an actor named foo, we could change its speed by sending it the message /actor/speed foo 1.5.

Using liblo it would look like this:

oscsend localhost 56101 /actor/speed sf foo 1.5     # using liblo

Here’s an example using SuperCollider:

n = NetAddr("localhost", 56101);
n.sendMsg("/actor/speed", 1.5);

We can replace localhost with any IP address of any device in the network, so we can control any number of animatron instances from remote devices, as long as they are in the same network.

Custom OSC messages

To add a new OSC input message, first you need to have the function it will call.

(define (foo . args)    (1)
    (message args))    (2)
  1. This function is called foo. The dot (.) means it accepts an arbitrary number of arguments, including none, which will be stored in a variable named args.

  2. Print the arguments received, if any.

Now we are ready to add an OSC message that will trigger this command:

(osc-add-input-command! "/foo" foo) (1)
  1. The OSC address "/foo" doesn’t need to be the same as the function it calls, but it makes sense it does.

Now, every time you send a message to it, it will print the arguments.

oscsend localhost 56101 /foo sf "hello" 1.5
=> ["hello", 1.5]

Sending OSC

Animatron can send messages to other applications and devices in the same network.

(osc-send "127.0.0.1" 8000 "/foo" "hi there" 1 2.3)
(osc-send *localhost* 8000 "/foo" "hi there" 1 2.3)     ; same as above
(osc-send "192.168.0.127" 8000 "/foo" "hi there" 1 2.3) ; imaginary remote machine in the same network

In the examples above, we are sending the same message on different IPs, but always on port 8000.