From 0e1c46cdcc79c04093707974a3e8b589fc240c39 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Mon, 16 Feb 2026 16:21:05 -0500 Subject: [PATCH] Add visual effects system documentation --- docs/how/effects.rst | 86 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 docs/how/effects.rst diff --git a/docs/how/effects.rst b/docs/how/effects.rst new file mode 100644 index 0000000..543a764 --- /dev/null +++ b/docs/how/effects.rst @@ -0,0 +1,86 @@ +============== +visual effects +============== + +the overlay system for transient visual effects like cloud trails. + +overview +======== + +effects are temporary overlays displayed on top of terrain in the viewport. +each effect has a position, character, color, and expiration time. they're +rendered last-wins on overlap, cleaned up passively in the game loop. + +data model +========== + +effect dataclass +---------------- + +defined in ``effects.py``:: + + @dataclass + class Effect: + x: int + y: int + char: str + color: str # ANSI code + expires_at: float # monotonic time + +global state +------------ + +single global list:: + + active_effects: list[Effect] = [] + +no per-zone partitioning. simple. + +core functions +============== + +``add_effect(x, y, char, color, ttl)`` + creates effect with expiry at ``time.monotonic() + ttl``, appends to list + +``get_effects_at(x, y)`` + returns active effects at position, auto-filters expired ones + +``clear_expired()`` + in-place list mutation to drop expired effects. called once per tick + (10/sec) in ``server.py`` game loop + +rendering +========= + +in ``look.py``, for each viewport tile: + +1. check ``get_effects_at(x, y)`` +2. if effects exist, take ``effects[-1]`` (most recent) +3. display its ``char`` and ``color``, overlaying terrain + +last-added effect wins on overlap. + +timing +====== + +uses ``time.monotonic()`` for consistent async timing. ttl in seconds. + +current usage: fly command creates cloud trail ("~" bright white) with +staggered ttls (1.5s base + 0.4s per step) so clouds fade origin to destination. + +design decisions +================ + +- global state, not per-zone (simplicity) +- passive cleanup via tick-based ``clear_expired()`` +- last-wins overlay (no z-index, no blending) +- just char + ANSI color (minimal rendering) +- monotonic time (no wall clock drift) + +code +==== + +- ``src/mudlib/effects.py`` - dataclass, functions, global state +- ``src/mudlib/look.py`` - viewport rendering with effect overlay +- ``src/mudlib/server.py`` - game loop calls ``clear_expired()`` +- ``content/commands/fly.toml`` - cloud trail effect usage