Skip to content

Support recording and rendering Kitty graphics protocol output (Kitty, Ghostty) #87

Closed

Description

@tig

Summary

The recording stack (tuirec + the tig/avt and tig/agg forks) supports Sixel graphics (#70, #72, #73, #77, #78) but does not support the Kitty graphics protocol (Kitty, Ghostty). Recording a Kitty-graphics app captures only the text cells / cell-rendered fallback — the inline images are dropped from the cast/GIF.

This is the Kitty counterpart of the Sixel umbrella #70, and the work splits across the same three layers.

Why this matters now

  • Terminal.Gui PR gui-cs/Terminal.Gui#5493 adds Kitty graphics protocol support and makes Kitty the preferred protocol, with Sixel as the fallback for non-Kitty terminals (Windows Terminal, etc). The new protocol-agnostic API is ImageView.UseRasterGraphics / IsUsingRasterGraphics.
  • Apps built on Terminal.Gui therefore now emit Kitty graphics on Kitty/Ghostty terminals. Concretely, winprint's TUI page-preview (PreviewPane → ImageView) emits Kitty graphics when run under Ghostty.
  • Ghostty is Kitty-only (no Sixel) and is a primary daily-driver terminal. On Ghostty the recording stack currently captures only the colored-cell fallback, so a recorded GIF/PNG cannot show — or prove — the real inline raster preview. Full-fidelity capture + visual regression for raster UIs is unavailable on Kitty terminals until the stack speaks the protocol.

Expected

tuirec should capture and render Kitty graphics protocol sequences (ESC _ G <control> ; <base64> ESC \) so terminal images are represented in the generated cast/GIF — the same way it now does for Sixel — or clearly report that Kitty capture is unsupported.

Actual

Kitty APC graphics sequences are not answered (so the app may not enable Kitty output), not modeled by avt, and not rendered by agg. The resulting cast/GIF contains the text UI but no Kitty image payloads.

Protocol notes (how Kitty differs from Sixel)

  • Transport is APC, not DCS: images arrive as ESC _ G <control data> ; <base64 payload> ESC \ rather than Sixel's ESC P ... ESC \. Large images are chunked across multiple APCs (m=1 on every chunk but the last, which sends m=0); the payload must be reassembled before base64-decode.
  • Capability handshake is a graphics query, not DA1: apps detect support by sending a query action (a=q, e.g. ESC _ G i=<id>,a=q,s=1,v=1,t=d,f=24 ; <base64 1px> ESC \) and reading the response (ESC _ G i=<id> ; OK ESC \). The recorder must answer OK during the handshake window so the app turns Kitty output on — this is the Kitty analogue of Answer sixel handshake queries so apps emit and size sixel correctly #77 (which answers DA1 for Sixel). Cell/pixel-size reporting (CSI 14/16/18 t) is already in place from the Sixel work and is shared.
  • Minimum useful subset: direct RGB/RGBA transmit-and-display at the cursor cell (a=T, f=24/f=32, t=d). Unicode-placeholder placement, z-index, and a=d deletion can follow.

Proposed work (mirrors the Sixel breakdown)

Repro context

  • App: any Terminal.Gui v2 app emitting raster graphics with ImageView.UseRasterGraphics on a Kitty/Ghostty terminal (e.g. winprint wp page preview), or the UICatalog Mandelbrot scenario once it advertises Kitty.
  • Record with tuirec record on macOS/Linux; inspect the .cast for Kitty APC starts (\e_G) — currently none are preserved/rendered.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions