User guide
Documentation
View classic BBS artwork in the native macOS app or your terminal, decode it from Rust, and export supported formats to PNG, APNG, or GIF.
Install
Install bbcat from crates.io with Cargo:
$ cargo install bbcat
Prebuilt Debian packages for amd64 and arm64 are also attached to each GitHub release. Development snapshots are published on the moving tip release.
To install from a source checkout instead:
$ cargo install --path .
bbcat has no runtime dependencies and requires only a Rust toolchain capable of compiling its current Rust edition.
macOS app
bbcat for macOS is a native AppKit viewer powered by the same Rust decoder and renderer. It adds timed ANSI animation, SAUCE metadata, crisp ×1 and ×2 display, native-size scrolling, Finder thumbnails, and full Quick Look previews.
Download bbcat-macos-arm64.zip from the latest bbcat-mac release, unzip it, and move bbcat.app to /Applications. The prebuilt app supports Apple silicon Macs running macOS 13 or newer and includes everything it needs. Launch it once to register its document types and Finder extensions.
The app also includes an optional copy of the bbcat command-line tool, which you can install to or remove from ~/.local/bin/bbcat from the app menu.
Usage
bbcat [OPTIONS] [FILE]...
Pass one or more files or use - for standard input. With no filename, bbcat reads redirected or piped input; when run interactively, it prints its help. Use -- before a filename that begins with -.
$ bbcat art.ans FILE_ID.DIZ
$ bbcat < art.ans
$ bbcat --kitty scene.xb
$ bbcat --output preview.png art.adf
$ bbcat --output - art.ans > preview.png
$ bbcat --apng animation.png animation.ans
$ bbcat --gif animation.gif animation.ans
$ bbcat --2x --kitty art.ans
$ bbcat --sauce art.ans
$ bbcat --baud 4x animation.ans
$ bbcat --asciimation starwars.txt
Looking for files to try? Browse and download BBS art packs at 16colo.rs.
Library API
Add bbcat to another Rust application to detect and decode supported BBS art formats into a common Document and Screen model:
$ cargo add bbcat
use bbcat::{DecodeOptions, Format};
use std::path::Path;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = std::fs::read("art/demo.ans")?;
let document = bbcat::decode_with_options(
&data,
DecodeOptions {
file_name: Some(Path::new("art/demo.ans")),
width: None,
},
)?;
println!(
"{}: {}x{} cells",
document.format, document.screen.width, document.screen.height
);
assert_eq!(document.format, Format::AnsiText);
std::fs::write("preview.png", document.encode_png(1)?)?;
Ok(())
}
Use decode for content-based detection with inferred dimensions, or decode_with_options to supply a filename hint and width override. A decoded Document reports its Format, final Screen, optional Sauce, and optional Animation.
Character screens expose cells, glyph and pixel dimensions, palette and font data; RIPscrip screens expose their indexed raster. Documents can be encoded directly to PNG, APNG, or GIF, while lower-level text and Kitty writers remain available for streaming output. ASCIImation has no format signature; decode it explicitly with decode_asciimation.
Example applications
bbcat-gtkis a small GTK4 demo that uses the library to open and render static and animated ANSI/BBS artwork. It also demonstrates file handling, responsive image display, and presenting SAUCE metadata in a desktop application.bbcat-thumbnaileris a Nautilus thumbnailer that demonstrates lower-levelScreenpixel sampling, square cropping and downscaling, and PNG output.
Output modes
| Mode | Option | Behavior |
|---|---|---|
| UTF-8 | default | Converts CP437 characters to Unicode and emits 24-bit ANSI colors. |
| Kitty | --kitty | Renders bitmap glyphs through Kitty graphics, cropping at the terminal's right edge. |
| PNG | -o FILE--output FILE | Writes one indexed-color PNG; use - to write it to standard output. |
| APNG | --apng FILE | Writes a looping indexed-color animated PNG from an ANSI or DDW animation. |
| GIF | --gif FILE | Writes a looping indexed-color animated GIF from an ANSI or DDW animation. |
Terminal output
UTF-8 output is intended for character art using the standard CP437 glyph set. Use Kitty or PNG output for RIPscrip, XBin 512-character fonts, or artwork whose embedded bitmap font must be reproduced exactly.
Kitty mode requires terminal stdout and a terminal that answers bbcat's Kitty graphics protocol probe. Kitty and Ghostty are supported on Linux and macOS, along with iTerm2 on macOS. Long images are emitted in strips so they remain available in terminal scrollback.
Image output
PNG, APNG, and GIF modes require exactly one input file. Use - as the output path to write the image to standard output. Choose only one image output mode; none can be combined with --kitty, --slow, --delay, or --sauce. Static PNG output cannot use --baud; APNG and GIF use it for frame timing.
Animation
bbcat recognizes ansimation from repeated ANSI screen rewrites and DarkDraw DDW animation frames, then plays them automatically when standard output is a terminal. Playback defaults to 1X. Use --baud RATE to choose an animation frame rate or set the row-reveal speed for static ANSI and text:
$ bbcat --baud 2400 animation.ans
$ bbcat --baud 57600 animation.ans
$ bbcat --baud 2x animation.ans
$ bbcat --baud 4x animation.ans
2400, 9600, 14400, 28800, 38400, 57600, 115200 (1X), 2X (230400), and 4X (460800) are suggested familiar rates. Run bbcat --baud to print the list. Any positive numeric rate is accepted, as is an Nx multiplier of 115200.
Animated playback uses each frame's source byte count to determine how long it remains visible. DDW uses its source-defined per-frame duration at 1X, scaled by the selected rate. Static art uses the same smooth row reveal as --slow: 1X is 25 milliseconds per row.
Terminals with synchronized-output support reveal each redraw atomically. Playback preserves CP437 text and source-defined 16-color, 256-color, and true-color SGR sequences. An animation that explicitly homes to the terminal's top-left clears the canvas before playback; relative animations leave the terminal intact. Both retain their final frame and return the prompt below it.
Redirected UTF-8 output and Kitty or PNG output render the last visible state instead of replaying the animation. --apng and --gif retain every detected frame and loop forever.
Supplying --baud explicitly replays an animation or uses the static row reveal even when UTF-8 output is redirected. It cannot be combined with Kitty, static PNG, --slow, or --delay.
ASCIImation text streams
The plain-text streams published by asciimation.co.nz contain no terminal control sequences, so bbcat does not detect them automatically. Play one explicitly:
$ bbcat --asciimation starwars.txt
The format stores a duration in 100 ms ticks followed by thirteen complete ASCII rows per frame. Playback requires terminal stdout and exactly one input, and redraws each frame atomically. It cannot be combined with Kitty/fit, image output, width, scaling, speed, or SAUCE flags.
Display and scaling
Slow mode
$ bbcat --slow art.ans
$ bbcat --delay 50 art.ans
$ bbcat --kitty --slow art.ans
--slow reveals one character row at a time with a 25 millisecond delay. --delay MS enables slow mode with a custom delay from 1 through 10,000 milliseconds. Both UTF-8 and Kitty modes flush each row before waiting; Kitty mode automatically uses one image strip per character row.
Slow mode is not supported with ANSI or DDW animation, image output, or RIPscrip raster graphics. Use --baud for baud-paced ANSI/text output. In Kitty slow mode, --chunk-lines has no effect.
2x scaling and fitting
$ bbcat --2x --kitty scene.xb
$ bbcat --kitty --fit wide.ans
$ bbcat --2x --output large.png drawing.rip
$ bbcat --2x --apng large.png animation.ans
--2x doubles graphical output dimensions. Kitty mode crops the doubled bitmap at terminal width unless --fit is present; image output writes an image with twice the width and height. It works with ANSI/text, DDW, XBin, ADF, and RIPscrip, and can be combined with Kitty slow mode. ASCIImation playback does not support scaling.
Scaling is unavailable in UTF-8 mode because repeating text characters would change strings and distort line art. Use --kitty, --output FILE, --apng FILE, or --gif FILE with --2x.
When UTF-8 output goes directly to a terminal, rows wider than the terminal are cropped to its current column count. Redirected output preserves the full artwork width. Kitty crops at terminal width by default; --fit scales the complete image down when at least one terminal row remains. Image output always retains its full dimensions.
SAUCE metadata
Use --sauce to show an artwork's available SAUCE title, author, group, and creation date as a compact gallery-style caption below the rendered art. Files without descriptive SAUCE metadata render without a caption. The option works with UTF-8 and Kitty output, including multiple input files, but cannot be combined with image output.
$ bbcat --sauce art.ans
Supported formats
- ANSI and plain CP437 text, including
.ANS,.DIZ,.ASC,.NFO,.MEM, and.TXT. Cursor movement, erasing, standard and bright colors, inverse video, blink/iCE colors, xterm-256 colors, wrapping, SAUCE dimensions, and baud-paced ansimation are handled. Ansimation also preserves true-color SGR sequences. - ASCIImation text streams containing a duration in 100 ms ticks followed by thirteen ASCII rows per frame. Because the format has no signature, use
--asciimationin the CLI ordecode_asciimationfrom Rust. - DarkDraw (
.DDW) UTF-8 JSON Lines text art and animation. Objects are painted in source order, group references are expanded recursively, and each frame uses its declared duration. Dimensions come from metadata when present or are inferred from positioned text. - XBin (
.XB) with embedded palettes, 8- or 16-color backgrounds, embedded fonts up to 32 pixels high, 256- and 512-character modes, and XBin RLE. - ArtWorx Data Format (
.ADF) version 1 with its embedded palette and 8×16 font. ADF is fixed at 80 columns. - RIPscrip (
.RIP) level-one vector graphics, including bitmap and proportional BGI stroke fonts. RIPscrip is rendered to a 640×350 canvas and requires Kitty or PNG output.
SAUCE metadata supplies content length, canvas dimensions, iCE color mode, 8- or 9-pixel VGA letter spacing, and named IBM VGA50, Amiga MicroKnight, Amiga Topaz 2+, and Empathy bitmap fonts when present. Kitty and image output reproduce exact glyph shapes; UTF-8 output remains a terminal-font approximation.
Common raster images such as PNG, GIF, JPEG, WebP, TIFF, ICO, BMP, and QOI are rejected by content with an explanatory error. Malformed, truncated, oversized, or unsupported BBS inputs also produce a non-zero exit status and a filename-scoped error. With multiple inputs, bbcat reports a rejected file and continues with the rest.
Options reference
| Option | Description |
|---|---|
-w COLS--width COLS | Override text width. ANSI/text accepts declared widths through 10,000 columns; untagged plain text is inferred through 1,000. DDW and XBin must match their declared width; untagged DDW may be widened but not narrowed. ADF must be 80 and RIPscrip must be 640. |
--chunk-lines ROWS | Set Kitty image-strip height from 1 through 256 character rows. The default is $LINES - 1, clamped to 1 through 64, or 24 when $LINES is unavailable. |
--kitty | Use Kitty graphics instead of colored UTF-8. |
--fit | Scale complete Kitty output to terminal width instead of cropping. Errors if the result would be shorter than one terminal row. |
--slow | Reveal one character row at a time using a 25 ms delay. |
--delay MS | Enable slow mode with a delay from 1 through 10,000 ms per row. |
--baud RATE | Control ANSI source-byte timing, DDW native frame timing, static ANSI/text row reveal, or APNG/GIF timing. 1X is 25 ms per row. Run bbcat --baud alone for suggested values. |
--2x | Double Kitty or image output width and height. Requires --kitty, --output, --apng, or --gif. |
--sauce | Show available SAUCE title, author, group, and creation date below the artwork. |
-o FILE--output FILE | Write an indexed-color PNG. Use - for standard output; requires exactly one input. |
--apng FILE | Write a looping indexed-color animated PNG from ANSI or DDW frames. Use - for standard output; requires exactly one input. --baud controls timing. |
--gif FILE | Write a looping indexed-color animated GIF from ANSI or DDW frames. Use - for standard output; requires exactly one input. --baud controls timing. |
--asciimation | Play one explicit asciimation.co.nz-style stream containing a duration plus thirteen ASCII rows per frame. Requires exactly one input and terminal stdout; cannot be combined with Kitty/fit, image output, width, scaling, speed, or SAUCE options. |
-h, --help | Print command help. |
-V, --version | Print the bbcat version. |