Skip to Content
ftui-widgetsObservability widgets

Observability widgets

The point of a widget library is rendering content, but the point of an observability widget is rendering the library itself. FrankenTUI ships a handful of diagnostic overlays you drop into a running screen when something is wrong (or when you want to prove it is right). Each is a normal widget — you can place one in a pane, wrap it in a Block, toggle it with a keybinding.

This page is a quick-reference for eight of them. For the full widget table see the catalog; for what each data source means, follow the cross-links into the intelligence layer.

Inspector — the big one

Source: inspector.rs:283 (100+ KB; one of the largest widgets in the tree).

Inspector is a live widget-tree inspector: you see the hierarchy of widgets that rendered this frame, their allocated rects, their registered hit regions, and their accessibility tree contribution. Hover over a widget in your UI and the inspector highlights the rect that produced it.

When to use it:

  • Layout is doing something unexpected and you want to see the concrete Rect every widget was given.
  • A hit region isn’t triggering and you suspect it was never registered.
  • The a11y tree for a screen reader looks wrong and you want to see what FrankenTUI is publishing.

Toggle: typically bound to F1 or a dev-mode keybinding.

DebugOverlay — live performance metrics

Source: debug_overlay.rs:92.

A small panel with:

  • Frame time histogram (p50 / p95 / p99)
  • Dirty rows per frame
  • Buffer statistics (total cells, styled cells, wide cells)
  • Current degradation level
  • Render-budget remaining

Useful for identifying which frames are blowing the budget and for correlating frame time with gestures (drags, scrolls, resizes).

ConstraintOverlay — layout in living colour

Source: constraint_overlay.rs:115.

Overlays every allocated Rect with a coloured outline and its input constraint (Length(4), Min(20), Percentage(50), etc.). Answers the question “why did this column end up 7 cells wide?” in one glance.

Pairs with the LayoutDebugger which shows the pre-solve constraint tree.

LogViewer — in-app tail

Source: log_viewer.rs:193.

Scrollable, filterable display of log entries. Backed by a ring buffer (log_ring), so it is bounded in memory regardless of runtime duration. Supports:

  • Regex filter
  • Level filter (INFO+, WARN+, etc.)
  • Auto-scroll with pause-on-hover
  • Jump to newest / oldest

Typical integration: pipe tracing output into the log ring via the ftui-extras logging subscriber, then render the viewer in a pane.

HistoryPanel — undo / redo visualised

Source: history_panel.rs:54.

Renders the undo stack as a tree, including divergent branches when the user undoes and then makes a new change. Useful for interactive editors; pairs with the UndoSupport generic undo plumbing.

DecisionCard — the Bayesian ledger, inline

Source: decision_card.rs:28.

A progressive-disclosure UI that renders a Bayesian evidence ledger — the same structure emitted by the command-palette scorer. Collapsed it shows prior odds and the final posterior; expanded it lists every factor and its rationale.

Useful anywhere a decision needs an auditable trail — hint ranking, capability detection, VOI sampling results. See /intelligence/bayesian-inference/command-palette-ledger for the data shape.

VoiDebugOverlay — measurement budget

Source: voi_debug_overlay.rs:178.

Renders the current state of a VOI (Value of Information) sampler: which candidates are being measured, what their posteriors look like, and the expected information gain from each pending measurement. You see why the sampler chose the action it did.

DriftVisualization — per-domain confidence

Source: drift_visualization.rs:56.

One sparkline per domain (capability, height prediction, palette ranking, …) showing the conformal prediction interval’s width over recent frames. Growing intervals mean the model is less confident — a drift signal.

Pair with DebugOverlay to correlate drift with frame-time spikes.

When to reach for each

SituationWidget
”Layout is wrong”ConstraintOverlay + Inspector
”We’re dropping frames”DebugOverlay
”Where did that log message go?”LogViewer
”My undo is buggy”HistoryPanel
”Why did the command palette rank X first?”DecisionCard
”Why is VOI sampling this cell?”VoiDebugOverlay
”Is my conformal predictor drifting?”DriftVisualization
”What is the a11y tree?”Inspector

Composition pattern

A common pattern is a dev-mode toggle that overlays a whole observability panel on top of the normal view:

use ftui_widgets::{ Widget, StatefulWidget, debug_overlay::DebugOverlay, log_viewer::{LogViewer, LogViewerState}, constraint_overlay::ConstraintOverlay, }; pub struct Model { dev_mode: bool, log_state: LogViewerState, // … real model } // `Model::view` is `&self`; this helper uses `&mut self` so // `StatefulWidget::render` can borrow `&mut self.log_state`. Wrap // `log_state` in `RefCell<LogViewerState>` to call from a real `view`. fn render_with_overlays(&mut self, frame: &mut ftui_render::frame::Frame) { render_normal_view(frame); if self.dev_mode { let area = frame.buffer.bounds(); // Right-side strip for logs + metrics let [_, right] = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Min(40), Constraint::Length(40)]) .split(area); let [metrics, logs] = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Length(12), Constraint::Min(10)]) .split(right); DebugOverlay::default().render(metrics, frame); StatefulWidget::render( &LogViewer::default(), logs, frame, &mut self.log_state, ); ConstraintOverlay::default().render(area, frame); } }

Pitfalls

  • Leaving observability widgets in production builds. They are debug tools. Feature-gate them or hide behind a dev-mode flag so they never render to end users.
  • Overlapping overlays. Multiple observability widgets rendered on top of each other make the screen unreadable. Pick one or arrange them in a dedicated panel.
  • Relying on LogViewer for anything persistent. The backing ring buffer is bounded; old entries are evicted. Use a file sink in parallel for durable logs.
  • Misreading DriftVisualization. A widening interval is not a bug — it is the predictor saying “I am less sure now”. Correlate with input rate changes before panicking.

Where next