Kitty graphics protocol — Inline pixel images (ESC _ G … ESC \)
Modern alternative to Sixel: stream PNG / RGBA bytes to the terminal via the Kitty APC frame, with sane chunking and a placement protocol.
Byte forms
Every common string-literal form so you can paste-and-search either direction.
\x1b_Ga=T,f=100,m=1;BASE64_CHUNK\x1b\\\033_Ga=...;PAYLOAD\033\\\e_G a=...;PAYLOAD \e\\ESC _ G key=value,... ; BASE64 ESC \1b 5f 47 ... 1b 5cDescription
The Kitty graphics protocol — designed by kitty.sh as a saner alternative to Sixel/iTerm-img — uses the APC (Application Program Command) frame: introducer \x1b_ (ESC _ ), the literal G to mark a graphics command, a comma-separated key=value control header (a=T transmit + display, f=100 PNG, f=24 RGB, f=32 RGBA, s v width/height in pixels, m=1 more chunks coming / m=0 last chunk, i=ID image ID for re-placement), ;, then a base64 payload of up to 4096 bytes per chunk, terminated by ST (\x1b\\). Supported natively by kitty + ghostty + wezterm; konsole has partial support. iTerm2's own \x1b]1337;File=... proprietary protocol is an alternative; both are converging on Kitty's design. Sixel (DCS Pq) is the legacy fallback for terminals without either.
Spec citation: Kitty Graphics Protocol (sw.kovidgoyal.net/kitty/graphics-protocol/)
Examples
# Display a PNG file inline (one-shot, no chunking):\nb64=$(base64 -w0 cat.png)\nprintf '\033_Ga=T,f=100;%s\033\\' "$b64"import base64, sys\npng = open('cat.png','rb').read()\nsys.stdout.write('\x1b_Ga=T,f=100;' + base64.b64encode(png).decode() + '\x1b\\')data, _ := os.ReadFile("cat.png")\nfmt.Printf("\x1b_Ga=T,f=100;%s\x1b\\\\", base64.StdEncoding.EncodeToString(data))import fs from 'node:fs';\nconst b64 = fs.readFileSync('cat.png').toString('base64');\nprocess.stdout.write('\x1b_Ga=T,f=100;' + b64 + '\x1b\\')/* read PNG into buf, base64-encode, then: */\nprintf("\x1b_Ga=T,f=100;%s\x1b\\\\", b64);Used in
Real-world tools that emit this sequence — anchors the bytes to commands you've already used.
- kitty `icat` (kitten icat)ships in the kitty distribution as `kitten icat <file>` — the canonical command that produced demand for the kitty-graphics protocol. Reads PNG / JPEG / GIF / WebP, emits the chunked `\x1bGa=T,f=100…\x1b\\` DCS stream and renders inline in the terminal at the current cursor position
- mpv terminal output (`--vo=kitty`)mpv 0.37+ ships a `kitty` video-output driver — `mpv --vo=kitty video.mp4` plays video as a series of kitty-graphics frames in the terminal. Frame rate is bounded by terminal blit speed (~ 15-30 fps on kitty / WezTerm / Ghostty); used for headless preview and over-SSH playback
- fastfetch / neofetch image renderingthe actively-maintained fastfetch (and its predecessor neofetch) use kitty-graphics for the system logo block when `--kitty` or auto-detect kitty / WezTerm / Ghostty — replaces the earlier Unicode-block fallback for visibly higher-fidelity rendering on supported terminals
- presenterm terminal slide deckspresenterm uses kitty-graphics to render markdown image references inline during a terminal slide deck — flips between slides issue `a=d` (delete-all) frames between renders to avoid image residue on overlapping slides
- yazi file manager preview paneyazi (Rust TUI file manager) detects kitty / WezTerm / Ghostty / kitty-graphics-aware terminals and renders image previews via kitty-graphics in its right-hand pane — falls back to sixel or Unicode blocks based on terminfo capability probe at startup
Frequently asked
Short answers to the questions developers actually search for this sequence.
- How is kitty graphics different from Sixel — when should I pick one over the other?
- Three deltas: (1) encoding — kitty uses base64 of the raw RGBA / PNG bytes inside a DCS-like APC envelope (
\x1b_G … \x1b\\), Sixel uses a base-6 packed-bitmap encoding that's smaller for low-colour images but expands worse for photos; (2) chunked transfer — kitty splits large images across multiple APC packets withm=1continuation markers, Sixel sends the whole image in one envelope, so kitty handles 50 MB photos cleanly while Sixel chokes the input loop; (3) persistence and placement — kitty references uploaded images by id and can place them at z-index / mouse-cell coordinates, Sixel just paints at the current cursor and is gone. Pick kitty for size + interactivity, Sixel for portability (it works on xterm, foot, mlterm out of the box; kitty graphics needs kitty / Ghostty / WezTerm). - How do I detect kitty graphics support before sending an image?
- Send a tiny 1×1 transparent PNG via the kitty graphics protocol with
q=1(query — don't actually display) and a unique id (i=<rand>):\x1b_Gi=42,q=1,f=100;<base64-1px-png>\x1b\\. Supporting terminals reply\x1b_Gi=42;OK\x1b\\within ~100 ms; unsupporting terminals stay silent (so set a 200 ms read timeout). The id avoids racing the reply against unrelated graphics responses. Alternatively, XTVERSION\x1b[>qreturns the terminal name + version — gate on a whitelist (kitty, Ghostty, WezTerm, konsole 24.04+).
Terminal support
- xterm
- no
- Linux console (fbcon)
- no
- macOS Terminal.app
- no
- iTerm2
- partial
- Windows Terminal
- no
- cmd.exe / ConPTY
- no
- kitty
- yes
- alacritty
- no
- WezTerm
- yes
- Ghostty
- yes
- GNOME Terminal
- no
- Konsole
- partial
- tmux
- no
- GNU screen
- no
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| no | no | no | partial | no | no | yes | no | yes | yes | no | partial | no | no |
Related sequences
In the family cookbook
DCS cookbook · 2. Pictures inside the stream — Sixel and Kitty graphics