Panels
TUI Panels
The TUI mode organizes the console into multiple panels, each displaying a different aspect of the running game.
Default Layout
The default layout uses a full-width tabbed arrangement with a collapsible header and status bar:
┌─────────────────────────────────────┐
│ My Table ● Running v1.0 │ ← Header (F4 to expand)
│ /path/to/config.cade │
├─────────────────────────────────────┤
│ ● Ball In Play P1 1,000 Ball 1/3│ ← Status bar (F5 to toggle)
├─────────────────────────────────────┤
│ [Logs] Events Console │ ← Tab bar (F1–F3)
├─────────────────────────────────────┤
│ │
│ Log output... │
│ │
├─────────────────────────────────────┤
│ q quit F1-F3 tabs F4 header F5 status │ ← Help bar
└─────────────────────────────────────┘
Logs, Events, and Console are top-level tabs rendered by the chrome tab bar. Switch between them with F1, F2, and F3. The Logs tab is shown by default on startup. The Cascade panel is accessible by pressing F7 and replaces the main content area when active.
Panel Types
Main Panel
The primary interaction area. Contains an inline command prompt (cade:debug>) and the console output view showing command results and scoring output. The input prompt is embedded at the bottom of this panel.
Events and Logs are separate top-level tabs accessible via F2 and F1 respectively, rendered by the chrome tab bar above the main content area.
Watch Panel
Monitors variables and expressions in real time. Renders in a borderless format with a bold label header and change indicators (▲/▼/◆). Supports three display modes:
- Compact – Variable names and current values in a dense list
- Persistent – Shows value history with sparkline trends below each variable
- Audit – Detailed view with timestamps and old→new value changes
The watch panel also displays game state information (active player, score, balls remaining) when a game session is active.
Score Panel
Displays the current game session state with color-coded phase indicators (● active, ■ game over, ○ idle):
- Game phase (Idle, Starting, Ball In Play, Between Balls, Game Over)
- Current player indicator with ball info
- Per-player leaderboard with scores (right-aligned, adaptive column widths)
- Total balls per game and extra ball counts
The score panel polls the game session manager and updates automatically.
Logs Panel
Streams structured log output from the engine and drivers as a scrollable, color-coded list. The Logs tab is the default view on startup (F1).
Each line shows:
12:13:44.205 DEBUG [audio.mixer] Parsed use block for voice=synth.plunger
- Timestamp — millisecond precision, from the log record
- Level —
DEBUG,INFO,WARN,ERROR; color-coded by severity - Source — the component that emitted the log, populated automatically from
sloggroup paths. Nested groups render as dotted paths (e.g.audio.mixer). When a record has no group or explicit source attr, the bracketed segment is omitted entirely — you never see empty[]brackets - Message — the formatted log message followed by any structured key/value fields
Filter, Search, and Pause
The Logs tab has three independent modes for working through high-volume output:
Text filter (/) — hides non-matching lines. Press / to open the filter bar above the viewport, type a substring, and press Enter to commit. The filter matches case-insensitively against the message, source, and structured fields. The status bar shows Filter: <text> while active. Press Esc to clear and exit the filter.
Search (Ctrl+F) — highlights matches in place without hiding other lines. Press Ctrl+F to open the search prompt, type a term, and press Enter. All occurrences on every visible line are highlighted. Use n / N to jump to the next / previous match; navigation wraps around at the ends of the list. Filter and search can be used together — search highlights matches within the currently filtered view.
Pause (p) — freezes the visible feed while new entries continue to buffer in the background. While paused, the status bar shows PAUSED (N buffered) with the current backlog count. The backlog is capped at the same 10,000-entry limit as the live buffer — older entries are dropped FIFO if the backlog overflows. Press p again to resume; buffered entries drain into the live list in order and the feed continues. Pause is independent of autoscroll — you can scroll up without pausing, and you can pause without disabling autoscroll.
Copy to Clipboard
Press Alt+C to copy the currently visible log content to the clipboard. The copied text uses the same format as the on-screen display, including the source bracket only when a source is present — you will never see stray [] in copied output.
Logs Panel Keyboard Shortcuts
| Shortcut | Action |
|---|---|
j / k or ↓ / ↑ | Scroll one line |
g / G | Jump to first / last entry |
Ctrl+U / Ctrl+D | Scroll half a page up / down |
a | Toggle autoscroll |
p | Toggle pause (freeze / resume the feed) |
/ | Enter text filter mode (hides non-matching lines) |
Ctrl+F | Enter search mode (highlights matches, does not hide) |
n / N | Next / previous search match (wraps at ends) |
Alt+C | Copy visible content to clipboard |
Esc | Exit filter or search mode; clear active filter |
Events Panel
Displays a live, hierarchical tree of game events organized by span — game sessions, balls, and active modes. The tree updates in real time as events arrive and supports interactive navigation with collapsing, filtering, and detail inspection.
Tree Structure
Events are grouped into a hierarchy. A live tree during multiball might look like this:
Full Example Table · ● RUNNING · localhost:50052 ● · v0.1.0
./cade/docs/examples/full-example-table-with-modes
────────────────────────────────────────────────────────────────────────
● Ball in Play player1 17,000 Ball 1/3
switch.hit ▁▁▁▁█▁▂▁▁▁ 31 flipper.pressed ▁▁▁▁▁█▁▁▁▁ 14 flipper.released ▁▁▁▁▁█▁▁▁▁ 14
────────────────────────────────────────────────────────────────────────
· [-] Player 1 Ball 1/1 Score: 17,000 Events: 59
╰── · [-] Ball 1 Score: 17,000 (34s) Events: 59
├── · [-] Active Modes (1)
│ ╰── · multiball pri:200 since +23.078s
├── ▸ ... 43 earlier ...
├── · +11.577s device.Kicker1.activated [switch] +10000
├── · +11.577s mode.multiball.started
├── · +11.596s ball_device.unhit <BallRelease>
├── · +11.610s switch.hit <StartBallControl> held 651ms
├── · +11.832s switch.hit <Wall5bottom>
├── · +11.857s switch.hit <Trigger1> held 2.5s
├── · +12.612s switch.pressed <launch_ball> held 1.5s
├── · +14.123s switch.hit <StartBallControl> held 254ms
├── · +14.557s switch.hit <Wall37>
├── · +14.581s switch.hit <Wall37>
├── · +14.662s device.Gate.activated [switch]
├── · +14.667s switch.unhit <Kicker1>
├── · +14.983s switch.hit <RubberWall3>
├── · +15.110s general.pressed <unknown>
├── · +15.111s system.ball.drain
├── · +15.152s system.game.end
╰── · [-] lifecycle
╰── · +11.577s mode.multiball started
Each span (player, ball, mode) can be collapsed ([+]) or expanded ([-]) independently. Active modes are grouped into an Active Modes subtree below their ball span. Events are stamped with a relative offset (+11.577s) from ball start and annotated with points (+10000), device context (<BallRelease>), held duration for merged pairs (held 651ms), and cascade processing time for events that trigger the scoring engine. Cascade durations under 0.05 ms are hidden to reduce visual noise — only meaningful timing values are displayed. Durations under 1 ms render in a dim style; durations at 1 ms or above render in a warning color to flag slow cascades.
Collapse state resets automatically when a new game starts. Tree keys like player and ball nodes are reused across games, so starting a new game clears any stale collapsed/expanded state from the previous session.
When a span accumulates more events than the display threshold, an overflow node (▸ ... N earlier ...) appears at the top of the list — press Enter or right-arrow (l) on it to page through the hidden history sixteen events at a time.
Archived Games
Finished games are retained in a bounded ring above the live game so you can scroll back and inspect prior sessions without leaving the TUI. When a new game starts (or the current game ends), the previous game is archived as a compact summary and the live tree resets.
· [+] Game started +01:23:45 Player 1: 42,300 Player 2: 18,900
· [+] Game started +01:41:07 Player 1: 12,500
· [-] Game (live)
╰── · [-] Player 1 Ball 2/3 Score: 6,000 Events: 18
╰── ...
Behavior:
- Up to three archived games are retained. When a fourth game starts, the oldest archive is evicted.
- Collapsed by default. Each archived game appears as a sibling above the live
Gameroot and stays collapsed on first render — expand withlorSpaceto drill in. - Summaries only. Archived entries retain the player leaderboard, per-ball summaries, completed-mode history, and lifecycle entries. Raw per-event leaves are dropped on archive — the ball node shows the aggregate event count (
Events: N) but has no event children. This is a deliberate trade-off: a ~95% memory reduction per archived game in exchange for losing the ability to inspect individual events after the game ends. - Overflow expansion works on archived history and lifecycle sections the same way it does on the live game.
The active game is never archived while in progress — it only enters the ring when the next game starts or when the current game ends cleanly.
Event Compression
The events panel automatically compresses related event pairs into single entries to reduce noise:
- Hit/unhit pairs: When a switch or ball device fires both a
hitandunhitevent in the same span, they are merged into one entry showing the held duration inline (e.g.,left_inlane held 234ms). Cross-span pairs are not merged. - Switch press/release pairs:
switch.pressedandswitch.releasedevents for the same device are merged into one entry showing the held duration. - Flipper pairs: A flipper press sequence (
left_flipperpress +staged_left_flipperpress + both releases) compresses from four events into a single entry, dramatically reducing flipper noise during normal gameplay.
Press p in either the flat or tree event view to toggle expand mode — this injects ephemeral synthetic rows for the closing half of each merged pair so you can see both events. The underlying data is unchanged; expanding is purely a display-time operation.
Overflow Expansion
When a span accumulates more events than the per-span display limit, older events are hidden behind an overflow node (▸ ... N earlier ...). Pressing Enter or right-arrow (l) on the overflow node loads the next 16 hidden events — press repeatedly to page through the full history. The placeholder disappears once all hidden events have been revealed. Collapse and re-expand the span to reset back to the default view.
Overflow expansion also applies to history and lifecycle sections on both the live game and archived games.
Sibling-Lock Mode
Sibling-lock constrains j/k navigation to a single depth level. This is useful when you want to step through siblings — for example, scanning through all completed modes in the history section without diving into their children.
Press s while the cursor is on a node to lock to that node’s parent. The hint bar changes to indicate lock mode:
[LOCK] j/k:siblings g/G:first/last esc:unlock
While locked:
j/k— move to next/previous sibling (wraps at boundary)g/G— jump to first/last siblingh/l/Space/Enter— still work normally for collapse/expand/detailsEsc— exit sibling-lock mode
The lock is automatically released if the locked parent is no longer visible (e.g., after a game span is evicted from history).
Memory Management
The event tree caps the number of retained entries (default 10,000). When the cap is reached, the oldest completed game span and all its events are evicted automatically. At least two game spans must be present before eviction occurs — the current active game is never removed.
This keeps memory usage bounded during long play sessions with high-frequency events.
Events Panel Keyboard Shortcuts
| Shortcut | Action |
|---|---|
j / k or ↓ / ↑ | Move cursor down/up |
g / G | Jump to first/last node |
l or Space | Expand node / descend into first child |
h | Collapse node / ascend to parent |
Enter or l (on overflow node) | Reveal the next 16 hidden events |
Enter (on other nodes) | Open detail view |
s | Toggle sibling-lock mode |
p | Toggle paired-event expand mode (show merged pair closers inline) |
Tab / Shift+Tab | Cycle through merged separator rows |
Alt+T | Cycle time display: hybrid → relative → wall-clock |
c | Open the cascade viewer for the selected event |
a | Toggle autoscroll |
/ | Enter filter mode |
Esc | Exit sibling-lock or clear filter |
Cascade Panel
Visualizes event cascades as interactive tree structures. See the Cascade Visualization page for details.
Profiler Panel
Displays real-time scoring profiler data in a sortable table:
- Event names with invocation counts
- Timing percentiles: Avg, P50, P95, P99, Max
- Toggle between event and expression profiler views
- Sort by any column (ascending or descending)
- Color-coded latency values (normal, warning, critical thresholds)
The profiler panel requires the scoring profiler to be started with the profile start command.
Input Panel
The command input area with readline-style editing. Features include:
- Ghost text completion suggestions
- Command history navigation (
Up/Downarrows) - History search (
Ctrl+Rfor reverse search,Ctrl+Sfor forward search) - Character limit of 256
In the default layout, the input panel is embedded inline at the bottom of the Main panel rather than appearing as a separate panel.
Chrome Widgets
Header
A persistent widget at the top of the screen showing table identity and engine status. Toggled between two modes with F4:
- Compact (default, 2 lines): Table name, engine status, platform health, and Cade version on the first line; config path on the second line.
- Regular (4 lines): Table name and engine status on line 1; config path on line 2; platform address and connection status on line 3; Cade version on line 4.
Game Status Bar
A collapsible widget between the header and the tab bar, toggled with F5. When visible it displays:
- Game phase: ● Ball In Play, ○ Starting, ■ Game Over (or idle when no game is active)
- Player: Current player number
- Score: Formatted with comma separators
- Ball: Current ball and balls-per-game (e.g.,
Ball 1/3) - Event sparklines: Ring-buffer chart of event activity over the last 60 seconds
The status bar adapts displayed items to the available terminal width, hiding lower-priority fields when space is constrained.
Tab Bar
A single-line widget at the top of the content area showing all registered tabs. The active tab is displayed in bold with brackets, while inactive tabs appear dimmed. Press the corresponding F-key (F1–F3) to switch tabs instantly.
Help Bar
A single-line widget at the bottom of the screen showing context-sensitive key hints. The hints update based on the active tab — each tab can register its own set of key descriptions. Falls back to global hints when no tab-specific hints are defined.
Keyboard Shortcuts
Global Shortcuts
| Shortcut | Action |
|---|---|
Ctrl+C or q | Quit the console |
F1 | Switch to Logs tab |
F2 | Switch to Events tab |
F3 | Switch to Console tab |
F4 | Toggle header between compact and regular mode |
F5 | Toggle game status bar |
F7 or Ctrl+E | Toggle the Cascade panel |
Ctrl+Right or Ctrl+L | Move focus to the panel on the right |
Ctrl+Left or Ctrl+J | Move focus to the panel on the left |
Ctrl+Up or Ctrl+K | Move focus to the panel above |
Ctrl+Down or Ctrl+; | Move focus to the panel below |
Alt+C | Copy active panel content to clipboard |
Alt+L | Cycle layout preset |
Tab | Accept completion |
Enter | Submit command |
Esc | Cancel current input or exit search mode |
Input Shortcuts
| Shortcut | Action |
|---|---|
Ctrl+R | Reverse history search |
Ctrl+S | Forward history search |
Ctrl+U | Clear the input line |
Ctrl+C | Cancel current input |
Ctrl+A | Move cursor to start of line |
Ctrl+E | Move cursor to end of line |
Ctrl+K | Delete from cursor to end of line |
Ctrl+W | Delete word before cursor |
Up / Down | Navigate command history |
Events Panel Shortcuts
See the Events Panel section for the full keyboard reference.
| Shortcut | Action |
|---|---|
j / k | Navigate tree nodes |
l / h | Expand / collapse |
Enter | Open details or expand overflow |
s | Toggle sibling-lock mode |
p | Toggle paired-event expand mode |
Esc | Exit lock mode or clear filter |
a | Toggle autoscroll |
/ | Filter |
Cascade Panel Shortcuts
| Shortcut | Action |
|---|---|
F7 or Ctrl+E | Toggle cascade panel |
↑ / ↓ | Navigate tree nodes |
← / → | Collapse / expand selected node |
Space | Toggle expand/collapse |
1–9 | Expand tree to that depth |
[ / ] | Previous / next cascade in history |
Ctrl+D | Toggle details pane |
Ctrl+F or / | Search |
Ctrl+A | Toggle auto-update |
Ctrl+R | Toggle replay mode |
P | Toggle performance overlay |
Alt+E | Toggle emoji icons |
? | Show cascade help |
See Cascade Visualization for the full reference, including replay-mode controls.
Logs Panel Shortcuts
See the Logs Panel section for the full keyboard reference.
| Shortcut | Action |
|---|---|
/ | Text filter (hides non-matching) |
Ctrl+F | Search (highlights matches) |
n / N | Next / previous search match |
p | Toggle pause |
a | Toggle autoscroll |
Alt+C | Copy visible content |
Esc | Exit filter or search mode |
Main Panel Shortcuts
| Shortcut | Action |
|---|---|
Ctrl+L | Clear the current view |
Themes
The TUI supports multiple built-in themes that control the color scheme of all panels:
| Theme | Description |
|---|---|
default | Balanced color scheme suitable for most terminals |
dark | Muted dark palette |
light | Bright, readable light mode |
high-contrast | Maximum contrast for accessibility |
monochrome | No colors, minimal distraction |
solarized-dark | Solarized Dark palette |
solarized-light | Solarized Light palette |
Change themes at runtime:
cade:debug> theme solarized-dark
The theme system automatically adapts to terminal color capabilities, supporting TrueColor (24-bit), 256-color, 16-color, and 8-color terminals with graceful degradation.
Panel Navigation
Panels are arranged in a spatial grid. Use Ctrl+Arrow keys to move focus between panels directionally. In the tabbed layout:
- The active tab (Logs, Events, or Console) occupies the full content area
- Cascade replaces the main content area when active (
F7)
The active panel is indicated by a highlighted border. Only the focused panel receives keyboard input.