Kitty Graphics Protocol in OCaml
terminal graphics ocaml

docs

+24
lib/kgp.ml
···
module Delete = Kgp_delete
module Animation_state = Kgp_animation_state
(* Configuration modules *)
module Placement = Kgp_placement
module Frame = Kgp_frame
module Animation = Kgp_animation
module Compose = Kgp_compose
(* Core modules *)
module Command = Kgp_command
···
module Delete = Kgp_delete
module Animation_state = Kgp_animation_state
+
(* Type aliases *)
+
type format = Format.t
+
type transmission = Transmission.t
+
type compression = Compression.t
+
type quiet = Quiet.t
+
type cursor = Cursor.t
+
type composition = Composition.t
+
type delete = Delete.t
+
type animation_state = Animation_state.t
+
(* Configuration modules *)
module Placement = Kgp_placement
module Frame = Kgp_frame
module Animation = Kgp_animation
module Compose = Kgp_compose
+
+
(* Command type and functions *)
+
type command = Kgp_command.t
+
+
let transmit = Kgp_command.transmit
+
let transmit_and_display = Kgp_command.transmit_and_display
+
let query = Kgp_command.query
+
let display = Kgp_command.display
+
let delete = Kgp_command.delete
+
let frame = Kgp_command.frame
+
let animate = Kgp_command.animate
+
let compose = Kgp_command.compose
+
let write = Kgp_command.write
+
let to_string = Kgp_command.to_string
(* Core modules *)
module Command = Kgp_command
+302 -8
lib/kgp.mli
···
OCaml programs to display images in terminals that support the protocol
(Kitty, WezTerm, Konsole, Ghostty, etc.).
-
The protocol uses APC (Application Programming Command) escape sequences
-
to transmit and display pixel graphics. Images can be transmitted as raw
-
RGB/RGBA data or PNG, and displayed at specific positions with various
-
placement options.
{2 Basic Usage}
{[
(* Display a PNG image *)
let png_data = read_file "image.png" in
-
let cmd = Kgp.Command.transmit_and_display ~format:`Png () in
let buf = Buffer.create 1024 in
-
Kgp.Command.write buf cmd ~data:png_data;
print_string (Buffer.contents buf)
]}
{2 Protocol Reference}
See {{:https://sw.kovidgoyal.net/kitty/graphics-protocol/} Kitty Graphics Protocol}
···
module Animation = Kgp_animation
module Compose = Kgp_compose
-
(** {1 Command and Response} *)
-
module Command = Kgp_command
module Response = Kgp_response
(** {1 Utilities} *)
module Unicode_placeholder = Kgp_unicode
module Detect = Kgp_detect
···
OCaml programs to display images in terminals that support the protocol
(Kitty, WezTerm, Konsole, Ghostty, etc.).
+
{1 Protocol Overview}
+
+
The Kitty Graphics Protocol is a flexible, performant protocol for rendering
+
arbitrary pixel (raster) graphics in terminal emulators. Key features:
+
+
- No requirement for terminal emulators to understand image formats
+
- Pixel-level positioning of graphics
+
- Integration with text (graphics can be drawn below/above text with alpha blending)
+
- Automatic scrolling with text
+
- Animation support with frame deltas for efficiency
+
+
{2 Escape Sequence Format}
+
+
All graphics commands use the Application Programming Command (APC) format:
+
+
{v <ESC>_G<control data>;<payload><ESC>\ v}
+
+
Where:
+
- [ESC _G] is the APC start sequence (bytes 0x1B 0x5F 0x47)
+
- Control data is comma-separated key=value pairs
+
- Payload is base64-encoded binary data (RFC-4648)
+
- [ESC] is the APC terminator (bytes 0x1B 0x5C)
+
+
Most terminal emulators ignore unrecognized APC sequences, making the
+
protocol safe to use even in unsupported terminals.
+
+
{2 Terminal Responses}
+
+
When an image ID is specified, the terminal responds:
+
- On success: [ESC _Gi=ID;OK ESC]
+
- On failure: [ESC _Gi=ID;error ESC]
+
+
Common error codes include [ENOENT] (image not found), [EINVAL] (invalid
+
parameter), and [ENOSPC] (storage quota exceeded).
+
+
{2 Image Storage}
+
+
Terminal emulators maintain a storage quota for images (typically ~320MB).
+
When the quota is exceeded, older images are deleted to make room for new
+
ones. Images without active placements are preferred for deletion.
+
+
For animations, frame data is stored separately with a larger quota
+
(typically 5x the base quota).
{2 Basic Usage}
{[
(* Display a PNG image *)
let png_data = read_file "image.png" in
+
let cmd = Kgp.transmit_and_display ~format:`Png () in
let buf = Buffer.create 1024 in
+
Kgp.write buf cmd ~data:png_data;
print_string (Buffer.contents buf)
]}
+
{[
+
(* Transmit an image, then display it multiple times *)
+
let png_data = read_file "icon.png" in
+
let cmd = Kgp.transmit ~image_id:1 ~format:`Png () in
+
Kgp.write buf cmd ~data:png_data;
+
+
(* Display at different positions *)
+
let cmd = Kgp.display ~image_id:1 () in
+
Kgp.write buf cmd ~data:"";
+
]}
+
{2 Protocol Reference}
See {{:https://sw.kovidgoyal.net/kitty/graphics-protocol/} Kitty Graphics Protocol}
···
module Animation = Kgp_animation
module Compose = Kgp_compose
+
(** {1 Commands} *)
+
+
type command = Kgp_command.t
+
(** A graphics protocol command. Commands are built using the functions below
+
and then serialized using {!write} or {!to_string}. *)
+
+
(** {2 Image Transmission}
+
+
Images can be transmitted to the terminal for storage and later display.
+
The terminal assigns storage and responds with success or failure.
+
+
For large images, the library automatically handles chunked transmission
+
(splitting data into 4096-byte base64-encoded chunks). *)
+
+
val transmit :
+
?image_id:int ->
+
?image_number:int ->
+
?format:Format.t ->
+
?transmission:Transmission.t ->
+
?compression:Compression.t ->
+
?width:int ->
+
?height:int ->
+
?size:int ->
+
?offset:int ->
+
?quiet:Quiet.t ->
+
unit ->
+
command
+
(** Transmit image data without displaying.
+
+
The image is stored by the terminal and can be displayed later using
+
{!val:display} with the same [image_id].
+
+
@param image_id Unique identifier (1-4294967295) for later reference.
+
If specified, the terminal responds with success/failure.
+
@param image_number Alternative to [image_id] where the terminal assigns
+
a unique ID and returns it in the response. Useful when multiple
+
programs share the terminal.
+
@param format Pixel format of the data. Default is [`Rgba32].
+
@param transmission How data is sent. Default is [`Direct] (inline).
+
@param compression Compression applied to data. Default is [`None].
+
@param width Image width in pixels (required for raw RGB/RGBA formats).
+
@param height Image height in pixels (required for raw RGB/RGBA formats).
+
@param size Size in bytes when reading from file.
+
@param offset Byte offset when reading from file.
+
@param quiet Response suppression level. *)
+
+
val transmit_and_display :
+
?image_id:int ->
+
?image_number:int ->
+
?format:Format.t ->
+
?transmission:Transmission.t ->
+
?compression:Compression.t ->
+
?width:int ->
+
?height:int ->
+
?size:int ->
+
?offset:int ->
+
?quiet:Quiet.t ->
+
?placement:Placement.t ->
+
unit ->
+
command
+
(** Transmit image data and display it immediately.
+
+
Combines transmission and display in a single command. The image is
+
rendered at the current cursor position unless placement options
+
specify otherwise.
+
+
See {!transmit} for parameter descriptions. The [placement] parameter
+
controls display position and scaling. *)
+
val query :
+
?format:Format.t ->
+
?transmission:Transmission.t ->
+
?width:int ->
+
?height:int ->
+
?quiet:Quiet.t ->
+
unit ->
+
command
+
(** Query terminal support without storing the image.
+
+
Performs the same validation as {!transmit} but does not store the
+
image. Useful for testing whether the terminal supports the graphics
+
protocol and specific formats.
+
+
To detect graphics support, send a query and check for a response:
+
{[
+
(* Send query with a tiny 1x1 RGB image *)
+
let cmd = Kgp.query ~format:`Rgb24 ~width:1 ~height:1 () in
+
Kgp.write buf cmd ~data:"\x00\x00\x00"
+
(* If terminal responds, it supports the protocol *)
+
]} *)
+
+
(** {2 Display}
+
+
Previously transmitted images can be displayed multiple times at
+
different positions with different cropping and scaling options. *)
+
+
val display :
+
?image_id:int ->
+
?image_number:int ->
+
?placement:Placement.t ->
+
?quiet:Quiet.t ->
+
unit ->
+
command
+
(** Display a previously transmitted image.
+
+
The image is rendered at the current cursor position. Use [placement]
+
to control cropping, scaling, z-index, and other display options.
+
+
Each display creates a "placement" of the image. Multiple placements
+
of the same image share the underlying image data.
+
+
@param image_id ID of a previously transmitted image.
+
@param image_number Image number (acts on the newest image with this number).
+
@param placement Display configuration (position, size, z-index, etc.). *)
+
+
(** {2 Deletion}
+
+
Images and placements can be deleted to free terminal resources.
+
Lowercase delete commands remove placements but keep image data;
+
uppercase variants also free the image data. *)
+
+
val delete : ?quiet:Quiet.t -> Delete.t -> command
+
(** Delete images or placements.
+
+
See {!Delete} for the full list of deletion targets.
+
+
Examples:
+
{[
+
(* Delete all visible images *)
+
Kgp.delete `All_visible
+
+
(* Delete specific image, keeping data for reuse *)
+
Kgp.delete (`By_id (42, None))
+
+
(* Delete specific image and free its data *)
+
Kgp.delete (`By_id_and_free (42, None))
+
+
(* Delete all placements at a specific cell *)
+
Kgp.delete (`At_cell (10, 5))
+
]} *)
+
+
(** {2 Animation}
+
+
The protocol supports both client-driven and terminal-driven animations.
+
Animations are created by first transmitting a base image, then adding
+
frames with optional delta encoding for efficiency.
+
+
Frame numbers are 1-based: frame 1 is the root (base) image, frame 2
+
is the first added frame, etc. *)
+
+
val frame :
+
?image_id:int ->
+
?image_number:int ->
+
?format:Format.t ->
+
?transmission:Transmission.t ->
+
?compression:Compression.t ->
+
?width:int ->
+
?height:int ->
+
?quiet:Quiet.t ->
+
frame:Frame.t ->
+
unit ->
+
command
+
(** Transmit animation frame data.
+
+
Adds a new frame to an existing image or edits an existing frame.
+
The frame can be a full image or a partial update (rectangle).
+
+
Use {!Frame.make} to configure the frame's position, timing, and
+
composition options.
+
+
@param frame Frame configuration including timing and composition. *)
+
+
val animate :
+
?image_id:int ->
+
?image_number:int ->
+
?quiet:Quiet.t ->
+
Animation.t ->
+
command
+
(** Control animation playback.
+
+
For terminal-driven animation:
+
{[
+
(* Start infinite loop animation *)
+
Kgp.animate ~image_id:1 (Animation.set_state ~loops:1 `Run)
+
+
(* Stop animation *)
+
Kgp.animate ~image_id:1 (Animation.set_state `Stop)
+
+
(* Change frame timing *)
+
Kgp.animate ~image_id:1 (Animation.set_gap ~frame:3 ~gap_ms:100)
+
]}
+
+
For client-driven animation:
+
{[
+
(* Manually advance to specific frame *)
+
Kgp.animate ~image_id:1 (Animation.set_current_frame 5)
+
]} *)
+
+
val compose :
+
?image_id:int ->
+
?image_number:int ->
+
?quiet:Quiet.t ->
+
Compose.t ->
+
command
+
(** Compose animation frames.
+
+
Copies a rectangular region from one frame onto another. Useful for
+
building complex frames from simpler components.
+
+
{[
+
(* Copy a 50x50 region from frame 2 to frame 5 *)
+
let comp = Compose.make
+
~source_frame:2 ~dest_frame:5
+
~width:50 ~height:50
+
~source_x:10 ~source_y:10
+
~dest_x:20 ~dest_y:20 () in
+
Kgp.compose ~image_id:1 comp
+
]} *)
+
+
(** {2 Output}
+
+
Commands are serialized to escape sequences that can be written
+
to the terminal. *)
+
+
val write : Buffer.t -> command -> data:string -> unit
+
(** Write the command to a buffer.
+
+
The [data] parameter contains the raw image/frame data (before base64
+
encoding). Pass an empty string for commands that don't include payload
+
data (like {!val:display}, {!val:delete}, {!val:animate}).
+
+
The library handles base64 encoding and chunking automatically. *)
+
+
val to_string : command -> data:string -> string
+
(** Convert command to a string.
+
+
Convenience wrapper around {!write} that returns the serialized
+
command as a string. *)
+
+
(** {1 Response} *)
+
module Response = Kgp_response
(** {1 Utilities} *)
module Unicode_placeholder = Kgp_unicode
module Detect = Kgp_detect
+
+
(** {1 Low-level Access} *)
+
+
module Command = Kgp_command
+
(** Low-level command module. The command functions are also available
+
at the top level of this module for convenience. *)
+92 -8
lib/kgp_animation.mli
···
-
(** Kitty Graphics Protocol Animation
-
Animation control operations. *)
type t =
[ `Set_state of Kgp_animation_state.t * int option
| `Set_gap of int * int
| `Set_current of int ]
-
(** Animation control operations. *)
val set_state : ?loops:int -> Kgp_animation_state.t -> t
-
(** Set animation state.
-
@param loops Number of loops: 0 = ignored, 1 = infinite, n = n-1 loops *)
val set_gap : frame:int -> gap_ms:int -> t
(** Set the gap (delay) for a specific frame.
-
@param frame 1-based frame number
-
@param gap_ms Delay in milliseconds (negative = gapless) *)
val set_current_frame : int -> t
-
(** Make a specific frame (1-based) the current displayed frame. *)
···
+
(** Animation Control
+
+
Operations for controlling animation playback. The protocol supports
+
both terminal-driven and client-driven animation modes.
+
+
{2 Protocol Overview}
+
+
Animation control uses action [a=a] with various keys:
+
- [s]: Set playback state (1=stop, 2=loading, 3=run)
+
- [c]: Set current frame (1-based frame number)
+
- [r]: Target frame number for gap changes
+
- [z]: Frame gap/delay in milliseconds
+
- [v]: Loop count
+
{2 Terminal-Driven Animation}
+
+
The terminal automatically advances frames based on each frame's gap
+
(delay). To start terminal-driven animation:
+
+
{[
+
(* Start infinite loop *)
+
Kgp.animate ~image_id:1 (Animation.set_state ~loops:1 `Run)
+
+
(* Run 3 times then stop *)
+
Kgp.animate ~image_id:1 (Animation.set_state ~loops:4 `Run)
+
+
(* Stop animation *)
+
Kgp.animate ~image_id:1 (Animation.set_state `Stop)
+
]}
+
+
{2 Client-Driven Animation}
+
+
The client manually controls which frame is displayed:
+
+
{[
+
(* Display specific frame *)
+
Kgp.animate ~image_id:1 (Animation.set_current_frame 5)
+
+
(* Advance to next frame in application logic *)
+
let next_frame = (current_frame mod total_frames) + 1 in
+
Kgp.animate ~image_id:1 (Animation.set_current_frame next_frame)
+
]}
+
+
{2 Modifying Frame Timing}
+
+
Frame gaps can be changed during playback:
+
+
{[
+
(* Slow down frame 3 *)
+
Kgp.animate ~image_id:1 (Animation.set_gap ~frame:3 ~gap_ms:200)
+
+
(* Make frame 5 instant/gapless *)
+
Kgp.animate ~image_id:1 (Animation.set_gap ~frame:5 ~gap_ms:(-1))
+
]}
+
+
{2 Loop Counting}
+
+
The [loops] parameter in {!set_state}:
+
- 0: Ignored (doesn't change loop setting)
+
- 1: Infinite loop
+
- n > 1: Loop (n-1) times, then stop *)
type t =
[ `Set_state of Kgp_animation_state.t * int option
| `Set_gap of int * int
| `Set_current of int ]
+
(** Animation control operations.
+
+
- [`Set_state (state, loops)] - Set animation playback state with
+
optional loop count.
+
- [`Set_gap (frame, gap_ms)] - Set the delay for a specific frame.
+
- [`Set_current frame] - Jump to a specific frame (1-based). *)
val set_state : ?loops:int -> Kgp_animation_state.t -> t
+
(** Set animation playback state.
+
+
@param loops Loop count: 0 = ignored, 1 = infinite, n > 1 = (n-1) loops.
+
Protocol key: [v].
+
@param state The target playback state.
+
+
Examples:
+
{[
+
set_state `Run (* Run with current loop setting *)
+
set_state ~loops:1 `Run (* Run infinitely *)
+
set_state ~loops:3 `Run (* Run twice, then stop *)
+
set_state `Stop (* Pause animation *)
+
set_state `Loading (* Run, wait for more frames at end *)
+
]} *)
val set_gap : frame:int -> gap_ms:int -> t
(** Set the gap (delay) for a specific frame.
+
+
@param frame 1-based frame number to modify. Protocol key: [r].
+
@param gap_ms Delay in milliseconds before next frame. Negative values
+
create gapless frames (not displayed, instant skip). Protocol key: [z].
+
+
Note: Frame 1 is the root/base image. Use 2+ for added frames. *)
val set_current_frame : int -> t
+
(** Make a specific frame the current displayed frame.
+
+
@param frame 1-based frame number to display. Protocol key: [c].
+
+
Used for client-driven animation where the application controls
+
frame advancement rather than the terminal. *)
+55 -5
lib/kgp_animation_state.mli
···
(** Animation Playback State
-
Controls the playback state of animated images. *)
type t = [ `Stop | `Loading | `Run ]
(** Animation playback states.
-
- [`Stop] - Halt animation playback
-
- [`Loading] - Run animation but wait for new frames at end
-
- [`Run] - Run animation normally and loop *)
val to_int : t -> int
-
(** Convert to protocol integer (1, 2, or 3). *)
···
(** Animation Playback State
+
Controls the playback state of animated images.
+
+
{2 Protocol Details}
+
+
The animation state is specified via the [s] key in the control data
+
when using action [a=a]:
+
- [s=1]: stop animation
+
- [s=2]: run in loading mode
+
- [s=3]: run normally
+
+
{2 Animation Modes}
+
+
The protocol supports two animation approaches:
+
+
{b Terminal-driven animation}: The terminal automatically advances
+
frames based on the gap (delay) specified for each frame. Use
+
[{`Run}] or [{`Loading}] states.
+
+
{b Client-driven animation}: The client manually sets the current
+
frame using [Kgp.Animation.set_current_frame]. Use [{`Stop}] state
+
to prevent automatic advancement.
+
+
{2 Stop State}
+
+
[{`Stop}] halts automatic frame advancement. The animation freezes
+
on the current frame. Use this when:
+
- Implementing client-driven animation
+
- Pausing an animation
+
- Displaying a static frame from an animated image
+
+
{2 Loading State}
+
+
[{`Loading}] runs the animation but waits for new frames when reaching
+
the end instead of looping. Use this when:
+
- Streaming animation frames progressively
+
- Building an animation while displaying it
+
- The animation is not yet complete
+
+
{2 Run State}
+
+
[{`Run}] runs the animation normally, looping back to the first frame
+
after the last. The loop count can be controlled via the [loops]
+
parameter in [Kgp.Animation.set_state]. *)
type t = [ `Stop | `Loading | `Run ]
(** Animation playback states.
+
- [`Stop] - Halt animation playback. The animation freezes on the
+
current frame and does not advance automatically.
+
- [`Loading] - Run animation but wait for new frames at end. When
+
the last frame is reached, the animation pauses until more frames
+
are added, then continues.
+
- [`Run] - Run animation normally and loop. After the last frame,
+
playback returns to the first frame (or stops after the specified
+
number of loops). *)
val to_int : t -> int
+
(** Convert to protocol integer.
+
+
Returns 1 for [`Stop], 2 for [`Loading], or 3 for [`Run].
+
These values are used in the [s=] control data key. *)
+88 -4
lib/kgp_compose.mli
···
-
(** Kitty Graphics Protocol Compose
-
Frame composition operations. *)
type t
-
(** Composition operation. *)
val make :
source_frame:int ->
···
?composition:Kgp_composition.t ->
unit ->
t
-
(** Compose a rectangle from one frame onto another. *)
(** {1 Field Accessors} *)
val source_frame : t -> int
val dest_frame : t -> int
val width : t -> int option
val height : t -> int option
val source_x : t -> int option
val source_y : t -> int option
val dest_x : t -> int option
val dest_y : t -> int option
val composition : t -> Kgp_composition.t option
···
+
(** Frame Composition
+
+
Operations for compositing rectangular regions between animation frames.
+
This allows building complex frames from simpler components.
+
+
{2 Protocol Overview}
+
+
Frame composition uses action [a=c] to copy a rectangular region from
+
one frame onto another. This is useful for:
+
+
- Building frames from reusable sprite components
+
- Applying partial updates to existing frames
+
- Creating complex animations efficiently
+
+
{2 Coordinate System}
+
+
All coordinates are in pixels, relative to the top-left corner of
+
the respective frame:
+
- [source_x], [source_y]: Top-left of rectangle in source frame
+
- [dest_x], [dest_y]: Top-left of destination in target frame
+
- [width], [height]: Size of the rectangle to copy
+
+
If width/height are omitted, the entire source frame is used.
+
+
{2 Composition Mode}
+
+
The [composition] parameter controls blending:
+
- [{`Alpha_blend}]: Standard alpha compositing (default)
+
- [{`Overwrite}]: Direct pixel replacement
+
+
{2 Error Conditions}
+
+
The terminal responds with errors for:
+
- [ENOENT]: Source or destination frame doesn't exist
+
- [EINVAL]: Rectangle out of bounds, or source equals destination
+
with overlapping regions
+
- [ENOSPC]: Not enough storage after composition
+
+
{2 Example}
+
+
{[
+
(* Copy a 32x32 sprite from frame 2 to frame 5 *)
+
let comp = Compose.make
+
~source_frame:2 ~dest_frame:5
+
~width:32 ~height:32
+
~source_x:0 ~source_y:0 (* From top-left of source *)
+
~dest_x:100 ~dest_y:50 () (* To position in dest *)
+
in
+
Kgp.compose ~image_id:1 comp
+
]} *)
type t
+
(** Composition operation. Opaque type; use {!make} to construct. *)
val make :
source_frame:int ->
···
?composition:Kgp_composition.t ->
unit ->
t
+
(** Create a composition operation.
+
+
@param source_frame 1-based frame number to copy from. Required.
+
Protocol key: [r].
+
@param dest_frame 1-based frame number to copy onto. Required.
+
Protocol key: [c].
+
@param width Width of rectangle in pixels. Default is full frame.
+
Protocol key: [w].
+
@param height Height of rectangle in pixels. Default is full frame.
+
Protocol key: [h].
+
@param source_x Left edge of source rectangle (default 0).
+
Protocol key: [X].
+
@param source_y Top edge of source rectangle (default 0).
+
Protocol key: [Y].
+
@param dest_x Left edge of destination position (default 0).
+
Protocol key: [x].
+
@param dest_y Top edge of destination position (default 0).
+
Protocol key: [y].
+
@param composition Blending mode. Default is alpha blending.
+
Protocol key: [C]. *)
(** {1 Field Accessors} *)
val source_frame : t -> int
+
(** 1-based source frame number. *)
+
val dest_frame : t -> int
+
(** 1-based destination frame number. *)
+
val width : t -> int option
+
(** Width of rectangle in pixels. *)
+
val height : t -> int option
+
(** Height of rectangle in pixels. *)
+
val source_x : t -> int option
+
(** Left edge of source rectangle. *)
+
val source_y : t -> int option
+
(** Top edge of source rectangle. *)
+
val dest_x : t -> int option
+
(** Left edge of destination position. *)
+
val dest_y : t -> int option
+
(** Top edge of destination position. *)
+
val composition : t -> Kgp_composition.t option
+
(** Blending mode for composition. *)
+39 -4
lib/kgp_composition.mli
···
(** Pixel Composition Mode
-
Controls how pixels are blended when compositing images or animation frames. *)
type t = [ `Alpha_blend | `Overwrite ]
(** Composition modes.
-
- [`Alpha_blend] - Full alpha blending (default)
-
- [`Overwrite] - Simple pixel replacement *)
val to_int : t -> int
-
(** Convert to protocol integer (0 or 1). *)
···
(** Pixel Composition Mode
+
Controls how pixels are blended when compositing images or animation frames.
+
+
{2 Protocol Details}
+
+
The composition mode is specified via the [X] key in the control data
+
(for animation frames) or the [C] key (for frame composition operations):
+
- Value 0 or omitted: alpha blending (default)
+
- Value 1: simple overwrite/replacement
+
+
{2 Alpha Blending}
+
+
[{`Alpha_blend}] performs standard alpha compositing using the source
+
pixel's alpha channel. For each pixel:
+
- If source alpha is 255 (opaque), source pixel replaces destination
+
- If source alpha is 0 (transparent), destination pixel is unchanged
+
- Otherwise, colors are blended proportionally
+
+
This mode is essential for:
+
- Transparent PNG images
+
- Overlaying graphics on backgrounds
+
- Anti-aliased edges and text
+
+
{2 Overwrite Mode}
+
+
[{`Overwrite}] simply replaces destination pixels with source pixels,
+
ignoring the alpha channel. This is useful for:
+
- Performance optimization when transparency isn't needed
+
- Replacing rectangular regions entirely
+
- Animation frames that completely replace the previous frame *)
type t = [ `Alpha_blend | `Overwrite ]
(** Composition modes.
+
- [`Alpha_blend] - Full alpha blending (default). Source pixels are
+
composited onto the destination using standard Porter-Duff "over"
+
compositing based on the source alpha channel.
+
- [`Overwrite] - Simple pixel replacement. Source pixels completely
+
replace destination pixels, ignoring alpha values. Faster but no
+
transparency support. *)
val to_int : t -> int
+
(** Convert to protocol integer.
+
+
Returns 0 for [`Alpha_blend] or 1 for [`Overwrite].
+
These values are used in the [X=] or [C=] control data keys. *)
+35 -5
lib/kgp_compression.mli
···
(** Data Compression
-
Specifies compression applied to image data before transmission. *)
type t = [ `None | `Zlib ]
(** Compression options.
-
- [`None] - Raw uncompressed data
-
- [`Zlib] - RFC 1950 zlib compression *)
val to_char : t -> char option
-
(** Convert to protocol character. Returns [None] for no compression,
-
[Some 'z'] for zlib. *)
···
(** Data Compression
+
Specifies compression applied to image data before transmission.
+
+
{2 Protocol Details}
+
+
Compression is specified via the [o] key in the control data:
+
- No [o] key means no compression
+
- [o=z] means zlib (RFC 1950 DEFLATE) compression
+
+
Compression is applied to the raw pixel/PNG data {i before} base64
+
encoding. The terminal decompresses after base64 decoding.
+
+
{2 When to Use Compression}
+
+
Zlib compression is beneficial for:
+
- Large images with repetitive patterns
+
- Screenshots and UI graphics
+
- Images with large solid color regions
+
+
It may not help (or could increase size) for:
+
- Already-compressed PNG data
+
- Photographic images with high entropy
+
- Very small images (compression overhead)
+
+
{2 PNG with Compression}
+
+
When using both [{`Png}] format and [{`Zlib}] compression, the [size]
+
parameter must be specified with the original (uncompressed) PNG size.
+
The terminal needs this to allocate the correct buffer for decompression. *)
type t = [ `None | `Zlib ]
(** Compression options.
+
- [`None] - Raw uncompressed data. No [o=] key is sent.
+
- [`Zlib] - RFC 1950 zlib/DEFLATE compression. Data is compressed
+
before base64 encoding and decompressed by the terminal. *)
val to_char : t -> char option
+
(** Convert to protocol character.
+
+
Returns [None] for [`None] (no key sent), or [Some 'z'] for [`Zlib].
+
When [Some c] is returned, [o=c] is added to the control data. *)
+40 -4
lib/kgp_cursor.mli
···
(** Cursor Movement Behavior
-
Controls cursor position after displaying an image. *)
type t = [ `Move | `Static ]
(** Cursor movement behavior.
-
- [`Move] - Advance cursor past the displayed image (default)
-
- [`Static] - Keep cursor in place *)
val to_int : t -> int
-
(** Convert to protocol integer (0 or 1). *)
···
(** Cursor Movement Behavior
+
Controls cursor position after displaying an image.
+
+
{2 Protocol Details}
+
+
Cursor movement is specified via the [C] key in the control data:
+
- [C=0] or no [C] key: move cursor after display (default)
+
- [C=1]: keep cursor in place (static)
+
+
This key was added in Kitty 0.20.0.
+
+
{2 Default Behavior}
+
+
By default ([{`Move}]), after displaying an image the cursor advances:
+
- Right by the number of columns the image occupies
+
- Down by the number of rows the image occupies
+
+
This matches how the cursor moves after printing text, allowing images
+
to flow naturally with text content.
+
+
{2 Static Cursor}
+
+
With [{`Static}], the cursor remains at its original position. This is
+
useful when:
+
- Overlaying images on existing content
+
- Positioning multiple images relative to the same starting point
+
- Implementing custom cursor management
+
+
{2 Relative Placements}
+
+
Note: When using relative placements (positioning images relative to
+
other placements), the cursor never moves regardless of this setting. *)
type t = [ `Move | `Static ]
(** Cursor movement behavior.
+
- [`Move] - Advance cursor past the displayed image (default).
+
Cursor moves right by the number of columns and down by the
+
number of rows occupied by the image.
+
- [`Static] - Keep cursor at its original position. The image
+
is displayed but cursor position is unchanged. *)
val to_int : t -> int
+
(** Convert to protocol integer.
+
+
Returns 0 for [`Move] or 1 for [`Static].
+
These values are used in the [C=] control data key. *)
+75 -15
lib/kgp_delete.mli
···
(** Image Deletion Target
-
Specifies which images or placements to delete. Each deletion type has
-
two variants: one that only removes placements and one that also frees
-
the underlying image data. *)
type t =
[ `All_visible
···
| `Frames_and_free ]
(** Deletion target specification.
-
- [`All_visible] - All visible placements
-
- [`By_id (id, placement_id)] - By image ID and optional placement ID
-
- [`By_number (n, placement_id)] - By image number and optional placement ID
-
- [`At_cursor] - Placement at cursor position
-
- [`At_cell (x, y)] - Placement at cell coordinates
-
- [`At_cell_z (x, y, z)] - Placement at cell with specific z-index
-
- [`By_column c] - All placements in column c
-
- [`By_row r] - All placements in row r
- [`By_z_index z] - All placements with z-index z
-
- [`By_id_range (min, max)] - All images with IDs in range
-
- [`Frames] - Animation frames only
-
The [_and_free] variants also release the image data from memory. *)
val to_char : t -> char
-
(** Convert to protocol character for the delete command. *)
···
(** Image Deletion Target
+
Specifies which images or placements to delete.
+
+
{2 Protocol Details}
+
+
Deletion is performed with action [a=d] and the [d] key specifies
+
the deletion type. The [d] key uses single characters:
+
+
{v
+
| Char | Meaning |
+
|------|--------------------------------------------------------|
+
| a/A | All placements visible on screen |
+
| i/I | By image ID (with optional placement ID) |
+
| n/N | By image number (newest with that number) |
+
| c/C | At current cursor position |
+
| p/P | At specific cell coordinates (x, y) |
+
| q/Q | At specific cell with z-index (x, y, z) |
+
| x/X | All in specific column |
+
| y/Y | All in specific row |
+
| z/Z | All with specific z-index |
+
| r/R | By image ID range (min_id to max_id) |
+
| f/F | Animation frames only |
+
v}
+
+
{2 Placements vs Image Data}
+
+
Each deletion type has two variants:
+
- {b Lowercase}: Removes placements only. The image data remains in
+
memory and can be displayed again later.
+
- {b Uppercase}: Removes placements AND frees the image data. The
+
image cannot be displayed again without retransmitting.
+
+
Example: [{`By_id (42, None)}] removes all placements of image 42 but
+
keeps the data. [{`By_id_and_free (42, None)}] removes placements and
+
frees the image data.
+
+
{2 Placement IDs}
+
+
When deleting by image ID or number, an optional placement ID can be
+
specified to delete only a specific placement. If [None], all placements
+
of that image are deleted.
+
+
{2 Coordinate-Based Deletion}
+
+
For [{`At_cell}] and [{`At_cell_z}], coordinates are 0-based cell
+
positions (not pixel positions). Only placements that intersect the
+
specified cell are deleted.
+
+
{2 Virtual Placements}
+
+
Virtual placements (used for Unicode placeholder mode) are only affected
+
by: [{`By_id}], [{`By_id_and_free}], [{`By_number}], [{`By_number_and_free}],
+
[{`By_id_range}], and [{`By_id_range_and_free}]. Other deletion commands
+
do not affect virtual placements. *)
type t =
[ `All_visible
···
| `Frames_and_free ]
(** Deletion target specification.
+
{b Screen-based:}
+
- [`All_visible] - All placements currently visible on screen
+
- [`At_cursor] - Placements at current cursor position
+
- [`At_cell (x, y)] - Placements intersecting cell at column x, row y
+
- [`At_cell_z (x, y, z)] - Like [`At_cell] but only with z-index z
+
- [`By_column x] - All placements intersecting column x
+
- [`By_row y] - All placements intersecting row y
- [`By_z_index z] - All placements with z-index z
+
{b ID-based:}
+
- [`By_id (id, placement_id)] - By image ID. If [placement_id] is
+
[Some p], only that specific placement; if [None], all placements.
+
- [`By_number (n, placement_id)] - By image number (newest image
+
with that number). Placement ID works as above.
+
- [`By_id_range (min, max)] - All images with IDs in range [min..max]
+
+
{b Animation:}
+
- [`Frames] - Animation frames only (not the base image)
+
+
All variants have an [_and_free] version that also releases image data. *)
val to_char : t -> char
+
(** Convert to protocol character for the delete command.
+
+
Returns the character used in the [d=] control data key. Lowercase
+
for placement-only deletion, uppercase for deletion with data free. *)
+37 -5
lib/kgp_format.mli
···
(** Image Data Format
-
Specifies the pixel format of image data being transmitted. *)
type t = [ `Rgba32 | `Rgb24 | `Png ]
(** Image data formats.
-
- [`Rgba32] - 32-bit RGBA (4 bytes per pixel)
-
- [`Rgb24] - 24-bit RGB (3 bytes per pixel)
-
- [`Png] - PNG encoded data *)
val to_int : t -> int
-
(** Convert to protocol integer value (32, 24, or 100). *)
···
(** Image Data Format
+
Specifies the pixel format of image data being transmitted to the terminal.
+
+
{2 Protocol Details}
+
+
The format is specified via the [f] key in the control data:
+
- [f=24] for RGB (3 bytes per pixel)
+
- [f=32] for RGBA (4 bytes per pixel, default)
+
- [f=100] for PNG
+
+
{2 Raw Pixel Formats}
+
+
For [{`Rgb24}] and [{`Rgba32}], the data consists of raw pixel values in
+
row-major order (left-to-right, top-to-bottom). The image dimensions must
+
be specified via the [width] and [height] parameters.
+
+
- [{`Rgb24}]: 3 bytes per pixel in sRGB color space (red, green, blue)
+
- [{`Rgba32}]: 4 bytes per pixel (red, green, blue, alpha)
+
+
{2 PNG Format}
+
+
For [{`Png}], the data is a complete PNG image. The terminal extracts
+
dimensions from PNG metadata, so [width] and [height] are optional.
+
+
When using both PNG format and zlib compression, you must also specify
+
the [size] parameter with the uncompressed PNG data size. *)
type t = [ `Rgba32 | `Rgb24 | `Png ]
(** Image data formats.
+
- [`Rgba32] - 32-bit RGBA (4 bytes per pixel). Default format.
+
Pixels are ordered red, green, blue, alpha. Alpha of 255 is fully
+
opaque, 0 is fully transparent.
+
- [`Rgb24] - 24-bit RGB (3 bytes per pixel). No alpha channel;
+
pixels are fully opaque. More compact than RGBA for opaque images.
+
- [`Png] - PNG encoded data. The terminal decodes the PNG internally.
+
Supports all PNG color types and bit depths. Most convenient format
+
as dimensions are embedded in the data. *)
val to_int : t -> int
+
(** Convert to protocol integer value.
+
+
Returns 24 for [`Rgb24], 32 for [`Rgba32], or 100 for [`Png].
+
These values are used in the [f=] control data key. *)
+93 -11
lib/kgp_frame.mli
···
-
(** Kitty Graphics Protocol Frame
-
Animation frame configuration. *)
type t
-
(** Animation frame configuration. *)
val make :
?x:int ->
···
t
(** Create a frame specification.
-
@param x Left edge where frame data is placed (pixels)
-
@param y Top edge where frame data is placed (pixels)
-
@param base_frame 1-based frame number to use as background canvas
-
@param edit_frame 1-based frame number to edit (0 = new frame)
-
@param gap_ms Delay before next frame in milliseconds
-
@param composition How to blend pixels onto the canvas
-
@param background_color 32-bit RGBA background when no base frame *)
val empty : t
-
(** Empty frame spec with defaults. *)
(** {1 Field Accessors} *)
val x : t -> int option
val y : t -> int option
val base_frame : t -> int option
val edit_frame : t -> int option
val gap_ms : t -> int option
val composition : t -> Kgp_composition.t option
val background_color : t -> int32 option
···
+
(** Animation Frame Configuration
+
+
Configuration for adding or editing animation frames. Frames can be
+
full images or partial updates (rectangles), with options for timing
+
and composition.
+
+
{2 Protocol Overview}
+
Animations are created by:
+
1. Transmitting a base image (becomes frame 1)
+
2. Adding frames using the frame action ([a=f])
+
3. Controlling playback with animation commands
+
+
Frame numbers are 1-based:
+
- Frame 1: The original/base image
+
- Frame 2+: Added animation frames
+
+
{2 Frame Positioning}
+
+
For partial frame updates, [x] and [y] specify where the new pixel
+
data is placed within the frame canvas:
+
- [x]: Left edge position in pixels (default 0)
+
- [y]: Top edge position in pixels (default 0)
+
+
The frame data dimensions come from the [width] and [height] parameters
+
of the frame command.
+
+
{2 Frame Canvas}
+
+
Each frame needs a background canvas to composite onto. Options:
+
+
{b Solid color background} ([background_color]):
+
Use a 32-bit RGBA color. Format: [0xRRGGBBAA] where AA is alpha.
+
Default is 0 (transparent black).
+
+
{b Copy from existing frame} ([base_frame]):
+
Use another frame as the starting canvas. Specified as 1-based frame
+
number. The base frame's pixels are copied, then new data is composited.
+
+
{2 Editing Existing Frames}
+
+
Instead of creating a new frame, you can edit an existing one:
+
- Set [edit_frame] to the 1-based frame number
+
- The frame itself becomes the canvas
+
- New data is composited onto it
+
+
{2 Frame Timing}
+
+
The [gap_ms] parameter controls the delay before transitioning to
+
the next frame:
+
- Positive value: Delay in milliseconds
+
- Zero: Ignored (keeps existing gap)
+
- Negative value: "Gapless" frame - not displayed, used as a base
+
for other frames
+
+
Default gap for new frames is 40ms. The root frame (frame 1) has
+
a default gap of 0ms.
+
+
{2 Composition Mode}
+
+
The [composition] parameter controls how new pixel data is blended
+
onto the canvas. *)
type t
+
(** Animation frame configuration. Opaque type; use {!make} to construct. *)
val make :
?x:int ->
···
t
(** Create a frame specification.
+
@param x Left edge where frame data is placed in pixels (default 0).
+
Protocol key: [x].
+
@param y Top edge where frame data is placed in pixels (default 0).
+
Protocol key: [y].
+
@param base_frame 1-based frame number to use as background canvas.
+
Frame 1 is the root image. Protocol key: [c].
+
@param edit_frame 1-based frame number to edit instead of creating new.
+
If 0 or unset, a new frame is created. Protocol key: [r].
+
@param gap_ms Delay before next frame in milliseconds. Negative values
+
create gapless frames. Protocol key: [z].
+
@param composition How to blend new pixels onto the canvas.
+
Default is alpha blending. Protocol key: [X].
+
@param background_color 32-bit RGBA background color when not using
+
a base frame. Format: [0xRRGGBBAA]. Protocol key: [Y]. *)
val empty : t
+
(** Empty frame spec with all defaults.
+
+
Creates a new frame with transparent black background, composited
+
at position (0, 0) with default timing (40ms gap). *)
(** {1 Field Accessors} *)
val x : t -> int option
+
(** Left edge position for frame data in pixels. *)
+
val y : t -> int option
+
(** Top edge position for frame data in pixels. *)
+
val base_frame : t -> int option
+
(** 1-based frame number to use as background canvas. *)
+
val edit_frame : t -> int option
+
(** 1-based frame number being edited (0 or None = new frame). *)
+
val gap_ms : t -> int option
+
(** Delay before next frame in milliseconds. *)
+
val composition : t -> Kgp_composition.t option
+
(** Pixel composition mode. *)
+
val background_color : t -> int32 option
+
(** 32-bit RGBA background color. *)
+114 -16
lib/kgp_placement.mli
···
-
(** Kitty Graphics Protocol Placement
-
Configuration for where and how to display images. *)
type t
-
(** Placement configuration. *)
val make :
?source_x:int ->
···
t
(** Create a placement configuration.
-
@param source_x Left edge of source rectangle in pixels (default 0)
-
@param source_y Top edge of source rectangle in pixels (default 0)
-
@param source_width Width of source rectangle (default: full width)
-
@param source_height Height of source rectangle (default: full height)
-
@param cell_x_offset X offset within the first cell in pixels
-
@param cell_y_offset Y offset within the first cell in pixels
-
@param columns Number of columns to display over (scales image)
-
@param rows Number of rows to display over (scales image)
-
@param z_index Stacking order (negative = under text)
-
@param placement_id Unique ID for this placement
-
@param cursor Cursor movement policy after display
-
@param unicode_placeholder Create virtual placement for Unicode mode *)
val empty : t
-
(** Empty placement with all defaults. *)
(** {1 Field Accessors} *)
val source_x : t -> int option
val source_y : t -> int option
val source_width : t -> int option
val source_height : t -> int option
val cell_x_offset : t -> int option
val cell_y_offset : t -> int option
val columns : t -> int option
val rows : t -> int option
val z_index : t -> int option
val placement_id : t -> int option
val cursor : t -> Kgp_cursor.t option
val unicode_placeholder : t -> bool
···
+
(** Image Placement Configuration
+
+
Configuration for where and how to display images. Placements control
+
cropping, scaling, positioning, and layering of images.
+
+
{2 Protocol Overview}
+
+
When displaying an image, the protocol allows specifying:
+
- Which part of the source image to display (source rectangle)
+
- Where to display it (cell position and pixel offsets)
+
- How large to display it (scaling to cell dimensions)
+
- How it layers with other content (z-index)
+
- Whether it can be referenced via Unicode placeholders
+
+
{2 Source Rectangle}
+
+
The source rectangle specifies which portion of the image to display:
+
- [source_x], [source_y]: Top-left corner in pixels (default: 0, 0)
+
- [source_width], [source_height]: Size in pixels (default: full image)
+
+
The displayed area is the intersection of this rectangle with the
+
actual image bounds. This allows cropping images without modifying
+
the original data.
+
+
{2 Cell-Based Sizing}
+
+
Images are sized in terminal cells:
+
- [columns]: Number of columns to span (width in cells)
+
- [rows]: Number of rows to span (height in cells)
+
+
If both are specified, the source rectangle is scaled to fit.
+
If only one is specified, the other is computed to maintain aspect ratio.
+
If neither is specified, the image is displayed at natural size.
+
{2 Pixel Offsets}
+
+
Fine-grained positioning within the starting cell:
+
- [cell_x_offset]: Horizontal offset in pixels from cell left edge
+
- [cell_y_offset]: Vertical offset in pixels from cell top edge
+
+
These offsets must be smaller than the cell dimensions.
+
+
{2 Z-Index Layering}
+
+
The [z_index] controls vertical stacking:
+
- Positive values: drawn above text
+
- Zero: drawn at text level
+
- Negative values: drawn below text
+
- Values < INT32_MIN/2 (-1,073,741,824): drawn under cells with
+
non-default background colors
+
+
Overlapping images with the same z-index are ordered by image ID
+
(lower ID draws first/underneath).
+
+
{2 Placement IDs}
+
+
Each placement can have a unique [placement_id] (1-4294967295). This
+
enables:
+
- Updating a specific placement without affecting others
+
- Deleting specific placements
+
- Moving placements by resending with same image_id + placement_id
+
+
If [placement_id] is 0 or unspecified, each display creates an
+
independent placement. *)
type t
+
(** Placement configuration. Opaque type; use {!make} to construct. *)
val make :
?source_x:int ->
···
t
(** Create a placement configuration.
+
@param source_x Left edge of source rectangle in pixels (default 0).
+
Protocol key: [x].
+
@param source_y Top edge of source rectangle in pixels (default 0).
+
Protocol key: [y].
+
@param source_width Width of source rectangle in pixels.
+
Default is the full image width. Protocol key: [w].
+
@param source_height Height of source rectangle in pixels.
+
Default is the full image height. Protocol key: [h].
+
@param cell_x_offset X offset within the first cell in pixels.
+
Must be smaller than cell width. Protocol key: [X].
+
@param cell_y_offset Y offset within the first cell in pixels.
+
Must be smaller than cell height. Protocol key: [Y].
+
@param columns Number of columns to display over. Image is scaled
+
to fit. Protocol key: [c].
+
@param rows Number of rows to display over. Image is scaled to fit.
+
Protocol key: [r].
+
@param z_index Stacking order. Positive = above text, negative = below.
+
Protocol key: [z].
+
@param placement_id Unique ID (1-4294967295) for this placement.
+
Allows updating/deleting specific placements. Protocol key: [p].
+
@param cursor Cursor movement policy after display.
+
@param unicode_placeholder If true, creates a virtual (invisible)
+
placement for Unicode placeholder mode. Protocol key: [U=1]. *)
val empty : t
+
(** Empty placement with all defaults.
+
+
Equivalent to [make ()]. The image displays at natural size at the
+
current cursor position with default z-index (0). *)
(** {1 Field Accessors} *)
val source_x : t -> int option
+
(** Left edge of source rectangle in pixels. *)
+
val source_y : t -> int option
+
(** Top edge of source rectangle in pixels. *)
+
val source_width : t -> int option
+
(** Width of source rectangle in pixels. *)
+
val source_height : t -> int option
+
(** Height of source rectangle in pixels. *)
+
val cell_x_offset : t -> int option
+
(** X offset within the first cell in pixels. *)
+
val cell_y_offset : t -> int option
+
(** Y offset within the first cell in pixels. *)
+
val columns : t -> int option
+
(** Number of columns to display over. *)
+
val rows : t -> int option
+
(** Number of rows to display over. *)
+
val z_index : t -> int option
+
(** Stacking order (z-index). *)
+
val placement_id : t -> int option
+
(** Unique placement identifier. *)
+
val cursor : t -> Kgp_cursor.t option
+
(** Cursor movement policy. *)
+
val unicode_placeholder : t -> bool
+
(** Whether this is a virtual placement for Unicode mode. *)
+40 -5
lib/kgp_quiet.mli
···
(** Response Suppression Level
-
Controls which terminal responses are sent back to the application. *)
type t = [ `Noisy | `Errors_only | `Silent ]
(** Response suppression levels.
-
- [`Noisy] - Send all responses (default)
-
- [`Errors_only] - Suppress OK responses, only send errors
-
- [`Silent] - Suppress all responses *)
val to_int : t -> int
-
(** Convert to protocol integer (0, 1, or 2). *)
···
(** Response Suppression Level
+
Controls which terminal responses are sent back to the application.
+
+
{2 Protocol Details}
+
+
The quiet level is specified via the [q] key in the control data:
+
- [q=0] or no [q] key: send all responses (default)
+
- [q=1]: suppress OK responses, only send errors
+
- [q=2]: suppress all responses
+
+
{2 Terminal Responses}
+
+
Normally, when an [image_id] is specified, the terminal responds:
+
- On success: [ESC _Gi=ID;OK ESC]
+
- On failure: [ESC _Gi=ID;ECODE:message ESC]
+
+
Response processing requires reading from the terminal, which can be
+
complex in some applications.
+
+
{2 Use Cases}
+
+
[{`Noisy}] (default): Use when you need to verify operations succeeded
+
or want to handle errors programmatically.
+
+
[{`Errors_only}]: Use when you want to detect failures but don't need
+
confirmation of success. Reduces response traffic.
+
+
[{`Silent}]: Use in fire-and-forget scenarios like shell scripts or
+
when the application cannot easily read terminal responses. Also useful
+
for high-frequency animation updates where response processing would
+
add latency. *)
type t = [ `Noisy | `Errors_only | `Silent ]
(** Response suppression levels.
+
- [`Noisy] - Send all responses including OK confirmations (default).
+
Required for detecting success and getting assigned image IDs.
+
- [`Errors_only] - Suppress OK responses, only send error messages.
+
Useful when success is expected but errors should be caught.
+
- [`Silent] - Suppress all responses including errors. Useful for
+
shell scripts or when response handling is not possible. *)
val to_int : t -> int
+
(** Convert to protocol integer.
+
+
Returns 0 for [`Noisy], 1 for [`Errors_only], or 2 for [`Silent].
+
These values are used in the [q=] control data key. *)
+52 -5
lib/kgp_transmission.mli
···
(** Data Transmission Method
-
Specifies how image data is transmitted to the terminal. *)
type t = [ `Direct | `File | `Tempfile ]
(** Transmission methods.
-
- [`Direct] - Data is sent inline in the escape sequence
-
- [`File] - Terminal reads from a file path
-
- [`Tempfile] - Terminal reads and deletes a temporary file *)
val to_char : t -> char
-
(** Convert to protocol character ('d', 'f', or 't'). *)
···
(** Data Transmission Method
+
Specifies how image data is transmitted to the terminal.
+
+
{2 Protocol Details}
+
+
The transmission method is specified via the [t] key in the control data:
+
- [t=d] for direct (inline) transmission (default)
+
- [t=f] for regular file
+
- [t=t] for temporary file (deleted after reading)
+
+
{2 Direct Transmission}
+
+
[{`Direct}] sends data inline within the escape sequence itself. The data
+
is base64-encoded in the payload section. This is the simplest method and
+
works over any connection (including SSH).
+
+
For images larger than 4096 bytes (after base64 encoding), the data is
+
automatically split into chunks using the [m=] key:
+
- [m=1] indicates more chunks follow
+
- [m=0] indicates the final chunk
+
+
{2 File Transmission}
+
+
[{`File}] tells the terminal to read data from a file path. The path is
+
sent base64-encoded in the payload. Additional parameters:
+
- [S=] specifies the number of bytes to read
+
- [O=] specifies the byte offset to start reading from
+
+
File transmission only works when the terminal and client share a
+
filesystem (i.e., local terminals, not SSH).
+
+
Security: The terminal will refuse to read device files, sockets, or
+
files in sensitive locations like [/proc], [/sys], or [/dev].
+
+
{2 Temporary File Transmission}
+
+
[{`Tempfile}] is like [{`File}] but the terminal deletes the file after
+
reading. The file must be in a recognized temporary directory:
+
- [/tmp]
+
- [/dev/shm]
+
- The [TMPDIR] environment variable location
+
- Platform-specific temp directories containing [tty-graphics-protocol] *)
type t = [ `Direct | `File | `Tempfile ]
(** Transmission methods.
+
- [`Direct] - Data is sent inline in the escape sequence (base64-encoded).
+
Works over any connection including SSH. Automatic chunking for large
+
images.
+
- [`File] - Terminal reads from a file path sent in the payload.
+
Only works when terminal and client share a filesystem.
+
- [`Tempfile] - Like [`File] but terminal deletes the file after reading.
+
File must be in a recognized temporary directory. *)
val to_char : t -> char
+
(** Convert to protocol character.
+
+
Returns ['d'] for [`Direct], ['f'] for [`File], or ['t'] for [`Tempfile].
+
These values are used in the [t=] control data key. *)