Guiltty Kitty Crate
Relevant source files
The following files were used as context for generating this wiki page:
The guiltty-kitty crate serves as the primary rendering backend for the guiltty library. Its core responsibility is to implement the Backend trait defined in guiltty-core, enabling the transmission of pixel-level graphics to terminals that support the Kitty graphics protocol. It is written in pure Rust without C FFI or external protocol wrappers like kittage.
Within the project architecture, guiltty-kitty acts as the bridge between the high-level Canvas buffer and the terminal's raw input stream. It transforms RGBA8 pixel data into the specific escape sequences required by the Kitty protocol, handling base64 encoding and payload chunking to satisfy terminal communication limits.
Sources: README.md:3-8, crates/guiltty-kitty/src/lib.rs:1-4, crates/guiltty/src/lib.rs:1-8
Core Architecture and Data Flow
The crate centers on the KittyBackend struct, which implements the Backend trait. This trait requires the implementation of the present method, which takes a reference to a Canvas and outputs terminal escape sequences.
Transmission Logic
The present method performs several distinct steps to transmit an image:
- Pixel Retrieval: It extracts the RGBA8 byte buffer from the provided
Canvas. - Encoding: It base64-encodes the entire buffer using the
base64crate. - Chunking: The encoded string is split into chunks of 4096 bytes (
MAX_CHUNK_LEN) to comply with the Kitty protocol's APC (Application Program Control) payload limits. - Sequence Generation: It generates
_GAPC sequences, including control keys for image identification, dimensions, and transmission status.
The following diagram illustrates the data flow from a Canvas to the terminal output:
The diagram shows how pixel data is transformed from a raw buffer into chunked escape sequences for terminal consumption.
Sources: crates/guiltty-kitty/src/lib.rs:56-105, crates/guiltty-core/src/lib.rs:173-180
Protocol Implementation Details
KittyBackend uses specific control keys to manage image persistence and cursor behavior.
Image and Placement Management
To prevent multiple present() calls from accumulating infinite images in terminal memory, the backend manages unique IDs:
NEXT_IMAGE_ID: A staticAtomicU32that hands out a unique ID to everyKittyBackendinstance upon creation.- Image/Placement ID Reuse: Each instance reuses its assigned ID for both the image (
i) and placement (p) control keys. This ensures that repeated frames from the same backend instance replace the previous on-screen image rather than creating new ones.
Control Keys Used in present()
| Key | Value | Description |
|---|---|---|
a | T | Action: Transmit and display the image immediately. |
f | 32 | Format: 32-bit RGBA pixels. |
i | {id} | Image ID: Unique identifier for the image data. |
p | {id} | Placement ID: Identifies the specific placement on the screen. |
q | 2 | Quiet: Suppress terminal OK/error responses to APC sequences. |
C | 1 | Do not move cursor: Keeps the cursor at the origin, allowing static redrawing. |
s/v | w/h | Dimensions: Width and height of the image in pixels. |
m | 0 or 1 | More: 1 if more chunks follow, 0 for the final chunk. |
Sources: crates/guiltty-kitty/src/lib.rs:16-20, crates/guiltty-kitty/src/lib.rs:73-95
Components and Structures
KittyBackend<W: Write>
The primary handle for the backend. It is generic over the output stream, allowing for injection of custom writers (like Vec<u8>) during testing.
pub struct KittyBackend<W: Write = io::Stdout> {
writer: W,
image_id: u32,
}
Sources: crates/guiltty-kitty/src/lib.rs:27-30
Key Functions
| Function | Signature | Description |
|---|---|---|
new | fn new() -> Self | Creates a backend writing to io::stdout with a fresh image ID. |
with_writer | fn with_writer(writer: W) -> Self | Creates a backend using a custom io::Write target. |
present | fn present(&mut self, canvas: &Canvas) -> Result<(), Error> | Encodes and writes the canvas to the terminal. |
Sources: crates/guiltty-kitty/src/lib.rs:41-55, crates/guiltty-kitty/src/lib.rs:70-105
Dependencies and Limitations
Dependencies
The crate minimizes external dependencies to maintain a small footprint:
base64: Used for encoding the RGBA buffer for APC payloads.guiltty-core: Provides theBackendtrait,Canvasstructure, andErrortypes.
Sources: crates/guiltty-kitty/Cargo.toml:13-16
Requirements and Limitations
- Terminal Support: Requires a terminal supporting Kitty graphics protocol version
0.20.0or later (specifically for theCcontrol key). - Zero-Size Canvases: A
Canvaswith dimensions of 0x0 is treated as a no-op inpresent(), as it cannot be represented in the protocol. - Synchronous Writing: Currently writes directly to the provided writer and flushes after all chunks are sent.
Sources: crates/guiltty-kitty/src/lib.rs:5-8, crates/guiltty-kitty/src/lib.rs:77-80
Conclusion
The guiltty-kitty crate provides the essential wire-format implementation for the Kitty graphics protocol. By abstracting the complexities of base64 chunking, image ID management, and APC sequence formatting, it allows the rest of the guiltty ecosystem to remain backend-agnostic while still achieving high-performance pixel-level rendering in modern terminal environments.