browsh
Batch 8 (readers / browsers / hierarchical-navigation TUIs).
What it is
Section titled “What it is”browsh renders real, fully-rendered web pages — including images, video, and CSS layout — into a terminal, by driving headless Firefox and converting its rendered output into terminal cells. The architecture is two parts: a Firefox webextension that runs inside the browser and extracts both the page’s text (with positions) and a downscaled pixel framebuffer, and a Go terminal client that receives that data and paints it to the TTY. Graphical regions are drawn with the unicode half-block character, encoding two vertically-stacked pixels in a single character cell; text regions are drawn as actual glyphs layered on top. Most keys and mouse gestures behave like a normal browser.
Deckline-relevance
Section titled “Deckline-relevance”- Half-block pixel rendering is the headline technique — the single strongest single-color rendering takeaway in this batch (see “Single-color adaptation”). It lets a text grid behave like a 2×-vertical-resolution pixel display.
- Browser-style UI chrome on a text grid. browsh reproduces the affordances people expect from a browser — a content viewport with a chrome strip (URL/address area, status) framing it. For KN-86 this validates the Row-0 status / Rows-1–23 content / Row-24 action layout (per Canonical Hardware Specification) as a legitimate “chrome around a viewport” pattern, and is a reference for any cart presenting a navigable document viewport with a persistent control strip.
- Dual text + graphics layers. browsh’s key architectural insight is keeping text as real glyphs and only the graphical remainder as half-block pixels, compositing them. KN-86’s SPLIT mode is exactly this: a TEXT plane and a BITMAP plane that coexist. browsh is the working proof that “crisp glyphs where there’s text, pixel-encoding where there’s imagery” is the right division — never pixel-encode text you could render as a glyph.
- Downscale-then-encode pipeline. browsh has Firefox downscale the page to terminal-cell resolution before shipping pixels, so the client just maps cells 1:1. KN-86’s image path should mirror this: scale source imagery to the target cell count first, then encode — don’t encode at full resolution and downscale glyphs.
- Client/renderer split. The thin terminal client + heavy off-device renderer split echoes KN-86’s own Pi (orchestrator/renderer) ↔ Pico coprocessor split and the emulator ↔ device split — a reference for keeping the display client dumb and the content producer authoritative.
Single-color adaptation
Section titled “Single-color adaptation”This is the entry’s payload. browsh’s half-block technique is already monochrome-ready — it’s a brightness/position trick that happens to carry color, and strips cleanly to single-color amber.
The half-block mechanism (from browsh’s own source): browsh uses the lower half-block ▄ (U+2584). One character cell then carries two stacked pixels: the top pixel is the cell’s background color, the bottom pixel is the cell’s foreground color (the color of the ▄ glyph itself). The renderer walks the pixel framebuffer two rows at a time (y += 2), reading the upper row as the background and the lower row as the foreground for each cell. Result: a character grid renders at 2× its vertical pixel resolution.
KN-86 amber-on-black adaptation: KN-86 is single-color, so “color per pixel” becomes “on/off per pixel” — or, with the amber-brightness ramp KN-86 already commits to, a small set of intensity levels. Each cell encodes two vertical sub-pixels:
| Top pixel | Bottom pixel | Cell |
|---|---|---|
| off | off | space (blank) |
| on | off | ▀ (upper half-block) |
| off | on | ▄ (lower half-block) |
| on | on | █ (full block) |
That four-glyph set ( ▀▄█) gives a pure-monochrome 2×-vertical-resolution pixel canvas with no color dependency at all — the position of the lit half is the pixel. Layering KN-86’s amber-intensity ramp on the fg/bg gives graded brightness per half-cell without leaving the monochrome palette. This is the canonical KN-86 pixel-from-glyph primitive, and it matches the ▀-halfblock technique already documented at asciinator and in the ascii-effects.md spec — browsh is the browser-scale proof that it works for full-page imagery, not just small effects.
- Go + headless Firefox is not a KN-86 dependency path — the Pi Zero 2 W can’t host headless Firefox, and KN-86 has no live web to render. The value is purely the half-block rendering technique and the text/graphics compositing discipline.
- Cross-link asciinator (Batch 3) — the half-block-
▀technique with fg+bg, three render modes; browsh is the same primitive proven at browser scale. - Cross-link ascii-effects.md — the KN-86 character-rendering spec the half-block path feeds.
- Cross-link mapscii — the braille-density sibling: half-block gives 2× vertical resolution and clean filled regions; braille gives 2×4 sub-cell resolution for fine sparse detail. KN-86 wants both in the toolkit, chosen by content type.
- Cross-link w3m — the true-overlay alternative to character-encoding imagery; browsh and w3m bracket the two ways to put a picture in a text UI.