tuika 0.12.0
Released 2026-09-15. crates.io · docs.rs · GitHub release
Released alongside tuika-charts 0.2.0, tuika-codeformatters 0.6.0,
tuika-html 0.2.0, and tuika-mermaid 0.4.0. Every companion’s tuika
requirement moves to 0.12, and all four drop the ratatui-core (or ratatui)
dependency they no longer use.
Highlights
tuika owns the cell grid — Rect, Color/Style, Line/Span,
Buffer/Cell, Backend, and Terminal are tuika’s own types now, so a host
takes one crate instead of two and is no longer exposed to a ratatui-core
major bump. Existing ratatui widgets still compose, behind the optional
ratatui feature.

- Dependencies: 55 crates to 32; the cold dependency build drops from roughly 32s to 6s.
- Performance:
render,frame_windowed, and the scroll paths fall 7.3–7.4% in instruction count. - Correctness:
Span::widthandLine::widthnow count grapheme-aware display columns, so they agree with whatSurfaceactually paints.
Rendering is unchanged on screen, so this release carries no new recording.
Breaking Changes
-
tuika no longer depends on ratatui. It now owns its own
Rect/Position,Color/Modifier/Style,Line/Span,Buffer/Cell,Backend, andTerminal. Every one of those types moved fromratatui-coreto tuika, so any signature naming one changes.For most hosts the migration is an import change — the canonical path is unchanged:
// before use ratatui_core::layout::Rect; use ratatui_core::style::{Color, Modifier, Style}; use ratatui_core::text::{Line, Span}; // after (or just `use tuika::prelude::*;`) use tuika::ui::{Color, Line, Modifier, Rect, Span, Style};A host driving its own terminal takes
tuika::term::terminal::{Terminal, TerminalOptions, Viewport}andtuika::term::backend::CrosstermBackendinstead of ratatui’s, andtuika::term::testbackend::TestBackendin tests.The types are deliberately shaped like the ones they replace, with two behavioral notes:
Span::widthandLine::widthcount grapheme-aware display columns (width::str_cols) rather than per-charwidths, so they now agree with whatSurfaceactually paints. A line containing a ZWJ emoji measures narrower than before — and correctly.Cellstores short grapheme clusters inline instead of in aCompactString.Cell::newis no longerconst; useCell::default()for a blank cell.
-
Ratatui interoperability is now behind the
ratatuifeature, off by default.Surface::render_ratatui,tuika::interop, andRatatuiViewneed it; a host wrapping ratatui widgets adds:tuika = { version = "0.12", features = ["ratatui"] }Every ratatui widget still works. The boundary is no longer a shared
Buffer— the two crates no longer share a cell type — but a cell-by-cell conversion over the rendered area, whichrender_ratatuiwas already doing a copy for. -
Surface::render_ratatuiwas split. The general escape hatch — a private scratch buffer, composited back through the clip — is nowSurface::render_scratchand takes tuika’sBuffer.render_ratatuiis the ratatui-specific wrapper around it. A caller using it for scratch access rather than for ratatui widgets should switch torender_scratch, which needs no feature. -
Line::rawandLine::styledsplit their content on line breaks, one span per line, matching what they replaced.Line::raw("")therefore yields a line with no spans.
Added
Surface::render_scratch— clipped scratch-buffer access without ratatui.Buffer::set_style,Buffer::content(),Cell::raw_symbol()(tells a wide grapheme’s placeholder apart from a blank cell).framebuffer::QUADRANTS— the sixteen quadrant block glyphs, previously reached throughratatui_core::symbols::pixel.Style::{bold, dim, italic, underlined, reversed, crossed_out}shorthands.tuika::term::backend::CrosstermBackendandtuika::term::testbackend::TestBackendare public, for a host drivingTerminalitself.
Changed
- Dependencies: 55 crates to 32. Dropping
ratatui-coreremoved 23, includingkasuari(a Cassowary solver),lru, and a secondhashbrown— all of which existed forratatui_core::layout::Layout, which tuika replaced with its own flex solver and never called — plusstrum,compact_str,itertools,unicode-truncate, and a secondsynmajor version. The cold dependency build drops from roughly 32s to 6s. - Rendering is ~7% cheaper.
render,frame_windowed, and the scroll paths fall 7.3–7.4% in instruction count, because aCellnow stores short grapheme clusters inline. The markdown paths rise ~2%, the cost of measuring widths grapheme-aware; the benchmark baseline is updated accordingly. scrolling-regionsis now a feature of tuika’s ownBackendtrait, and no longer pulls inratatui-crosstermto forward a flag.- The companion crates no longer depend on ratatui.
tuika-charts,tuika-html, andtuika-mermaiddroppedratatui-core, andtuika-codeformattersdropped the fullratatuiumbrella; none of them had named a ratatui type since tuika took over the cell grid.ratatuiis no longer part oftuika-codeformatters’ public interface, so a dependant pins onlytuika. - Public documentation follows the new model: the guides, the component gallery,
and the getting-started page import from
tuika::uiinstead ofratatui::*, and no longer describe ratatui as running underneath.
Fixed
-
The workspace builds on its declared MSRV again. A dependency in the root manifest was written as a multi-line inline table, which TOML 1.0 does not allow and the Cargo on Rust 1.88 rejects outright — so
cargofailed to parseCargo.tomlbefore compiling anything. Only the manifest changed; no dependency version or feature moved.The MSRV CI job did not catch it because it never ran the MSRV: the job set 1.88 as the
rustupdefault, whichrust-toolchain.toml’s development pin outranks, so every check ran on the newer toolchain. The job now pinsRUSTUP_TOOLCHAINand fails if the active toolchain is not therust-versioninCargo.toml.
What’s Changed
- refactor(deps)!: own the cell grid and drop ratatui (#114)
- fix(ci): make the MSRV job run the MSRV (#131)
- fix(demos): re-record scroll and close the broken-capture class (#132)
- chore(deps): drop the companion crates’ unused ratatui dependencies
- docs: retire ratatui from the guides, gallery, and durable knowledge
- fix(release): keep companion dev-dependencies out of the published manifest