Cascade Visualization
Cascade Visualization
The cascade viewer shows event cascades as interactive tree structures, so you can see the chain of effects produced by a single event. Each time an event fires in the scoring engine, the console captures the resulting cascade of rule evaluations, variable changes, and child events.
Demo
The screenshot below is a real capture from the live scoring engine: the root is the switch event that fired, and the children are the effects its .cade handlers actually produced — score contributions, variable changes, and the events those handlers emitted.
Loading the cade engine…
The sections below document the viewer as it appears in the console.
Opening the Viewer
Toggle the cascade viewer with F7 (or Ctrl+E). After triggering an event, the cascade is captured automatically:
cade:debug> trigger device.Bumper1.activated
Event cascade captured. Press F7 to view.The viewer replaces the main content area while it is open. Press F7 again to return.
You can also jump straight to a cascade from the Events tab: put the cursor on an event and press c.
Commands
The cascade command has three subcommands:
cade:debug> cascade last # summarize (or load) the most recent cascade
cade:debug> cascade export # write the current cascade to JSON
cade:debug> cascade export run1.json
cade:debug> cascade depth # show the current capture depth
cade:debug> cascade depth 5 # set capture depth (1–10)cascade last prints a summary — timestamp, duration in microseconds, event count, and score change:
cade:debug> cascade last
Last Event Cascade:
Timestamp: 12:13:44.205
Duration: 3750μs
Event Count: 5
Score Change: +5000When the TUI viewer is open, cascade last loads that cascade into the viewer instead and reports ✓ Last cascade loaded. Use Ctrl+E to view.
cascade depth controls how many levels deep the engine captures. Values outside 1–10 are rejected.
Note:
cascade exportandcascade depthact on the TUI cascade viewer, so they only take effect in TUI mode. In pipe mode they do nothing. Export is JSON only; with no filename it writescascade_<YYYYMMDD_HHMMSS>.jsonin the working directory.
Reading the Tree
A captured cascade looks like this:
🏆 switch_hit:left_orbit
Trigger: switch_hit:left_orbit | Depth: 3 | Queue: 2
switch_hit:left_orbit Total: 3750μs | Events: 5 | Score: +5000 | Mult: x3
└─▼ switch_hit:left_orbit [5000 → 5000] +5000
├─ → award_bonus [bonus:1000]
├─ play_sound:orbit_hit
└─▼ → update_multiplier [x1 → x3]
└─ → flash_lights:orbit
Score Breakdown:
switch_hit:left_orbit: 5000
Total: 5000
──────────────────────────────────────────────────────────────────
Node: switch_hit:left_orbit | Type: scoring | Duration: 2500μs | Score: +5000 | Calc: 5000 | Children: 3 (expanded) | Changes: scoreFor simpler cascades (single event, no children), the header shows device context instead of depth:
Trigger: device.Bumper1.activated | Device: switch | Key: Bumper1
device.Bumper1.activated Total: 4μs | Events: 1 | Score: +1000
└─ device.Bumper1.activated [1000 → 1000] +1000
Score Breakdown:
device.Bumper1.activated: 1000
Total: 1000Header Line
| Field | Meaning |
|---|---|
Trigger | Event name that started the cascade |
Device / Key | Device type and key (single-event captures) |
Depth | Number of levels in the cascade tree |
Queue | Pending child events not yet expanded |
Summary Line
| Field | Meaning |
|---|---|
Total | Wall-clock duration for the whole cascade |
Events | Number of nodes in the tree |
Score | Total points awarded by the cascade |
Mult | Active multiplier (shown when it changes during the cascade) |
Node Line
Each node line is assembled from these parts, in order:
| Part | Meaning |
|---|---|
▼ / ▶ | Expanded / collapsed (leaves show neither) |
| Icon | Event-type icon — 🎯 scoring, ✖️ multiplier, 🔄 combo, 🔊 sound, 📊 variable, ⚡ generic. Only with emoji mode on (Alt+E) |
| Name | The event or effect name, colored by event type |
→ prefix | The node is a future effect — queued by its parent but not yet run. Rendered dim |
| Badge | Score contribution, variable change, or future-effect marker |
[…] | Timing — see below |
(pending) | The cascade is still in flight |
+N / -N | Points gained or lost at this node |
Connectors are ├─ for intermediate children and └─ for the last child.
Timing
Per-node duration renders in brackets, scaled to the magnitude:
| Duration | Rendered as |
|---|---|
| Under 1000 μs | [450μs] |
| Under 1 s | [12.4ms] |
| 1 s and above | [1.05s] |
Anything over 10 ms is highlighted in a warning color, and with emoji mode on is prefixed 🐢. Anything under 100 μs is prefixed ⚡. A collapsed node shows the summed duration of its whole branch with a trailing Σ.
Press t to hide or show timing; compact mode (c) suppresses it too.
Detail Bar
The line below the divider describes the selected node:
| Field | Meaning |
|---|---|
Node | Selected node name |
Type | scoring, effect, sound, or system |
Duration | Time spent in this node |
Score | Points awarded by this node |
Calc | Calculated expression value (before any score modifier) |
Children | Child count and expanded/collapsed state |
Changes | Variables touched by this node, comma-separated |
Keyboard Shortcuts
Navigation
| Key | Action |
|---|---|
↑ / k, ↓ / j | Move to previous / next node |
← / h, → / l | Collapse / expand the selected node |
Space or Enter | Toggle expand/collapse |
g / G | Jump to first / last node |
E / C | Expand all / collapse all |
1–9 | Expand the tree to that depth level |
[ / ] | Step backward / forward through the cascade history buffer |
Display Toggles
| Key | Action |
|---|---|
t | Show/hide per-node timing |
T | Toggle the timeline |
m | Toggle the minimap |
b | Toggle the breadcrumb trail |
c | Toggle compact mode |
P | Toggle the performance analysis overlay |
Alt+E | Toggle emoji icons |
Ctrl+H | Hide / show future-effect nodes |
Ctrl+D | Toggle the details pane |
Search, Export, Replay
| Key | Action |
|---|---|
/ or Ctrl+F | Start a search |
n / N | Next / previous match |
Ctrl+/ or Esc | Clear the search |
Ctrl+A | Toggle auto-update (jump to latest cascade on capture) |
Ctrl+E | Export the current cascade to JSON |
Ctrl+R | Enter or exit replay mode |
p | Play the sound for a selected sound node |
Replay Mode
Press Ctrl+R to step through a cascade event by event. Replay adds a playback bar and remaps a few keys:
| Key | Action |
|---|---|
Space | Play / pause |
← / → | Step one event backward / forward |
+ or = | Double playback speed |
- | Halve playback speed |
Home / End | Jump to first / last event |
Esc | Exit replay mode |
Performance Analysis
Press P to overlay bottleneck analysis on the cascade. The overlay reports:
Overview — total duration, event count, max depth, average duration, score change, and a per-type event distribution with counts and percentages.
Critical Path — the longest chain of sequential operations, numbered and indented by depth. Steps over 20 ms are flagged critical, over 5 ms medium.
Bottlenecks — the nodes consuming the most time, each with the path that reaches it. Severity is keyed to the share of total cascade time: over 50%, over 25%, and over 10%.
Timing Anomalies — entries marked HIGH, MEDIUM, or LOW, each with a suggestion.
Optimization Suggestions — concrete recommendations, each with an impact and difficulty rating. The suggestions you may see are:
- Parallelize child operations
- Optimize dominant bottleneck
- Cache or pre-compute slow operation
- Investigate timing anomalies
- Reduce cascade depth
The cascade buffer stores the 100 most recent cascades, so [ and ] let you step back through recent history and compare runs by eye.
Filtering Events
The cascade viewer itself offers free-text search (/) rather than structured filters. For structured filtering, use the Events tab (F2), whose filter bar accepts space-separated clauses that are ANDed together:
type:scoring score>100
name:switch_* duration>1ms
kind:cascade complete:true
| Clause | Accepts |
|---|---|
type: | scoring, multiplier, combo, sound, variable, generic |
kind: | cascade, signal |
name: | Substring, or a glob when it contains * or ? |
complete: | true/yes/1 or false/no/0 |
score: duration: events: | Numeric comparison with >, <, or = (e.g. duration>1ms) |
A bare word with no prefix is treated as a case-insensitive substring match on the event name. See Panels for the Events tab reference.