Animation helper functions

Luxor provides some functions to help you create animations—at least, it provides some assistance in creating lots of individual frames that can later be stitched together to form a moving animation, such as a GIF or MP4.

There are four steps to creating an animation.

1 Use Sequence to create a Sequence object which determines the title and dimensions.

2 Define a suitable backdrop(seq::Sequence, framenumber, framerange) function that contains graphics functions that are used on every frame of an animation sequence. For example, this is a good place to define a constant background color.

3 Define a suitable frame(seq::Sequence, framenumber, framerange) function that constructs the contents of the frame numbered framenumber. The total framerange is available for possible reference inside the function.

4 Call the animate(seq::Sequence, framerange, backdrop, frame) function, passing in your two functions (which don't have to be called anything special, but which should have the arguments shown above). This creates all the frames in the given framerange and saves them in a temporary directory.

Example

using Luxor

demo = Sequence(400, 400, "test")

function backdropf(demo, framenumber, framerange)
    background("black")
end

function framef(demo, framenumber, framerange)
    xpos = 100 * cos(framenumber/100)
    ypos = 100 * sin(framenumber/100)
    sethue(Colors.HSV(rescale(framenumber, 0, length(framerange), 0, 360), 1, 1))
    circle(xpos, ypos, 90, :stroke)
    gsave()
    translate(xpos, ypos)
    juliacircles(50)
    grestore()
    text(string("frame $framenumber of $(length(framerange))"), O)
end

animate(demo, 1:630, backdropf, framef, createanimation=true)

animation example

Luxor.SequenceType.

The Sequence type and the animate() function are designed to help you create the frames that can be used to make an animated GIF or movie.

Provide width, height, and a title to the Sequence constructor:

demo = Sequence(400, 400, "test")

Then define suitable backdrop and frame functions.

Finally run the animate() function, calling those functions.

source
Luxor.animateFunction.
animate(seq::Sequence, frames::Range, backdrop_func, frame_func;
        createanimation = true)

Create frames in the range frames, using a backdrop function and a frame function.

The backdrop function is called for every frame.

function backdropf(demo, framenumber, framerange)
...
end

The frame generating function draws the graphics for a single frame.

function framef(demo, framenumber, framerange)
...
end

Then call animate() like this:

animate(demo, 1:100, backdropf, framef)

If createanimation is true, the function tries to call ffmpeg on the resulting frames to build the animation.

source

Making the animation

Building an animation such as a GIF or MOV file is best done outside Julia, using something like ffmpeg, with its thousands of options, which include frame-rate adjustment and color palette tweaking. The animate function has a go at running it on Unix platforms, and assumes that ffmpeg is installed. Inside animate(), the first pass creates a color palette, the second builds the file:

run(`ffmpeg -f image2 -i $(tempdirectory)/%10d.png -vf palettegen -y $(seq.stitle)-palette.png`)

run(`ffmpeg -framerate 30 -f image2 -i $(tempdirectory)/%10d.png -i $(seq.stitle)-palette.png -lavfi paletteuse -y /tmp/$(seq.stitle).gif`)

Passing information to later frames

Sometimes you want some information to be passed from frame to frame, such as the updated position of a graphical shape. Currently, the only way to do this is to store things in the sequence's parameters dictionary.

For example, for a "bouncing ball" animation, you can store the current position and direction of the ball in the Sequence.parameters dictionary at the end of a frame, and then recall them at the start of the next frame.

function frameF(seq::Sequence, framenumber, framerange)
    pos          = seq.parameters["pos"]
    direction    = seq.parameters["direction"]
    spriteradius = seq.parameters["spriteradius"]

    # ... code to modify position, direction, and radius

    seq.parameters["pos"]          = newpos
    seq.parameters["direction"]    = newdirection
    seq.parameters["spriteradius"] = spriteradius
end

bouncing ball