forked from genewildish/Mainline
- Fix TerminalDisplay: add screen clear each frame (cursor home + erase down) - Fix CameraStage: use set_canvas_size instead of read-only viewport properties - Fix Glitch effect: preserve visible line lengths, remove cursor positioning - Fix Fade effect: return original line when fade=0 instead of empty string - Fix Noise effect: use input line length instead of terminal_width - Remove HUD effect from all presets (redundant with border FPS display) - Add regression tests for effect dimension stability - Add docs/ARCHITECTURE.md with Mermaid diagrams - Add mise tasks: diagram-ascii, diagram-validate, diagram-check - Move markdown docs to docs/ (ARCHITECTURE, Refactor, hardware specs) - Remove redundant requirements files (use pyproject.toml) - Add *.dot and *.png to .gitignore Closes #25
137 lines
2.8 KiB
Markdown
137 lines
2.8 KiB
Markdown
---
|
|
name: mainline-sensors
|
|
description: Sensor framework for real-time input in Mainline
|
|
compatibility: opencode
|
|
metadata:
|
|
audience: developers
|
|
source_type: codebase
|
|
---
|
|
|
|
## What This Skill Covers
|
|
|
|
This skill covers Mainline's sensor framework - how to use, create, and integrate sensors for real-time input.
|
|
|
|
## Key Concepts
|
|
|
|
### Sensor Base Class (engine/sensors/__init__.py)
|
|
|
|
```python
|
|
class Sensor(ABC):
|
|
name: str
|
|
unit: str = ""
|
|
|
|
@property
|
|
def available(self) -> bool:
|
|
"""Whether sensor is currently available"""
|
|
return True
|
|
|
|
@abstractmethod
|
|
def read(self) -> SensorValue | None:
|
|
"""Read current sensor value"""
|
|
...
|
|
|
|
def start(self) -> None:
|
|
"""Initialize sensor (optional)"""
|
|
pass
|
|
|
|
def stop(self) -> None:
|
|
"""Clean up sensor (optional)"""
|
|
pass
|
|
```
|
|
|
|
### SensorValue Dataclass
|
|
|
|
```python
|
|
@dataclass
|
|
class SensorValue:
|
|
sensor_name: str
|
|
value: float
|
|
timestamp: float
|
|
unit: str = ""
|
|
```
|
|
|
|
### SensorRegistry
|
|
|
|
Discovers and manages sensors globally:
|
|
|
|
```python
|
|
from engine.sensors import SensorRegistry
|
|
registry = SensorRegistry()
|
|
sensor = registry.get("mic")
|
|
```
|
|
|
|
### SensorStage
|
|
|
|
Pipeline adapter that provides sensor values to effects:
|
|
|
|
```python
|
|
from engine.pipeline.adapters import SensorStage
|
|
stage = SensorStage(sensor_name="mic")
|
|
```
|
|
|
|
## Built-in Sensors
|
|
|
|
| Sensor | File | Description |
|
|
|--------|------|-------------|
|
|
| MicSensor | sensors/mic.py | Microphone input (RMS dB) |
|
|
| OscillatorSensor | sensors/oscillator.py | Test sine wave generator |
|
|
| PipelineMetricsSensor | sensors/pipeline_metrics.py | FPS, frame time, etc. |
|
|
|
|
## Param Bindings
|
|
|
|
Effects declare sensor-to-param mappings:
|
|
|
|
```python
|
|
class GlitchEffect(EffectPlugin):
|
|
param_bindings = {
|
|
"intensity": {"sensor": "mic", "transform": "linear"},
|
|
}
|
|
```
|
|
|
|
### Transform Functions
|
|
|
|
- `linear` - Direct mapping to param range
|
|
- `exponential` - Exponential scaling
|
|
- `threshold` - Binary on/off
|
|
|
|
## Adding a New Sensor
|
|
|
|
1. Create `engine/sensors/my_sensor.py`
|
|
2. Inherit from `Sensor` ABC
|
|
3. Implement required methods
|
|
4. Register in `SensorRegistry`
|
|
|
|
Example:
|
|
```python
|
|
class MySensor(Sensor):
|
|
name = "my-sensor"
|
|
unit = "units"
|
|
|
|
def read(self) -> SensorValue | None:
|
|
return SensorValue(
|
|
sensor_name=self.name,
|
|
value=self._read_hardware(),
|
|
timestamp=time.time(),
|
|
unit=self.unit
|
|
)
|
|
```
|
|
|
|
## Using Sensors in Effects
|
|
|
|
Access sensor values via EffectContext:
|
|
|
|
```python
|
|
def process(self, buf, ctx):
|
|
mic_level = ctx.get_sensor_value("mic")
|
|
if mic_level and mic_level > 0.5:
|
|
# Apply intense effect
|
|
...
|
|
```
|
|
|
|
Or via param_bindings (automatic):
|
|
|
|
```python
|
|
# If intensity is bound to "mic", it's automatically
|
|
# available in self.config.intensity
|
|
```
|