Wire Encoding and Base64
Relevant source files
The following files were used as context for generating this wiki page:
Wire encoding in the guiltty project refers to the process of transforming a Canvas's raw pixel buffer into a sequence of bytes that can be understood by a terminal implementing the Kitty graphics protocol. This process primarily involves converting RGBA8 pixel data into Base64-encoded strings and wrapping them in specific Application Program Command (APC) escape sequences.
The system ensures that high-resolution graphical data is transmitted efficiently over standard terminal streams by adhering to the protocol's chunking requirements and utilizing specific control keys to manage image lifecycle, placement, and cursor behavior.
Encoding Pipeline and Architecture
The encoding logic resides within the guiltty-kitty crate, specifically within the KittyBackend implementation of the Backend trait. The pipeline follows a structured flow from raw pixel extraction to the final transmission of chunked escape sequences.
Data Flow Overview
The following diagram illustrates the transformation of data from the core Canvas to the terminal output:
The encoding process begins by flattening the Canvas pixels into a row-major byte vector.
Sources: crates/guiltty-kitty/src/lib.rs:82-88, crates/guiltty-core/src/lib.rs:172-178
Components and Key Functions
| Component | Function/Constant | Description |
|---|---|---|
| Base64 Engine | BASE64 | Uses base64::engine::general_purpose::STANDARD for encoding. |
| Chunk Limit | MAX_CHUNK_LEN | 4096 bytes: The maximum size of an APC payload allowed by the protocol. |
| Encoder | KittyBackend::present | Orchestrates the encoding, chunking, and writing process. |
| Pixel Source | Canvas::rgba8_bytes | Flattens the 2D Color buffer into a 1D Vec<u8>. |
Sources: crates/guiltty-kitty/src/lib.rs:11-14, crates/guiltty-kitty/src/lib.rs:82-84, crates/guiltty-core/src/lib.rs:172-178
Protocol Escape Sequences
The backend generates escape sequences following the pattern \x1b_G<control_keys>;<payload>\x1b\\. The control keys define how the terminal should interpret the Base64 payload.
Control Key Reference
When KittyBackend::present is called, it uses several specific keys to ensure consistent rendering and avoid terminal drift:
| Key | Value | Purpose |
|---|---|---|
a | T | Action: Transmit and display the image immediately. |
f | 32 | Format: Specifies 32-bit RGBA pixel format. |
i | {id} | Image ID: Unique ID to identify the image in the terminal memory. |
p | {id} | Placement ID: Reuses the Image ID to ensure the image replaces itself rather than accumulating. |
q | 2 | Quiet Mode: Suppresses OK/Error responses from the terminal to avoid polluting stdin. |
C | 1 | Do Not Move Cursor: Prevents the cursor from advancing after the image is drawn. |
s/v | {w}/{h} | Size: Width (s) and Height (v) of the image in pixels. |
m | 0/1 | More: 1 if more chunks follow, 0 if it is the final chunk. |
Sources: crates/guiltty-kitty/src/lib.rs:104-124, crates/guiltty-kitty/src/lib.rs:5-8
Base64 Chunking Logic
Because the Kitty protocol limits individual APC sequences to 4096 bytes, large images must be split across multiple sequences.
- Initial Sequence: Includes all metadata control keys (
a,f,i,p,q,C,s,v) and the first chunk of data. It setsm=1if more data follows. - Subsequent Sequences: Only include the
mcontrol key and the payload chunk. - Final Sequence: Includes the final payload chunk and sets
m=0.
A sequence diagram showing the multi-chunk transmission flow for a large image.
Sources: crates/guiltty-kitty/src/lib.rs:98-129, crates/guiltty-kitty/src/lib.rs:205-234
Implementation Details
The implementation avoids unnecessary UTF-8 validation by writing Base64 chunks as raw bytes directly to the underlying io::Write handle.
// crates/guiltty-kitty/src/lib.rs:125-128
// Written as raw bytes rather than through a `str`/`write!` conversion --
// base64 output is always ASCII, but this avoids an unnecessary UTF-8
// validation (and its associated `expect`/panic risk) on the hot path.
self.writer.write_all(chunk).map_err(to_backend_err)?;
self.writer.write_all(b"\x1b\\").map_err(to_backend_err)?;
Sources: crates/guiltty-kitty/src/lib.rs:125-128
Image Identity Management
To ensure that repeated calls to present() update the same graphical area rather than creating new images, KittyBackend utilizes a static atomic counter for unique Image IDs. Each instance of a backend gets one ID and reuses it for both the image and the placement ID.
Diagram showing the relationship between the Backend instance and its globally unique Image ID.
Sources: crates/guiltty-kitty/src/lib.rs:16-17, crates/guiltty-kitty/src/lib.rs:43-50
Conclusion
Wire encoding in guiltty is a specialized transformation layer that bridges the gap between high-level Canvas operations and the low-level byte-oriented Kitty graphics protocol. By utilizing Base64 encoding, chunking, and strict adherence to APC escape sequence formatting, the system enables reliable pixel-level graphics in a standard terminal environment.
Sources: crates/guiltty-kitty/src/lib.rs:1-8, README.md:1-10, tasks/plan.md:41-65