Preserve the byte-native path first, then measure the complete interaction under representative output.
Uint8Array chunks. Avoid decoding to strings and encoding it
again before calling write() or connect().connect() sequence incoming chunks with writeAsync() instead of building an unbounded
application queue.worker: 'dedicated' and renderer: 'auto'. Change them after profiling your target
browsers and terminal count.readViewport(), full-buffer reads, snapshots, or full accessibility mirroring
on a hot output path unless the feature requires them. Use narrow readBuffer() pages for
scrollback consumers.CoreRuntime for multiple terminals so they share the compiled WASM module.Worker writes copy each input chunk into transferable storage so application-owned buffers remain safe to reuse. This is predictable, but it means avoid producing avoidable intermediate copies before the terminal boundary.
write() or writeAsync()write() queues work and returns immediately. It is appropriate when an upstream transport already
has a bounded queue and no parse boundary is needed.
writeAsync() resolves after the chunk has been parsed and rendered. If the active renderer is
recovering or falling back, the boundary waits for the retained frame to be repainted. It is the
safer primitive for flow control, tests, ordered snapshots, and producers that must not outpace the
terminal.
The repository includes a headless parse/render throughput benchmark:
pnpm bench:throughput
It runs warmups and multiple measured samples, then reports the median. Use it for controlled comparisons on the same machine, runtime, WASM artifact, input fixture, and power state. Do not use a single local result as a universal browser throughput claim.
Use the visible-browser runner for end-to-end and xterm.js compatibility comparisons:
pnpm bench:browser
pnpm bench:browser -- --profile ci
pnpm bench:browser -- --candidate npm:next --baseline npm:latest --browser chromium,firefox
It builds isolated consumers, records exact package and machine provenance, randomizes implementation order with a recorded seed, validates frame cadence, and separates parser, completion-callback, render, and following-frame presentation boundaries. The report preserves raw samples, confidence intervals, variance warnings, long-task health, and normalized candidate ratios. Published packages without internal phase instrumentation are reported only at their supported public callback boundary; their time is never relabeled as parser time. See the published-package harness guide for the full workload and output schema.
For browser decisions, measure separately:
terminal.renderer.backend.Subscribe to the renderer event when a benchmark spans device loss or context restoration. Keep
pre- and post-fallback samples separate instead of attributing them to one backend.
Record browser version, hardware, device pixel ratio, terminal geometry, worker policy, renderer, accessibility mode, scrollback limit, font, and output corpus with every result.
worker: 'shared' reduces worker count by multiplexing sessions. Compare it with dedicated workers
using the product's mix of active and idle terminals. Shared execution can lower fixed overhead but
also lets one busy session contend with its neighbors.
Lazy-create terminals that are visible or imminently needed. Dispose hidden sessions that the product does not intend to preserve, or snapshot them before disposal when restoration is cheaper than keeping them live.