4 releases (breaking)

Uses new Rust 2024

0.4.0 Apr 3, 2026
0.3.0 Apr 2, 2026
0.2.0 Apr 1, 2026
0.1.0 Apr 1, 2026

#1007 in Text processing

MIT license

49KB
994 lines

Bad Crab Apple πŸ¦€πŸ

A standalone, single-binary CLI player for "Bad Apple!!" written in Rust. Audio and video are compiled directly into the binary β€” no external files or dependencies needed at runtime.

Building

cargo build --release

This takes a moment: it embeds ~15MB of compressed audio and video frames into the binary.

Running

./target/release/bad-apple

This plays the video in the default block mode. The video scales automatically to your terminal size, maintaining the original 4:3 aspect ratio. Press q, Esc, or Ctrl+C to quit.

Render Modes

The renderer maps each 1-bit pixel to a terminal character. Because terminal characters are taller than they are wide, each row samples two video rows (top half and bottom half), giving four possible states per character: empty, top-lit, bottom-lit, and fully-lit.

There are five built-in modes:

Mode Flag Characters Notes
classic --classic ' ' - * @ Default. Sampled from " .:-=+*#%@".
block --block ' ' β–€ β–„ β–ˆ Highest visual quality.
ascii --ascii '.' ^ v @ Narrow ASCII characters.
shading --shading ' ' β–‘ β–’ β–ˆ Unicode block shading.
korean --korean μ‹œ 뽁 λŠ™ λΎƒ Wide (2-column) Korean glyphs. Aspect ratio is corrected automatically.

Use either the flag shorthand or --mode <name>:

./target/release/bad-apple --shading
./target/release/bad-apple --mode shading

Custom Characters

--chars β€” specify all four states directly

Provide exactly 4 characters in the order: empty Β· top-lit Β· bottom-lit Β· fully-lit.

./target/release/bad-apple --chars " .':"
./target/release/bad-apple --chars " 가을뿔"

--gradient / -g β€” sample from a palette

Provide a string of 2 or more characters from darkest to brightest. Four characters are sampled evenly from it (at 0%, 33%, 67%, 100%) and used for the four states.

./target/release/bad-apple -g " .:-=+*#%@"
./target/release/bad-apple -g " β–‘β–’β–“β–ˆ"

For both options, character display width is detected automatically β€” wide/CJK characters (2 columns) get a different aspect ratio correction than narrow characters (1 column).

How it works

The original video was thresholded to 1-bit per pixel (pure black and white) and scaled to 160Γ—120. At 1 bit per pixel, 8 pixels pack into a single byte. The resulting frames.bin contains 6,572 frames at 30 fps and is ~15MB. Audio is stored as a compressed MP3. Both are embedded into the binary at compile time via include_bytes!.

Dependencies

~9–42MB
~619K SLoC