An X11 server that renders its framebuffer as ASCII art in your terminal, powered by libcaca.
Run regular X11 GUI applications as terminal art over SSH, in headless environments, or just for the aesthetic.
Built on the Kdrive/TinyX framework (same architecture as Xephyr). No root required.
This is experimental, be warned.
- Currently targets Ubuntu 24.04 and derivatives (e.g. Linux Mint 22.3). Currently untested on other distros, but I intend to improve support in the future.
- libcaca (
libcaca-dev) - meson + ninja
- xorg-server build dependencies
sudo apt install meson ninja-build libcaca-dev
sudo apt build-dep xserver-xephyrcd xorg-server
meson setup builddir \
-Dxcaca=true \
-Dxephyr=false \
-Dxorg=false \
-Dxvfb=false \
-Dxnest=false \
-Dglx=false \
-Dsecure-rpc=false
ninja -C builddirBinary: xorg-server/builddir/hw/kdrive/caca/Xcaca
Xcaca takes over the terminal it runs in to display ASCII art, so it must run in the foregrounds. Use two terminals, two TTYs, or a tmux split:
# Terminal 1: Xcaca renders here
./xorg-server/builddir/hw/kdrive/caca/Xcaca :1 -screen 640x480
# Terminal 2: run X clients
DISPLAY=:1 xeyes
DISPLAY=:1 xclock
DISPLAY=:1 xterm| Option | Description | Default |
|---|---|---|
-screen WxH |
Framebuffer resolution | 640x480 |
-dither <alg> |
Dither algorithm: none, ordered2, ordered4, ordered8, random, fstein |
fstein |
-charset <set> |
Character set: ascii, blocks, shades, utf8, ... |
ascii |
-brightness <f> |
Brightness multiplier | 1.0 |
-gamma <f> |
Gamma correction | 1.0 |
-contrast <f> |
Contrast adjustment | 1.0 |
-cell-aspect <f|auto> |
Terminal cell width/height ratio | auto |
Xcaca uses libcaca for rendering. The driver is auto-selected but can be overridden via the CACA_DRIVER environment variable:
| Driver | Description |
|---|---|
ncurses |
ncurses terminal (default, best compatibility) |
slang |
S-Lang terminal (fallback) |
CACA_DRIVER=slang Xcaca :1 -screen 640x480In each case, run Xcaca in one terminal and the X client in another:
# Blocks charset looks great for UI elements
Xcaca :1 -screen 320x240 -charset blocks # terminal 1
DISPLAY=:1 xlogo # terminal 2
# Force Floyd-Steinberg dither with boosted contrast
Xcaca :1 -screen 640x480 -dither fstein -contrast 1.4
DISPLAY=:1 xterm
# Ordered dither — faster, retro look
Xcaca :1 -screen 640x480 -dither ordered4 -charset shadesMost terminals use cells that are roughly twice as tall as wide (aspect ratio ≈ 0.5). Xcaca auto-detects this via TIOCGWINSZ at startup.
If the output looks stretched or squished, override manually:
# Typical terminal (8×16 cells)
Xcaca :1 -cell-aspect 0.5
# Square cells (rare)
Xcaca :1 -cell-aspect 1.0
# Auto-detect from terminal
Xcaca :1 -cell-aspect auto- Mouse precision is limited to terminal cell granularity (~8×16 px per cell)
- Input latency of ~16ms (caca events are polled in the server's block handler — no fd to select on)
- Key mapping is lossy: dead keys, AltGr, and compose sequences don't work through a terminal
- No GPU acceleration — pure software rendering
- Single screen only
- Ctrl+C shutdown hangs: pressing Ctrl+C begins shutdown but the process blocks until something connects to the X socket. Workaround:
pkill -x Xcacafrom another terminal
Xcaca is a Kdrive backend that:
- Allocates a 32bpp ARGB framebuffer in memory
- Exposes it as a standard X11 display (any X client can connect)
- On each server cycle, checks for framebuffer damage
- When damaged, calls
caca_dither_bitmap()to convert the framebuffer to ASCII art - Refreshes the terminal display with
caca_refresh_display()
Input events (keyboard, mouse) are polled from libcaca and translated to X11 input events via evdev scancodes.
X client (xeyes, xterm, ...)
↕ X11 protocol
Xcaca server
├── 32bpp ARGB framebuffer (malloc'd)
├── Damage tracking (fires on client rendering)
├── caca_host.c — libcaca abstraction
│ ├── caca_dither_bitmap() → ASCII art
│ └── caca_get_event() → keyboard/mouse
└── cacainput.c — evdev scancode translation
Xcaca is licensed under the X11 License.
Xcaca is built on:
- xorg-server (X11 License) — compatible source license
- libcaca (GPLv2) — the compiled binary inherits GPLv2 obligations
The source code can remain under its original X11 license, but the compiled Xcaca binary is effectively GPLv2 due to libcaca linking. See GPL linking for details.

