Ghostty's Implementation of the Kitty Graphics Protocol: Architecture and API

Ghostty implements the Kitty graphics protocol as a three-layer Zig subsystem that parses OSC _G escape sequences, manages image storage and viewport layout through ImageStorage, and exposes a stable C ABI via GhosttyKittyGraphics* handles for downstream integration.

Ghostty, the GPU-accelerated terminal emulator written in Zig, provides full support for the Kitty graphics protocol through a self-contained subsystem integrated into its terminal core. This implementation enables terminal applications to display images, animations, and other graphical content using standard escape sequences. The architecture deliberately separates parsing logic, storage management, and API exposure while maintaining strict compliance with the protocol specification.

Architecture of the Graphics Subsystem

Ghostty's Kitty graphics implementation consists of three distinct layers that handle different aspects of the protocol. Each layer resides in specific source files within the src/terminal/kitty/ directory.

  • Parsing and command handling in graphics_command.zig tokenizes the OSC _G escape sequences and builds strongly-typed Command structures.
  • Storage and layout in graphics_storage.zig maintains ImageStorage instances attached to each screen, handling allocation, eviction, and viewport calculations.
  • C-API façade in src/terminal/c/kitty_graphics.zig exposes opaque pointers and iterators that wrap the Zig internals for C consumers.

The public entry point re-exports these modules through src/terminal/kitty.zig and registers the capability under the .kitty_graphics namespace accessible via terminal.get(...).

Parsing and Command Handling

When Ghostty receives an escape sequence starting with \x1b_G (the Kitty graphics OSC), the parser in src/terminal/kitty/graphics_command.zig processes the parameters (e.g., a=T,t=d,f=24,i=1,p=1,…). The parser constructs a Command union enum that represents the specific operation:

pub const Command = union(enum) {
    transmit: Transmit,
    display: Display,
    delete: Delete,
    // …
};

Each variant contains a strongly-typed struct mirroring the Kitty spec, including fields for image format, compression, placement coordinates, and z-index. The parser enforces strict validation—unknown parameters immediately return an invalid_value error that the terminal surface reports as a failed OSC sequence.

Image Storage and Layout Management

All images and their placements reside in an ImageStorage instance attached to each screen (main or alternate). The implementation in src/terminal/kitty/graphics_storage.zig provides comprehensive resource management:

  • Image management via addImage, imageById, and imageByNumber, with automatic eviction based on a configurable total_limit memory budget.
  • Placement management through addPlacement, gridSize, pixelSize, and rect methods that handle pixel-to-grid mapping and source-rectangle clipping.
  • Viewport calculations using computeViewportPos, which translates internal placement pins into viewport-relative coordinates while handling scrolling and virtual placements.

The Placement struct defines the layout metadata:

pub const Placement = struct {
    location: Location,
    x_offset: u32 = 0,
    y_offset: u32 = 0,
    source_x: u32 = 0,
    source_y: u32 = 0,
    source_width: u32 = 0,
    source_height: u32 = 0,
    columns: u32 = 0,
    rows: u32 = 0,
    z: i32 = 0,
    // …
};

C API Façade for External Integration

The stable C ABI exposed in src/terminal/c/kitty_graphics.zig allows the rest of Ghostty (and external bindings) to interact with the graphics subsystem without importing Zig internals. This façade conditionally compiles only when the kitty_graphics build option is enabled, using compile-time guards:

if (comptime !build_options.kitty_graphics) return .no_value;

Key abstractions include:

  • KittyGraphics – an opaque pointer to the ImageStorage for the current screen.
  • ImageHandle – a nullable pointer to a stored image (*const Image).
  • PlacementIterator – an opaque iterator for walking placements with configurable filters.

The public header at include/ghostty/vt/kitty_graphics.h defines all enums (such as ImageData, PlacementData, and PlacementLayer) and function signatures for C consumers.

Public Entry Point and Module Organization

The src/terminal/kitty.zig module serves as the public interface, re-exporting the graphics, key, and color sub-modules. Graphics objects are retrieved through the generic terminal.get API:

var graphics: KittyGraphics = undefined;
try testing.expectEqual(Result.success,
    terminal_c.get(t, .kitty_graphics, @ptrCast(&graphics)));

This design allows the terminal surface to query the graphics capability uniformly across different screen instances while keeping the implementation details encapsulated.

Practical Code Examples

The following examples demonstrate how client code interacts with Ghostty's Kitty graphics subsystem through the C API.

Listing All Image IDs in the Current Screen

This snippet iterates over all placements to extract associated image identifiers:

Result r;
KittyGraphics gfx;
PlacementIterator *iter = NULL;

/* Obtain the graphics storage for the terminal `term`. */
r = ghostty_kitty_graphics_get(term, DataPlacementIterator, &iter);
if (r != ResultSuccess) return r;

/* Create a fresh iterator */
r = placement_iterator_new(NULL, &iter);
if (r != ResultSuccess) return r;

/* Walk the placements */
while (placement_iterator_next(iter)) {
    uint32_t img_id;
    r = placement_get(iter, PlacementDataImageId, &img_id);
    if (r == ResultSuccess) {
        printf("placement uses image %u\n", img_id);
    }
}
placement_iterator_free(iter);

Querying Pixel Size of a Displayed Image

To determine the pixel dimensions of a rendered image:

/* Assume we already have an ImageHandle `img` from image_get_handle(...). */
uint32_t w, h;
Result r = placement_pixel_size(iter, img, term, &w, &h);
if (r == ResultSuccess) {
    printf("Image occupies %u × %u pixels\n", w, h);
}

Deleting Placements by Cell Intersection

To filter and remove specific placements based on grid position:

/* Delete placements that intersect column 42, without deleting the images. */
PlacementIteratorOption opt = PlacementIteratorOptionColumn;
uint32_t col = 42;
Result r = placement_iterator_set(iter, opt, &col);
if (r != ResultSuccess) return r;

/* The iterator now only yields placements that intersect column 42. */
while (placement_iterator_next(iter)) {
    /* Perform custom cleanup … */
}

The underlying filter logic executes through ImageStorage.delete methods such as delete_by_column.

Summary

  • Ghostty's Kitty graphics protocol implementation resides in src/terminal/kitty/ as a modular Zig subsystem with three distinct layers.
  • Strict parsing in graphics_command.zig converts OSC _G sequences into strongly-typed Command unions, rejecting malformed input immediately.
  • Centralized storage in graphics_storage.zig manages image lifecycles and placement geometry through the ImageStorage struct, supporting eviction policies and viewport-aware positioning.
  • Stable C interoperability is provided by src/terminal/c/kitty_graphics.zig, which exposes GhosttyKittyGraphics* handles and placement iterators while supporting conditional compilation.
  • Public access occurs through src/terminal/kitty.zig via the .kitty_graphics terminal capability, enabling uniform access across main and alternate screens.

Frequently Asked Questions

What file handles the parsing of Kitty graphics escape sequences in Ghostty?

The parser lives in src/terminal/kitty/graphics_command.zig. This module tokenizes the OSC _G parameters and constructs a Command union enum representing transmit, display, or delete operations, with strict validation that rejects unknown parameters via invalid_value errors.

How does Ghostty manage memory limits for stored images?

Memory management is handled by the ImageStorage struct in src/terminal/kitty/graphics_storage.zig. The implementation tracks a configurable total_limit budget and performs automatic eviction when new image data would exceed the allocated memory threshold, ensuring the terminal remains responsive under heavy graphics load.

Is the Kitty graphics subsystem always included in Ghostty builds?

No. The implementation is gated by the kitty_graphics build option. The C façade in src/terminal/c/kitty_graphics.zig uses compile-time guards (if (comptime !build_options.kitty_graphics)) to return .no_value when the feature is disabled, allowing for smaller binaries when graphics support is not required.

How can C applications query specific placements by grid coordinates?

C applications use the PlacementIterator API with filter options. Call placement_iterator_set with PlacementIteratorOptionColumn or similar filters to constrain the iteration, then walk the results with placement_iterator_next and placement_get to retrieve metadata such as PlacementDataImageId for each intersecting placement.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →