AbstractTUI
The terminal, composed. A reactive, compositor-grade terminal UI engine for Rust.
AbstractTUI is built on fine-grained reactive signals — not immediate mode, not a virtual DOM. Reading a signal inside a view tracks it; writing one re-runs exactly the computations that depended on it, and those re-renders damage exactly the screen regions they own. Damaged regions flow through a real compositor (z-ordered layers, alpha blending, per-layer offset/opacity), a frame diff, and a byte emitter that plays the terminal like an instrument — cursor-motion economy, minimal SGR runs, synchronized output where the terminal supports it. The result: an idle app emits zero bytes and allocates nothing, and a blinking cursor repaints one cell, not the screen.

The dashboard example — live line charts, sub-cell progress bars, a
software-rendered 3D mark, a scrolling event log, a sortable table, toasts and a
modal, all animating while the rest of the screen stays still.
3D in the terminal — a real GLB, rasterized to cells

cargo run --example viewer3d turning the standard damaged-helmet glTF
model (15,452 triangles) —
a hand-written perspective rasterizer with a z-buffer, textures and lighting,
presented through half-block, quadrant, sextant and braille mosaics. No GPU, no
external renderer.
The design system on one screen — restyled under one keypress

The gallery example — every token, widget state, chart, and text style on one
board. Pressing a key swaps the theme signal and the whole screen re-renders
through ordinary reactivity.
Highlights
- Widgets + layout — buttons, text inputs (with Codex-compatible
word/line navigation and word-delete chords), a multiline composer
(
TextAreawith history and completion dropdowns), selects (Select/Combobox/MultiSelectover anchored popups that layer above modals), lists and sortable tables with distinct selection and activation events (single click selects; Enter or double-click activates; lists also support trailing accessory columns, rich row labels, and row context requests that open reusable keyboard-accessibleContextMenupopups — seepresence_board), tabs, checkboxes, radio groups, scroll regions, panels (closable via an opt-in title-row ✕), a directoryFilePicker, badges, progress bars, spinners, modals, toasts, tooltips — plus the app-shell trio:PageHost(full pages behind one themed tab bar — container-reserved chords, reactive tab badges, overflow windowing),Drawer(edge-anchored overlay panels, modal or glanceable, sliding from any edge) andDrawerDock(a right-edge rail of always-visible vertical tabs, rendered portably as stacked graphemes, fronting docked side panels — one open at a time, fully collapsed otherwise, reactive badge dots) — arranged by a flexbox-style solver (row/column,grow,gap, padding) and a track-based grid (fr/cells/percent, spans). - Transcripts and documents —
Feedrenders append-only conversations and logs with keyed rich blocks (markdown, code with syntax and diff tinting, multi-ink rich lines, custom draw); streaming markdown items re-typeset only the open block per token and speak the full doc vocabulary — GFM tables (a streamed table renders as a table live), task lists, strikethrough, and lazy in-flow images.MarkdownViewadds the reading surface: heading outline with anchor jumps, and find-in-document with highlighted matches.Scroll::follow_tailpins to the bottom until the user scrolls and re-pins at the edge; a screen-text drag freezes a pinned tail until the copy or cancellation, so the rows under the highlight cannot slide away mid-selection. - Live data — feed the UI from background threads through
channel_source/latest_source/bounded_source(drop or coalesce policies with honest drop counters), a cancellableintervaltimer, and waker deduplication;TimeSerieshistory rings put relative time axes under the charts (a sampling pause draws as a hole, never a compressed x-axis), andreactive::connectionowns the reconnect lifecycle with jittered exponential backoff. An idle app still costs zero — offline included. - Selection + clipboard — drag to select rendered text (wide-glyph safe, pane-clamped), copy via OSC 52, and keep a live follow-tail transcript still while selecting; or suspend mouse capture for native terminal selection.
- 26 built-in themes — catppuccin, rose-pine, tokyo-night, nord, one-dark,
dracula, monokai, gruvbox, solarized, everforest and the Abstract originals —
over 36 semantic design tokens, contrast-audited against WCAG floors, and
hot-swappable at runtime through one signal.
ThemeSwitcheris the drop-in chrome: a ☾/☼ chip opening a grouped Dark/Light menu with live preview, or a one-click dark↔light toggle that remembers your theme per mode. Bring your own palette throughtheme::Paletteand it runs the same audited derivation the built-ins do. - Input everywhere — keyboard and mouse (click, hover, drag, wheel), the
kitty keyboard protocol and xterm modifyOtherKeys decoded automatically when
present, bracketed paste hardened against multi-megabyte and hostile input,
focus events, key chords with modifiers — plus a paste intercept
(
on_paste) with a cross-terminal file-drop classifier, so a file dropped onto the terminal becomes an attachment instead of pasted text. - Voice and AV plumbing — key press/release state with honest fidelity
(true hold detection where the terminal reports releases; never a
fabricated "held" on legacy wires), a
PushToTalkgesture built on it (hold-to-talk, labeled latch fallback, capture stops on focus loss), andMeter/AudioScopewidgets that render live levels with real ballistics and go fully idle when the signal does. - Images — PNG, JPEG (baseline and progressive), and GIF decoding built in, drawn through the best channel your terminal offers: kitty graphics, iTerm2, sixel, or unicode mosaic (half-block / quadrant / sextant / braille). Capability detection is automatic and every degradation is labeled, never silent.
- Animation — animated GIF and APNG play in the cell grid through
AnimatedImage, one timer per frame and nothing between frames. Video (.mp4,.mov,.avi,.webm) is NOT decoded — those codecs are patent-pooled and larger than this crate; the file is recognized, named, and refused with the command that converts it. - Software-rasterized 3D — load GLB files (node hierarchies, textures, vertex colors, animation, skinning) and render them into the same cell pipeline. No GPU, no native dependencies.
- Motion — cell shaders (shimmer, dissolve, hue-drift, and more) that cost work only where damage exists, plus tweens, easings, and timelines.
- A boot identity — a 2-second animated splash (3D mark with a pure-cell 2D
fallback), skippable with any key, auto-disabled on non-TTY,
NO_COLOR, andTERM=dumb. - Headless testing — drive the production pipeline against a captured terminal and assert on the rendered screen. No pty required.
- Screenshots — capture any screen as a plain value (
Driver::screenshot(), theapp::request_screenshotkey-bindable verb, or the VT model in headless tests) and export it as plain text, replayable ANSI, or a GitHub-renderable SVG — deterministic artifacts for docs, bug reports, and test evidence, with protocol-image regions honestly labeled. - Vector strokes + an extension family — a public sub-cell canvas
(braille/quadrant dot grids, lines, beziers, arcs, eighth-block
fills) in core, and diagram-class capability as opt-in sibling
crates:
abstracttui-graph(auto-layout + graph widget) andabstracttui-mermaid(honest-subset mermaid). See docs/graphs-and-diagrams.md.
Your first app
Fifteen lines, one import:
use *;
Tab focus, Enter/Space activation, and Ctrl+C quit are all defaults. The count
line re-renders fine-grained through dyn_view — nothing else repaints. Keys go
to the focused widget, and a screen that should start with the caret in a field
says so with .autofocus() — see
Focus — who receives keys. The
walkthrough lives in docs/getting-started.md.
Install
Rust 2021 edition. The dependency policy is deliberately austere — unicode-width,
unicode-segmentation, miniz_oxide, plus libc on unix / windows-sys on
Windows, and nothing else. ANSI emission, input parsing, the layout solver, the
signals runtime, PNG/JPEG decoding, glTF parsing, and the 3D rasterizer are all
implemented in-crate.
The extension family installs only when you need it (same MIT license, same dependency discipline, public core API only — ADR-0004):
Run the examples
Twenty-three runnable examples live in examples/ — ordered there as a learning path — plus three more in the extension crates, and every one exits cleanly with a notice when no interactive terminal is present, so they are safe to run anywhere. Start with these six:
dashboard— the flagship ops screen: charts, log tail, sortable table, toasts, modal help, spatial pane navigation.shell— the app shell: three full pages behind a globalPageHosttab bar (live tab badge, Ctrl+PgUp/PgDn, digit jumps) plusDrawerpanels from both edges (iinspector,gnav).gallery— the whole design system on one screen; one keypress restyles it.themes— every theme as a live card grid with a preview pane and measured contrast ratios.viewer3d— orbit a GLB model with measured fps (cargo run --example viewer3d -- path/to/model.glb).images— four mosaic families side by side, dithering, and pixel-protocol placement with the chosen channel named.
ABSTRACTTUI_THEME=rose-pine cargo run --example hello themes any example from
the environment; --caps on dashboard, viewer3d, and images prints the
detected capability report and exits.
The animations above are recorded straight from these examples with
vhs; the tapes live in
docs/media/ and regenerate with vhs docs/media/<name>.tape.
Platform support
| Platform | Status |
|---|---|
| macOS | Verified — the full test suite includes live pty tests (real controlling terminal, signal-driven resize, suspend/resume). |
| Linux | Verified — same unix code paths; the full default suite runs in CI on ubuntu, and the live pty suite runs in a dedicated CI job (live pty (ubuntu), real pseudo-terminal, examples prebuilt). |
| Windows | Best-effort — compiles clean and lint-free against the MSVC target, the library suite runs in CI on a real Windows runner, but it has not yet been run on a live Windows console. Treat the first Windows run as a beta event. |
Minimum supported Rust version: 1.87 (declared as rust-version in
Cargo.toml and checked by a pinned-toolchain CI job; raising it is a
minor-version event, declared in the CHANGELOG).
The terminal is always restored — on quit, on panic, and on Ctrl+Z suspend — including cursor style, mouse modes, and kitty keyboard flags.
Performance
Measured (release build, M-class laptop): a full 200×60 diff+present costs
~0.5 ms, a keystroke reaches the painted frame in ~50 µs through the real event
loop, and an idle app costs zero — zero bytes written, zero heap allocations,
zero wakeups. The allocation budgets gate every CI run; the release-mode
timing budgets and byte-emission ratchets gate on a weekly scheduled job
(perf.yml, also runnable by hand — see CONTRIBUTING) — budgets, not
aspirations, with the honest split stated.
Documentation
- Getting started — install to first pixels, step by step.
- Architecture — signals, damage, the compositor, the render pipeline.
- API guide — the public surface, module by module.
- Graphs and diagrams — the extension family: graph layout,
GraphView, the mermaid subset. - Live data — background threads into the UI, bounded and honest.
- FAQ and Troubleshooting.
- Examples catalog — what each demo proves and the keys it answers to.
- API reference on docs.rs (family crates: abstracttui-graph, abstracttui-mermaid).
License
MIT — see LICENSE.