Flipbook
Write optimized animated GIF and APNG files from Ruby images.
Formats · Installation · API · Examples · Development
Flipbook writes animated GIFs and APNGs from Tessel::Image frames. GIF palettes use Tessel's shared quantizer; APNG keeps full RGBA color. Both writers can crop unchanged frame regions.
Formats
| Format | Colors | Transparency | Encoding |
|---|---|---|---|
| GIF | Up to 256 palette entries | One transparent palette index | GIF89a output with global or per-frame palettes and LZW |
APNG (.png, .apng) |
Full RGBA | Full alpha | PNG-compatible first frame, acTL / fcTL / fdAT animation chunks |
GIF uses a single global palette by default so colors stay stable across frames. Use palette: :per_frame when streaming frames with different color ranges. Delta cropping is most effective for opaque GIF frames; APNG supports alpha-safe cropped updates.
Installation
gem "flipbook"
Then run bundle install. Flipbook requires Ruby 3.1 or newer and Tessel 0.2 or newer.
API
require "flipbook"
frames = 60.times.map do |index|
image = Tessel::Image.new(320, 240, fill: "#101827")
image.fill_rect(index * 4 % 320, 100, 32, 32, "#38bdf8")
image
end
Flipbook.write("animation.gif", frames, fps: 30, loop: true)
Use delay: in seconds instead of fps:. It accepts one duration or one duration per frame; Rational(1, 30) avoids floating-point timing drift. GIF delays use cumulative centisecond rounding. Viewers may lengthen delays below 1/50 second.
For streaming GIF output, choose a per-frame palette:
Flipbook::GIF::Writer.open("recording.gif", width: 320, height: 240, palette: :per_frame) do |writer|
writer.add(frame, delay: Rational(1, 30))
end
Use a .png or .apng path for full-color animation. The first frame remains a valid PNG for viewers that do not animate APNG:
Flipbook.write("animation.png", frames, fps: 30, loop: true)
optimize: false writes full-size frames. The default crops each changed frame to its smallest bounding rectangle. GIF cropping is used for opaque frames; APNG cropping preserves alpha changes.
Read GIFs as full-canvas Tessel::Image frames. The reader applies frame offsets, transparency, interlacing, and disposal before returning:
frames = Flipbook.read("animation.gif")
max_pixels:, max_frames:, and max_total_pixels: can lower the decoder's resource limits for untrusted files.
API contracts
Flipbook.write(path, frames, fps: or delay:)requires one or more same-sizedTessel::Imageobjects and a.gif,.png, or.apngoutput path.GIF::Writer#addraisesTypeErrorfor non-image frames andArgumentErrorfor invalid dimensions or timing.APNG::Writer#addaccepts positive numeric delays in seconds and raises for frames that do not match the canvas dimensions.Flipbook.read(path)returns fully composited GIF frames and rejects malformed streams or files over its configured limits.- GIF palette colors are RGB triples of integer channels from 0 to 255. GIF transparency is binary; partial alpha is encoded as an opaque palette color.
Examples
Generate a rotating square, a color gradient, and transparent GIF/APNG samples:
ruby examples/generate.rb

Pass an output directory as the first argument to choose where the files are written.
GIF format acknowledgement: The Graphics Interchange Format© is the Copyright property of CompuServe Incorporated. GIF® is a Service Mark property of CompuServe Incorporated.
Development
bundle install
bundle exec rake verify
Optional external checks for generated files are listed in docs/verification.md.