"""Discover built-in effects with editor completion and effect-specific types.
Type ``effects.`` to browse effects, then ``effects.snow.play(preset=...)``
for snow preset completion. ``effects.snow.presets()`` explains the presets by
returning independent SnowSettings copies. Runtime extensions remain available
through ``effect_registry`` and ``play("custom_name", ...)``.
"""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from os import PathLike
from typing import Generic, Literal, Never, TextIO, TypeVar, cast
from .bruheffect.registry import EffectEntry, effect_registry
from .bruheffect.settings import (
AudioSettings,
AutomatonSettings,
BoidsSettings,
ClothSettings,
DiffusionSettings,
DrawLinesSettings,
FireSettings,
FireworkSettings,
GameOfLifeSettings,
MatrixSettings,
MetaballsSettings,
NoiseSettings,
OffsetSettings,
PerlinSettings,
PlasmaSettings,
RainSettings,
SandSettings,
SmokeSettings,
SnowSettings,
StarSettings,
TerrainSettings,
TwinkleSettings,
VoronoiSettings,
WaterSettings,
)
from .bruhutil.bruhtypes import EffectType as EffectName
from .capture import Frame
from .resize import ResizePolicy
SettingsT = TypeVar("SettingsT")
PresetT = TypeVar("PresetT", bound=str)
[docs]
@dataclass(frozen=True)
class EffectInfo(Generic[SettingsT, PresetT]):
"""Typed view of a registry entry, without constructing a running effect."""
name: EffectName
@property
def description(self) -> str:
"""Human-readable description from the live registry."""
return effect_registry.get(self.name).description
[docs]
def defaults(self) -> SettingsT:
"""Return a fresh default configuration, or None for unconfigured effects."""
cls = effect_registry.get(self.name).settings_cls
return cast(SettingsT, cls() if cls is not None else None)
[docs]
def presets(self) -> dict[PresetT, SettingsT]:
"""Return preset names and independent, editable configuration copies."""
return cast(dict[PresetT, SettingsT], effect_registry.presets(self.name))
[docs]
def preset(self, name: PresetT) -> SettingsT:
"""Return one preset's settings; editors suggest this effect's names."""
return cast(SettingsT, effect_registry.resolve_settings(self.name, preset=name))
[docs]
def play(
self,
*,
preset: PresetT | None = None,
settings: SettingsT | None = None,
seed: int | None = None,
fps: float | None = 30,
updates_per_second: float | None = None,
frames: int | None = None,
duration: float | None = None,
on_complete: Literal["hold", "exit"] = "hold",
on_resize: ResizePolicy = "raise",
background: str = " ",
event_handler: Callable[[int], bool] | None = None,
) -> int:
"""Play this effect with typed presets/settings through the shared player.
duration is wall-clock seconds after startup; None is unlimited and zero
starts no effect. See bruhanimate.play for timing and ownership details.
"""
from .player import play
return play(
self.name,
preset=preset,
settings=settings,
seed=seed,
fps=fps,
updates_per_second=updates_per_second,
frames=frames,
duration=duration,
on_complete=on_complete,
on_resize=on_resize,
background=background,
event_handler=event_handler,
)
[docs]
def capture(
self,
*,
on_frame: Callable[[Frame], None],
preset: PresetT | None = None,
settings: SettingsT | None = None,
seed: int | None = None,
width: int = 80,
height: int = 24,
fps: float = 30,
updates_per_second: float | None = None,
frames: int | None = None,
duration: float | None = None,
on_complete: Literal["hold", "exit"] = "exit",
background: str = " ",
) -> int:
"""Stream immutable frames with typed presets/settings and virtual timing.
Requires frames or duration; see bruhanimate.capture for lifecycle,
reproducibility and timing details. seed overrides the selected settings.
"""
from .capture import capture
return capture(
self.name,
on_frame=on_frame,
preset=preset,
settings=settings,
seed=seed,
width=width,
height=height,
fps=fps,
updates_per_second=updates_per_second,
frames=frames,
duration=duration,
on_complete=on_complete,
background=background,
)
[docs]
def record(
self,
output: str | PathLike[str] | TextIO,
*,
preset: PresetT | None = None,
settings: SettingsT | None = None,
seed: int | None = None,
width: int = 80,
height: int = 24,
fps: float = 30,
updates_per_second: float | None = None,
frames: int | None = None,
duration: float | None = None,
on_complete: Literal["hold", "exit"] = "exit",
background: str = " ",
overwrite: bool = False,
) -> int:
"""Record an asciicast v2 file or borrowed text stream, without a terminal.
Requires frames or duration; see bruhanimate.record. Existing files are
protected unless overwrite=True. Preset/settings hints match this effect.
"""
from .capture import record
return record(
self.name,
output,
preset=preset,
settings=settings,
seed=seed,
width=width,
height=height,
fps=fps,
updates_per_second=updates_per_second,
frames=frames,
duration=duration,
on_complete=on_complete,
background=background,
overwrite=overwrite,
)
[docs]
def names() -> list[str]:
"""List all currently registered names, including custom effects."""
return effect_registry.names()
[docs]
def get(name: str) -> EffectEntry:
"""Inspect a live registry entry, including custom effects."""
return effect_registry.get(name)
static: EffectInfo[None, Never] = EffectInfo("static")
"""Fills the screen with a static background character."""
OffsetPreset = Literal["right", "left"]
offset: EffectInfo[OffsetSettings, OffsetPreset] = EffectInfo("offset")
"""Scrolling offset background."""
NoisePreset = Literal["sparse", "dense", "color"]
noise: EffectInfo[NoiseSettings, NoisePreset] = EffectInfo("noise")
"""Random noise pixels."""
StarPreset = Literal["greyscale", "color"]
stars: EffectInfo[StarSettings, StarPreset] = EffectInfo("stars")
"""Blinking star field."""
PlasmaPreset = Literal["greyscale", "color", "blocks", "random"]
plasma: EffectInfo[PlasmaSettings, PlasmaPreset] = EffectInfo("plasma")
"""Animated sine-wave plasma."""
GameOfLifePreset = Literal["plain", "decay", "color"]
gol: EffectInfo[GameOfLifeSettings, GameOfLifePreset] = EffectInfo("gol")
"""Conway's Game of Life with optional color decay."""
RainPreset = Literal["drizzle", "storm", "thunderstorm", "monsoon"]
rain: EffectInfo[RainSettings, RainPreset] = EffectInfo("rain")
"""Falling rain with wind direction and collision."""
MatrixPreset = Literal["default", "fast"]
matrix: EffectInfo[MatrixSettings, MatrixPreset] = EffectInfo("matrix")
"""Cascading random-character digital rain."""
DrawLinesPreset = Literal["thin", "thick"]
drawlines: EffectInfo[DrawLinesSettings, DrawLinesPreset] = EffectInfo("drawlines")
"""Bresenham line drawing onto the buffer."""
SnowPreset = Literal["light", "moderate", "blizzard", "windy"]
snow: EffectInfo[SnowSettings, SnowPreset] = EffectInfo("snow")
"""Falling snow with wind and ground accumulation."""
TwinklePreset = Literal["sparse", "dense"]
twinkle: EffectInfo[TwinkleSettings, TwinklePreset] = EffectInfo("twinkle")
"""Characters that pulse in brightness."""
FireworkPreset = Literal["plain", "color", "random"]
firework: EffectInfo[FireworkSettings, FireworkPreset] = EffectInfo("firework")
"""Firework explosions with multiple burst patterns."""
FirePreset = Literal["campfire", "inferno", "windy"]
fire: EffectInfo[FireSettings, FirePreset] = EffectInfo("fire")
"""Particle-based fire simulation."""
julia: EffectInfo[None, Never] = EffectInfo("julia")
"""Animated Julia-set fractal."""
BoidsPreset = Literal["default", "dense", "fast"]
boids: EffectInfo[BoidsSettings, BoidsPreset] = EffectInfo("boids")
"""Reynolds flocking simulation: separation, alignment, and cohesion rules."""
SandPreset = Literal["light", "normal", "heavy"]
sand: EffectInfo[SandSettings, SandPreset] = EffectInfo("sand")
"""Falling-sand cellular automaton; particles spawn at the top and pile up."""
DiffusionPreset = Literal["coral", "spots", "stripes", "organic"]
diffusion: EffectInfo[DiffusionSettings, DiffusionPreset] = EffectInfo("diffusion")
"""Gray-Scott reaction-diffusion; produces evolving organic spots and stripes."""
AutomatonPreset = Literal["rule30", "rule90", "rule110", "rule184"]
automaton: EffectInfo[AutomatonSettings, AutomatonPreset] = EffectInfo("automaton")
"""Wolfram 1-D elementary cellular automaton scrolling downward."""
VoronoiPreset = Literal["slow", "fast", "dense"]
voronoi: EffectInfo[VoronoiSettings, VoronoiPreset] = EffectInfo("voronoi")
"""Animated Voronoi diagram with drifting seed points."""
PerlinPreset = Literal["sparse", "dense", "fast"]
perlin: EffectInfo[PerlinSettings, PerlinPreset] = EffectInfo("perlin")
"""Smooth animated noise field built from multiple sine-wave octaves."""
AudioPreset = Literal[
"objects",
"tiles",
"glow",
"bars",
"mirror",
"waveform",
"spectrum",
"minimal",
]
audio: EffectInfo[AudioSettings, AudioPreset] = EffectInfo("audio")
"""Seven audio modes: objects, tiles, glow, bars, mirror, waveform, spectrum."""
WaterPreset = Literal["pond", "rain", "storm"]
water: EffectInfo[WaterSettings, WaterPreset] = EffectInfo("water")
"""Damped water ripples with reflecting edges and interacting impulses."""
SmokePreset = Literal["plume", "ink", "windy"]
smoke: EffectInfo[SmokeSettings, SmokePreset] = EffectInfo("smoke")
"""Rising smoke or sinking ink, with density advection and obstacles."""
MetaballsPreset = Literal["lava", "orbit", "outline"]
metaballs: EffectInfo[MetaballsSettings, MetaballsPreset] = EffectInfo("metaballs")
"""Implicit blobs merging and separating along independent orbits."""
ClothPreset = Literal["flag", "checker", "banner"]
cloth: EffectInfo[ClothSettings, ClothPreset] = EffectInfo("cloth")
"""Pinned waving cloth carrying a flag, text, or custom ASCII art."""
TerrainPreset = Literal["hills", "mountains", "contours"]
terrain: EffectInfo[TerrainSettings, TerrainPreset] = EffectInfo("terrain")
"""Perspective flyover of seeded hills with shaded or contour rendering."""
__all__ = [
"WaterPreset",
"water",
"SmokePreset",
"smoke",
"MetaballsPreset",
"metaballs",
"ClothPreset",
"cloth",
"TerrainPreset",
"terrain",
"EffectInfo",
"EffectName",
"names",
"get",
"static",
"OffsetPreset",
"offset",
"NoisePreset",
"noise",
"StarPreset",
"stars",
"PlasmaPreset",
"plasma",
"GameOfLifePreset",
"gol",
"RainPreset",
"rain",
"MatrixPreset",
"matrix",
"DrawLinesPreset",
"drawlines",
"SnowPreset",
"snow",
"TwinklePreset",
"twinkle",
"FireworkPreset",
"firework",
"FirePreset",
"fire",
"julia",
"BoidsPreset",
"boids",
"SandPreset",
"sand",
"DiffusionPreset",
"diffusion",
"AutomatonPreset",
"automaton",
"VoronoiPreset",
"voronoi",
"PerlinPreset",
"perlin",
"AudioPreset",
"audio",
]