Skip to main content
ansicode

DCS Sixel — Inline raster graphics (ESC P q … ESC \)

Embed pixel images in the terminal stream using the Sixel device-control payload.

Byte forms

Every common string-literal form so you can paste-and-search either direction.

\\x1b[\x1bPq <sixel data> \x1b\\
\\033[\033Pq … \033\\
\\e[\eP q … \e\\
ESC [ESC P q DATA ESC \
hex1b 50 71 ... 1b 5c

Description

Sixel is a DEC-era inline pixel graphics format (DEC VT240/VT340) revived by modern terminals. The frame begins with the Device Control String introducer \x1bP (DCS), an optional parameter run, the q final byte that selects Sixel mode, then a payload of ?..~ printable characters where each byte encodes a 6-pixel-tall vertical slice (hence 'sixel'). The frame ends with the String Terminator — either \x1b\\ (ST, spec-correct) or \x07 (BEL, widely accepted). libsixel, chafa, viu, timg, ranger-style image previews, kitten icat --transfer-mode=stream (Sixel fallback for Kitty's native protocol), and mpv --vo=sixel all emit this sequence. Terminal support varies: xterm needs +sb compile and -ti vt340, mintty + foot + wezterm + iTerm2 + Windows Terminal Canary + ghostty work out of the box, kitty + alacritty + macOS Terminal do not (Kitty has its own better protocol).

Spec citation: DEC VT340 Programmer Reference / xterm-ctlseqs (DCS Ps; Ps; Ps q)

Examples

bash
# A 12x6 magenta block via the Sixel raw payload\nprintf '\033Pq#0;2;100;0;100#0~~\033\\'
python
import sys; sys.stdout.write('\x1bPq#0;2;100;0;100#0~~\x1b\\')
go
fmt.Print("\x1bPq#0;2;100;0;100#0~~\x1b\\")
javascript
process.stdout.write('\x1bPq#0;2;100;0;100#0~~\x1b\\')
c
printf("\x1bPq#0;2;100;0;100#0~~\x1b\\");

Used in

Real-world tools that emit this sequence — anchors the bytes to commands you've already used.

  • libsixel + `img2sixel` CLIlibsixel is the reference encoder — `img2sixel input.png | cat` produces a `\x1bPq…\x1b\\` DCS stream that any sixel-aware terminal (xterm `+T --tn xterm-direct`, mlterm, foot, WezTerm with `enable_kitty_graphics=false`) renders inline. libsixel also powers most other tools' sixel output paths via dynamic linking
  • gnuplot `set terminal sixel`gnuplot 5.4+ supports `set terminal sixel size 800,600` for inline plot rendering in the terminal — useful in scientific pipelines where you want to glance at a generated plot during a long-running fit without opening an X11 window or saving to PNG
  • ranger / mc image previewranger (with the `img2sixel` preview script) and Midnight Commander on sixel-capable terminals render image-file previews inline in the right pane. Preferred over kitty-graphics for portability — sixel runs on xterm / mlterm / foot / WezTerm / Windows Terminal ≥ 1.22 / Black Box, broader than kitty-graphics' kitty / WezTerm / Ghostty trio
  • matplotlib `mpl_sixel` backendPython: `import matplotlib; matplotlib.use('module://mpl_sixel'); plt.plot([1,2,3]); plt.show()` renders the plot as sixel directly in the Jupyter-less terminal — popular in HPC contexts where Jupyter is unavailable but interactive numeric work still happens at the shell
  • Black Box / Windows Terminal sixel previewBlack Box (GNOME terminal emulator built on VTE 0.73+) and Windows Terminal 1.22+ added native sixel rendering — `cat photo.six` displays inline. Both ship sixel-aware test patterns in their CI to catch regressions; integrators target these as the modern reference renderers

Frequently asked

Short answers to the questions developers actually search for this sequence.

What's the maximum image size a Sixel terminal can render in one DCS sequence?
There's no spec-mandated cap — Sixel images stream pixel-row groups inside one DCS envelope (\x1bPq … \x1b\\) so the limit is the terminal's pixel-buffer allocation. Practical ceilings: xterm uses decGraphicsMaxSize (default 1000×1000) and silently truncates beyond; mlterm / WezTerm / Konsole / foot accept multi-megapixel images bounded only by RAM; Windows Terminal added Sixel in v1.22 with a soft 10 MP cap. Performance — not the spec — is the real limiter: a 4K full-screen image is ~2 MB of base-6-encoded payload that the terminal decodes serially while blocking the input loop.
Why does my Sixel image render as gibberish in tmux even though the terminal supports it?
tmux historically strips DCS payloads — Sixel arrives as \x1bP…\x1b\\ and tmux's parser eats both the introducer and the terminator, leaving the base-6 body to land as literal characters. Two fixes: (1) set -g allow-passthrough on plus wrapping each Sixel in \x1bPtmux;<escaped>\x1b\\ (the tmux; passthrough envelope, with inner \x1b doubled to \x1b\x1b); (2) since tmux 3.4, native Sixel support is opt-in via set -g sixel on — no passthrough envelope needed. Use option 2 if you're on 3.4+; option 1 is the only path on older versions.

Terminal support

xterm
partial
Linux console (fbcon)
no
macOS Terminal.app
no
iTerm2
yes
Windows Terminal
partial
cmd.exe / ConPTY
no
kitty
no
alacritty
no
WezTerm
yes
Ghostty
yes
GNOME Terminal
partial
Konsole
yes
tmux
partial
GNU screen
no

Related sequences

In the family cookbook

DCS cookbook · 2. Pictures inside the stream — Sixel and Kitty graphics