TIL
Back

OpenTUI's Zig Core

OpenTUI puts a TypeScript API over a native library written mainly in Zig. TypeScript owns the renderable tree, scheduler, input, and events. Native code owns Yoga layout primitives, cell buffers, frame diffing, and terminal output.1

Platform-specific npm packages ship a shared library that @opentui/core loads through Bun or Node foreign-function interfaces (FFI). JavaScript receives typed, generation-based handles rather than pointers, allowing Zig to reject stale handles.2

A frame has three passes. Yoga calculates flexbox layout. TypeScript walks the tree to apply positions, ordering, clipping, and culling, producing a flat command list. Those commands draw through FFI into Zig's OptimizedBuffer.3 Separate arrays store character identifiers, foregrounds, backgrounds, and attributes. Tagged identifiers represent pooled graphemes, wide-character continuation cells, and images.4

The renderer compares current and next screen buffers. It skips equal rows, then emits ANSI cursor, style, hyperlink, and text sequences only for changed cells. A frame with no cell, cursor, image, or pointer changes emits nothing. Images use Kitty graphics, Sixel, or Unicode block fallbacks.5

Output goes to a double-buffered stdout or memory backend, or a native span feed consumed by a custom TypeScript writable such as an SSH channel. The feed publishes whole frames and carries backpressure to the renderer. A failed write forces a later full repaint.6

The core also implements text editing, terminal emulation, images, audio, and clipboard access. The UI tree and event loop remain in TypeScript: OpenTUI is a split runtime.

References

  1. OpenTUI, repository overview and CliRenderer.

  2. OpenTUI, FFI bindings and handle registry.

  3. OpenTUI, Renderable.

  4. OpenTUI, optimized buffer.

  5. OpenTUI, native renderer.

  6. OpenTUI, output backends.