Phos4 · Terminal-UI Engine

Phos4

The Y3K Lab terminal-UI engine — pure bash, zero dependencies, fluent in A3K.

Built for the year 3000

Phos4reads phos-forphosphor — the coating that makes a CRT glow
P₄white phosphorus — the molecule that glows on its own
The family resemblance is the embedded numeral: Y3K carries a 3 — Phos4 answers with a 4.
The engine at work · a demo session · every colour below is theme data
❯ PHOS4_THEME=y3k PHOS4_ANIMATE=1 ./demo.sh
╔═════════════════════════════════╗ ╔═╗ ╦═╗ ╔═╗ ╦ ╔═╗ ╔═╗ ╔╦╗ ╔═╗ ╠═╝ ╠╦╝ ║ ║ ║ ╠═ ║ ║ ╚═╗ ╩ ╩╚═ ╚═╝ ╚╝ ╚═╝ ╚═╝ ╩ ╚═╝ ╚═════════════════════════════════╝
phos4_step_ok — the good news phos4_step_warn — the heads-up phos4_step_err — the bad news · phos4_step_info — the aside ───────────────────────────────────────────────────── phos4_choose — pick one ───────────────────────────────────────────────────── 1 banner the wordmark, boxed and swept 2 picker this very menu 3 panel the completion box ↑/↓ navigate · enter to select · type number to jump · esc to cancel

Hand-made in HTML/CSS from the engine's golden masters — the real thing is bash writing ANSI. The wordmark is the y3k theme's default; replays its power-on, and PS_MONO=1 re-renders the same markup from the grey band — a theme swap, live.

01

What Phos4 is

Phos4 is a pure-bash, themeable terminal-UI engine — gradient-swept wordmarks, arrow-key pickers, panels, spinners, progress — shipped as a single file any CLI script can source. No curses, no Python, no npm — bash 3.2 and ANSI escapes, nothing else.

It exists because the look outgrew its birthplace. A3K — the Y3K design language — took shape inside the Project System, entangled across three scripts; the installer even carried its own duplicate copies of the animations. Good enough to reuse, too tangled to travel. Phos4 is the extraction: the engine (mechanics) pulled clean of the look (data), so the machinery is shared once and the look is swappable per consumer.

The verbs stay disciplined: a surface wears A3K; Phos4 is fluent in it and renders it. An engine never builds the look — “built” stays reserved for the tagline, Built for the year 3000.

02

Engine vs. theme

The architecture is one clean cleave, three roles. The engine owns the mechanics — how a gradient sweeps a ramp across characters, how a wordmark gets boxed in rails, how a picker repaints in place. A theme is pure data — colour indices, gradient stops, rail glyphs, literal wordmark rows — no rendering code in a theme, ever; the contract is locked. And the consumer — the script that sourced the file — owns choreography: what happens, in what order, is its business. How it looks is not.

The whole theme contract · six functions of pure data
Theme functionSupplies
y3k_palettethe colour indices — accent, ok / warn / err, rails, highlight
y3k_rampthe gradient stops — 201 171 135 99 75 45 51, magenta → cyan
y3k_anim_rampthe longer 16-stop loop the power-on animation flows through
y3k_wm_widththe wordmark row width every row is padded to (31)
y3k_railthe box rails — top, bottom, side; every glyph is theme data
y3k_wordmarkliteral glyph-rows for each wordmark key

That table is the theme side of the seam — swap the prefix and you’ve named a new theme; the engine dispatches through PHOS4_THEME and never knows the difference. The seam is proven, not promised: a second theme — a different brand with its own logo language, flat colour, single-line box — renders through the same engine with zero engine changes. The one gap it exposed (a hardcoded side glyph) was closed by promoting that glyph to theme data; the pure-data contract held, no escape hatch.

Even greyscale is data: PS_MONO=1 swaps the ramp for a mid-grey band and the engine renders on, colour-blind — that’s the toggle under the demo above.

03

The primitives

The API is small, and all of it is namespaced: source one file, get every phos4_* call. Prompts answer the bash way — through environment variables and exit status, never parsed stdout — and ESC always means no.

CallRenders
phos4_render_bannerthe rail-boxed, gradient-swept wordmark — with a sub-second power-on entrance when PHOS4_ANIMATE=1
phos4_render_splashrail-less splash art — install banners, mascots, shapes that aren’t a boxed wordmark
phos4_gradient_textthe theme ramp swept per-character across any string
phos4_choose · confirm · inputthe arrow-key picker, the Yes/No toggle, the line prompt
phos4_step_ok · warn · err · infothe ✓ ⚠ ✗ · status lines
phos4_header · rule · panelsection chrome and the bordered completion box
phos4_spin · loadbara spinner (⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏) that wraps a command; the self-clearing fill bar
phos4_celebrate · celebrate_bannerthe shimmer sign-off; giant block letters for the moment a surface finishes something
04

The correctness rules

Half of Phos4’s value is invisible: the accumulated rules that keep a pure-bash renderer from corrupting a terminal. They live as comments at their site in the engine — no external doc to consult — and every one of them was paid for.

Rule 1 — TTY-gate every visual
Off a terminal the style strings are empty, and the same printf emits plain text. Pipe it, log it, test it — the escapes simply aren’t there. The engine never animates into a pipe.
Rule 2 — Guard the locale
Box glyphs are multibyte. ${#s} has to count characters, not bytes, or the per-character gradient miscounts and the box tears.
Rule 3 — Box borders are literals
Never loop-build a multibyte — concatenation corrupts in the C locale. Every rail ships as a hand-typed literal string.
Rule 4 — len on its own line
A combined local s="$1" len=${#s} measures s before it’s assigned — length zero, and the gradient silently vanishes. The engine’s signature bug, immortalized as a rule.
Rule 5 — Leave no dirty terminal
Anything that hides the cursor restores it under a trap — on every exit path, Ctrl-C included. The terminal is handed back the way it was found.
05

Proven pixel-identical

Extraction invites drift: rewrite the machinery and the look shifts a shade. Phos4’s acceptance bar refused that — byte-identical output, enforced by a golden master: renders captured from the original source before extraction, and every engine render since diffed against them, raw ANSI and all.

❯ ./test/parity.sh Parity ────────────────────────────────────────── the built engine vs the frozen golden master banner-default — byte-identical choose-nav — byte-identical celebrate — byte-identical · 24 more captures — every one green
╭───────────────────────────────────────────────────────╮ │ │ Parity green 27 of 27 captures byte-identical │ │ ╰───────────────────────────────────────────────────────╯
Certified Y3K Ready

Twenty-seven captures — banners, pickers, panels, both themes, colour and mono — all green. Vendoring the engine back into the Project System deleted ~960 lines of duplicated look from its first consumer, and that consumer’s release script re-copies the built engine every time it runs — a stale copy can’t ship.

06

One file, every theme

Authored split, shipped single. Source is an engine plus one file per theme; the build is a concatenation — this is bash, and the build step is a cat with opinions:

src/engine.sh the mechanics — rendering + the correctness rules src/themes/y3k.sh the default theme: A3K as pure data (the canonical values) build.sh engine + themes → one file dist/phos4.sh what consumers vendor — every theme aboard test/ the golden-output parity harness

Consumers copy dist/phos4.sh into their own repo and source it. Zero dependencies, nothing to install, no version to negotiate — the file that ships is the whole engine:

# in any bash script source phos4.sh # every phos4_* call, every theme phos4_render_banner default # the boxed, gradient-swept wordmark phos4_step_ok "did the thing" phos4_choose "Pick one" "Alpha|first" "Beta|second" echo "$PHOS4_CHOSEN_TITLE" # prompts answer via environment

Three environment variables drive everything: PHOS4_THEME picks the theme (default y3k — the A3K look), PHOS4_ANIMATE=1 opts into the power-on entrance, and PS_MONO=1 goes greyscale.

07

Where it lives

Phos4 has no public repo and no standalone download — yet. Today it ships the way it was always meant to: vendored inside a consumer. The Project System kit carries it as bin/phos4.sh, rendering the dashboard, the lifecycle scripts, and the installer. A standalone kit in the Blue Steel mold is planned — and until something actually ships, this page stays a read.