hottyHTML over the TTY

Architecture

hotty (HTML over the TTY) bridges two traditionally separate worlds: the streaming character-cell grid of the Unix terminal and the rich layout tree of HTML and CSS.

It does so without transforming the terminal into an Electron container, without requiring local web servers, and without breaking the Unix pipeline. Everything travels in-band across standard input and output streams.

stdout: OSC 7279 doc & delta click & input click & input Terminal Application hotty-demo / Bubble Tea In-band TTY Stream PTY / SSH / Containers Native Host: hottyterm Ghostty compositor in Zig Dioxus Blitz Engine Stylo + Taffy + Vello Web Host: Browser xterm.js + xterm-addon-hotty Sandboxed <iframe> Native Blink / Gecko Engine In-band Input Events stdin: OSC 7279 ev

1. The Wire Protocol

A terminal program communicates with the host entirely through terminal escape sequences.


2. In the Browser: Reusing the Host Engine

Building an in-browser terminal emulator that supports HTML usually faces a dilemma: compiling an HTML layout engine to WebAssembly introduces megabytes of duplicate binary payload and redundant layout passes.

With xterm-addon-hotty, the solution reuses what is already present: the host browser is already a mature, hardware-accelerated HTML and CSS engine.

xterm.js Canvas Grid Character Cells (c, r) Cell-to-Pixel Projection Viewport Bounding Box Sandboxed <iframe> Overlay CSS Isolation & Security Native Browser Engine Blink / Gecko / WebKit
  1. Cell-to-Pixel Projection: xterm-addon-hotty monitors font metrics, character cell dimensions, and scroll offsets in xterm.js. When the program places a surface at (c=10, r=4, w=60, h=auto), the addon computes the exact viewport bounding box in CSS pixels.
  2. Sandboxed Iframes: Each surface is rendered inside a lightweight, sandboxed <iframe> positioned directly above the terminal canvas:
    • CSS isolation: Terminal styles and surface styles remain independent.
    • Security: No script execution, no storage access, and no navigation permissions unless explicitly granted by policy.
    • Native fidelity: Subpixel font rendering, flexbox, CSS grid, SVG, transitions, and native form controls work out of the box with zero runtime overhead.
  3. Transparent Event Marshalling: When the user clicks or types inside an iframe, standard DOM event listeners intercept the interaction, prevent default browser navigation, and serialize the event into the hotty a=ev format on the virtual PTY. The program receives the event seamlessly on standard input.

3. In Native Terminals: Embedded Rendering with Blitz

In a native desktop terminal like hottyterm, there is no ambient browser engine. Embedding a full browser engine like Chromium or WebKit would introduce gigabytes of memory consumption, slow cold starts, and complex dependencies.

hotty uses hotty-blitz, powered by Dioxus Blitz, a modular native Rust HTML and CSS rendering engine:

Native Integration in hottyterm

hottyterm is a fork of Ghostty (written in Zig) that incorporates hotty-blitz through a C ABI:

  1. In-Band Decoding: Ghostty's VT parser detects the OSC 7279 escape sequence as stdout is processed.
  2. Headless Layout: Documents are passed across the C ABI to hotty-blitz. Blitz parses the HTML/CSS, resolves styles via Stylo, computes geometry via Taffy, and renders the document into shared pixel buffers or GPU textures.
  3. Unified Compositor: Ghostty composites text cell glyphs and HTML surface textures within the same GPU render loop at full display refresh rates (60–120 Hz).
  4. Performance: Resizing, scrolling, and delta updates happen with sub-millisecond latency.

4. The Polyfill Strategy: Terminal Graphics Proxies

An architectural question that naturally arises is whether terminals without native hotty support can still display surfaces if they implement a terminal image protocol, such as the Kitty graphics protocol or Sixel.

In theory, an intermediary PTY proxy—such as the experimental hotty run utility in hotty-blitz—can bridge this gap:

  1. Proxying the PTY: The proxy wraps the application inside a virtual terminal stream, intercepting OSC 7279 escape sequences before they reach the host terminal.
  2. Headless Offscreen Rasterization: Intercepted HTML documents and delta updates are passed to a headless Blitz instance and rendered into offscreen image buffers.
  3. Graphics Protocol Emission: The rendered pixel buffers are encoded into Kitty graphics protocol escapes (ESC _G ... ST) and emitted into the host terminal's stream.

Architectural Trade-offs & Current Status

While translating markup to image escapes offers an interesting compatibility bridge for terminals like Kitty and WezTerm, this approach introduces significant architectural trade-offs:

For reliable deployment today, the stack emphasizes two robust paths: native hosts (hottyterm and xterm-addon-hotty) for interactive surfaces, and graceful cell fallback (CSI c) for standard terminals.


5. Acknowledgements

hotty builds upon the work of several foundational open-source projects and their maintainers:

Loading hotty-demo…