# termflix [![Crates.io](https://img.shields.io/crates/v/termflix)](https://crates.io/crates/termflix) ![Runs on Linux | macOS | Windows](https://img.shields.io/badge/runs%20on-Linux%20%7C%20macOS%20%7C%20Windows-blue) ![Arch x86-64 | ARM | AppleSilicon](https://img.shields.io/badge/arch-x86--64%20%7C%20ARM%20%7C%20AppleSilicon-blue) ![License](https://img.shields.io/badge/license-MIT-green) A terminal animation player with 60 procedurally generated animations, multiple render modes, and true color support. Low CPU impact, works great in tmux, only needs your terminal. [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://buymeacoffee.com/probello3) ![termflix screenshot](https://raw.githubusercontent.com/paulrobello/termflix/main/screenshot.png) **[Live gallery →](https://paulrobello.github.io/termflix/)** — every animation as a still and animated GIF, regenerated by CI on each push to `main`. ## Features - **60 Animations** — Fire, matrix rain, starfields, plasma, ocean waves, aurora, lightning, and much more - **3 Render Modes** — Braille (highest resolution), half-block, and ASCII density mapping - **4 Color Modes** — Mono, ANSI 16, ANSI 256, and 24-bit true color - **ANSI-256 Dithering** — 4×4 Bayer ordered dithering makes gradients look near-true-color on 256-color terminals (`--dither`) - **Colorblind-Safe** — Remap any animation onto a perceptually-uniform palette (`--palette`) or apply daltonization correction (`--colorblind`) - **Per-Animation Defaults** — Each animation auto-selects its best render mode - **Runtime Hotkeys** — Cycle animations, render modes, and color modes on the fly - **Recording & Playback** — Record sessions and replay them - **Auto-Cycle** — Rotate through animations on a timer - **Particle System** — Reusable procedural particle engine powering many animations - **Low CPU** — Efficient rendering with minimal resource usage ## Animations | Animation | Description | Default Render | |-----------|-------------|---------------| | `fire` | Doom-style fire effect with heat propagation | Half-block | | `matrix` | Matrix digital rain — hiragana, katakana, Latin & digit glyphs | ASCII | | `plasma` | Classic plasma with overlapping sine waves | Half-block | | `starfield` | 3D starfield with depth parallax | Braille | | `wave` | Sine wave interference from moving sources | Half-block | | `life` | Conway's Game of Life cellular automaton | Braille | | `particles` | Fireworks bursting with physics and fade | Braille | | `pendulum` | Pendulum wave with mesmerizing phase patterns | Half-block | | `rain` | Raindrops with splash particles and wind | Half-block | | `fountain` | Water fountain with jets, splashes, and mist | Half-block | | `flow` | Perlin noise flow field with particle trails | Braille | | `spiral` | Rotating multi-arm spiral pattern | Half-block | | `ocean` | Ocean waves with foam and depth shading | Half-block | | `aurora` | Aurora borealis with layered curtains | Half-block | | `lightning` | Lightning bolts with recursive branching | Braille | | `smoke` | Smoke rising with Perlin turbulence | Half-block | | `ripple` | Ripple interference from random drop points | Half-block | | `snow` | Snowfall with accumulation on the ground | Half-block | | `garden` | Growing garden with rain, clouds, and blooming plants | ASCII | | `fireflies` | Fireflies blinking with warm glow | Half-block | | `dna` | Rotating DNA double helix with base pairs | ASCII | | `pulse` | Expanding pulse rings from center | Half-block | | `boids` | Boids flocking simulation with trails | Half-block | | `lava` | Lava lamp blobs rising, merging, and splitting | Half-block | | `sandstorm` | Blowing sand with dune formation | Half-block | | `petals` | Cherry blossom petals drifting in wind | Half-block | | `campfire` | Campfire with rising ember sparks | Half-block | | `waterfall` | Cascading water with mist spray | Half-block | | `eclipse` | Moon crossing sun with corona rays | Half-block | | `blackhole` | Black hole with accretion disk and lensing | Half-block | | `radar` | Rotating radar sweep with fading blips | Half-block | | `rainforest` | Layered rainforest with parallax scrolling, rain, birds, and falling leaves | Half-block | | `crystallize` | DLA crystal growth from center seed | Braille | | `hackerman` | Scrolling hex/binary hacker terminal | ASCII | | `visualizer` | Audio spectrum analyzer with bouncing bars | Half-block | | `cells` | Cell division and mitosis animation | Half-block | | `atom` | Electrons orbiting a nucleus in 3D | Half-block | | `automata` | Cellular automata cycling through multiple rulesets | Half-block | | `globe` | Rotating wireframe Earth with continents | Half-block | | `dragon` | Dragon curve fractal with color cycling | Braille | | `sierpinski` | Animated Sierpinski triangle with zoom | Braille | | `mandelbrot` | Mandelbrot set with zoom and color cycling | Braille | | `maze` | Animated maze generation with recursive backtracking and BFS solving | Half-block | | `metaballs` | Organic metaballs merging and splitting with smooth distance fields | Half-block | | `nbody` | N-body gravitational simulation with colorful orbiting masses and merging | Half-block | | `langton` | Langton's Ant cellular automaton | Half-block | | `sort` | Sorting algorithm visualizer | Half-block | | `tetris` | Self-playing Tetris with AI piece placement | Half-block | | `snake` | Self-playing Snake game AI | Half-block | | `invaders` | Space Invaders attract mode demo | Half-block | | `pong` | Self-playing Pong with AI paddles | Half-block | | `flappy_bird` | Self-playing Flappy Bird with AI | Half-block | | `reaction_diffusion` | Gray-Scott reaction-diffusion coral/brain patterns | Half-block | | `voronoi` | Animated Voronoi diagram with drifting colored cells and edge detection | Half-block | | `galton` | Galton board with balls cascading into a bell-curve histogram | Half-block | | `solar_system` | Solar system with planets, moons, rings, and an asteroid belt | Half-block | | `physarum` | Physarum slime mold agents self-organizing into networks | Half-block | | `newtons_cradle` | Newton's cradle with energy-conserving swings | Half-block | | `strange_attractor` | Lorenz strange attractor with a rotating rainbow trail | Half-block | | `ink_in_water` | Colored ink puffs dispersing through a turbulent flow field | Half-block | ## Installation ### Quick Install (Linux / macOS / WSL) ```bash curl -sL https://raw.githubusercontent.com/paulrobello/termflix/main/install.sh | bash ``` Installs the latest release binary to `/usr/local/bin`. Custom install location: ```bash INSTALL_DIR=~/.local/bin curl -sL https://raw.githubusercontent.com/paulrobello/termflix/main/install.sh | bash ``` ### From crates.io ```bash cargo install termflix ``` ### From Source Requires Rust 1.85+ (edition 2024): ```bash git clone https://github.com/paulrobello/termflix cd termflix make install ``` ### Pre-built Binaries Download from [GitHub Releases](https://github.com/paulrobello/termflix/releases/latest): | Platform | Binary | |----------|--------| | Linux x86_64 | `termflix-linux-x86_64` | | Linux ARM64 | `termflix-linux-aarch64` | | macOS x86_64 | `termflix-macos-x86_64` | | macOS ARM64 (Apple Silicon) | `termflix-macos-aarch64` | | Windows x86_64 | `termflix-windows-x86_64.exe` | **macOS note:** After downloading manually, remove the quarantine flag: ```bash xattr -cr termflix-macos-* chmod +x termflix-macos-* ``` ## Usage ```bash # Run default animation (fire) termflix # Run a specific animation termflix starfield # List all animations termflix --list # Set render mode (braille, half-block, ascii) termflix plasma -r braille # Set color mode (mono, ansi16, ansi256, true-color) termflix fire -c true-color # ANSI-256 with Bayer dithering (near-true-color on 256-color terminals) termflix plasma -c ansi256 --dither # Colorblind-safe palette remap (viridis, magma, inferno, plasma, okabe-ito) termflix fire --palette viridis # Daltonization correction (protanopia, deuteranopia, tritanopia) termflix plasma --colorblind deuteranopia # Auto-cycle through animations every 10 seconds termflix --cycle 10 # Scale particle density termflix rain --scale 1.5 # Remove FPS cap (render as fast as terminal allows) termflix --unlimited # Clean mode (no status bar) termflix --clean # Screensaver mode (exits on any keypress or focus) termflix matrix --clean --screensaver # Screensaver mode but keep hotkeys active (any unbound key still dismisses) termflix matrix --clean --screensaver --screensaver-keys # Record a session termflix matrix --record session.asciianim # Play back a recording termflix --play session.asciianim # Post-processing: bloom, vignette, scanlines termflix fire --bloom-intensity 0.5 --bloom-threshold 0.6 --vignette 0.4 --scanlines # Profile per-frame timing (prints a summary on exit) termflix --profile plasma # Full redraw every frame (disables dirty-cell rendering; fixes tearing under tmux) termflix plasma --full-frames # Render inline, no writer thread (for debugging / A-B comparison) termflix plasma --single-threaded # Drive parameters from an external NDJSON file (one JSON object per line) termflix --data-file /tmp/termflix.json ``` ## Hotkeys | Key | Action | |-----|--------| | `q` / `Esc` | Quit | | `←` / `→` (or `n` / `p`) | Previous / next animation | | `r` | Cycle render mode (braille → half-block → ascii) | | `c` | Cycle color mode | | `b` | Toggle bloom | | `s` | Toggle brightness smoothing | | `d` | Toggle ANSI-256 dithering | | `h` | Toggle status bar | ## How It Works termflix uses a pixel-level canvas that gets rendered to terminal characters: - **Braille mode** (`⠁⠂⠃...⣿`) — 2×4 pixels per terminal cell = highest resolution - **Half-block mode** (`▀▄█`) — 1×2 pixels per cell = good balance of resolution and color - **ASCII mode** (` .:-=+*#%@`) — 1×1 pixel per cell = widest compatibility Each animation implements the `Animation` trait, writing to the canvas at sub-cell resolution. The renderer converts the canvas to terminal escape sequences with cursor positioning (no newlines — eliminates flickering). A reusable `ParticleSystem` generator powers many of the particle-based animations with configurable emitters, gradients, gravity, and drag. ## tmux Support termflix auto-detects tmux and adapts: - **Adaptive frame pacing** — Automatically adjusts frame rate to match tmux's throughput, preventing output backlog and input lag - **Responsive quit** — Runs `tmux clear-history` on exit to flush buffered output - **Split-safe** — No lockups when splitting panes; FPS scales with pane size - **Background-safe** — No output backlog when switching away from iTerm2 ### Tearing or flickering rows under tmux By default termflix uses **differential (dirty-cell) rendering** — each frame sends only the cells that changed, which is the big throughput win under tmux. tmux forwards those updates to your terminal; if it doesn't wrap them in synchronized-output, the terminal applies them non-atomically and you may see brief tearing or a few "stale" rows (most noticeable when the status bar updates each second). Enable tmux's synchronized-output passthrough to fix it: ```bash tmux set -as terminal-features '*:sync' # apply now, current server echo "set -as terminal-features '*:sync'" >> ~/.tmux.conf # persist across restarts ``` This needs a terminal that supports synchronized output — iTerm2, Alacritty, kitty, WezTerm, Ghostty, and Warp all do; macOS **Terminal.app does not**. If yours doesn't, run termflix with `--full-frames` under tmux to disable dirty-cell rendering (reverts to a full redraw every frame — no tearing, but no throughput win). Typical FPS in tmux (200×44, halfblock truecolor): - Full pane: ~10 fps (smooth) - Split pane: ~20 fps (less output per frame) - Outside tmux: 24 fps (full speed) ## Configuration termflix supports a TOML config file for persistent defaults. CLI flags always override config settings. ```bash # Generate default config file termflix --init-config # Show config file path and current settings termflix --show-config ``` Config location: - **macOS**: `~/Library/Application Support/termflix/config.toml` - **Linux**: `~/.config/termflix/config.toml` - **Windows**: `%APPDATA%\termflix\config.toml` Example config: ```toml # Default animation animation = "plasma" # Render mode: braille, half-block, ascii render = "half-block" # Color mode: mono, ansi16, ansi256, true-color color = "true-color" # Target FPS (1-120) fps = 24 # Scale factor for particle density (0.5-2.0) scale = 1.0 # Hide status bar clean = false # Auto-cycle interval in seconds (0 = disabled) cycle = 0 # Remove FPS cap and render as fast as possible (overrides fps) unlimited_fps = false # Colorblind-safe remap palette: viridis | magma | inferno | plasma | okabe-ito # palette = "viridis" # Daltonization correction: protanopia | deuteranopia | tritanopia # (mutually exclusive with palette) # colorblind = "deuteranopia" # Ordered (Bayer 4x4) dithering for ANSI-256 mode (reduces banding) # dither = true # Temporal brightness smoothing time constant in seconds (0 = off) # smoothing = 0.08 # Color quantization step (0 = off, 4/8/16 = coarser colors, less output) # color_quant = 0 # External control via an NDJSON file (one JSON object per line) # data_file = "/tmp/termflix.json" # Post-processing effects # [postproc] # bloom = 0.3 # Glow intensity (0.0-1.0) # bloom_threshold = 0.6 # Brightness threshold to trigger bloom (0.0-1.0) # vignette = 0.4 # Edge darkening (0.0-1.0) # scanlines = false # CRT scanline effect # Custom keybindings (action -> key name) # [keybindings] # next = "Right" # prev = "Left" # quit = "q" # render = "r" # color = "c" # status = "h" ``` ## Gallery A live PNG + GIF gallery of every animation is published at ****, regenerated by the `Gallery` workflow on every push to `main` and on manual dispatch (Actions → Gallery → Run workflow). To regenerate locally: ```bash make gallery # all animations → ./gallery make gallery ARGS="fire,plasma" # subset make gallery ARGS="fire --gallery-dir /tmp/g" ``` The `gallery/` directory is gitignored — never commit the generated binaries; let CI publish them. The workflow auto-enables Pages on its first run via `actions/configure-pages` with `enablement: true`. If your fork has Pages disabled organization-wide, flip **Settings → Pages → Build and deployment → Source** to **GitHub Actions** manually before the first run. ## Contributing Contributions are welcome! To add a new animation: 1. Create `src/animations/your_animation.rs` implementing the `Animation` trait 2. Register it in `src/animations/mod.rs` 3. Run `cargo build --release` and test ```bash cargo fmt # Format code cargo clippy # Lint cargo build # Build ``` ## License This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details. ## Author Paul Robello — probello@gmail.com ## Links - **GitHub**: [https://github.com/paulrobello/termflix](https://github.com/paulrobello/termflix) - **Crates.io**: [https://crates.io/crates/termflix](https://crates.io/crates/termflix)