feat: Enable and configure figment mode via new CLI flags, update documentation, and improve Cairo library detection on macOS.
This commit is contained in:
20
README.md
20
README.md
@@ -45,6 +45,8 @@ python3 mainline.py # news stream
|
|||||||
python3 mainline.py --poetry # literary consciousness mode
|
python3 mainline.py --poetry # literary consciousness mode
|
||||||
python3 mainline.py -p # same
|
python3 mainline.py -p # same
|
||||||
python3 mainline.py --firehose # dense rapid-fire headline mode
|
python3 mainline.py --firehose # dense rapid-fire headline mode
|
||||||
|
python3 mainline.py --figment # enable periodic SVG glyph overlays
|
||||||
|
python3 mainline.py --figment-interval 30 # figment every 30 seconds (default: 60)
|
||||||
python3 mainline.py --refresh # force re-fetch (bypass cache)
|
python3 mainline.py --refresh # force re-fetch (bypass cache)
|
||||||
python3 mainline.py --no-font-picker # skip interactive font picker
|
python3 mainline.py --no-font-picker # skip interactive font picker
|
||||||
python3 mainline.py --font-file path.otf # use a specific font file
|
python3 mainline.py --font-file path.otf # use a specific font file
|
||||||
@@ -80,6 +82,7 @@ All constants live in `engine/config.py`:
|
|||||||
| `FRAME_DT` | `0.05` | Frame interval in seconds (20 FPS) |
|
| `FRAME_DT` | `0.05` | Frame interval in seconds (20 FPS) |
|
||||||
| `GRAD_SPEED` | `0.08` | Gradient sweep speed (cycles/sec, ~12s full sweep) |
|
| `GRAD_SPEED` | `0.08` | Gradient sweep speed (cycles/sec, ~12s full sweep) |
|
||||||
| `FIREHOSE_H` | `12` | Firehose zone height (terminal rows) |
|
| `FIREHOSE_H` | `12` | Firehose zone height (terminal rows) |
|
||||||
|
| `FIGMENT_INTERVAL` | `60` | Seconds between figment appearances (set by `--figment-interval`) |
|
||||||
| `NTFY_TOPIC` | klubhaus URL | ntfy.sh JSON stream endpoint |
|
| `NTFY_TOPIC` | klubhaus URL | ntfy.sh JSON stream endpoint |
|
||||||
| `NTFY_RECONNECT_DELAY` | `5` | Seconds before reconnecting after a dropped SSE stream |
|
| `NTFY_RECONNECT_DELAY` | `5` | Seconds before reconnecting after a dropped SSE stream |
|
||||||
| `MESSAGE_DISPLAY_SECS` | `30` | How long an ntfy message holds the screen |
|
| `MESSAGE_DISPLAY_SECS` | `30` | How long an ntfy message holds the screen |
|
||||||
@@ -129,15 +132,11 @@ Update `NTFY_TOPIC` in `engine/config.py` to point at your own topic.
|
|||||||
|
|
||||||
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.
|
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):
|
**Enable it** with the `--figment` flag:
|
||||||
|
|
||||||
```python
|
```bash
|
||||||
from engine.effects.registry import get_registry
|
uv run mainline.py --figment # glyph every 60 seconds (default)
|
||||||
plugin = get_registry().get("figment")
|
uv run mainline.py --figment --figment-interval 30 # every 30 seconds
|
||||||
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.
|
**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.
|
||||||
@@ -159,7 +158,7 @@ Built-in commands: `TRIGGER`, `SET_INTENSITY`, `SET_INTERVAL`, `SET_COLOR`, `STO
|
|||||||
**System dependency:** Figment mode requires the Cairo C library (`brew install cairo` on macOS) in addition to the `figment` extras group:
|
**System dependency:** Figment mode requires the Cairo C library (`brew install cairo` on macOS) in addition to the `figment` extras group:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv sync --extras figment # adds cairosvg
|
uv sync --extra figment # adds cairosvg
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -287,7 +286,7 @@ Requires Python 3.10+ and [uv](https://docs.astral.sh/uv/).
|
|||||||
```bash
|
```bash
|
||||||
uv sync # minimal (no mic, no figment)
|
uv sync # minimal (no mic, no figment)
|
||||||
uv sync --extras mic # with mic support (sounddevice + numpy)
|
uv sync --extras mic # with mic support (sounddevice + numpy)
|
||||||
uv sync --extras figment # with figment mode (cairosvg + system Cairo)
|
uv sync --extra figment # with figment mode (cairosvg + system Cairo)
|
||||||
uv sync --all-extras # all optional features
|
uv sync --all-extras # all optional features
|
||||||
uv sync --all-extras --group dev # full dev environment
|
uv sync --all-extras --group dev # full dev environment
|
||||||
```
|
```
|
||||||
@@ -343,7 +342,6 @@ 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
|
- **Parallax secondary column** — a second, dimmer, faster-scrolling stream of ambient text at reduced opacity on one side
|
||||||
|
|
||||||
### Cyberpunk Vibes
|
### 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
|
- **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
|
- **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)
|
- **Keyword watch list** — highlight or strobe any headline matching tracked terms (names, topics, tickers)
|
||||||
|
|||||||
@@ -413,6 +413,14 @@ def main():
|
|||||||
if config.FIREHOSE:
|
if config.FIREHOSE:
|
||||||
boot_ln("Firehose", "ENGAGED", True)
|
boot_ln("Firehose", "ENGAGED", True)
|
||||||
|
|
||||||
|
if config.FIGMENT:
|
||||||
|
try:
|
||||||
|
from effects_plugins.figment import FigmentEffect # noqa: F401
|
||||||
|
|
||||||
|
boot_ln("Figment", f"ARMED [{config.FIGMENT_INTERVAL}s interval]", True)
|
||||||
|
except (ImportError, OSError):
|
||||||
|
boot_ln("Figment", "UNAVAILABLE — run: brew install cairo", False)
|
||||||
|
|
||||||
time.sleep(0.4)
|
time.sleep(0.4)
|
||||||
slow_print(" > STREAMING...\n")
|
slow_print(" > STREAMING...\n")
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
|
|||||||
@@ -196,6 +196,8 @@ MODE = (
|
|||||||
else "news"
|
else "news"
|
||||||
)
|
)
|
||||||
FIREHOSE = "--firehose" in sys.argv
|
FIREHOSE = "--firehose" in sys.argv
|
||||||
|
FIGMENT = "--figment" in sys.argv
|
||||||
|
FIGMENT_INTERVAL = _arg_int("--figment-interval", 60) # seconds between appearances
|
||||||
|
|
||||||
# ─── NTFY MESSAGE QUEUE ──────────────────────────────────
|
# ─── NTFY MESSAGE QUEUE ──────────────────────────────────
|
||||||
NTFY_TOPIC = "https://ntfy.sh/klubhaus_terminal_mainline/json"
|
NTFY_TOPIC = "https://ntfy.sh/klubhaus_terminal_mainline/json"
|
||||||
|
|||||||
@@ -7,8 +7,20 @@ Follows the same pixel-pair approach as engine/render.py for OTF fonts.
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
|
# cairocffi (used by cairosvg) calls dlopen() to find the Cairo C library.
|
||||||
|
# On macOS with Homebrew, Cairo lives in /opt/homebrew/lib (Apple Silicon) or
|
||||||
|
# /usr/local/lib (Intel), which are not in dyld's default search path.
|
||||||
|
# Setting DYLD_LIBRARY_PATH before the import directs dlopen() to those paths.
|
||||||
|
if sys.platform == "darwin" and not os.environ.get("DYLD_LIBRARY_PATH"):
|
||||||
|
for _brew_lib in ("/opt/homebrew/lib", "/usr/local/lib"):
|
||||||
|
if os.path.exists(os.path.join(_brew_lib, "libcairo.2.dylib")):
|
||||||
|
os.environ["DYLD_LIBRARY_PATH"] = _brew_lib
|
||||||
|
break
|
||||||
|
|
||||||
import cairosvg
|
import cairosvg
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
|||||||
@@ -55,14 +55,16 @@ def stream(items, ntfy_poller, mic_monitor, display: Display | None = None):
|
|||||||
frame_number = 0
|
frame_number = 0
|
||||||
|
|
||||||
# Figment overlay (optional — requires cairosvg)
|
# Figment overlay (optional — requires cairosvg)
|
||||||
try:
|
figment = None
|
||||||
from effects_plugins.figment import FigmentEffect
|
if config.FIGMENT:
|
||||||
from engine.effects.registry import get_registry
|
try:
|
||||||
|
from effects_plugins.figment import FigmentEffect
|
||||||
|
|
||||||
_fg_plugin = get_registry().get("figment")
|
figment = FigmentEffect()
|
||||||
figment = _fg_plugin if isinstance(_fg_plugin, FigmentEffect) else None
|
figment.config.enabled = True
|
||||||
except ImportError:
|
figment.config.params["interval_secs"] = config.FIGMENT_INTERVAL
|
||||||
figment = None
|
except (ImportError, OSError):
|
||||||
|
pass
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if queued >= config.HEADLINE_LIMIT and not active:
|
if queued >= config.HEADLINE_LIMIT and not active:
|
||||||
|
|||||||
Reference in New Issue
Block a user