imagine.animation
import imagine.animation
imaginelifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelledimagine.animation.*needsimport imagine.animation.
Animation: an ordered set of frames with per-frame delays, which is
what an animated GIF or WebP decodes to and encodes from.
Frames are full images rather than deltas, so each can be edited on its own and the encoder works out what actually changed.
Classes
Animation
class imagine.Animation
A sequence of images with a delay between each, read from or written to an animated format.
Frames are whole images, already composited against whatever came before them, so frame 5 can be pulled out and used on its own without replaying the first four. That is the useful shape almost all of the time, and it is why the disposal and transparency rules an animated GIF is built from never surface here.
import imagine { Animation }
var animation = Animation.open('loading.gif')
echo '${animation.length()} frames, ${animation.duration()}ms total'
animation
.map(@(frame) {
return frame.grayscale()
})
.save('loading-grey.gif')
What can be read and written
Animated GIF and animated WebP can both be read. Only GIF can be
written; an animation saved as WebP raises EncodeError rather than
quietly writing one frame. [[imagine.capabilities]] lists what is
available under animated.
Memory
Every frame is a full image, so a 100-frame 500x500 animation is 100 MB
decoded. Animations are worth streaming frame by frame when they are
large, which frames() allows by handing back the list itself.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
imagine.Animation(frames: list, delay, repeat, format)
Creates an animation from a list of images.
Every frame must be the same size, since animated formats have one canvas that each frame paints into.
Parameters
frames(list) — A list of [[imagine.Image]].delay(?number|list) — Milliseconds per frame, either one number for all of them or one per frame - Default: 100.repeat(?number) — How many times to loop, 0 for forever - Default: 0.format(?string) — The format these frames were decoded from, recorded as metadata - Default: nil.
Raises ImageError When the frames are not all images of one size.
Animation.open()
imagine.Animation.open(source) -> Animation
Opens an animated image file.
A still image opens as a one-frame animation rather than an error, so code that handles both does not need to branch.
Parameters
source(string|file)
Returns Animation
Raises DecodeError When the file is not a readable image.
Animation.decode()
imagine.Animation.decode(data: bytes) -> Animation
Decodes animated image data held in memory.
Parameters
data(bytes)
Returns Animation
Raises DecodeError When the data is not a readable image.
Animation.length()
imagine.Animation.length() -> number
How many frames the animation has.
Returns number
Animation.frames()
imagine.Animation.frames() -> list
The frames, as a list of [[imagine.Image]].
This is the live list, not a copy: changing an image in it changes the
animation, which is what makes frame-by-frame editing possible without
duplicating everything. Use map() when you want the original left
alone.
Returns list
Animation.frame()
imagine.Animation.frame(index: number) -> Image
One frame by index, counting from zero.
Parameters
index(number)
Returns Image
Raises ImageError When there is no such frame.
Animation.delays()
imagine.Animation.delays() -> list
The per-frame delays in milliseconds.
Returns list
Animation.duration()
imagine.Animation.duration() -> number
How long one pass through the animation takes, in milliseconds.
Returns number
Animation.width()
imagine.Animation.width() -> number
The frames’ shared width in pixels.
Returns number
Animation.height()
imagine.Animation.height() -> number
The frames’ shared height in pixels.
Returns number
Animation.format()
imagine.Animation.format() -> ?string
The format this animation was decoded from, or nil.
Returns ?string
Animation.repeat()
imagine.Animation.repeat(times: number)
Sets how many times the animation loops when written out.
Parameters
times(number) — 0 loops forever.
Returns — self
Animation.delay()
imagine.Animation.delay(delay)
Sets the delay between frames.
Parameters
delay(number|list) — One value for every frame, or one per frame.
Returns — self
Animation.map()
imagine.Animation.map(fn: function) -> Animation
Applies a function to every frame, returning a new animation.
Each frame is copied before the function sees it, so a filter chain
works directly as the body and this animation is left alone. That copy
is the reason map() costs as much memory again as the animation
itself; to filter in place instead, walk frames() and change each
image directly.
var grey = animation.map(@(frame) {
return frame.grayscale().blur(1)
})
Parameters
fn(function(1))
Returns Animation
Raises ImageError When the function returns anything but an image.
Animation.reverse()
imagine.Animation.reverse() -> Animation
Returns a new animation with the frames in reverse order.
The frames themselves are shared with this animation rather than copied,
since reordering them changes nothing about them. Editing one afterwards
therefore shows up in both; map() is the one that copies.
Returns Animation
Animation.to_image()
imagine.Animation.to_image() -> Image
Returns the animation as a single image: its first frame.
Returns Image
Animation.encode()
imagine.Animation.encode(format, options) -> bytes
Encodes the animation and returns the bytes.
Parameters
format(?string) — Default:GIF.options(?dict)
Returns bytes
Raises EncodeError When the format cannot hold an animation.
Animation.save()
imagine.Animation.save(path: string, options)
Writes the animation to a file.
Parameters
path(string)options(?dict) —format, plus everythingencode()takes.
Returns — self
Animation.to_string()
imagine.Animation.to_string()
2026, Richard Ore and Zuri contributors