feat(effects): add entropy parameter to effect plugins
- Add entropy field to EffectConfig (0.0 = calm, 1.0 = chaotic) - Provide compute_entropy() method in EffectContext for dynamic scoring - Update Fade, Firehose, Glitch, Noise plugin defaults with entropy values - Enables finer control: intensity (strength) vs entropy (randomness) This separates deterministic effect strength from probabilistic chaos, allowing more expressive control in UI panel and presets. Fixes #32
This commit is contained in:
@@ -5,7 +5,7 @@ from engine.effects.types import EffectConfig, EffectContext, EffectPlugin
|
|||||||
|
|
||||||
class FadeEffect(EffectPlugin):
|
class FadeEffect(EffectPlugin):
|
||||||
name = "fade"
|
name = "fade"
|
||||||
config = EffectConfig(enabled=True, intensity=1.0)
|
config = EffectConfig(enabled=True, intensity=1.0, entropy=0.1)
|
||||||
|
|
||||||
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
|
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
|
||||||
if not ctx.ticker_height:
|
if not ctx.ticker_height:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from engine.terminal import C_DIM, G_DIM, G_LO, RST, W_GHOST
|
|||||||
|
|
||||||
class FirehoseEffect(EffectPlugin):
|
class FirehoseEffect(EffectPlugin):
|
||||||
name = "firehose"
|
name = "firehose"
|
||||||
config = EffectConfig(enabled=True, intensity=1.0)
|
config = EffectConfig(enabled=True, intensity=1.0, entropy=0.9)
|
||||||
|
|
||||||
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
|
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
|
||||||
firehose_h = config.FIREHOSE_H if config.FIREHOSE else 0
|
firehose_h = config.FIREHOSE_H if config.FIREHOSE else 0
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from engine.terminal import DIM, G_LO, RST
|
|||||||
|
|
||||||
class GlitchEffect(EffectPlugin):
|
class GlitchEffect(EffectPlugin):
|
||||||
name = "glitch"
|
name = "glitch"
|
||||||
config = EffectConfig(enabled=True, intensity=1.0)
|
config = EffectConfig(enabled=True, intensity=1.0, entropy=0.8)
|
||||||
|
|
||||||
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
|
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
|
||||||
if not buf:
|
if not buf:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from engine.terminal import C_DIM, G_DIM, G_LO, RST, W_GHOST
|
|||||||
|
|
||||||
class NoiseEffect(EffectPlugin):
|
class NoiseEffect(EffectPlugin):
|
||||||
name = "noise"
|
name = "noise"
|
||||||
config = EffectConfig(enabled=True, intensity=0.15)
|
config = EffectConfig(enabled=True, intensity=0.15, entropy=0.4)
|
||||||
|
|
||||||
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
|
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
|
||||||
if not ctx.ticker_height:
|
if not ctx.ticker_height:
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ class PartialUpdate:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class EffectContext:
|
class EffectContext:
|
||||||
|
"""Context passed to effect plugins during processing.
|
||||||
|
|
||||||
|
Contains terminal dimensions, camera state, frame info, and real-time sensor values.
|
||||||
|
"""
|
||||||
|
|
||||||
terminal_width: int
|
terminal_width: int
|
||||||
terminal_height: int
|
terminal_height: int
|
||||||
scroll_cam: int
|
scroll_cam: int
|
||||||
@@ -56,6 +61,26 @@ class EffectContext:
|
|||||||
items: list = field(default_factory=list)
|
items: list = field(default_factory=list)
|
||||||
_state: dict[str, Any] = field(default_factory=dict, repr=False)
|
_state: dict[str, Any] = field(default_factory=dict, repr=False)
|
||||||
|
|
||||||
|
def compute_entropy(self, effect_name: str, data: Any) -> float:
|
||||||
|
"""Compute entropy score for an effect based on its output.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
effect_name: Name of the effect
|
||||||
|
data: Processed buffer or effect-specific data
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Entropy score 0.0-1.0 representing visual chaos
|
||||||
|
"""
|
||||||
|
# Default implementation: use effect name as seed for deterministic randomness
|
||||||
|
# Better implementations can analyze actual buffer content
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
data_str = str(data)[:100] if data else ""
|
||||||
|
hash_val = hashlib.md5(f"{effect_name}:{data_str}".encode()).hexdigest()
|
||||||
|
# Convert hash to float 0.0-1.0
|
||||||
|
entropy = int(hash_val[:8], 16) / 0xFFFFFFFF
|
||||||
|
return min(max(entropy, 0.0), 1.0)
|
||||||
|
|
||||||
def get_sensor_value(self, sensor_name: str) -> float | None:
|
def get_sensor_value(self, sensor_name: str) -> float | None:
|
||||||
"""Get a sensor value from context state.
|
"""Get a sensor value from context state.
|
||||||
|
|
||||||
@@ -80,6 +105,7 @@ class EffectContext:
|
|||||||
class EffectConfig:
|
class EffectConfig:
|
||||||
enabled: bool = True
|
enabled: bool = True
|
||||||
intensity: float = 1.0
|
intensity: float = 1.0
|
||||||
|
entropy: float = 0.0 # Visual chaos metric (0.0 = calm, 1.0 = chaotic)
|
||||||
params: dict[str, Any] = field(default_factory=dict)
|
params: dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user