Expand description
tuika — the application framework for Rust terminal UIs, built over
ratatui.
Where ratatui owns the cell buffer and the widgets drawn into it, tuika
owns the layer an application needs above that, so a TUI starts as a
described screen rather than a render loop.
tuika adds the pieces ratatui leaves to you — a flexbox-style layout
solver, anchored overlays, focus/input-ownership, a host for either screen
mode (alternate screen or a split footer over live terminal scrollback),
and a set of components (text, boxes, scroll, select, spinner, progress) —
while letting ratatui keep ownership of the cell buffer and its diff against
the terminal. It builds against ratatui-core (and ratatui-crossterm for
the backend) directly rather than the ratatui umbrella — it renders none of
ratatui’s own widgets — so ratatui-widgets and ratatui-macros stay out of
its dependency tree. It otherwise depends only on crossterm, textwrap,
unicode-segmentation, and unicode-width.
It was extracted from the yolop coding agent, whose full-screen renderer is built on it, but it knows nothing about any host application.
§Model
- Views (
view::View) are ephemeral, rebuilt from application state each frame; ratatui diffs the resulting cell buffer, so this is cheap. - State that must persist across frames (
components::ScrollState,components::SelectState,focus::FocusRegistry) lives in the host, in theStatefulWidgetidiom. - Layout is a flexbox subset (
layout); overlays (overlay) anchor over the base tree; the host (host) owns the screen (screen::ScreenMode— the alternate screen, or a split footer over live terminal scrollback), translates crossterm input, and composites the frame. - Scene composition is owned with
Scene, or borrows a host-state view for one frame withScopedScene; both use the same ordered overlay and focus semantics.
§Finding things
The crate root re-exports the framework: the view model, layout,
events, styling, and the host seam — the types you compose with. The
widgets themselves live in components. Owned Element trees use
Scene; a concrete root that borrows large application state uses
ScopedScene without cloning it. Everything that talks to the
terminal outside the cell grid (clipboard, hyperlinks, images, native
progress, capability detection) lives in term.
For application code that wants the common surface in one line, glob-import
prelude:
use tuika::prelude::*;
let screen = element(Flex::column().fixed(1, element(Text::raw("hello"))));§Extending
Add a component by implementing view::View in a new module under
components. No registration step; containers accept any boxed View.
Existing ratatui widgets should normally be wrapped in
RatatuiView, which preserves Tuika clipping without
exposing the frame buffer. TerminalSession and runner::Runner are
optional host-side lifecycle helpers; with feature = "async",
runner::AsyncRunner is the same loop for hosts that already
run on Tokio.
Re-exports§
pub use event::Event;pub use event::EventFlow;pub use event::Key;pub use event::KeyCode;pub use event::Mouse;pub use event::MouseButton;pub use event::MouseKind;pub use geometry::Padding;pub use geometry::Size;pub use host::TerminalSession;pub use host::paint;pub use host::paint_scene;pub use host::paint_with_sheet;pub use host::translate_event;pub use layout::Align;pub use layout::Dimension;pub use layout::Direction;pub use layout::Justify;pub use layout::LayoutStyle;pub use overlay::Overlay;pub use overlay::OverlaySpec;pub use runner::AsyncRunner;asyncpub use runner::Signal;asyncpub use runner::Runner;pub use runner::RunnerConfig;pub use scene::Backdrop;pub use scene::Scene;pub use scene::SceneOverlay;pub use scene::ScopedScene;pub use screen::ScreenMode;pub use screen::Scrollback;pub use style::SemanticRole;pub use style::StyleSheet;pub use style::Theme;pub use surface::Surface;pub use view::Element;pub use view::RenderCtx;pub use view::View;pub use view::element;
Modules§
- anim
- Animation helpers: easing curves and a frame phase.
- components
- Component library.
- event
- Input events, decoupled from crossterm.
- focus
- Focus registry and input ownership.
- framebuffer
FrameBuffer— a mutable RGBA canvas with sprite blitting and per-pixel shaders, rendered to cells with half-blocks.- geometry
- Geometry helpers shared across
tuika. - highlight
- The
Highlighterseam — how a host plugs syntax highlighting intoCodeBlockandMarkdownwithout tuika taking on any grammar dependency. - host
- Terminal host: screen-mode lifecycle, event translation, compositor.
- interop
- Safe interoperability with ratatui widgets.
- keymap
- A host-agnostic keymap engine: declarative key bindings resolved to named commands, with layered scoping, mode gating, and multi-stroke sequences.
- layout
- Flexbox-style layout solver.
- live
- Small observable values for data-driven views.
- mouse
- Mouse interaction over the rendered cell grid: text selection, click hit-testing, and click detection.
- overlay
- Overlay positioning (Pi’s overlay model).
- prelude
- The common surface in one import.
- probe
- Reading laid-out rects back out of the view tree.
- runner
- Small full-screen run loops.
- scene
- Owned and borrowed base-tree composition with owned overlays.
- screen
- Screen modes: which part of the terminal a
tuikaframe owns. - style
- Styling and theming.
- surface
- Clipped drawing surface over a ratatui
Buffer. - term
- Terminal capabilities that live outside the cell grid.
- testing
- Public helpers for hermetic view and resize tests.
- themes
- Bundled standard themes.
- view
- The
Viewtrait — the extensibility seam for components. - width
- Grapheme-aware display-width measurement.