Skip to content

Animation

animate plays a stack of precomputed frames back entirely in the browser on a WebGL canvas. You compute the frames once in Julia; playback runs on the GPU, so a slow simulation still plays at 60 fps and nothing touches Julia during playback.

Return an animate(…) from a cell to render the player (play/pause, a scrubber, and a frame counter).

Heatmap frames (default)

kind=:heatmap takes a vector of 2-D scalar matrices, colormapped for you:

julia
xs = range(-3, 3; length = 120)
frames = [[exp(-((x-cos(t))^2 + (y-sin(t))^2)) for x in xs, y in xs] for t in range(0, ; length = 60)]
animate(frames; x = xs, y = xs, title = "moving gaussian", autoplay = true)

Control how frames are colour-scaled with clim:

climMeaning
:global (default)one scale across all frames — frames are directly comparable
:symmetricsigned fields → a diverging map centred at 0 (skips transform)
:perframerescale each frame to its own min/max
(lo, hi)an explicit fixed range

Other keywords: colormap (:auto or any name), fps, transform (e.g. log), dither, loop, autoplay, title, colorbar, x/y axis coordinates, and times (per-frame time values, shown in the player's readout).

height, width and maxheight set the displayed size in CSS pixels. Left alone, the canvas fills the cell width and is capped at 560 px tall.

maxbytes caps the raw frame stack, default 128 MB. A larger stack raises an error telling you to use fewer or smaller frames, or to raise the cap.

animate(f, nframes) is the generator form: frame i comes from f(i).

Image frames

kind=:image plays back true-color frames — a Vector of H×W color matrices (e.g. Matrix{RGB} from VideoIO.jl or Images.jl) or H×W×3 arrays — with no colormap:

julia
using VideoIO
reader = VideoIO.openvideo("clip.mp4")
frames = [read(reader) for _ in 1:120]      # Vector{Matrix{RGB{N0f8}}}
animate(frames; kind = :image, fps = 25, title = "clip")

Overlays

overlay draws frame-synced markers on top of either kind — a Vector with one entry per frame, each a list of (x, y) or (x, y, id) points in frame-pixel space. An id keeps a point's colour and trail stable across frames (handy for tracking):

julia
tracks = [[(x1(t), y1(t), 1), (x2(t), y2(t), 2)] for t in 1:120]   # per-frame detections
animate(frames; kind = :image, overlay = tracks, fps = 25, title = "tracked beetles")

Reacting to the current frame — playhead

animate plays without involving Julia, but you can still react to playback with the playhead driven control. It's a @bind target that receives the animation's current 1-based frame index (it has no input of its own):

julia
#%% code id=anim
anim = animate(frames; x = xs, y = xs)

#%% code id=t
@bind t playhead(anim)

#%% code id=readout
"frame $t / $(length(frames)) — t = $(round(times[t]; digits = 2))"

Any cell that reads t recomputes as the animation plays — so a caption, a marker, or a linked chart tracks the frame. Updates are throttled and never block playback. See Widgets & @bind and Reactive Cells.

Compute once, cache it

The frame stack is usually the expensive part. Put it in its own cell so the reactive engine computes it once; expensive cells are also auto-cached and restored after a restart.