Skip to content

ink-web

ink-web renders Ink components into an xterm.js terminal in the browser. The same Ink component tree that draws to a real terminal draws to an xterm.js canvas in a web page — identical output in both targets. It is, in effect, Ink with a second render backend, proving that a component-described TUI is portable across “real terminal” and “terminal emulator embedded in another host.”

It ships ink-ui, a component library distributed as a shadcn registry (you pull components into your project via the shadcn CLI rather than installing a monolithic dependency — copy-in, own-the-source). The catalog is the interesting part — it is a concrete, opinionated answer to “what does a complete TUI component library contain”:

  • ascii — large banner text via figlet
  • gradient — multi-color gradient text
  • link — OSC-8 hyperlinks (clickable in supporting terminals)
  • multi-select — checkbox list, multiple selection
  • select-input — single-select list with a cursor/highlight
  • spinner — animated loading indicator
  • status-bar — a bottom bar of keybind hints rendered as inverse-bold badges (e.g. an inverse badge next to “Submit”, an inverse q next to “Quit”)
  • tab-bar — a row of tabs with the active tab drawn in inverse highlight
  • table — rounded box-drawing borders, per-column alignment, per-cell styling, and a footer row
  • text-input — single-line editable input with a cursor

Why this matters for KN-86 — three distinct signals

Section titled “Why this matters for KN-86 — three distinct signals”

(a) The status-bar component is the canonical Row-74 keybind-hint-bar reference

Section titled “(a) The status-bar component is the canonical Row-74 keybind-hint-bar reference”

KN-86’s chrome contract reserves the bottom row as a runtime-owned action bar — under ADR-0027’s 128×75 grid, that is Row 74 (the old 80×25 “Row 24” language is superseded; rows 1..73 are cart-usable, row 0 and row 74 are chrome). The action bar’s job is exactly what ink-ui’s status-bar does: advertise the currently-available key actions as compact badges. ink-ui renders each hint as an inverse-bold badge — the key glyph in inverse video, the label adjacent in normal weight — which is precisely the idiom an amber-on-black monochrome device wants, because inverse video is the one “second color” a monochrome display gets for free (swap fg/bg → black-on-amber badge against the amber-on-black field). No palette needed; the contrast does the work.

Treat ink-ui’s status-bar as the design reference for the Row-74 action bar spec: badge composition, spacing between hint groups, truncation when hints overflow the 128-column width, and the active/inactive distinction. This is directly relevant to the REPL’s permanent Row-74 advertisement (the TERM-key REPL surface per the runtime docs) and to every cart that needs to surface its current verb set. The runtime owns Row 74, so this is a nOSh chrome reference, not a cart-facing one.

(b) The full ink-ui set is a “component catalog” answer for KN-86

Section titled “(b) The full ink-ui set is a “component catalog” answer for KN-86”

ink-ui is a compact, complete inventory of the widgets a keyboard-driven TUI actually needs: select-input, multi-select, text-input, table, tab-bar, status-bar, spinner. This pairs with the widget-inventory note in termui.md (BarChart, Gauge, Sparkline, Plot, Table, Tabs, List, Tree, Canvas). Between the two, KN-86 has a strong baseline for what an optional Fe-side UI library should offer cart authors and chrome:

  • select-input / multi-select → the mission board’s card selection, intake-form choice fields, any list pick. These are focus-manager consumers — see the focus-management pattern in ink.md.
  • text-input → the REPL command line, CIPHER seed capture, handle entry. Note the multi-tap numpad text-entry model is runtime-owned (ADR-0022/ADR-0027 on-multi-tap), so KN-86’s text-input is keyboard-cycle-driven, not a raw-key field.
  • tab-bar → the bare-deck STATUS / CIPHER / LAMBDA / LINK / SYS tabs. Inverse highlight for the active tab is the same monochrome-friendly idiom as the status-bar badges.
  • table → mission/contract lists, deck-state readouts, any tabular cart content. Rounded borders map to CP437/box-drawing glyphs already in the KN-86 character set; alignment + footer are exactly the table features cart authors otherwise hand-roll.

These are patterns to re-implement against the ADR-0027 cell API, not components to import — but the catalog tells KN-86 which Fe-side widgets are worth building first.

(c) Terminal + browser parity ≈ KN-86 device + desktop-emulator parity

Section titled “(c) Terminal + browser parity ≈ KN-86 device + desktop-emulator parity”

This is the strongest architecture signal in the entry. ink-web’s whole thesis is one component description, two render backends, identical output (real terminal ↔ xterm.js-in-browser). KN-86 has the same shape of problem and ADR-0027 makes it sharper than before: post-ratification the desktop emulator becomes a normal terminal program (run it in iTerm/kitty/alacritty — “no SDL window, no --scale knob”) while the device runs the same binary on a Linux-console tty1. Both targets drive termbox2 against the same 128×75 cell grid. ink-web is external validation that a TUI authored once against a cell abstraction renders identically across a “real” and an “emulated/embedded” surface — which is exactly the device/emulator parity ADR-0025 + ADR-0027 already commit KN-86 to. It also gestures at a third future surface: if KN-86 ever wants a browser-playable cart demo or web-based attract loop (cf. remotion.md for the video pipeline), rendering the same cell stream into xterm.js is a known-viable path.

No image downloaded — captured as a component-catalog and parity reference. The repo’s live demo (Ink components running in an xterm.js page) is worth viewing for the status-bar badge styling and the inverse-highlight tab-bar, which are the two most directly transplantable visual idioms.

  • Cross-link ink.md — ink-web is Ink with a second backend; the component-model architecture analysis lives there. This entry is “the component catalog + the parity proof.”
  • Cross-link tui-library-shortlist.md — the status-bar/tab-bar/table idioms feed the “what an optional Fe UI library should contain” half of the Task-3 deliverable.
  • Cross-link termui.md — the data-viz widget inventory (sparkline/gauge/plot); ink-ui covers the interaction widgets (select/input/table/status-bar). Together = the full KN-86 widget baseline.
  • Cross-link the runtime docssoftware/runtime/bare-deck-content-brief.md (the STATUS/CIPHER/LAMBDA/LINK/SYS tab-bar) and software/runtime/repl.md (the permanent Row-74 hint advertisement) are the two surfaces the tab-bar and status-bar components map onto most directly. Per ADR-0027’s documentation-updates checklist, both are being recomposed at 128×73 usable rows.
  • Row terminology: this entry uses Row 74 (ADR-0027, 128×75 grid). Older docs say “Row 24” (the superseded 80×25 ADR-0014 grid) — same concept (bottom chrome row), new coordinate.
  • shadcn-registry distribution is itself a note worth keeping: copy-in-and-own-the-source (vs. depend-on-a-package) is the right distribution model for a KN-86 Fe-UI library too — cart authors get readable Fe source they can adapt, not an opaque dependency.