Skip to content

Commit b46002f

Browse files
Hud improvements (#36)
* Keep HUD open even after task finishes * Add pan/scroll for flow diagram area * Assertions of diagram rendering * add strip_ascii method * WIP * better junctions * getting close * Almost there * Basic cases fixed! * Move file * Hud full rendering * full hud rendering * WIP - pan clamping and left border need fixing * fix diagram panning * fix flow diagram centering * Flow diagram frame refactor * More fixes * fix pan scroll * Remove concerns * Fix flow diagram redundancy * Fix specs * add notes for future
1 parent 9d62e62 commit b46002f

14 files changed

Lines changed: 1510 additions & 131 deletions

HUD.md

Lines changed: 65 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ Use `Minigun::HUD.run_with_hud` to automatically run your task with HUD monitori
7676
Minigun::HUD.run_with_hud(MyPipelineTask)
7777
```
7878

79+
**Note**: When the pipeline finishes, the HUD stays open to display final statistics. Press `q` to exit. This allows you to review the final state, throughput metrics, and latency percentiles before closing.
80+
7981
### Option 3: Manual Control
8082

8183
For more control, manually create and manage the HUD controller:
@@ -101,36 +103,76 @@ hud_thread.join
101103

102104
| Key | Action |
103105
|-----|--------|
104-
| `q` / `Q` | Quit HUD |
105-
| `Space` | Pause/Resume updates |
106-
| `h` / `H` / `?` | Toggle help overlay |
107-
| `r` / `R` | Force refresh / recalculate layout |
106+
| `q` / `Q` | Quit HUD (works anytime, including when pipeline finished) |
107+
| `Space` | Pause/Resume updates (disabled when finished) |
108+
| `h` / `H` / `?` | Toggle help overlay (disabled when finished) |
109+
| `r` / `R` | Force refresh / recalculate layout (disabled when finished) |
108110
| `` / `` | Scroll process list |
109-
| `d` / `D` | Toggle detailed view (future) |
111+
| `w` / `s` | Pan flow diagram up/down |
112+
| `a` / `d` | Pan flow diagram left/right |
110113
| `c` / `C` | Compact view (future) |
111114

112115
## Display Elements
113116

114117
### Flow Diagram (Left Panel)
115118

116-
The left panel shows your pipeline stages as an animated flow diagram:
117-
118-
- **Stage icons**:
119-
- `` Producer (generates data)
120-
- `` Processor (transforms data)
121-
- `` Consumer (consumes data)
122-
- `` Accumulator (batches items)
123-
- `` Router (distributes to multiple stages)
124-
- `` Fork (IPC/COW process)
119+
The left panel shows your pipeline stages as boxes with animated connections. Use `w`/`a`/`s`/`d` keys to pan the diagram for large pipelines.
125120

126-
- **Status indicators**:
127-
- `` Active (currently processing)
128-
- `` Idle (waiting for work)
129-
- `` Bottleneck (slowest stage)
130-
- `` Error (failures detected)
131-
- `` Done (completed)
121+
```
122+
┌─────────────────┐
123+
│ ▶ generator ⚡ │
124+
└──── 23.5/s ─────┘
125+
⣿ ← flowing animation
126+
┌─────────────────┐
127+
│ ◆ processor ⚡ │
128+
└──── 23.5/s ─────┘
129+
130+
┌─────────────────┐
131+
│ ◀ consumer ⏸ │
132+
└─────────────────┘
133+
```
132134

133-
- **Animations**: Flowing characters indicate active data movement
135+
**Box Components:**
136+
- **Header Line**: Top border with stage name
137+
- **Content**: Icon + Stage Name + Status Indicator
138+
- **Footer**: Bottom border with throughput rate (when active)
139+
- **Colors**: Status-based (green=active, yellow=bottleneck, red=error, gray=idle)
140+
141+
**Stage Icons:**
142+
- `` Producer (generates data)
143+
- `` Processor (transforms data)
144+
- `` Consumer (consumes data)
145+
- `` Accumulator (batches items)
146+
- `` Router (distributes to multiple stages)
147+
- `` Fork (IPC/COW process)
148+
149+
**Status Indicators:**
150+
- `` Active (currently processing)
151+
- `` Idle (waiting for work)
152+
- `` Bottleneck (slowest stage)
153+
- `` Error (failures detected)
154+
- `` Done (completed)
155+
156+
**Connection Animations:**
157+
- Active connections show flowing Braille characters: `⠀⠁⠃⠇⠏⠟⠿⡿⣿`
158+
- Horizontal lines pulse with dashed patterns: `─╌┄┈`
159+
- Inactive connections shown as static gray lines
160+
- Flow direction top-to-bottom through pipeline stages
161+
- Fan-out patterns use proper split/fork characters: `┬ ┼` for tree-like visualization
162+
163+
**Example Fan-Out Pattern:**
164+
```
165+
┌──────────┐
166+
│ producer │
167+
└──────────┘
168+
169+
┬───┴───┬
170+
│ │ │
171+
┌───┘ │ └───┐
172+
┌──────┐┌──────┐┌──────┐
173+
│cons1 ││cons2 ││cons3 │
174+
└──────┘└──────┘└──────┘
175+
```
134176

135177
### Process Statistics (Right Panel)
136178

@@ -155,9 +197,9 @@ The right panel displays a performance table:
155197
### Status Bar (Bottom)
156198

157199
Shows:
158-
- **Pipeline status**: RUNNING or PAUSED
200+
- **Pipeline status**: RUNNING, PAUSED, or FINISHED
159201
- **Pipeline name**: Current pipeline being monitored
160-
- **Keyboard hints**: Available controls
202+
- **Keyboard hints**: Available controls (changes to "Press [q] to exit..." when finished)
161203

162204
## Example
163205

TODO-CLAUDE.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ Minigun is a high-performance data processing pipeline framework for Ruby with s
4242
### Phase 1.01: HUD
4343

4444
- [X] Initial HUD work:
45-
- make a HUD inspired by htop to run as part of CLI
46-
- two columns:
47-
- LHS: flow diagram (ascii) on the other side, with ascii flow animations. make it inspired by cyberpunk (blade-runner/matrix/hackers)
48-
- RHS: list of processes on one side
49-
- use keys to navigate the hud.
50-
- use ascii colors
51-
- Before doing anything, plan it all out.
45+
- [X] make a HUD inspired by htop to run as part of CLI
46+
- [X] two columns:
47+
- [X] LHS: flow diagram (ascii) on the other side, with ascii flow animations. make it inspired by cyberpunk (blade-runner/matrix/hackers)
48+
- [X] RHS: list of processes on one side
49+
- [X] use keys to navigate the hud.
50+
- [X] use ascii colors
51+
- [X] Before doing anything, plan it all out.
5252

5353
- [X] Running hud
5454
- [X] task.hud to run in IRB/Rails console
@@ -57,11 +57,22 @@ Minigun is a high-performance data processing pipeline framework for Ruby with s
5757
- [ ] Add hud to all examples when running
5858
- [ ] Add idiomatic representation for each example
5959

60-
- [ ] HUD IPC support
61-
- [ ] Process tree, forked routing
60+
- [ ] HUD UI improvement
61+
- [ ] Introduce Hud::DiagramStage and DiagramPipeline/Executor
62+
- [ ] Re-add throughput and bottleneck icons to stages
63+
- [ ] Improve animations, use 24-frame counter (or just int counter which rolls over?)
64+
- [ ] Arrows on lines?
65+
- [ ] fix up/down of stages (not clearing lines)
66+
- [ ] auto-size width of stage columns
67+
- [ ] p95 rather than p99?
68+
- [ ] HUD IPC support
69+
- [ ] Process tree, forked routing
70+
- [ ] process wrappers
6271

6372
- [ ] HUD QoL
6473
- [ ] % completion metrics
74+
- [ ] CPU / MEM / disk / processes / queues
75+
- [ ] tab menu?
6576
- [ ] Error/log stream at bottom
6677

6778

examples/03_fan_out_pattern.rb

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,38 @@ def initialize
2525
users = [
2626
{ id: 1, name: 'Alice', message: 'Hello Alice' },
2727
{ id: 2, name: 'Bob', message: 'Hello Bob' },
28-
{ id: 3, name: 'Charlie', message: 'Hello Charlie' }
28+
{ id: 3, name: 'Charlie', message: 'Hello Charlie' },
29+
{ id: 4, name: 'Diana', message: 'Hello Diana' },
30+
{ id: 5, name: 'Eve', message: 'Hello Eve' },
31+
{ id: 6, name: 'Frank', message: 'Hello Frank' },
32+
{ id: 7, name: 'Grace', message: 'Hello Grace' },
33+
{ id: 8, name: 'Hank', message: 'Hello Hank' }
2934
]
30-
users.each { |user| output << user }
35+
users.each do |user|
36+
output << user
37+
sleep 0.05 if ENV['MINIGUN_HUD'] == '1' # Slow down for HUD visualization
38+
end
3139
end
3240

3341
# Email consumer
34-
consumer :email_sender do |user|
42+
consumer :email_sender, threads: 2 do |user|
43+
sleep rand(0.02..0.05) if ENV['MINIGUN_HUD'] == '1' # Simulate work
3544
@mutex.synchronize do
3645
emails << "Email to #{user[:name]}: #{user[:message]}"
3746
end
3847
end
3948

4049
# SMS consumer
41-
consumer :sms_sender do |user|
50+
consumer :sms_sender, threads: 2 do |user|
51+
sleep rand(0.03..0.06) if ENV['MINIGUN_HUD'] == '1' # Simulate work
4252
@mutex.synchronize do
4353
sms_messages << "SMS to #{user[:name]}: #{user[:message]}"
4454
end
4555
end
4656

4757
# Push notification consumer
48-
consumer :push_sender do |user|
58+
consumer :push_sender, threads: 2 do |user|
59+
sleep rand(0.01..0.04) if ENV['MINIGUN_HUD'] == '1' # Simulate work
4960
@mutex.synchronize do
5061
push_notifications << "Push to #{user[:name]}: #{user[:message]}"
5162
end
@@ -55,7 +66,16 @@ def initialize
5566

5667
if __FILE__ == $PROGRAM_NAME
5768
pipeline = FanOutPipeline.new
58-
pipeline.run
69+
70+
if ENV['MINIGUN_HUD'] == '1'
71+
require_relative '../lib/minigun/hud'
72+
puts 'Starting fan-out pipeline with HUD...'
73+
puts 'Press [q] to quit the HUD when done'
74+
sleep 1
75+
Minigun::HUD.run_with_hud(pipeline)
76+
else
77+
pipeline.run
78+
end
5979

6080
puts 'Fan-Out Pipeline Results:'
6181
puts "\nEmails sent: #{pipeline.emails.size}"

examples/hud_demo.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
# Demo script showing Minigun HUD in action
55
# Run with: ruby examples/hud_demo.rb
66

7-
require_relative 'lib/minigun'
8-
require_relative 'lib/minigun/hud'
7+
require_relative '../lib/minigun'
8+
require_relative '../lib/minigun/hud'
99

1010
# Define a demo pipeline with various stages
1111
class HudDemoTask

lib/minigun/hud.rb

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require_relative 'hud/theme'
55
require_relative 'hud/keyboard'
66
require_relative 'hud/flow_diagram'
7+
require_relative 'hud/flow_diagram_frame'
78
require_relative 'hud/process_list'
89
require_relative 'hud/stats_aggregator'
910
require_relative 'hud/controller'
@@ -85,15 +86,27 @@ def self.run_with_hud(task)
8586
end
8687
end
8788

88-
# Monitor for user quit
89+
# Monitor for user quit or task completion
8990
loop do
9091
if user_quit
9192
# User pressed 'q' in HUD - exit immediately
9293
task_thread.kill if task_thread.alive?
9394
break
9495
end
9596

96-
break unless task_thread.alive?
97+
# Check if task finished
98+
unless task_thread.alive?
99+
# Task finished - notify HUD and wait for user to press key
100+
hud.pipeline_finished = true
101+
102+
# Wait for user to quit via HUD
103+
loop do
104+
break if user_quit
105+
sleep 0.1
106+
end
107+
break
108+
end
109+
97110
sleep 0.1
98111
end
99112

0 commit comments

Comments
 (0)