Skip to main content
ansicode

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[\x1b_Ga=T,f=100,m=1;BASE64_CHUNK\x1b\\
\\033[\033_Ga=...;PAYLOAD\033\\
\\e[\e_G a=...;PAYLOAD \e\\
ESC [ESC _ G key=value,... ; BASE64 ESC \
hex1b 5f 47 ... 1b 5c

Description

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

bash
# Display a PNG file inline (one-shot, no chunking):\nb64=$(base64 -w0 cat.png)\nprintf '\033_Ga=T,f=100;%s\033\\' "$b64"
python
import base64, sys\npng = open('cat.png','rb').read()\nsys.stdout.write('\x1b_Ga=T,f=100;' + base64.b64encode(png).decode() + '\x1b\\')
go
data, _ := os.ReadFile("cat.png")\nfmt.Printf("\x1b_Ga=T,f=100;%s\x1b\\\\", base64.StdEncoding.EncodeToString(data))
javascript
import fs from 'node:fs';\nconst b64 = fs.readFileSync('cat.png').toString('base64');\nprocess.stdout.write('\x1b_Ga=T,f=100;' + b64 + '\x1b\\')
c
/* 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 with m=1 continuation 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[>q returns 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

Related sequences

In the family cookbook

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