"""AnimationBase ABC — all animations implement render() and from_params().""" from abc import ABC, abstractmethod class AnimationBase(ABC): """Pure animation renderer — no I/O, stateless or state-per-instance. Each animation computes pixel data from time t and strip length. No networking, no disk I/O — just math. """ @abstractmethod def render(self, t: float, led_count: int) -> list[tuple]: """Render frame at time t (seconds since animation started). Returns list of (R, G, B) tuples, length == led_count. All channel values in range 0-255. """ ... @classmethod @abstractmethod def from_params(cls, params: dict) -> "AnimationBase": """Construct from CueModel.params dict. Missing keys use animation-specific defaults. """ ...