Skip to content

Terminal Context

The Terminal context renders elements to a character-based terminal using Unicode braille patterns (U+2800–U+28FF). Each terminal cell encodes a 2×4 grid of sub-pixel dots, giving 8× the resolution of plain text. It supports ANSI truecolor for full-color output.

Demo

The demo below renders a bar chart live in an xterm.js terminal widget — the same @ripl/terminal code that runs in Node.js:

Installation

The terminal context is provided by the @ripl/terminal package. For Node.js usage, also install @ripl/node:

bash
npm install @ripl/terminal @ripl/node

Usage

Node.js

Import from @ripl/node to automatically configure the runtime factory:

ts
import '@ripl/node';

import {
    createCircle,
    createNodeOutput,
    createRect,
    createTerminalContext,
} from '@ripl/node';

const output = createNodeOutput();
const context = createTerminalContext(output);

createCircle({
    fill: '#3a86ff',
    cx: context.width / 2,
    cy: context.height / 2,
    radius: 40,
}).render(context);

Browser (xterm.js)

Since @ripl/terminal is runtime-agnostic, you can wire it to any output that implements the TerminalOutput interface — including an xterm.js instance in the browser:

ts
import {
    Terminal,
} from '@xterm/xterm';

import {
    BrailleRasterizer,
    TerminalContext,
} from '@ripl/terminal';

const xterm = new Terminal({ disableStdin: true });
xterm.open(document.getElementById('terminal'));

const output = {
    write: (data) => xterm.write(data),
    columns: xterm.cols,
    rows: xterm.rows,
};

const context = new TerminalContext(output, {
    rasterizer: new BrailleRasterizer(xterm.cols, xterm.rows),
});

How It Works

The terminal context:

  1. Records drawing commands (lines, arcs, curves, rects) from elements
  2. Rasterizes them onto a sub-pixel grid using algorithms like Bresenham's line, midpoint circle, and adaptive Bézier subdivision
  3. Applies scanline fill for filled shapes
  4. Maps CSS colors to ANSI truecolor escape sequences
  5. Encodes each 2×4 cell into a Unicode braille character
  6. Flushes the serialized output to the TerminalOutput adapter

Logical Sizing

By default the context's coordinate space is the braille pixel grid — columns × 2 wide by rows × 4 tall (an 80×24 terminal is a 160×96 space). A scene authored in typical screen pixels (fixed radii, offsets in the hundreds) will overflow that space entirely.

Pass logicalWidth/logicalHeight to author in a larger logical space instead. The context then reports the logical size via context.width/context.height and uniformly scales + centres (letterboxes) it into the character grid — the same way the canvas context maps CSS pixels onto its device-pixel backing store:

ts
// A scene written for a 800×600 canvas renders proportionally in any terminal.
const context = createContext(output, {
    logicalWidth: 800,
    logicalHeight: 600,
});

The scale factor is uniform on both axes, so circles stay circular. Text glyphs remain cell-sized (inherent to terminals); only their position follows the logical space, and measureText reports metrics in logical units. On terminal resize the logical size is preserved and the mapping is recomputed. The docs playground's Terminal mode uses this to render examples with the same proportions as the Canvas and SVG modes.

Extensible Rasterizer

The default BrailleRasterizer can be swapped for alternative character sets by implementing the Rasterizer interface:

ts
interface Rasterizer {
    readonly pixelWidth: number;
    readonly pixelHeight: number;
    resize(cols: number, rows: number): void;
    setPixel(x: number, y: number, color: string): void;
    setChar(col: number, row: number, char: string, color: string): void;
    clear(): void;
    serialize(): string;
}

Pass a custom rasterizer via the rasterizer option when creating a context.

Limitations

  • No interaction — Terminal contexts do not support pointer events or hit testing
  • No gradients — CSS gradient strings are not supported; use solid colors
  • No image drawingdrawImage is a no-op
  • Monospace text — Text is placed at character-grid positions; font metrics are approximate
  • No transformsrotate, scale, translate are currently no-ops
  • Resolution — Limited by braille dot density (2×4 per cell)

When to Use Terminal

Terminal is the best choice when:

  • Server-side rendering — Visualize data in CI/CD pipelines, monitoring dashboards, or CLI tools
  • No browser available — Render charts and graphics in headless environments
  • Quick prototyping — See rendering output without setting up a browser environment