@mdxe/ink
Ink 7 terminal viewer over the @mdxe/tui seam
@mdxe/ink
The Ink viewer for the @mdxe/tui seam. It displays rendered terminal bytes and handles input; it never renders MDX itself, never invents or changes a byte, and never attaches to a pipe.
Ink is the no-native-binary viewer: Node ≥ 22 and Bun, with ink ^7 and react ^19.2 as peer dependencies.
Installation
Usage
frames is a FrameStream — an AsyncIterable<Uint8Array | string> where each chunk is one complete frame from the renderer (@mdxui/text). Input is decoded from stdin by the seam's shared createInputSource and mapped through defaultKeymap; pass events and/or keymap on mount to supply your own.
Choosing a viewer at runtime
inkViewer(options) is a ViewerFactory that imports even this package's viewer module lazily:
Guarantees
- Lazy — importing
@mdxe/inkloads neitherinknorreact;mount()does, after the TTY guard has passed. - Never on pipes — when
stdoutorstdinis not a TTY,mount()rejects with aViewerErrorwhosecodeis the stable stringNOT_A_TTY, writes nothing, and never touches raw mode. Route agents to the plain bytes instead. strip(paint(bytes)) === bytes— each frame is laid out with Ink'srenderToStringand compared to the register bytes before it is written. Whenever Ink would alter a byte (it trims trailing whitespace per line and wraps lines wider than its layout width) the frame is written verbatim instead, so Ink never wraps a line — the terminal does.- Terminal-width layout — each paint lays out at
terminal.stdout.columns(a resize is honoured;DEFAULT_COLUMNS= 80 when unreported). Ink's layout cost is linear in the width, so wrapping is prevented by the verbatim fallback, not by a huge width. - Unmount releases — raw mode is released, the cursor restored, and nothing is written afterwards.
unmount()is idempotent; aquitaction unmounts.
Options
paint(frame, runtime, columns?) is exported as a pure function for hosts that want the laid-out bytes without a terminal; it reports which engine produced them (ink or verbatim).
Conformance and benchmark
The @mdxe/tui/conformance suite runs against this viewer in its test suite. pnpm --filter @mdxe/ink bench runs the shared benchmark harness and prints JSON (startupMs, installBytes, repaint p50Ms/p95Ms/maxMs).