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 a white-hot → deep green gradient. 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.


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

First run bootstraps a local .mainline_venv/ and installs deps (feedparser, Pillow, sounddevice, numpy). Subsequent runs start immediately, loading from cache.


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
FONT_DIR fonts/ Folder scanned for .otf, .ttf, .ttc files
FONT_PATH first file in FONT_DIR Active display font (overridden by picker or --font-file)
FONT_INDEX 0 Face index within a font collection file
FONT_PICKER True Show interactive font picker at boot (--no-font-picker to skip)
FONT_SZ 60 Font render size (affects block density)
RENDER_H 8 Terminal rows per headline line
SSAA 4 Super-sampling factor (render at 4× then downsample)
SCROLL_DUR 5.625 Seconds per headline
FRAME_DT 0.05 Frame interval in seconds (20 FPS)
GRAD_SPEED 0.08 Gradient sweep speed (cycles/sec, ~12s full sweep)
FIREHOSE_H 12 Firehose zone height (terminal rows)
NTFY_TOPIC klubhaus URL ntfy.sh JSON endpoint to poll
NTFY_POLL_INTERVAL 15 Seconds between ntfy polls
MESSAGE_DISPLAY_SECS 30 How long an ntfy message holds the screen

Fonts

A fonts/ directory is bundled with demo faces (AlphatronDemo, CSBishopDrawn, CyberformDemo, KATA, Microbots, Neoform, Pixel Sparta, Robocops, Xeonic, and others). On startup, an interactive picker lists all discovered faces with a live half-block preview rendered at your configured size.

Navigation: / or j/k to move, Enter or q to select. The selected face persists for that session.

To add your own fonts, drop .otf, .ttf, or .ttc files into fonts/ (or point --font-dir at any other folder). Font collections (.ttc, multi-face .otf) are enumerated face-by-face.


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 poller runs in a background thread; incoming messages interrupt the scroll and render full-screen until dismissed or expired

Architecture

mainline.py is a thin entrypoint (venv bootstrap → engine.app.main()). All logic lives in the engine/ package:

engine/
  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
  app.py          main(), font picker TUI, boot sequence, signal handler

ntfy.py and mic.py have zero internal dependencies and can be imported by any other visualizer.


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.


ntfy.sh Integration

Mainline polls a configurable ntfy.sh topic in the background. When a message arrives, the scroll pauses and the message renders full-screen for MESSAGE_DISPLAY_SECS seconds, then the stream resumes.

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. The NtfyPoller class is fully standalone and can be reused by other visualizers:

from engine.ntfy import NtfyPoller
poller = NtfyPoller("https://ntfy.sh/my_topic/json?since=20s&poll=1")
poller.start()
# in render loop:
msg = poller.get_active_message()  # returns (title, body, timestamp) or None

Ideas / Future

Performance

  • Concurrent feed fetching — startup currently blocks sequentially on ~25 HTTP requests; concurrent.futures.ThreadPoolExecutor would cut load time to the slowest single feed
  • Background refresh — re-fetch feeds in a daemon thread so a long session stays current without restart
  • Translation pre-fetch — run translate calls concurrently during the boot sequence rather than on first render

Graphics

  • Matrix rain underlay — katakana column rain rendered at low opacity beneath the scrolling blocks as a background layer
  • CRT simulation — subtle dim scanlines every N rows, occasional brightness ripple across the full screen
  • Sixel / iTerm2 inline images — bypass half-blocks entirely and stream actual bitmap frames for true resolution; would require a capable terminal
  • Parallax secondary column — a second, dimmer, faster-scrolling stream of ambient text at reduced opacity on one side

Cyberpunk Vibes

  • 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

macOS only (script/system font paths for translation are hardcoded). Primary display font is user-selectable via the bundled fonts/ picker. Python 3.9+.

test

Description
A full-screen terminal news stream in a Matrix/THX-1138 aesthetic — scrolling live global headlines in large block type, with per-region translation and mic-reactive glitch effects. Supports a --poetry mode for public-domain literary passages.
Readme 4.6 MiB
Languages
Python 100%