--- name: mainline-effects description: How to add new effect plugins to Mainline's effect system compatibility: opencode metadata: audience: developers source_type: codebase --- ## What This Skill Covers This skill covers Mainline's effect plugin system - how to create, configure, and integrate visual effects into the pipeline. ## Key Concepts ### EffectPlugin ABC (engine/effects/types.py) All effects must inherit from `EffectPlugin` and implement: ```python class EffectPlugin(ABC): name: str config: EffectConfig param_bindings: dict[str, dict[str, str | float]] = {} supports_partial_updates: bool = False @abstractmethod def process(self, buf: list[str], ctx: EffectContext) -> list[str]: """Process buffer with effect applied""" ... @abstractmethod def configure(self, config: EffectConfig) -> None: """Configure the effect""" ... ``` ### EffectContext Passed to every effect's process method: ```python @dataclass class EffectContext: terminal_width: int terminal_height: int scroll_cam: int ticker_height: int camera_x: int = 0 mic_excess: float = 0.0 grad_offset: float = 0.0 frame_number: int = 0 has_message: bool = False items: list = field(default_factory=list) _state: dict[str, Any] = field(default_factory=dict) ``` Access sensor values via `ctx.get_sensor_value("sensor_name")`. ### EffectConfig Configuration dataclass: ```python @dataclass class EffectConfig: enabled: bool = True intensity: float = 1.0 params: dict[str, Any] = field(default_factory=dict) ``` ### Partial Updates For performance optimization, set `supports_partial_updates = True` and implement `process_partial`: ```python class MyEffect(EffectPlugin): supports_partial_updates = True def process_partial(self, buf, ctx, partial: PartialUpdate) -> list[str]: # Only process changed regions ... ``` ## Adding a New Effect 1. Create file in `effects_plugins/my_effect.py` 2. Inherit from `EffectPlugin` 3. Implement `process()` and `configure()` 4. Add to `effects_plugins/__init__.py` (runtime discovery via issubclass checks) ## Param Bindings Declarative sensor-to-param mappings: ```python param_bindings = { "intensity": {"sensor": "mic", "transform": "linear"}, "rate": {"sensor": "oscillator", "transform": "exponential"}, } ``` Transforms: `linear`, `exponential`, `threshold` ## Effect Chain Effects are chained via `engine/effects/chain.py` - processes each effect in order, passing output to next. ## Existing Effects See `effects_plugins/`: - noise.py, fade.py, glitch.py, firehose.py - border.py, crop.py, tint.py, hud.py