- Remove \033[1;1H, \033[2;1H, \033[3;1H from HUD rendering
- HUD text now appears at correct positions without cursor interference
- Prompt appears at left margin as expected
- Fix raw mode enabling to not duplicate with UI border mode
- Add REPL_USAGE.md with comprehensive guide
- Add examples/repl_demo_terminal.py example script
- Detect REPL effect in pipeline and enable interactive mode
- Enable raw terminal mode for REPL input capture
- Add keyboard input loop for REPL commands
- Add _handle_pipeline_mutation() function for pipeline control
Implement a Read-Eval-Print Loop (REPL) effect that provides a
HUD-style overlay for interactive pipeline control.
## New Files
- engine/effects/plugins/repl.py - REPL effect plugin with command processor
- engine/display/backends/terminal.py - Added raw mode and input handling
- examples/repl_simple.py - Simple demonstration script
- tests/test_repl_effect.py - 18 comprehensive tests
## Features
### REPL Interface
- HUD-style overlay showing FPS, command history, output buffer size
- Command history navigation (Up/Down arrows)
- Command execution (Enter)
- Character input and backspace support
- Output buffer with scrolling
### Commands
- help - Show available commands
- status - Show pipeline status and metrics
- effects - List all effects in pipeline
- effect <name> <on|off> - Toggle effect
- param <effect> <param> <value> - Set parameter
- pipeline - Show current pipeline order
- clear - Clear output buffer
- quit - Show exit message
### Terminal Input Support
- Added set_raw_mode() to TerminalDisplay for capturing keystrokes
- Added get_input_keys() to read keyboard input
- Proper terminal state restoration on cleanup
## Usage
Add 'repl' to effects in your configuration:
## Testing
All 18 REPL tests pass, covering:
- Effect registration
- Command processing
- Navigation (history, editing)
- Configuration
- Rendering
## Integration
The REPL effect integrates with the existing pipeline system:
- Uses EffectPlugin interface
- Supports partial updates
- Reads metrics from EffectContext
- Can be controlled via keyboard when terminal display is in raw mode
Next steps:
- Integrate REPL input handling into pipeline_runner.py
- Add keyboard event processing loop
- Create full demo with interactive features
Implement Option 5: Hybrid preset-graph system that combines preset
simplicity with graph flexibility, providing 70% reduction in config
file size compared to verbose node DSL.
## New Files
- engine/pipeline/hybrid_config.py - Core hybrid config parser
- examples/hybrid_config.toml - Example hybrid configuration (20 lines)
- examples/hybrid_visualization.py - Demo script using hybrid config
- tests/test_hybrid_config.py - Comprehensive test suite (17 tests)
- docs/hybrid-config.md - Complete documentation
## Key Features
1. **Concise Syntax** (70% smaller than verbose DSL):
2. **Automatic Connections**: Linear pipeline order is inferred
3. **Flexible Configuration**:
- Inline objects:
- Array notation:
- Shorthand:
4. **Python API**:
- - Load from TOML
- - Convert from preset
- - Convert to pipeline
- - Convert to graph for further manipulation
## Usage
Loading hybrid configuration...
======================================================================
✓ Hybrid config loaded from hybrid_config.toml
Source: headlines
Camera: scroll
Effects: 4
- noise: intensity=0.3
- fade: intensity=0.5
- glitch: intensity=0.2
- firehose: intensity=0.4
Display: terminal
[38;5;226mAuto-injected stages for missing capabilities: ['camera_update', 'render'][0m
✓ Pipeline created with 9 stages
Stages: ['source', 'camera', 'noise', 'fade', 'glitch', 'firehose', 'display', 'camera_update', 'render']
[?25l✓ Pipeline initialized
Executing pipeline...
[2;38;5;34m>[0m [2;38;5;245mMIT Tech Review [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [10][0m
[2;38;5;34m>[0m [2;38;5;245mQuanta [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [5][0m
[2;38;5;34m>[0m [2;38;5;245mPhys.org [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [30][0m
[2;38;5;34m>[0m [2;38;5;245mArs Technica [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [20][0m
[2;38;5;34m>[0m [2;38;5;245mScience Daily [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [60][0m
[2;38;5;34m>[0m [2;38;5;245mNature [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [75][0m
[2;38;5;34m>[0m [2;38;5;245mNew Scientist [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [99][0m
[2;38;5;34m>[0m [2;38;5;245mNASA [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [10][0m
[2;38;5;34m>[0m [2;38;5;245mBBC Business [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [54][0m
[2;38;5;34m>[0m [2;38;5;245mBBC Science [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [36][0m
[2;38;5;34m>[0m [2;38;5;245mMarketWatch [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [10][0m
[2;38;5;34m>[0m [2;38;5;245mNPR [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [10][0m
[2;38;5;34m>[0m [2;38;5;245mEconomist [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [299][0m
[2;38;5;34m>[0m [2;38;5;245mAl Jazeera [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [25][0m
[2;38;5;34m>[0m [2;38;5;245mFrance24 [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [24][0m
[2;38;5;34m>[0m [2;38;5;245mGuardian World [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [45][0m
[2;38;5;34m>[0m [2;38;5;245mBBC World [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [28][0m
[2;38;5;34m>[0m [2;38;5;245mABC Australia [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [23][0m
[2;38;5;34m>[0m [2;38;5;245mDW [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [124][0m
[2;38;5;34m>[0m [2;38;5;245mSmithsonian [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [10][0m
[2;38;5;34m>[0m [2;38;5;245mAeon [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [20][0m
[2;38;5;34m>[0m [2;38;5;245mWired [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [48][0m
[2;38;5;34m>[0m [2;38;5;245mThe Hindu [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [60][0m
[2;38;5;34m>[0m [2;38;5;245mJapan Times [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [29][0m
[2;38;5;34m>[0m [2;38;5;245mNautilus [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [10][0m
[2;38;5;34m>[0m [2;38;5;245mGuardian Culture [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [24][0m
[2;38;5;34m>[0m [2;38;5;245mLiterary Hub [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [10][0m
[2;38;5;34m>[0m [2;38;5;245mThe Conversation [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [48][0m
[2;38;5;34m>[0m [2;38;5;245mThe Marginalian [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [20][0m
[2;38;5;34m>[0m [2;38;5;245mLongreads [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [25][0m
[2;38;5;34m>[0m [2;38;5;245mDer Spiegel [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [19][0m
[2;38;5;34m>[0m [2;38;5;245mAtlas Obscura [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m. [38;5;34mLINKED [27][0m
[2;38;5;34m>[0m [2;38;5;245mSCMP [38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[38;5;22m.[H[JThe Download: OpenAI is building a fully automated researcher, and a psychedelic
pe e r o in e a
- n b an t l r i l
nl ad n co ut n h l h a h t e o d d t r c e
C n ua t m co e s a h a e p s o f nd
h w r o n ec le o e cl r a e
T e D w o h en a o ’s new A ns, and n x - n u a r c s
W t do ne nucl ar r tors ea f w s ?
h Penta o s l nni g or I co p nies o tr in cl s i d t def nse o
T ownl d pe I s S mi t dea , an ok’ CS M ws it
T J lies T a vol d er nt y K i e
Qu nt m y o ap Pi ee n r g rd
T e a h T a E p i y B urve Are ver er
Why u a d Stil t u le W t t ll S uff?
W e e ome ee S s, She S es S ace T e M e o F ac l
[2;38;5;34m [0m [2;38;5;37mウ[0m[2;38;5;238m┋[0m [2;38;5;238m [0m [38;5;22m [0m [2;38;5;37m [0m[2;38;5;238m [0m [2;38;5;34mウ[0m [2;38;5;37mホ[0m [2;38;5;34m [0m [2;38;5;37m [0m [38;5;22m [0m[2;38;5;37m [0m [2;38;5;238mウ[0m[2;38;5;37m [0m[38;5;22m┆[0m [38;5;22m [0m [2;38;5;238m [0m [2;38;5;238m [0m[2;38;5;37m [0m [2;38;5;34mメ[0m [2;38;5;37mキ[0m [2;38;5;238m [0m[2;38;5;34mケ[0m [2;38;5;37m┃[0m[2;38;5;37m [0m [2;38;5;238m [0m[2;38;5;238m [0m
Ligh - s d n u t s ar f cia str r a mi h s f ng o
New resea h exp r s h a ad of i ms' u q e t chnol g s
L mi e j bl k oc ob o por nit s f y ng pe in oas l n
Are hu a a ural vi l nt? ew re arc c ll o - e a s ons
a m l e e r q a s?
New cove e p o s ow stro eil m t a ter t Ge in 8 e e
o a t g 3 a g ye b r b
How DICER cuts microRNAs with single-nucleotide precision [38;5;34mLINKED [50][0m
======================================================================
Visualization Output:
======================================================================
The Download: OpenAI is building a fully automated researcher, and a psychedelic
pe e r o in e a
- n b an t l r i l
nl ad n co ut n h l h a h t e o d d t r c e
C n ua t m co e s a h a e p s o f nd
h w r o n ec le o e cl r a e
T e D w o h en a o ’s new A ns, and n x - n u a r c s
W t do ne nucl ar r tors ea f w s ?
h Penta o s l nni g or I co p nies o tr in cl s i d t def nse o
T ownl d pe I s S mi t dea , an ok’ CS M ws it
T J lies T a vol d er nt y K i e
Qu nt m y o ap Pi ee n r g rd
T e a h T a E p i y B urve Are ver er
Why u a d Stil t u le W t t ll S uff?
W e e ome ee S s, She S es S ace T e M e o F ac l
[2;38;5;34m [0m [2;38;5;37mウ[0m[2;38;5;238m┋[0m [2;38;5;238m [0m [38;5;22m [0m [2;38;5;37m [0m[2;38;5;238m [0m [2;38;5;34mウ[0m [2;38;5;37mホ[0m [2;38;5;34m [0m [2;38;5;37m [0m [38;5;22m [0m[2;38;5;37m [0m [2;38;5;238mウ[0m[2;38;5;37m [0m[38;5;22m┆[0m [38;5;22m [0m [2;38;5;238m [0m [2;38;5;238m [0m[2;38;5;37m [0m [2;38;5;34mメ[0m [2;38;5;37mキ[0m [2;38;5;238m [0m[2;38;5;34mケ[0m [2;38;5;37m┃[0m[2;38;5;37m [0m [2;38;5;238m [0m[2;38;5;238m [0m
Ligh - s d n u t s ar f cia str r a mi h s f ng o
New resea h exp r s h a ad of i ms' u q e t chnol g s
L mi e j bl k oc ob o por nit s f y ng pe in oas l n
Are hu a a ural vi l nt? ew re arc c ll o - e a s ons
a m l e e r q a s?
New cove e p o s ow stro eil m t a ter t Ge in 8 e e
o a t g 3 a g ye b r b
How DICER cuts microRNAs with single-nucleotide precision
======================================================================
✓ Successfully rendered 24 lines
## Comparison
| Format | Lines | Use Case |
|--------|-------|----------|
| Preset | 10 | Simple configs |
| **Hybrid** | **20** | **Most use cases (recommended)** |
| Verbose DSL | 39 | Complex DAGs |
All existing functionality preserved - verbose node DSL still works.
Add script that renders the standard Mainline visualization using the
graph-based DSL. This demonstrates the default behavior with:
- Headlines source data
- Scroll camera mode
- Terminal display
- Classic effects: noise, fade, glitch, firehose
Files added:
- examples/default_visualization.py - Main script
- examples/default_visualization.toml - TOML configuration
- examples/README.md - Documentation for all examples
Usage:
python examples/default_visualization.py
- fix(demo-lfo-effects): Fix math.sin() usage (was angle.__sin__())
- feat(pipeline): Add set_effect_intensity() method for runtime effect control
- Allows changing effect intensity during pipeline execution
- Returns False if effect not found or intensity out of range
- Used by LFO modulation demo
The demo-lfo-effects.py script now works correctly with proper
math.sin() usage and the new set_effect_intensity() method provides
a clean API for runtime effect intensity control.
Add comprehensive documentation for the graph-based pipeline DSL:
- docs/graph-dsl.md: Complete DSL reference with TOML, Python, and CLI syntax
- docs/GRAPH_SYSTEM_SUMMARY.md: Implementation overview and architecture
- examples/graph_dsl_demo.py: Demonstrates imperative Python API usage
- examples/test_graph_integration.py: Integration test verifying pipeline execution
The documentation follows a wiki-like approach with navigable structure:
- Overview section explaining the concept
- Syntax examples for each format (TOML, Python, CLI)
- Node type reference table
- Advanced features section
- Comparison with old XYZStage approach
This provides users with multiple entry points to understand and use the
new graph-based pipeline system.
Add support for loading pipelines from TOML graph configs in the
pipeline runner, maintaining full backward compatibility with presets.
- Add graph_config parameter to run_pipeline_mode() function
- Support both preset mode and graph mode with conditional logic
- Graph mode: loads from TOML file, uses graph-defined stages
- Preset mode: maintains existing behavior with manual stage building
- Handle items/context appropriately for each mode (graph uses own data sources)
- CLI display flag works in both modes
Backward compatible: graph_config defaults to None, so existing calls
to run_pipeline_mode(preset_name) continue to work unchanged.
Allow pipelines to be defined in TOML format with intuitive
node-and-connection syntax that's easy to read and edit.
- Add graph_toml.py with TOML parsing using tomllib
- Support simple format: "source": "headlines"
- Support full format: {"type": "camera", "mode": "scroll"}
- Parse connection strings in "A -> B -> C" chain format
- Add example pipeline_graph.toml demonstrating usage
Example TOML:
[nodes.source]
type = "source"
source = "headlines"
[nodes.camera]
type = "camera"
mode = "scroll"
[connections]
list = ["source -> camera -> display"]
Bridge the new graph abstraction with existing Stage-based pipeline
system for backward compatibility.
- Add GraphAdapter class to map nodes to Stage implementations
- Handle effect intensity configuration (sets global effect state)
- Map camera modes to Camera factory methods (feed, scroll, horizontal, etc.)
- Auto-inject required dependencies (render, camera_update) via pipeline capabilities
- Support for all major node types: source, camera, effect, position, display
The adapter ensures that graphs seamlessly integrate with the existing
pipeline architecture while providing a cleaner abstraction layer.
Introduce Node, Connection, and Graph classes for defining pipelines
as graphs instead of verbose XYZStage naming convention.
- Add NodeType enum (SOURCE, CAMERA, EFFECT, DISPLAY, etc.)
- Add Node, Connection, and Graph dataclasses with type hints
- Add validation for cycles and disconnected nodes using DFS
- Add factory methods: node(), connect(), chain() for easy graph building
- Support for both imperative and declarative graph construction
This provides the foundation for the graph-based DSL that replaces
the verbose XYZStage naming convention with intuitive node-and-connection syntax.
- Added PositioningMode enum (ABSOLUTE, RELATIVE, MIXED)
- Created PositionStage class with configurable positioning modes
- Updated terminal display to support positioning parameter
- Updated PipelineParams to include positioning field
- Updated DisplayStage to pass positioning to terminal display
- Added documentation in docs/positioning-analysis.md
Positioning modes:
- ABSOLUTE: Each line has cursor positioning codes (\033[row;1H)
- RELATIVE: Lines use newlines (no cursor codes, better for scrolling)
- MIXED: Base content uses newlines, effects use absolute positioning (default)
Usage:
# In pipeline or preset:
positioning = "absolute" # or "relative" or "mixed"
# Via command line (future):
--positioning absolute
The terminal display was using which concatenated lines
without separators, causing text to render incorrectly and appear to jump
vertically.
Changed to so lines are properly separated with
newlines, allowing the terminal to render each line on its own row.
The ANSI cursor positioning codes (\033[row;colH) added by effects like
HUD and firehose still work correctly because:
1. \033[H moves cursor to (1,1) and \033[J clears screen
2. Newlines move cursor down for subsequent lines
3. Cursor positioning codes override the newline positions
4. This allows effects to position content at specific rows while the
base content flows naturally with newlines
Rename the mise task from 'run' to 'mainline' to make it more semantic:
- 'mise run mainline' is clearer than 'mise run run'
- Old 'run' task is kept as alias that depends on sync-all
- Preserves backward compatibility with existing usage
- Change line 477 in controller.py to use self.config.display or "terminal"
- Previously hardcoded "terminal" ignored config and CLI arguments
- Now auto-injection respects the validated display configuration
fix(app): Add warnings for auto-selected display
- Add warning in pipeline_runner.py when --display not specified
- Add warning in main.py when --pipeline-display not specified
- Both warnings suggest using null display for headless mode
feat(completion): Add bash/zsh/fish completion scripts
- completion/mainline-completion.bash - bash completion
- completion/mainline-completion.zsh - zsh completion
- completion/mainline-completion.fish - fish completion
- Provides completions for --display, --pipeline-source, --pipeline-effects,
--pipeline-camera, --preset, --theme, --viewport, and other flags
Instead of duplicating HTML generation code, use the existing
acceptance_report.py infrastructure which already has:
- ANSI code parsing for color rendering
- Frame capture and display
- Index report generation
- Comprehensive styling
This eliminates code duplication and leverages the existing
acceptance testing patterns in the codebase.
- Add source stage (headlines, poetry, or empty)
- Add viewport filter and font stage for headlines/poetry
- Add camera stages (camera_update and camera)
- Add effect stages based on preset
- Fix stage order: message_overlay BEFORE display
- Add null display stage with recording enabled
- Capture frames from null display recording
The fix ensures that the comparison framework uses the same pipeline structure
as the main pipeline runner, producing proper block character rendering for
headlines and poetry sources.
- Created analysis/visual_output_comparison.md with detailed architectural comparison
- Added capture utilities for output comparison (capture_output.py, capture_upstream.py, compare_outputs.py)
- Captured and compared output from upstream/main vs sideline branch
- Documented fundamental architectural differences in rendering approaches
- Updated Gitea issue #50 with findings
- Import MessageOverlayStage in pipeline_runner.py
- Add message overlay stage when preset.enable_message_overlay is True
- Add overlay stage in both initial construction and preset change handler
- Use config.NTFY_TOPIC and config.MESSAGE_DISPLAY_SECS for configuration
- Add enable_message_overlay field to PipelinePreset dataclass
- Enable message overlay in demo, ui, and firehose presets
- Add test-message-overlay preset for testing
- Update preset loader to support new field from TOML files
- Add Theme class and THEME_REGISTRY to engine/themes.py
- Add set_active_theme() function to config.py
- Add msg_gradient() function to use theme-based message gradients
- Support --theme CLI flag to select theme (green, orange, purple)
- Initialize theme on module load with fallback to default
- tests/test_canvas.py: 33 tests for Canvas (2D rendering surface)
- tests/test_firehose.py: 5 tests for FirehoseEffect
- tests/test_pipeline_order.py: 3 tests for execution order verification
- tests/test_renderer.py: 22 tests for ANSI parsing and PIL rendering
These tests provide solid coverage for foundational modules.
- Add can_hot_swap() function to Pipeline class
- Add cleanup_stage() method to Pipeline class
- Fix remove_stage() to rebuild execution order after removal
- Extend ui_panel.execute_command() with docstrings for mutation commands
- Update WebSocket handler to support pipeline mutation commands
- Add _handle_pipeline_mutation() function for command routing
- Add comprehensive integration tests in test_pipeline_mutation_commands.py
- Update AGENTS.md with mutation API documentation
Issue: #35 (Pipeline Mutation API)
Acceptance criteria met:
- ✅ can_hot_swap() checker for stage compatibility
- ✅ cleanup_stage() cleans up specific stages
- ✅ remove_stage_safe() rebuilds execution order (via remove_stage)
- ✅ Unit tests for all operations
- ✅ Integration with WebSocket commands
- ✅ Documentation in AGENTS.md