You keep rebuilding the same pane manager in every app: split views, stacks, dashboards, resize handles, focus order, and panel insertion rules.
panes is a pane layout and runtime engine. It computes panel rectangles without rendering them, so the same layout logic can power ratatui, egui, the browser, canvas, wasm, or your own renderer.
Describe panels in rows, columns, and tiling presets. panes solves the geometry via Taffy, tracks runtime state like focus and mutations, and hands back a map of PanelId -> Rect. No widget system. No renderer lock-in.
Use it when you need more than static flexbox: split-pane apps, IDE-like shells, dashboards, game HUDs, TUI workspaces, or any UI where panels are added, removed, resized, focused, or restored from snapshots.
Proof
use ;
// Game HUD: health bar pinned at 40px, viewport fills the rest
let layout = layout! ?;
let resolved = layout.resolve?;
for entry in resolved.panels
Install
cargo add panes
Optional features:
| Feature | What it enables |
|---|---|
serde |
Serialize/Deserialize on Rect, PanelId, NodeId |
toml |
Load layouts from TOML strings/files (implies serde) |
Usage
Build custom layouts or pick from 13 presets. Pass any coordinate system: pixels, logical points, terminal cells.
// Custom — full control with the layout macro
let layout = layout! ?;
// Preset — one-liner for common patterns
master_stack.master_ratio.gap
// Runtime — add/remove panels, focus navigation, frame diffing
let mut rt = master_stack
.master_ratio.gap.into_runtime?;
rt.add_panel?; // insert after focused, rebuild via strategy
rt.add_panel_with?; // append to end
rt.swap_next; // reorder in sequence
rt.focus_next;
rt.focus_direction_current?;
let frame = rt.resolve?;
let diff = rt.last_diff; // added, removed, moved, resized, unchanged
// Snapshot — save session state, restore later
let snapshot = rt.snapshot?;
// serde_json::to_string(&snapshot)?; // with `serde` feature
let mut rt2 = from_snapshot?;
Adapters convert rects to renderer-native types:
| Crate | Target | Rect type |
|---|---|---|
panes-ratatui |
ratatui | ratatui::layout::Rect (u16, edge-rounded) |
panes-egui |
egui | egui::Rect (f32) |
panes-css |
Browser | CSS declarations (browser solves layout) |
panes-wasm |
Canvas/JS | WasmRect (f64) |
See the demo app for a working ratatui example, or try the live wasm demo.
For ratatui, panes_ratatui::resolve() handles the f32→u16 terminal cell conversion automatically — no manual quantization:
terminal.draw?;
For other adapters, panels() yields PanelEntry { id, kind, rect, kind_index } with native rect types — no hashmap, no cross-referencing.
Performance
LayoutRuntime resolves a 100-panel flat layout in <1µs on the hot path — roughly 3x over raw Taffy. The abstraction layer (tree compilation, rect resolution, frame diffing) adds minimal overhead.
See benches/ for methodology.
Documentation
See the User Guide for the full API: all 13 presets, the layout macro, TOML configuration, runtime mutations, frame diffing, animation, and render adapters.
License
MIT or Apache 2.0, at your option. See LICENSE-MIT and LICENSE-APACHE.