Pippin
pippin consumes images (png, jpeg, svg) and outputs high-resolution
ASCII / UTF-8 representations to your terminal. With --animate it consumes
an animated gif (or video: mp4/mpeg/mov/avi/mkv/webm) and
re-renders every frame as text — exporting a frame directory, a self-playing
text-animation gif, or a text-animation video (mp4/mpeg).
Features
- Input:
png,jpeg,svg(plus anything Pillow opens: bmp, gif, webp, tiff) - Charsets:
ascii,utf8,blocks(+--custom-chars) - Preview to terminal (ANSI truecolor optional) and export to
.txt/.ansi - Color coding of characters (foreground truecolor sampled from source)
- Contrast / brightness / invert / aspect correction
- GIF animation mode (
--animate): live terminal playback, frame-directory export, and self-playing text-animation.gifre-export - Video animation mode (
--animatewithmp4/mpeg/mov/avi/mkv/webminput, requires systemffmpeg): live terminal playback, frame-directory export, and frame-for-frame text-animation video re-export (-o out.mp4/-o out.mpeg, source audio muxed by default)
Install
No Python install required: each v* tag ships self-contained single-file
binaries (.github/workflows/release.yml, matrix linux-x64|osx-arm64|win-x64)
attached to that tag's GitHub Release. SVG works out of the box — cairo is
bundled inside the binary.
curl -fSL -o /tmp/pippin-dl/pippin-linux-x64 https://github.com/fluxion-dev/pippin/releases/download/v0.1.0/pippin-linux-x64
chmod +x /tmp/pippin-dl/pippin-linux-x64
/tmp/pippin-dl/pippin-linux-x64 --version
# 0.1.0
gh release download v0.1.0 -p 'pippin-linux-x64' -D /tmp/pippin-dl --repo fluxion-dev/pippin
chmod +x /tmp/pippin-dl/pippin-linux-x64
/tmp/pippin-dl/pippin-linux-x64 --version
# 0.1.0
Direct asset URLs (each v* tag attaches the three binaries plus the sdist/wheel):
- https://github.com/fluxion-dev/pippin/releases/download/v0.1.0/pippin-linux-x64
- https://github.com/fluxion-dev/pippin/releases/download/v0.1.0/pippin-osx-arm64
- https://github.com/fluxion-dev/pippin/releases/download/v0.1.0/pippin-win-x64.exe
| RID | Binary | Size (attached asset) |
|---|---|---|
linux-x64 |
pippin-linux-x64 |
36,280,472 bytes (~34.6 MiB) |
osx-arm64 |
pippin-osx-arm64 |
16,520,016 bytes (~15.8 MiB) |
win-x64 |
pippin-win-x64.exe |
23,468,705 bytes (~22.4 MiB) |
Notes:
- macOS builds are arm64 (Apple silicon) only. Downloaded binaries are
unsigned — on macOS run
xattr -d com.apple.quarantine pippin-osx-arm64after downloading; Windows may show a SmartScreen prompt. - Prefer pip?
pip install pippin-art(orpipx install pippin-art), thenpippin --version. SVG via pip needs system cairo (see below).
From source (editable install with dev extras):
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
System deps for SVG (cairosvg needs cairo):
# Fedora
sudo dnf install cairo pango gdk-pixbuf2
# Debian/Ubuntu
sudo apt install libcairo2 libpango-1.0-0 libgdk-pixbuf2.0-0
Usage
# Preview (UTF-8 + color by default)
pippin photo.jpg
# ASCII, no color, fixed width
pippin logo.png --charset ascii --no-color --width 80
# Preview + export (ANSI escapes preserved when --color)
pippin input.svg --charset utf8 --color --width 120 --export out.ansi
# Export only (no terminal preview)
pippin input.jpg --export out.txt --no-preview
# Tweak rendering
pippin input.png --width 160 --contrast 1.2 --brightness 1.1 --invert
pippin input.png --charset blocks --custom-chars " .:-=+*#%@"
# Animate (uniform 12fps playback/encode by default)
pippin anim.gif --animate --width 100
pippin anim.gif --animate --width 100 --no-preview -o frames/ # frame_*.txt/.ansi + meta.json
pippin anim.gif --animate --width 100 --no-preview -o text_anim.gif # self-playing text gif
pippin anim.gif --animate --native-timing --width 80 # preserve source frame timing
# Animate video (requires ffmpeg on PATH; audio muxed by default)
pippin clip.mp4 --animate --width 100 --no-preview -o text.mp4 # text video, frame for frame
pippin clip.mpeg --animate --width 100 --no-preview -o text.mpeg # mpeg -> mpeg text video
pippin clip.mp4 --animate --native-timing --width 80 # preserve source fps
pippin clip.mp4 --animate --width 100 --no-preview --no-audio -o silent.mp4
# Aspect presets: one flag picks width default + center-crop (long-form vs shorts)
pippin clip.mp4 --animate --preset landscape --no-preview -o longform.mp4 # 16:9
pippin clip.mp4 --animate --preset portrait --no-preview -o short.mp4 # 9:16 center-crop
pippin clip.mp4 --animate --preset portrait --width 80 -o short.mp4 # preset, wider grid
pippin clip.mp4 --animate --preset portrait --no-crop -o stretched.mp4 # stretch, don't crop
CLI reference
pippin INPUT [-w WIDTH] [-H HEIGHT] [--charset {ascii,utf8,blocks} | --custom-chars STR]
[--color | --no-color] [--preview | --no-preview]
[-o FILE] [--invert] [--contrast F] [--brightness F] [--aspect F]
[--animate] [--fps FPS] [--native-timing] [--max-frames N] [--sample N]
[--loop N] [--gif-font PATH] [--gif-font-size N] [--audio | --no-audio]
[--gpu | --no-gpu]
| Flag | Default | Meaning |
|---|---|---|
INPUT |
— | Input image path (--animate: .gif or video mp4/mpeg/mpg/mov/avi/mkv/webm) |
-w, --width |
100 |
Output width in characters (1–2000; preset default when --preset given and --width omitted) |
-H, --height |
auto | Output height in characters; auto preserves aspect with correction (explicit --height also disables preset crop) |
--preset |
— | landscape (16:9, 100 cols) or portrait (9:16, 60 cols): one-flag recipe, explicit flags still override |
--quality |
medium |
Global grid-size multiplier: low 0.6x, medium 1x, high 1.6x (stills + animation) |
--jobs |
auto | Parallel frame-render workers for --animate video (0=auto by clip length, 1=serial) |
--crop / --no-crop |
crop |
Center-crop to the --preset aspect / stretch to fit |
--charset |
utf8 |
ascii, utf8, or blocks ramp |
--custom-chars |
— | Overrides --charset with your own dark→light ramp |
--color / --no-color |
color |
ANSI truecolor foreground per character |
--preview / --no-preview |
preview |
Print to stdout (still) / play animation (--animate) |
-o, --export |
— | Still: rendering file (.txt/.ansi); --animate: frame dir, .gif, or video (.mp4/.mpeg) |
--invert |
off | Invert luminance ramp |
--contrast |
1.0 |
Pillow contrast factor |
--brightness |
1.0 |
Pillow brightness factor |
--aspect |
0.55 |
Height correction for terminal cell aspect (char H ≈ 2× W). Lower = taller image. |
--animate |
off | Animation mode: render all frames as text frames (gif or video) |
--fps |
12 |
Uniform playback/encode rate (0 < fps ≤ 60); ignored with --native-timing |
--native-timing |
off | Preserve source timing (gif durations / video fps) instead of uniform --fps |
--max-frames |
all | Cap frames kept after sampling |
--sample |
1 |
Keep every Nth frame |
--loop |
infinite preview / source loop for .gif |
Animation plays / GIF loop count, 0=infinite (ignored for video output) |
--gif-font |
system monospace | TTF/OTF path for --animate .gif / video rasterization |
--gif-font-size |
20 |
Font size for --animate .gif / video rasterization (8–72) |
--audio / --no-audio |
audio |
Mux source audio into --animate video output / drop it |
--gpu / --no-gpu |
gpu |
Use GPU video encode/decode when a working backend exists / force software |
Export format: if --color is on, the export file contains ANSI escapes
(.ansi-ready). With --no-color it is plain text.
Ramps
ascii:.:-=+*#%@(10 levels, pure 7-bit)utf8:`^\",:;Il!i~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$(70 levels)blocks:░▒▓█(5 levels, uniform blocks)
Notes
- SVG is rasterized via
cairosvgat 3× target width, then downsampled — so vector edges stay sharp at high resolutions. - Transparency is composited onto black (use
--invertfor light terminals, compositing background is fixed black for predictable luminance). - For best quality use
--width 120–240with--charset utf8. - Video mode (
--animatewith video input/output) shells out to the systemffmpeg/ffprobebinaries — installffmpegand keep it onPATH. Conversion streams frame-by-frame (decode → convert → rasterize → encode), so RAM stays flat (~250 MB peak on a 1080p feature clip) regardless of length. Rasterization dominates CPU time, so identical frames are deduped (static scenes skip re-rendering) and convert+rasterize fans out to worker processes (--jobs, auto by clip length). The output video re-uses the text rasterizer from.gifexport, so--gif-font/--gif-font-sizeapply to video too. Source audio is muxed by default (--no-audiodrops it);.mpegoutput usesmpeg2video(arbitrary fps like the 12fps default work, unlikempeg1video). - GPU acceleration is best-effort and on by default (
--no-gpuforces software): decode triesffmpeg -hwaccel auto, encode prefers a probed working hardware encoder (h264_nvenc/h264_qsv/h264_amf/h264_videotoolbox/h264_vaapi, plusmpeg2/vp9variants) and falls back to software when none works. Probes run a real tiny encode, since capability lists don't guarantee a usable device (e.g. VMs).
Metadata
Release files for pippin-art 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pippin_art-0.3.0.tar.gz | 36.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pippin_art-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 67.6 kB
Release files / pippin_art-0.3.0.tar.gz
| Download URL | pippin_art-0.3.0.tar.gz |
|---|---|
| Size | 36.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5f6cc70ab5399bc0f3a3c82d5714a302131cf21b43cea1cfe1b65b4e2a172dd8
|
|
BLAKE2b-256 checksum How to use checksums |
75cc92858e0fc97477e19831efe4ae27889daf1b59cba4bd39a3c00ce23aef5b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / pippin_art-0.3.0-py3-none-any.whl
| Download URL | pippin_art-0.3.0-py3-none-any.whl |
|---|---|
| Size | 31.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1a94a568d0c22498cefda2aae521b3a6f107934c6f675422313c0c26cd05efce
|
|
BLAKE2b-256 checksum How to use checksums |
5d8717b4e03c7fd5c4aff9c2c558146ce330b7d509dad3eb15369076f5c7c10b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency log