You keep solving the same panel layout problem — splits, stacks, grids, resize — from scratch in every project.
panes is a spatial layout engine that computes rectangles without rendering them.
Describe panels in rows, columns, and presets. panes solves the geometry via Taffy (flexbox and CSS Grid) and hands back a map of PanelId → Rect. No framework. No widget system. No opinions about pixels.
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.
Each adapter provides a panels() iterator that yields PanelEntry { id, kind, rect, kind_index } — no hashmap, no cross-referencing:
for entry in panels
panes-ratatui also provides focused_panels(), which pairs each entry with a focus bool — decorations (_tab / _title) light up automatically when their content panel is focused.
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.