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.
1. The Wire Protocol
A terminal program communicates with the host entirely through terminal escape sequences.
- Handshake: At startup, the program sends
ESC ] 7279 ; a=q:n=1 STfollowed by standard Primary Device Attributes (CSI c). If the terminal supports hotty, it responds with its capabilities before answeringCSI c. IfCSI carrives first, the program knows it is talking to a conventional text terminal and falls back cleanly to drawing characters in cells. - Documents (
a=doc): Transmitted as base64-encoded HTML payloads. Documents are retained in host memory by name. - Placements (
a=place): Anchored to character-cell coordinates(col, row, width, height). A surface occupies a defined grid rectangle and moves with the terminal's text flow. - Deltas (
a=delta): Instead of retransmitting whole documents, programs send fine-grained deltas addressed directly by element ID (text,attr,var,morph). A streaming metric graph or counter update costs well under a hundred bytes on the wire, and a frame's changes to a surface travel together, as one list of ops. - Events (
a=ev): When a user clicks a button, types in an input field, or submits a form, the host packages the interaction as an escape sequence and writes it directly to the program'sstdin. To the program, interactive events arrive in the same stream as keyboard strokes.
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.
- Cell-to-Pixel Projection:
xterm-addon-hottymonitors 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. - 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.
- 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=evformat 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:
- Stylo (Parallel CSS Engine): Blitz leverages Stylo, the production-grade CSS styling engine developed by Mozilla and used in Firefox, resolving CSS cascading, selectors, and inheritance in parallel.
- Taffy: Fast flexbox and CSS grid layout algorithms implemented in pure Rust.
- Vello & Direct Compositing: Hardware-accelerated GPU path rasterization via Wgpu and Vello.
- Minimal Footprint: Complete modern CSS layout and vector drawing with a binary footprint measured in megabytes rather than hundreds of megabytes.
Native Integration in hottyterm
hottyterm is a fork of Ghostty (written in Zig) that incorporates hotty-blitz through a C ABI:
- In-Band Decoding: Ghostty's VT parser detects the
OSC 7279escape sequence as stdout is processed. - 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. - 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).
- 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:
- Proxying the PTY: The proxy wraps the application inside a virtual terminal stream, intercepting
OSC 7279escape sequences before they reach the host terminal. - Headless Offscreen Rasterization: Intercepted HTML documents and delta updates are passed to a headless Blitz instance and rendered into offscreen image buffers.
- 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:
- Loss of Semantic Interactivity: Unlike native surfaces—where text remains selectable, vector fonts stay sharp under zoom, and form controls accept native keyboard focus—rasterized image streams flatten the document, making text unselectable and requiring complex hit-testing layers for basic interaction.
- PTY Synchronization & Scrolling: Coordinating asynchronous image placements with terminal scrollback, window resizes, and full-screen TUI redraw cycles across PTY boundaries introduces challenging synchronization edge cases.
- Current Status: The
hotty runproxy is an active research area and proof-of-concept. It requires substantial QA and polish before it matches the reliability of native hosts.
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:
- Mitchell Hashimoto and the Ghostty Community: For Ghostty and
libghostty. Ghostty's high-performance Zig architecture, robust VT emulation, and clean multi-platform GPU compositor provided the foundation for buildinghottytermand proving native cell/HTML compositing. - Daniel Imms and the xterm.js Contributors: For xterm.js, the standard for web terminal emulation. Its reliable character-cell canvas, font measurement pipeline, and flexible addon architecture made
xterm-addon-hottyand the browser experience possible. - Jonathan Kelley and the Dioxus Labs Team: For Blitz. Their vision of a modular, embeddable Rust layout and rendering engine made lightweight, native terminal HTML rendering viable without browser bloat.
- The Servo and Mozilla Projects: For Stylo and the foundational layout engines that bring production-grade parallel CSS evaluation to independent native applications.