Files
Mainline/README.md
Gene Johnson 3a1aa975d1 docs: update README for figment mode
- Add figment mode to intro paragraph
- New Figment Mode section: enabling, assets, trigger protocol, deps
- Architecture table updated with engine/figment_render.py,
  figment_trigger.py, and effects_plugins/ directory breakdown
- Dev setup: separate uv sync --extras entries (mic vs figment)
- Testing section: mentions figment test coverage and Cairo skip
- Roadmap: adds figment follow-up items (CLI flag, intensity wiring,
  ntfy trigger)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 13:39:58 -07:00

15 KiB
Raw Permalink Blame History

MAINLINE

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. 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.


Contents


Using

Run

python3 mainline.py                      # news stream
python3 mainline.py --poetry             # literary consciousness mode
python3 mainline.py -p                   # same
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 --display websocket  # web browser display only
python3 mainline.py --display both       # terminal + web browser
python3 mainline.py --refresh            # force re-fetch (bypass cache)
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-dir ~/fonts   # scan a different font folder
python3 mainline.py --font-index 1       # select face index within a collection

Or with uv:

uv run mainline.py

First run bootstraps dependencies. Use uv sync --all-extras for mic support.

Command & Control (C&C)

Control mainline remotely using cmdline.py:

uv run cmdline.py                    # Interactive TUI
uv run cmdline.py /effects list      # List all effects
uv run cmdline.py /effects stats     # Show performance stats
uv run cmdline.py -w /effects stats  # Watch mode (auto-refresh)

Commands are sent via ntfy.sh topics - useful for controlling a daemonized mainline instance.

Config

All constants live in engine/config.py:

Constant Default What it does
HEADLINE_LIMIT 1000 Total headlines per session
FEED_TIMEOUT 10 Per-feed HTTP timeout (seconds)
MIC_THRESHOLD_DB 50 dB floor above which glitches spike
NTFY_TOPIC klubhaus URL ntfy.sh JSON stream for messages
NTFY_CC_CMD_TOPIC klubhaus URL ntfy.sh topic for C&C commands
NTFY_CC_RESP_TOPIC klubhaus URL ntfy.sh topic for C&C responses
NTFY_RECONNECT_DELAY 5 Seconds before reconnecting after dropped SSE
MESSAGE_DISPLAY_SECS 30 How long an ntfy message holds the screen
FONT_DIR fonts/ Folder scanned for .otf, .ttf, .ttc files
FONT_PATH first file in FONT_DIR Active display font
FONT_PICKER True Show interactive font picker at boot
FONT_SZ 60 Font render size (affects block density)
RENDER_H 8 Terminal rows per headline line
SSAA 4 Super-sampling factor
SCROLL_DUR 5.625 Seconds per headline
FRAME_DT 0.05 Frame interval in seconds (20 FPS)
FIREHOSE_H 12 Firehose zone height (terminal rows)
GRAD_SPEED 0.08 Gradient sweep speed
FIGMENT_INTERVAL 60 Seconds between figment appearances (set by --figment-interval)

Display Modes

Mainline supports multiple display backends:

  • Terminal (--display terminal): ANSI terminal output (default)
  • WebSocket (--display websocket): Stream to web browser clients
  • Sixel (--display sixel): Sixel graphics in supported terminals (iTerm2, mintty)
  • Both (--display both): Terminal + WebSocket simultaneously

WebSocket mode serves a web client at http://localhost:8766 with ANSI color support and fullscreen mode.

Feeds

~25 sources across four categories: Science & Technology, Economics & Business, World & Politics, Culture & Ideas. Add or swap feeds in engine/sources.pyFEEDS.

Poetry mode pulls from Project Gutenberg: Whitman, Dickinson, Thoreau, Emerson. Sources are in engine/sources.pyPOETRY_SOURCES.

Fonts

A fonts/ directory is bundled with demo faces. On startup, an interactive picker lists all discovered faces with a live half-block preview.

Navigation: / or j/k to move, Enter or q to select.

To add your own fonts, drop .otf, .ttf, or .ttc files into fonts/.

ntfy.sh

Mainline polls a configurable ntfy.sh topic in the background. When a message arrives, the scroll pauses and the message renders full-screen.

To push a message:

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 with the --figment flag:

uv run mainline.py --figment                        # glyph every 60 seconds (default)
uv run mainline.py --figment --figment-interval 30  # every 30 seconds

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:

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:

uv sync --extra figment   # adds cairosvg

Internals

How it works

  • On launch, the font picker scans fonts/ and presents a live-rendered TUI for face selection; --no-font-picker skips directly to stream
  • Feeds are fetched and filtered on startup (sports and vapid content stripped); results are cached to .mainline_cache_news.json / .mainline_cache_poetry.json for fast restarts
  • Headlines are rasterized via Pillow with 4× SSAA into half-block characters (▀▄█ ) at the configured font size
  • The ticker uses a sweeping white-hot → deep green gradient; ntfy messages use a complementary white-hot → magenta/maroon gradient to distinguish them visually
  • Subject-region detection runs a regex pass on each headline; matches trigger a Google Translate call and font swap to the appropriate script (CJK, Arabic, Devanagari, etc.) using macOS system fonts
  • 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 for messages and C&C commands; 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

engine/
  __init__.py           package marker
  app.py                main(), font picker TUI, boot sequence, C&C poller
  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/              plugin architecture for visual effects
    types.py            EffectPlugin ABC, EffectConfig, EffectContext
    registry.py         effect registration and lookup
    chain.py            effect pipeline chaining
    controller.py       handles /effects commands
    performance.py      performance monitoring
    legacy.py           legacy functional effects
  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
  display/              Display backend system
    __init__.py         DisplayRegistry, get_monitor
    backends/
      terminal.py       ANSI terminal display
      websocket.py      WebSocket server for browser clients
      sixel.py          Sixel graphics (pure Python)
      null.py           headless display for testing
      multi.py          forwards to multiple displays
  benchmark.py          performance benchmarking tool

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

Development

Setup

Requires Python 3.10+ and uv.

uv sync                              # minimal (no mic, no figment)
uv sync --extra mic                  # with mic support (sounddevice + numpy)
uv sync --extra 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:

mise run test            # run test suite
mise run test-cov       # run with coverage report

mise run lint           # ruff check
mise run lint-fix       # ruff check --fix
mise run format         # ruff format

mise run run            # terminal display
mise run run-websocket  # web display only
mise run run-sixel     # sixel graphics
mise run run-both       # terminal + web
mise run run-client     # both + open browser

mise run cmd            # C&C command interface
mise run cmd-stats      # watch effects stats

mise run benchmark      # run performance benchmarks
mise run benchmark-json # save as JSON

mise run topics-init    # initialize ntfy topics

Testing

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.

uv run pytest
uv run pytest --cov=engine --cov-report=term-missing

# Run with mise
mise run test
mise run test-cov

# Run performance benchmarks
mise run benchmark
mise run benchmark-json

# Run benchmark hook mode (for CI)
uv run python -m engine.benchmark --hook

Performance regression tests are in tests/test_benchmark.py marked with @pytest.mark.benchmark.

Linting

uv run ruff check engine/ mainline.py
uv run ruff format engine/ mainline.py

Pre-commit hooks run lint automatically via hk.


Roadmap

Performance

  • Concurrent feed fetching with ThreadPoolExecutor
  • Background feed refresh daemon
  • Translation pre-fetch during boot

Graphics

  • Matrix rain katakana underlay
  • CRT scanline simulation
  • Sixel/iTerm2 inline images
  • Parallax secondary column

Cyberpunk Vibes

  • Figment intensity wiringconfig.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
  • Theme switcher--amber (phosphor), --ice (electric cyan), --red (alert state) palette modes via CLI flag
  • Persona modes--surveillance, --oracle, --underground as feed presets with matching color themes and boot copy
  • Synthesized audio — short static bursts tied to glitch events, independent of mic input

Extensibility

  • serve.py — HTTP server that imports engine.render and engine.fetch directly to stream 1-bit bitmaps to an ESP32 display
  • Rust portntfy.py and render.py are the natural first targets; clear module boundaries make incremental porting viable

Python 3.10+. Primary display font is user-selectable via bundled fonts/ picker.