# Mainline Pipeline ## Architecture Overview The Mainline pipeline uses a **Stage-based architecture** with **capability-based dependency resolution**. Stages declare capabilities (what they provide) and dependencies (what they need), and the Pipeline resolves dependencies using prefix matching. ``` Source Stage → Render Stage → Effect Stages → Display Stage ↓ Camera Stage (provides camera.state capability) ``` ### Capability-Based Dependency Resolution Stages declare capabilities and dependencies: - **Capabilities**: What the stage provides (e.g., `source`, `render.output`, `display.output`, `camera.state`) - **Dependencies**: What the stage needs (e.g., `source`, `render.output`, `camera.state`) The Pipeline resolves dependencies using **prefix matching**: - `"source"` matches `"source.headlines"`, `"source.poetry"`, etc. - `"camera.state"` matches the camera state capability provided by `CameraClockStage` - This allows flexible composition without hardcoding specific stage names ### Minimum Capabilities The pipeline requires these minimum capabilities to function: - `"source"` - Data source capability (provides raw items) - `"render.output"` - Rendered content capability - `"display.output"` - Display output capability - `"camera.state"` - Camera state for viewport filtering These are automatically injected if missing by the `ensure_minimum_capabilities()` method. ### Stage Registry The `StageRegistry` discovers and registers stages automatically: - Scans `engine/stages/` for stage implementations - Registers stages by their declared capabilities - Enables runtime stage discovery and composition ## Stage-Based Pipeline Flow ```mermaid flowchart TD subgraph Stages["Stage Pipeline"] subgraph SourceStage["Source Stage (provides: source.*)"] Headlines[HeadlinesSource] Poetry[PoetrySource] Pipeline[PipelineSource] end subgraph RenderStage["Render Stage (provides: render.*)"] Render[RenderStage] Canvas[Canvas] Camera[Camera] end subgraph EffectStages["Effect Stages (provides: effect.*)"] Noise[NoiseEffect] Fade[FadeEffect] Glitch[GlitchEffect] Firehose[FirehoseEffect] Hud[HudEffect] end subgraph DisplayStage["Display Stage (provides: display.*)"] Terminal[TerminalDisplay] Pygame[PygameDisplay] WebSocket[WebSocketDisplay] Null[NullDisplay] end end subgraph Capabilities["Capability Map"] SourceCaps["source.headlines
source.poetry
source.pipeline"] RenderCaps["render.output
render.canvas"] EffectCaps["effect.noise
effect.fade
effect.glitch"] DisplayCaps["display.output
display.terminal"] end SourceStage --> RenderStage RenderStage --> EffectStages EffectStages --> DisplayStage SourceStage --> SourceCaps RenderStage --> RenderCaps EffectStages --> EffectCaps DisplayStage --> DisplayCaps style SourceStage fill:#f9f,stroke:#333 style RenderStage fill:#bbf,stroke:#333 style EffectStages fill:#fbf,stroke:#333 style DisplayStage fill:#bfb,stroke:#333 ``` ## Stage Adapters Existing components are wrapped as Stages via adapters: ### Source Stage Adapter - Wraps `HeadlinesDataSource`, `PoetryDataSource`, etc. - Provides `source.*` capabilities - Fetches data and outputs to pipeline buffer ### Render Stage Adapter - Wraps `StreamController`, `Camera`, `render_ticker_zone` - Provides `render.output` capability - Processes content and renders to canvas ### Effect Stage Adapter - Wraps `EffectChain` and individual effect plugins - Provides `effect.*` capabilities - Applies visual effects to rendered content ### Display Stage Adapter - Wraps `TerminalDisplay`, `PygameDisplay`, etc. - Provides `display.*` capabilities - Outputs final buffer to display backend ## Pipeline Mutation API The Pipeline supports dynamic mutation during runtime: ### Core Methods - `add_stage(name, stage, initialize=True)` - Add a stage - `remove_stage(name, cleanup=True)` - Remove a stage and rebuild execution order - `replace_stage(name, new_stage, preserve_state=True)` - Replace a stage - `swap_stages(name1, name2)` - Swap two stages - `move_stage(name, after=None, before=None)` - Move a stage in execution order - `enable_stage(name)` / `disable_stage(name)` - Enable/disable stages ### Safety Checks - `can_hot_swap(name)` - Check if a stage can be safely hot-swapped - `cleanup_stage(name)` - Clean up specific stage without removing it ### WebSocket Commands The mutation API is accessible via WebSocket for remote control: ```json {"action": "remove_stage", "stage": "stage_name"} {"action": "swap_stages", "stage1": "name1", "stage2": "name2"} {"action": "enable_stage", "stage": "stage_name"} {"action": "cleanup_stage", "stage": "stage_name"} ``` ## Camera Modes The Camera supports the following modes: - **FEED**: Single item view (static or rapid cycling) - **SCROLL**: Smooth vertical scrolling (movie credits style) - **HORIZONTAL**: Left/right movement - **OMNI**: Combination of vertical and horizontal - **FLOATING**: Sinusoidal/bobbing motion - **BOUNCE**: DVD-style bouncing off edges - **RADIAL**: Polar coordinate scanning (radar sweep) Note: Camera state is provided by `CameraClockStage` (capability: `camera.state`) which updates independently of data flow. The `CameraStage` applies viewport transformations (capability: `camera`). ## Animation & Presets ```mermaid flowchart LR subgraph Preset["Preset"] PP[PipelineParams] AC[AnimationController] end subgraph AnimationController["AnimationController"] Clock[Clock] Events[Events] Triggers[Triggers] end subgraph Triggers["Trigger Types"] TIME[TIME] FRAME[FRAME] CYCLE[CYCLE] COND[CONDITION] MANUAL[MANUAL] end PP --> AC Clock --> AC Events --> AC Triggers --> Events ``` ## Camera Modes State Diagram ```mermaid stateDiagram-v2 [*] --> Vertical Vertical --> Horizontal: mode change Horizontal --> Omni: mode change Omni --> Floating: mode change Floating --> Trace: mode change Trace --> Vertical: mode change state Vertical { [*] --> ScrollUp ScrollUp --> ScrollUp: +y each frame } state Horizontal { [*] --> ScrollLeft ScrollLeft --> ScrollLeft: +x each frame } state Omni { [*] --> Diagonal Diagonal --> Diagonal: +x, +y each frame } state Floating { [*] --> Bobbing Bobbing --> Bobbing: sin(time) for x,y } state Trace { [*] --> FollowPath FollowPath --> FollowPath: node by node } ```