Skip to main content

Kitty graphics protocol

AI-Generated Content
This page was generated with the assistance of AI and may contain inaccuracies. It is intended as a placeholder for future human verification. If you spot issues ahead of its initial review, please report them on GitHub!
Experimental

Kitty graphics protocol is a modern terminal graphics protocol that transmits images using base64-encoded data within APC (Application Program Command) sequences. It supports multiple image formats, random-access placement, chunked transfers, and persistent image storage by ID.

Syntax​

APC G key=value,key=value ; payload ST      Kitty graphics command
Formal syntax
kitty-graphics = 0x1b, "_G", control-data, [ ";", payload ], ( 0x1b, "\\" ) ;
control-data   = key-value, { ",", key-value } ;
key-value      = key, "=", value ;
key            = letter, { letter } ;
value          = char, { char } ;
payload        = base64-char, { base64-char } ;
base64-char    = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
             | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T"
             | "U" | "V" | "W" | "X" | "Y" | "Z"
             | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j"
             | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t"
             | "u" | "v" | "w" | "x" | "y" | "z"
             | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
             | "+" | "/" | "=" ;
letter         = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j"
             | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t"
             | "u" | "v" | "w" | "x" | "y" | "z" ;
char           = letter | digit ;
digit          = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;

Parameters​

Action keys (a):

ValueActionDescription
tTransmitUpload image data to the terminal without displaying it
TTransmit + DisplayUpload and immediately display the image
pDisplayDisplay a previously transmitted image by its ID
qQueryTest whether the terminal supports the protocol
dDeleteRemove images from the terminal's memory or screen
fFrameAnimation frame control (see animation)

Transmission keys:

KeyDescriptionValues
fPixel format24 (RGB), 32 (RGBA), 100 (PNG)
tTransmission mediumd (direct/inline), f (file path), t (temp file), s (shared memory)
sImage width in pixelsInteger
vImage height in pixelsInteger
STotal data size in bytesInteger
mChunked transfer flag0 (last chunk or no chunking), 1 (more chunks follow)
oCompressionz (zlib-compressed payload)

Image identification keys:

KeyDescription
iImage ID (32-bit unsigned integer)
IImage number (client-side identifier for deduplication)

Display/placement keys:

KeyDescription
pPlacement ID
xX offset within the image (source region left)
yY offset within the image (source region top)
wSource region width (0 = full width)
hSource region height (0 = full height)
cDisplay width in terminal columns
rDisplay height in terminal rows
XHorizontal pixel offset within the cell
YVertical pixel offset within the cell
zZ-index for layering
CCursor movement policy: 0 (move cursor) or 1 (do not move cursor)

Delete keys (when a=d):

Value of dDescription
a or ADelete all images (visible only / all)
i or IDelete by image ID (visible only / all placements)
p or PDelete by placement ID
c or CDelete by column
r or RDelete by row
x or XDelete by column range
y or YDelete by row range
z or ZDelete by z-index

Response​

When querying (a=q) or when a transmission error occurs, the terminal responds with:

APC G i=<id> ; OK ST          Success
APC G i=<id> ; <error> ST Failure

Description​

The Kitty graphics protocol, introduced by the Kitty terminal emulator, provides a full-featured system for displaying images in the terminal. Unlike Sixel, which encodes pixel data character-by-character, the Kitty protocol transmits complete image files (PNG, raw RGB, or raw RGBA) as base64-encoded payloads.

The protocol separates image transmission from image display. An application can upload an image once and display it multiple times at different positions and sizes. Images are identified by a numeric ID (i key), which allows persistent storage and later recall.

Chunked transfers​

Large images can be split across multiple APC sequences using the m (more) key. Set m=1 on every chunk except the last, which uses m=0 (or omits m). This avoids overwhelming the terminal's input parser with extremely long sequences.

Image placement​

When displaying an image, the application can specify which portion of the source image to show (using x, y, w, h) and how many terminal cells it should occupy (using c, r). The terminal scales the image to fit the requested cell dimensions.

Query mode​

Applications can detect protocol support by sending a query command. A supporting terminal will respond with an OK message; a non-supporting terminal will silently ignore the APC sequence.

note

The Kitty graphics protocol uses APC (ESC _) as the introducer rather than the more common CSI or OSC. Some terminal multiplexers strip or ignore APC sequences, which can prevent the protocol from working through tmux or screen.

Examples​

# Query protocol support (transmit a 1x1 PNG and check for response)
printf '\e_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\e\\'

# Transmit and display a small 2x2 red PNG image inline
printf '\e_Gf=100,a=T;iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAADklEQVQI12P4z8BQDwAEgAF/QualzQAAAABJRU5ErkJggg==\e\\'

# Transmit image with ID 1 without displaying
printf '\e_Ga=t,i=1,f=100;iVBORw0KGgoAAAANSUhEUg...\e\\'

# Display previously transmitted image ID 1
printf '\e_Ga=p,i=1\e\\'

# Display image ID 1 scaled to 10 columns by 5 rows
printf '\e_Ga=p,i=1,c=10,r=5\e\\'

# Delete all visible images
printf '\e_Ga=d,d=a\e\\'

# Chunked transfer (two chunks)
printf '\e_Gf=100,a=T,m=1;iVBORw0KGgoAAAAN...\e\\'
printf '\e_Gm=0;...remaining-base64...\e\\'

Specifications​

SpecificationSection
Kitty Graphics Protocol—

Terminal support​

TerminalSupportVersionNotes
Terminal Emulators
Alacritty✗NoNot implemented
Bobcat✗NoNo APC G sequences found
contour✗NoAPC parsing exists but no Kitty graphics implementation
foot✗NoAPC sequences are ignored (state_sos_pm_apc_string only ignores)
Ghostty✓v1.0.0
iTerm2✓v20260216-nightlyAPC G protocol via KittyImageCommand
Kitty✓0.19.3
Konsole✓YesAPC G protocol with image cache support
mintty✗NoAPC sequences (including Kitty graphics) are explicitly ignored
mlterm✗NoAPC sequences parsed but no Kitty graphics implementation
PuTTY✗NoAPC sequences recognized but explicitly ignored (terminal.c:3244-3246)
Rio✗NoImplementation exists in development branch (zero-dot-three) but not yet released
rxvt-unicode✗NoNo APC sequence handler
st✗NoAPC sequences recognized but not processed
terminology✗No
VT100✗No
VTE✗NoAPC sequences are parsed but no Kitty graphics protocol handler exists
WezTerm✓20220101-133340-7edc5b5a
Windows Terminal✗NoNo APC G handler found. Only Sixel graphics are implemented
xterm✗NoNot implemented - APC sequences ignored
xterm.js✓0.9.0Requires @xterm/addon-image addon. Added in addon version 0.9.0 (unreleased, currently in development).
Multiplexers
cy✗No
GNU Screen✗NoAPC only handles status strings, not graphics
tmux✗NoAPC strings parsed but only used for window titles, not graphics
tuios✓v0.6.0
Zellij✗No

See also​


Unicode placeholders​

Experimental

Unicode placeholders allow applications to place images at specific cell positions by emitting a special Unicode character (U+10EEEE) into the terminal's text grid. The terminal replaces these placeholder characters with the corresponding region of a previously transmitted image.

Placeholder syntax​

U+10EEEE [+ diacritics]      Unicode placeholder character
Formal syntax
placeholder     = 0x10EEEE, [ row-diacritic ], [ col-diacritic ] ;
row-diacritic   = ? U+0305 to U+0CF4 ? ;        (* diacritic encoding the row index *)
col-diacritic   = ? U+0305 to U+0CF4 ? ;        (* diacritic encoding the column index *)

Placeholder characters use combining diacritical marks to encode positioning information. Each diacritic maps to a numeric index representing the row or column of the image tile that should be rendered in that cell.

ComponentDescription
U+10EEEEThe placeholder base character (Private Use Area, Plane 16)
Row diacriticCombining character encoding the image row index (0-based)
Column diacriticCombining character encoding the image column index (0-based)

The diacritic-to-index mapping uses a predefined table of combining Unicode characters starting from U+0305. The first diacritic (U+0305) represents index 0, the next represents index 1, and so on.

The image ID is communicated by setting the foreground color of the placeholder cell to the image ID value. The placement ID can be specified through additional attributes.

How placeholders work​

Standard Kitty graphics commands display images at the current cursor position or at absolute coordinates, which works well for full-screen applications but creates problems for text-mode programs that rely on the terminal's text reflow, scrolling, and cursor movement. Unicode placeholders solve this by embedding image references directly into the text stream.

When the terminal encounters U+10EEEE in its text grid, it looks up the associated image ID (encoded in the cell's foreground color) and renders the appropriate tile of that image in place of the character. The row and column diacritics tell the terminal which portion of the image to show in each cell.

  1. Transmit the image using the standard Kitty graphics protocol (a=t or a=T), assigning it an image ID.
  2. Emit placeholder characters into the terminal at the desired cell positions. Set the foreground color to the image ID, and use diacritics to specify which tile of the image each cell should display.
  3. The terminal replaces the placeholder characters with the corresponding image regions during rendering.

This approach preserves text-grid semantics. Placeholders reflow with surrounding text when the terminal is resized, scroll naturally with the screen buffer, and can be overwritten like any other character.

note

Unicode placeholders require the image to be transmitted first via the Kitty graphics protocol. The placeholder character alone does not contain any image data -- it only references a previously uploaded image by ID.

# Step 1: Transmit a 2-cell-wide, 1-cell-tall image with ID 42
printf '\e_Ga=t,i=42,f=100;iVBORw0KGgoAAAANSUhEUg...\e\\'

# Step 2: Place the image using Unicode placeholders
# Set foreground color to image ID 42 via SGR 38;5;42,
# then emit U+10EEEE with row=0,col=0 diacritic and row=0,col=1 diacritic
printf '\e[38;5;42m\U0010EEEE\u0305\u0305\U0010EEEE\u0305\u0306\e[39m'

# Step 3: Display the placement
printf '\e_Ga=p,i=42,U=1\e\\'

Terminal support — Unicode placeholders​

TerminalSupportVersionNotes
Terminal Emulators
Alacritty✗NoNot implemented
Bobcat✗No
contour✗No
foot✗NoNo Unicode placeholder U+10EEEE support found
Ghostty✓v1.0.0Unicode placeholder U+10EEEE with diacritic encoding for row/col
iTerm2✓v20260216-nightlyUnicode placeholder U+10EEEE supported
Kitty✓0.28.0
Konsole✗NoNo evidence of U+10EEEE unicode placeholder handling
mintty✗No
mlterm✗No
PuTTY✗NoGraphics protocol not supported
Rio✗NoImplementation exists in development branch but not yet released
rxvt-unicode✗NoNo graphics protocol support
st✗NoNo Unicode placeholder handling for graphics
terminology✗No
VT100✗No
VTE✗No
WezTerm✗No
Windows Terminal✗NoKitty graphics protocol not implemented
xterm✗No
xterm.js??Kitty graphics protocol is implemented via addon, but Unicode placeholder support is uncertain from source inspection.
Multiplexers
cy✗No
GNU Screen✗NoKitty graphics protocol not implemented
tmux✗No
tuios✗NoU+10EEEE unicode placeholders not implemented
Zellij✗No

Animation​

Experimental

Animation extends the Kitty graphics protocol with frame-based animation support. Applications can define multiple frames for an image, control inter-frame timing, and specify how frames are composited together.

Animation syntax​

APC G a=f,... ; payload ST      Animation frame command
APC G a=a,... ST Animation control command
Formal syntax
animation-frame   = 0x1b, "_G", frame-data, [ ";", payload ], ( 0x1b, "\\" ) ;
animation-control = 0x1b, "_G", control-data, ( 0x1b, "\\" ) ;
frame-data        = "a=f", { ",", key-value } ;
control-data      = "a=a", { ",", key-value } ;
key-value         = key, "=", value ;
key               = letter, { letter } ;
value             = char, { char } ;
payload           = base64-char, { base64-char } ;
base64-char       = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
                | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T"
                | "U" | "V" | "W" | "X" | "Y" | "Z"
                | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j"
                | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t"
                | "u" | "v" | "w" | "x" | "y" | "z"
                | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
                | "+" | "/" | "=" ;
letter            = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j"
                | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t"
                | "u" | "v" | "w" | "x" | "y" | "z" ;
char              = letter | digit ;
digit             = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;

Frame editing keys (when a=f):

KeyDescriptionDefault
iImage ID to add frames to(required)
rFrame number to edit or createAppend new frame
xX offset of the frame data within the image canvas0
yY offset of the frame data within the image canvas0
cComposition mode for this frame (see below)0
zGap in milliseconds before showing the next frame0 (use previous gap)
fPixel format (24 for RGB, 32 for RGBA, 100 for PNG)32
sFrame data width in pixelsImage width
vFrame data height in pixelsImage height

Composition modes (c):

ValueModeDescription
0OverwriteThe frame data completely replaces the canvas at the specified offset
1Blend (alpha composite)The frame data is alpha-composited over the existing canvas content

Animation control keys (when a=a):

KeyDescriptionValues
iImage ID to control(required)
sAnimation state1 (stop), 2 (run/loop), 3 (run once and show last frame)
rFrame to jump toFrame number (1-based)
zDefault gap in millisecondsInteger
vNumber of loops0 (infinite), or a positive integer

Frame model​

An animated image is a single image ID with multiple frames. The first frame is the base image transmitted with the standard a=t or a=T action. Additional frames are added using the a=f action.

Each frame consists of pixel data that is drawn onto the image canvas at a specified offset (x, y). The composition mode determines how the new frame data interacts with the existing canvas:

  • Overwrite (c=0): The frame's pixels replace the corresponding region of the canvas.
  • Blend (c=1): The frame's pixels are alpha-composited over the canvas, allowing partial updates where only changed regions are sent.

Timing and playback​

The gap (z) specifies the delay in milliseconds before advancing to the next frame. Each frame can have its own gap value, or a default can be set via the animation control command. A gap of 0 means the frame inherits the previously set gap value.

After all frames are defined, the animation can be controlled using the a=a action:

  • Set s=2 to start looping the animation
  • Set s=3 to play through once and stop on the last frame
  • Set s=1 to stop the animation
  • Set r=N to jump to a specific frame
  • Set v=N to limit the number of loops
note

Animations consume terminal resources proportional to the number and size of frames. Applications should delete animated images when they are no longer needed using the standard Kitty graphics delete command (a=d).

# Step 1: Transmit the base image (frame 1) with ID 7
printf '\e_Ga=T,i=7,f=32,s=100,v=100;...base64-frame1...\e\\'

# Step 2: Add frame 2 with a 100ms gap
printf '\e_Ga=f,i=7,z=100,f=32,s=100,v=100;...base64-frame2...\e\\'

# Step 3: Add frame 3 with a 100ms gap, using alpha blending
printf '\e_Ga=f,i=7,z=100,c=1,f=32,s=100,v=100;...base64-frame3...\e\\'

# Start the animation (loop forever)
printf '\e_Ga=a,i=7,s=2\e\\'

# Play the animation once
printf '\e_Ga=a,i=7,s=3\e\\'

# Stop the animation
printf '\e_Ga=a,i=7,s=1\e\\'

# Jump to frame 2 and set gap to 200ms
printf '\e_Ga=a,i=7,r=2,z=200\e\\'

# Loop 3 times then stop
printf '\e_Ga=a,i=7,s=2,v=3\e\\'

Terminal support — Animation​

TerminalSupportVersionNotes
Terminal Emulators
Alacritty✗NoNot implemented
Bobcat✗No
contour✗No
foot✗NoNo Kitty graphics protocol support
Ghostty✗NoExplicitly listed as unimplemented in TODO comments
iTerm2✓v20260216-nightlyAnimation frames and control supported
Kitty✓0.20.0
Konsole✗NoNo animation frame parameters handled
mintty✗No
mlterm✗No
PuTTY✗NoGraphics protocol not supported
Rio??Unable to determine from source code review
rxvt-unicode✗NoNo graphics protocol support
st✗NoNo graphics protocol support
terminology✗No
VT100✗No
VTE✗No
WezTerm✓20220101-133340-7edc5b5a
Windows Terminal✗NoKitty graphics protocol not implemented
xterm✗No
xterm.js✗NoThe README explicitly states 'No animation support' for image formats.
Multiplexers
cy✗No
GNU Screen✗NoKitty graphics protocol not implemented
tmux✗No
tuios~v0.6.0Animation commands acknowledged but not yet implemented
Zellij✗No