Skip to content

neo — Matrix digital rain (canonical single-color screensaver reference)

Batch 8 — rendering / screensaver / ambient-display cluster (highest single-color relevance).

neo recreates the Matrix “digital rain” — endless columns of characters cascading down the screen, each column a falling stream with a bright leading head and a dimming tail trailing behind it. It ships as a single binary with a deep customization surface: charset selection (default half-width katakana, plus ascii and arbitrary user charsets via --charset / --chars), color selection (-c/--color, 16 / 256 / 32-bit truecolor, --colormode=0 for monochrome), speed control (-S/--speed, adjustable live with arrow keys), glitch/shimmer toggle (--noglitch), full-width support (-F), and a centered message overlay (-m/--message). It auto-detects terminal color and Unicode support and handles resize.

The whole effect is a screensaver in the literal original sense: an idle, evolving, content-free animation that fills the screen and signals “the machine is alive but at rest.” For KN-86 that is exactly the missing affordance — what the deck shows when the operator walks away.

neo is the cleanest mechanical reference in the whole cluster because its visual identity reduces to one variable rendered well: brightness as a function of distance behind the head. Reading src/cloud.cpp, each cell’s color-pair index is computed as a linear ramp:

colorPair = numColorPairs - round((headPutLine - line) / length * (numColorPairs - 1))

The head sits at the brightest pair; every cell further up the trail steps down the ramp by its fractional distance, clamped to [1, numColorPairs-1]. The droplet model (src/droplet.cpp) tracks a head and a tail crawling down each column independently with their own put/cur line positions and stop timing, so columns desync naturally and the field never looks like a metronome. The glitch layer re-randomizes occasional settled cells in place (the shimmer), and --noglitch disables it.

That is the entire cascade: per-column head/tail crawl + per-cell brightness-by-distance ramp + optional in-place character re-roll. No image input, no per-frame raster, no heavy math — it is a procedural field generator, which is precisely the profile that fits an idle-mode budget.

neo’s single-color adaptation is trivial and exemplary — which is why it’s the canonical reference for this cluster. The effect already is a single-color effect with a brightness ramp; the green is incidental. To land it on KN-86:

  • Replace the green color-pair ramp with an amber brightness ramp. KN-86 is amber #E6A020 on black #000000 (see CLAUDE.md Canonical Hardware Specification — monochrome, no other colors). The N color pairs become N intensity steps of the single amber phosphor: head at full amber, tail dimming toward black. On the prototype the panel is a real LCD, so “dimming” is amber-at-reduced-luminance, not a palette swap — the same colorPair integer just indexes an intensity LUT instead of an ncurses pair. This is the textbook demonstration that brightness gradient is the primary single-color rendering lever: vary luminance of one hue and the cascade reads exactly as it does in full color.
  • Charset → CP437 / KN-86 code page. neo’s katakana default is non-period-correct for KN-86. The deck’s font is Press Start 2P + CP437 box drawing (Canonical Hardware Spec). The rain charset should be drawn from the KN-86 code page — digits, punctuation, box fragments, the Lisp-primitive glyphs — so the cascade reads as the deck’s own alphabet falling, not generic katakana. neo’s --charset / --chars mechanism shows the charset is a clean injection point.
  • Glitch as restraint. neo’s shimmer is good but loud; the KN-86 dispatch voice is terse and unshowy. Default the glitch rate low.

Proposed Deckline ambient / screensaver mode (neo as the seed)

Section titled “Proposed Deckline ambient / screensaver mode (neo as the seed)”

neo and astroterm together seed a Deckline ambient mode — the idle state the nOSh runtime enters after an inactivity timeout. Proposed architecture:

  • Trigger. A nOSh idle timer (reuse the power-idle path from the platform layer — CPU governor / screen-blank already exists in the device config). After timeout, instead of blanking, nOSh enters ambient mode on the primary 128×75 grid. Any key exits instantly back to the prior surface.
  • Renderer is procedural, not raster. Ambient scenes are field generators that write directly into the termbox2 cell grid (per ADR-0027 — 128×75, 8×8 PSF, half-block 128×150 pseudo-pixel canvas). neo is the first scene: amber rain at the deck’s own charset. astroterm is the second: a slow star-map drift. Both are pure CPU procedural loops with no image decode — the right profile for an always-may-be-running idle animation.
  • Frame budget. Cap ambient mode at a low refresh (neo runs fine well under 20 fps; the cascade reads at 10–15 fps). This sits comfortably inside the 20 fps animation cap nOSh already enforces and keeps the Pi Zero 2 W idle-cool — ambient mode should lower average draw vs. an active cart, not raise it.
  • Scene roster as a SYS setting. Like the CRT-glitch intensity setting already persisted at /home/shared/nosh-config.toml, the ambient-scene choice (rain / starfield / off) is a SYS-tab setting. This composes with the accelerometer-driven ambient CRT-glitch system already in the spec — ambient mode is the natural home for that motion-reactive glitch.

Relation to the (reveal …) visual language

Section titled “Relation to the (reveal …) visual language”

The ambient field and the (reveal …) primitive (ADR-0033) are the same family of “characters changing over time toward or away from a target.” neo’s per-cell character re-roll is mechanically identical to :char-flicker’s per-cell flicker-to-settle — the difference is only that the rain never settles. Ambient-mode exit is a natural (unreveal …) / (reveal …) handoff: the rain collapses and the prior surface reveals back in, reusing the existing primitive rather than authoring a bespoke transition.

  • GPL-3.0 — do not vendor. The cascade algorithm is ~tens of lines and fully understood from the source read above; reimplement from first principles in nOSh’s own permissively-licensed C, the same posture taken with no-more-secrets (also GPL).
  • Performance caveat is real and informative. neo’s own README warns it “can be a bit of a CPU hog, especially on large screens with slow terminal emulators.” That cost is mostly terminal-emulator escape-sequence overhead, which nOSh avoids by writing the termbox2 cell grid directly rather than emitting ANSI. The field math itself is cheap. Still — measure ambient-mode draw on the Pi Zero 2 W during bring-up and confirm it stays below active-cart draw before committing it as the default idle behaviour.
  • Cross-link astroterm — the other half of the ambient-mode seed (starfield scene to neo’s rain scene).
  • Cross-link ascii-effects.md and reveal-styles.md — the brightness-gradient lever here is the same one the hover-brighten effect and :char-flicker reveal use.
  • Cross-link no-more-secrets — sibling per-cell character-flicker effect; neo is the never-settling version, no-more-secrets the settle-to-target version.
  • Cross-link libcaca and react-video-ascii — those convert imagery to text; neo and astroterm generate the field procedurally. Two distinct rendering modes the deck wants both of.