Panels
TUI Panels
TUI mode presents a tabbed content area with three tabs, a sidebar of live status panels on the right, a cascade overlay, and a persistent frame of header, status bar, and help bar around them.
Layout
┌─────────────────────────────────────────────────────────────┐
│ 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 │ Watch │
├────────────────────────────────────────────┤ score 1,000 │
│ │ Score │
│ Log output... │ P1 Ball 1/3 │ ← Sidebar
│ │ Metrics │
│ │ Profiler │
├────────────────────────────────────────────┴────────────────┤
│ q quit F1-F3 tabs F4 header F5 status │ ← Help bar
└─────────────────────────────────────────────────────────────┘| Tab | Key | Shows |
|---|---|---|
| Logs | F1 | Structured log output from the engine and drivers (default on startup) |
| Events | F2 | Live hierarchical event tree, grouped by game / ball / mode |
| Console | F3 | The cade:debug> REPL prompt and its output |
The right-hand sidebar stacks four always-visible status panels — Watch, Score, Metrics, and Profiler. It takes about a quarter of the terminal width and hides automatically when the terminal is narrower than 100 columns, giving the active tab the full width.
Tab moves keyboard focus from the active tab into the sidebar panels and around again; Shift+Tab cycles backward. The focused panel is the one that receives panel-specific keys (the Metrics keys, the Profiler sort keys, and so on).
The Cascade viewer is an overlay rather than a tab — press F7 (or Ctrl+E) to open it as a floating panel over the dimmed screen, and F7, Ctrl+E, or Esc to dismiss it. See Cascade Visualization.
Logs Tab
Streams structured log output as a scrollable, color-coded list.
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. Nested components render as dotted paths (e.g.
audio.mixer). When a record has no source the bracketed segment is omitted entirely — you never see empty[]brackets - Message — the formatted message followed by any structured key/value fields
Filter, Search, and Pause
Three independent modes for working through high-volume output:
Text filter (/) — hides non-matching lines. Press /, type a substring, press Enter. Matching is case-insensitive against the message, source, and structured fields. Press / again or Esc to clear.
Search (Ctrl+F) — highlights matches in place without hiding other lines. Use n / N to jump between matches. Filter and search compose: search highlights within the filtered view.
Source filter (s) — opens a picker listing the sources currently present. Select with Space, commit with Enter, dismiss with Esc or q.
Pause (p) — freezes the visible feed while new entries continue to buffer. Press p again to resume; buffered entries drain in order. Pause is independent of autoscroll.
Logs Tab Shortcuts
| Shortcut | Action |
|---|---|
j / k or ↓ / ↑ | Scroll one line (moves the cursor when autoscroll is off) |
PgUp / PgDn | Half page up / down |
g / Home, G / End | Jump to first / last entry |
a | Toggle autoscroll |
p | Toggle pause |
w | Toggle word wrap |
f | Toggle the filter status bar |
d / i / W / e | Filter to Debug / Info / Warn / Error level |
s | Open the source-filter picker |
/ | Text filter (hides non-matching lines) |
Ctrl+F | Search (highlights matches) |
n / N | Next / previous search match |
Esc | Clear the search, then the active filter |
? | Open the keybinding help overlay |
The Logs tab is the one view with a built-in help overlay — press ? for a two-column reference, and any key to dismiss it.
Events Tab
A live, hierarchical tree of game events organized by span — game sessions, balls, and active modes. The tree updates in real time and supports collapsing, filtering, and detail inspection.
Tree Structure
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
────────────────────────────────────────────────────────────────────────
· [-] Player 1 Ball 1/1 Score: 17K Events: 59
╰── · [-] Ball 1 Score: 17K (34s) Events: 59
├── · [-] Active Modes (1)
│ ╰── · +23.078s — multiball pri:200
├── ▸ ... 43 earlier ...
├── · +11.577s device.Kicker1.activated [switch] +10K
├── · +11.577s mode.multiball.started
├── · +11.596s ball_device.unhit <BallRelease>
├── · +11.610s switch.hit <StartBallControl> held 651ms
├── · +12.612s switch.pressed <launch_ball> held 1.5s
├── · +14.662s device.Gate.activated [switch]
├── · +15.111s system.ball.drain
├── · 12:14:03.257 system.game.end
╰── · [-] lifecycle
╰── · +11.577s — mode.multiball.startedEach span can be collapsed ([+]) or expanded ([-]) independently. Active modes are grouped into an Active Modes subtree below their ball span. Events carry a leading time column, either +11.577s relative to ball start or a wall-clock stamp (see Time Display), and are annotated with points (+10K), device context (<BallRelease>), and held duration for merged pairs (held 651ms). Cascade durations under 0.05 ms are hidden to reduce noise; under 1 ms renders dim, 1 ms and above renders in a warning color to flag slow cascades.
A mode that just ended lingers in Active Modes for a couple of seconds, greyed out with its score frozen, before rolling off. If the same mode restarts while the prior activation is still fading, both appear as separate rows; only the live one keeps accumulating.
Collapse state resets when a new game starts.
Time Display
The leading time column has three modes. Press Alt+T on the Events tab to cycle between them; the hint bar at the bottom names the mode you will land on next.
| Mode | Shows |
|---|---|
| Hybrid (default) | Ball-relative offsets (+11.577s) for gameplay events, and wall-clock time (12:14:03.257) for the infrastructure and operator events: game start and end, coin insert, pause |
| Relative | Ball-relative offsets on every row |
| Wall clock | Wall-clock time on every row |
Hybrid is the default because it answers both questions at once: how far into the ball a shot landed, and what time of day the game itself started and ended. Switch to wall clock when you are lining the tree up against an external log or a screen recording, and to relative when you want every row measured from the same ball start.
The column is padded to the widest value on screen, so switching modes shifts the event names left or right but keeps them aligned.
Archived Games
Finished games are retained in a bounded ring above the live game so you can scroll back without leaving the TUI.
· [+] Game started +01:23:45 Player 1: 42K Player 2: 18K
· [+] Game started +01:41:07 Player 1: 12K
· [-] Game (live)
╰── · [-] Player 1 Ball 2/3 Score: 6000 Events: 18
╰── ...- Up to three archived games are retained; a fourth evicts the oldest.
- Collapsed by default — expand with
lorSpace. - Summaries only. Archived entries keep the player leaderboard, per-ball summaries, completed-mode history, and lifecycle entries. Raw per-event leaves are dropped, so the ball node shows an aggregate count (
Events: N) but has no event children — a large memory saving in exchange for losing per-event inspection after the game ends.
The active game is never archived while in progress.
Event Compression
Related event pairs are automatically merged into single entries:
- Hit/unhit pairs — a switch or ball device firing both
hitandunhitin the same span becomes one entry showing held duration (left_inlane held 234ms). Cross-span pairs are not merged. - Switch press/release pairs — merged the same way.
- Flipper pairs — a full press sequence (flipper press + staged press + both releases) compresses from four events into one, dramatically reducing flipper noise.
Press p to toggle expand mode, which injects synthetic rows for the closing half of each merged pair. This is display-only; the underlying data is unchanged.
Overflow Expansion
When a span exceeds the per-span display limit, older events hide behind an overflow node (▸ ... N earlier ...). Press Enter or l on it to reveal the next 16, repeatedly to page through. Collapse and re-expand the span to reset.
Sibling-Lock Mode
Sibling-lock constrains j/k to one depth level — useful for scanning all completed modes without diving into their children. Press s to lock to the current node’s parent:
[LOCK] j/k:siblings g/G:first/last esc:unlockWhile locked, j/k move between siblings, g/G jump to first/last, and h/l/Space/Enter still collapse, expand, and open details. Esc unlocks. The lock releases automatically if the locked parent stops being visible.
Memory Management
The event tree caps retained entries (default 10,000). At the cap, the oldest completed game span and its events are evicted. At least two game spans must exist before eviction, and the active game is never removed.
Events Tab Shortcuts
| Shortcut | Action |
|---|---|
j / k or ↓ / ↑ | Move cursor down / up |
g / Home, G / End | Jump to first / last |
l / → | Expand node, or descend into first child |
h / ← | Collapse node, or ascend to parent |
[ / ] | Previous / next sibling |
Space | Toggle collapse of the selected node |
Enter | Reveal the next 16 hidden events on an overflow node; open the detail view on any other node |
s | Toggle sibling-lock mode |
p | Toggle paired-event expand mode |
Alt+T | Cycle the time column (hybrid → relative → wall clock) |
c | Open the cascade viewer for the selected event |
a | Toggle autoscroll |
/ | Enter filter mode (press again to clear) |
Esc | Release sibling lock, then clear the filter |
The filter bar accepts structured clauses — see Filtering Events for the syntax.
Console Tab
The REPL. Contains the cade:debug> prompt and a scrollback view of command results and scoring output.
The input line offers ghost-text completion suggestions, history navigation, and readline-style editing:
| Shortcut | Action |
|---|---|
Enter | Submit the command (accepts the history-search result when searching) |
Tab | Accept the offered completion; with no completion showing, move focus to the sidebar |
↑ / ↓ | Navigate command history |
Ctrl+R | Reverse history search |
Ctrl+S | Step forward through history-search results |
Ctrl+U | Clear the line and return the cursor to the start |
Ctrl+/ | Toggle the search bar |
Esc | Cancel history search |
Note:
qquits the console from the Logs and Events tabs, but not from the Console tab — there it types the letterqinto your command. UseCtrl+Cto quit from anywhere.
Sidebar
The sidebar’s four panels update live while you work in any tab. They render top to bottom in this order and are cycled through with Tab / Shift+Tab.
Watch Panel
The watch list — every variable and expression you have added with watch, updated in real time, plus the active player’s score and ball while a game is in progress. Open it when you want scoring state visible at all times without re-running inspect.
The header shows the current display mode:
| Mode | Shows |
|---|---|
Compact | Names and current values only |
Persistent | Adds a sparkline trend per numeric variable |
Audit | Adds a “Recent Changes” log of the latest value changes |
With the Watch panel focused:
| Shortcut | Action |
|---|---|
m | Cycle display mode (Compact → Persistent → Audit) |
c | Clear all watched variables and expressions |
Launch with --watch=false to leave the Watch panel out of the sidebar entirely.
Score Panel
Current game state at a glance: the game phase, each player’s score with the active player highlighted, the ball number, and the credit balance (or free play). Display-only — it has no keys of its own. It mirrors what the game status bar shows, but stays visible even when the status bar is toggled off.
Metrics Panel
Runtime health, grouped into categories:
| Category | Shows |
|---|---|
| System | CPU, memory, goroutine count, heap objects, GC pause time |
| gRPC | Events sent/received, active and total streams, uptime |
| Performance | FPS, frame time, update rate (populated while an engine is running) |
| Scoring | Events/sec, average latency, cache hit rate, committed and pending counts (populated when a scoring engine is loaded) |
With the Metrics panel focused:
| Shortcut | Action |
|---|---|
Enter | Drill into category selection — Tab / Shift+Tab then cycle categories, Esc exits |
h | Toggle the history view |
e | Export current metrics and history to a JSON file |
r | Reset collected metrics |
+ / - | Speed up / slow down the update rate |
Profiler Panel
Live per-event timing from the scoring profiler: one row per event with Count, Avg, P50, P95, P99, and Max in microseconds, sorted by P95 by default. The panel shows No profiling data yet until you start the profiler with profile start.
With the Profiler panel focused:
| Shortcut | Action |
|---|---|
s | Cycle the sort column (Event, Count, Avg, P50, P95, P99, Max) |
r | Reverse the sort direction |
↑ / ↓ or k / j | Move the row selection |
Chrome
Header
Shows table identity and engine status. F4 toggles between two modes:
- Compact (default, 2 lines) — table name, engine status, platform health, and Cade version on line 1; config path on line 2.
- Regular (4 lines) — table name and engine status; config path; platform address and connection status; Cade version.
Game Status Bar
Toggled with F5. When visible it shows:
- Game phase — ● Ball In Play, ○ Starting, ■ Game Over, or idle
- Player, Score (comma-separated), and Ball (e.g.
Ball 1/3) - Event sparklines — event activity over the last 60 seconds
The status bar drops lower-priority fields when the terminal is narrow.
Tab Bar
A single line showing the three tabs. The active tab is bold and bracketed; inactive tabs are dimmed. Press the matching F-key to switch instantly.
Help Bar
A single line at the bottom showing the global key hints: q quit, F1-F3 tabs, F4 header, F5 status.
Global Shortcuts
| Shortcut | Action |
|---|---|
Ctrl+C | Quit the console |
q | Quit (Logs and Events tabs only — see the note above) |
Tab / Shift+Tab | Cycle focus forward / backward through the active tab and the sidebar panels |
F1 / F2 / F3 | Switch to the Logs / Events / Console tab |
F4 | Toggle header between compact and regular |
F5 | Toggle the game status bar |
F7 or Ctrl+E | Toggle the cascade overlay |
Alt+C | Copy the active panel’s content to the clipboard |
Alt+Shift+C | Copy the focused log entry (Logs tab) |
Alt+L | Cycle to the next layout preset |
Esc | Close an open overlay, otherwise pass through to the active tab |
Copied log text uses the same format as the display, including the source bracket only when a source is present — you never get stray [] in copied output.
Themes
The TUI ships these built-in themes:
| Theme | Description |
|---|---|
default | Balanced 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 |
Pick one at launch:
cade console --theme dark
Or switch live from the prompt — every panel and the chrome repaint immediately:
cade:debug> theme # show the current theme and the full list
cade:debug> theme solarized-dark # switch, with a color previewAn unknown name is rejected with the list of valid ones.
The theme system adapts to terminal color capability — TrueColor (24-bit), 256-color, 16-color, and 8-color — degrading gracefully.
Separately, the console’s own output colors (prompt, values, errors) are set by the colors block in the console config file, which offers default, solarized, monokai, and custom. See Configuration.