diff --git a/README.md b/README.md index f284838..83227d6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > *Digital consciousness stream. Matrix aesthetic · THX-1138 hue.* -A full-screen terminal news ticker that renders live global headlines in large OTF-font block characters with selectable color gradients (Verdant Green, Molten Orange, or Violet Purple). Headlines auto-translate into the native script of their subject region. Ambient mic input warps the glitch rate in real time. A `--poetry` mode replaces the feed with public-domain literary passages. Live messages can be pushed to the display over [ntfy.sh](https://ntfy.sh). +A full-screen terminal news ticker that renders live global headlines in large OTF-font block characters with selectable color gradients (Verdant Green, Molten Orange, or Violet Purple). Headlines auto-translate into the native script of their subject region. Ambient mic input warps the glitch rate in real time. A `--poetry` mode replaces the feed with public-domain literary passages. Live messages can be pushed to the display over [ntfy.sh](https://ntfy.sh). **Figment mode** overlays flickery, theme-colored SVG glyphs on the running stream at timed intervals — controllable from any input source via an extensible trigger protocol. --- @@ -95,6 +95,43 @@ curl -d "Body text" -H "Title: Alert title" https://ntfy.sh/your_topic Update `NTFY_TOPIC` in `engine/config.py` to point at your own topic. +### Figment Mode + +Figment mode periodically overlays a full-screen SVG glyph on the running ticker — flickering through a reveal → hold (strobe) → dissolve cycle, colored with a randomly selected theme gradient. + +**Enable it** by setting the plugin's config at runtime (no CLI flag yet): + +```python +from engine.effects.registry import get_registry +plugin = get_registry().get("figment") +if plugin: + plugin.config.enabled = True + plugin.config.params["interval_secs"] = 60 # seconds between appearances + plugin.config.params["display_secs"] = 4.5 # duration of each appearance +``` + +**Figment assets** live in `figments/` — drop any `.svg` file there and it will be picked up automatically. The bundled set contains Mayan and Aztec glyphs. Figments are selected randomly, avoiding immediate repeats, and rasterized into half-block terminal art at display time. + +**Triggering manually** — any object with a `poll() -> FigmentCommand | None` method satisfies the `FigmentTrigger` protocol and can be passed to the plugin: + +```python +from engine.figment_trigger import FigmentAction, FigmentCommand + +class MyTrigger: + def poll(self): + if some_condition: + return FigmentCommand(action=FigmentAction.TRIGGER) + return None +``` + +Built-in commands: `TRIGGER`, `SET_INTENSITY`, `SET_INTERVAL`, `SET_COLOR`, `STOP`. + +**System dependency:** Figment mode requires the Cairo C library (`brew install cairo` on macOS) in addition to the `figment` extras group: + +```bash +uv sync --extras figment # adds cairosvg +``` + --- ## Internals @@ -109,6 +146,7 @@ Update `NTFY_TOPIC` in `engine/config.py` to point at your own topic. - The mic stream runs in a background thread, feeding RMS dB into the glitch probability calculation each frame - The viewport scrolls through a virtual canvas of pre-rendered blocks; fade zones at top and bottom dissolve characters probabilistically - An ntfy.sh SSE stream runs in a background thread; incoming messages interrupt the scroll and render full-screen until dismissed or expired +- Figment mode rasterizes SVGs via cairosvg → PIL → greyscale → half-block encode, then overlays them with ANSI cursor-positioning commands between the effect chain and the ntfy message layer ### Architecture @@ -116,27 +154,40 @@ Update `NTFY_TOPIC` in `engine/config.py` to point at your own topic. ``` engine/ - __init__.py package marker - app.py main(), font picker TUI, boot sequence, signal handler - config.py constants, CLI flags, glyph tables - sources.py FEEDS, POETRY_SOURCES, language/script maps - terminal.py ANSI codes, tw/th, type_out, boot_ln - filter.py HTML stripping, content filter - translate.py Google Translate wrapper + region detection - render.py OTF → half-block pipeline (SSAA, gradient) - effects.py noise, glitch_bar, fade, firehose - fetch.py RSS/Gutenberg fetching + cache load/save - ntfy.py NtfyPoller — standalone, zero internal deps - mic.py MicMonitor — standalone, graceful fallback - scroll.py stream() frame loop + message rendering - viewport.py terminal dimension tracking (tw/th) - frame.py scroll step calculation, timing - layers.py ticker zone, firehose, message overlay rendering - eventbus.py thread-safe event publishing for decoupled communication - events.py event types and definitions - controller.py coordinates ntfy/mic monitoring and event publishing - emitters.py background emitters for ntfy and mic - types.py type definitions and dataclasses + __init__.py package marker + app.py main(), font picker TUI, boot sequence, signal handler + config.py constants, CLI flags, glyph tables + sources.py FEEDS, POETRY_SOURCES, language/script maps + terminal.py ANSI codes, tw/th, type_out, boot_ln + filter.py HTML stripping, content filter + translate.py Google Translate wrapper + region detection + render.py OTF → half-block pipeline (SSAA, gradient) + effects.py noise, glitch_bar, fade, firehose + fetch.py RSS/Gutenberg fetching + cache load/save + ntfy.py NtfyPoller — standalone, zero internal deps + mic.py MicMonitor — standalone, graceful fallback + scroll.py stream() frame loop + message rendering + viewport.py terminal dimension tracking (tw/th) + frame.py scroll step calculation, timing + layers.py ticker zone, firehose, message + figment overlay rendering + figment_render.py SVG → cairosvg → PIL → half-block rasterizer with cache + figment_trigger.py FigmentTrigger protocol, FigmentAction enum, FigmentCommand + eventbus.py thread-safe event publishing for decoupled communication + events.py event types and definitions + controller.py coordinates ntfy/mic monitoring and event publishing + emitters.py background emitters for ntfy and mic + types.py type definitions and dataclasses + themes.py THEME_REGISTRY — gradient color definitions + +effects_plugins/ + __init__.py plugin discovery (ABC issubclass scan) + noise.py NoiseEffect — random character noise + glitch.py GlitchEffect — horizontal glitch bars + fade.py FadeEffect — edge fade zones + firehose.py FirehoseEffect — dense bottom ticker strip + figment.py FigmentEffect — periodic SVG glyph overlay (state machine) + +figments/ SVG assets for figment mode ``` `ntfy.py` and `mic.py` have zero internal dependencies and can be imported by any other visualizer. @@ -204,11 +255,15 @@ See `Mainline Renderer + ntfy Message Queue for ESP32.md` for the full server + Requires Python 3.10+ and [uv](https://docs.astral.sh/uv/). ```bash -uv sync # minimal (no mic) -uv sync --all-extras # with mic support (sounddevice + numpy) +uv sync # minimal (no mic, no figment) +uv sync --extras mic # with mic support (sounddevice + numpy) +uv sync --extras figment # with figment mode (cairosvg + system Cairo) +uv sync --all-extras # all optional features uv sync --all-extras --group dev # full dev environment ``` +Figment mode also requires the Cairo C library: `brew install cairo` (macOS). + ### Tasks With [mise](https://mise.jdx.dev/): @@ -226,7 +281,7 @@ mise run run-firehose # uv run mainline.py --firehose ### Testing -Tests live in `tests/` and cover `config`, `filter`, `mic`, `ntfy`, `sources`, and `terminal`. +Tests live in `tests/` and cover `config`, `filter`, `mic`, `ntfy`, `sources`, `terminal`, and the full figment pipeline (`figment_render`, `figment_trigger`, `figment`, `figment_overlay`). Figment tests are automatically skipped if Cairo is not installed. ```bash uv run pytest @@ -258,6 +313,9 @@ Pre-commit hooks run lint automatically via `hk`. - **Parallax secondary column** — a second, dimmer, faster-scrolling stream of ambient text at reduced opacity on one side ### Cyberpunk Vibes +- **Figment CLI flag** — expose `--figment` and `--figment-interval N` to enable figment mode from the command line without code changes +- **Figment intensity wiring** — `config.intensity` currently stored but not yet applied to reveal/dissolve speed or strobe frequency +- **ntfy figment trigger** — built-in `NtfyFigmentTrigger` that listens on a dedicated topic to fire figments on demand - **Keyword watch list** — highlight or strobe any headline matching tracked terms (names, topics, tickers) - **Breaking interrupt** — full-screen flash + synthesized blip when a high-priority keyword hits - **Live data overlay** — secondary ticker strip at screen edge: BTC price, ISS position, geomagnetic index