Skip to content

Repository files navigation

wterm

A terminal emulator for the web.

wterm ("dub-term") renders to the DOM — native text selection, copy/paste, find, and accessibility come for free. The core is written in Zig and compiled to WASM for near-native performance.

Packages

Package Description
@wterm/core Headless WASM bridge, TerminalCore interface, WebSocket transport
@wterm/dom DOM renderer, input handler — vanilla JS terminal
@wterm/react React component + useTerminal hook (TypeScript)
@wterm/vue Vue 3 component + template ref API
@wterm/ghostty Full-featured VT emulation core powered by libghostty
@wterm/just-bash In-browser Bash shell powered by just-bash
@wterm/markdown Render Markdown in the terminal

Features

  • Pluggable cores — built-in lightweight Zig core (~12 KB) or opt-in libghostty backend (~400 KB) for full VT compliance
  • Zig + WASM core — VT100/VT220/xterm escape sequence parser compiled to a ~12 KB .wasm binary (release build)
  • DOM rendering — native text selection, clipboard, browser find, and screen reader support
  • Dirty-row tracking — only touched rows are re-rendered each frame via requestAnimationFrame
  • Themes — CSS custom properties with built-in Default, Solarized Dark, Monokai, and Light themes
  • Alternate screen buffervim, less, htop, and similar apps work correctly
  • Scrollback history — configurable ring buffer
  • Wide Unicode cells — CJK, fullwidth, and emoji codepoints keep cursor-addressed redraws aligned
  • 24-bit color — full RGB SGR support
  • Auto-resizeResizeObserver-based terminal resizing
  • WebSocket transport — connect to a PTY backend with binary framing and reconnection

Development

Prerequisites

Setup

pnpm install

Build the WASM binary

zig build

For a release build:

zig build -Doptimize=ReleaseSmall

The built binary is committed at packages/@wterm/core/wasm/wterm.wasm and CI fails if it does not match the Zig sources, so rebuild and commit it with any change under src/.

Regenerate the Unicode width table

src/unicode_width_table.zig holds the East Asian Width ranges the core uses to decide cell width. It is generated, not hand-edited. Run this when Unicode publishes a new version, after bumping UNICODE_VERSION in the script:

node scripts/gen-unicode-width.mjs

Build all packages

pnpm build

Run the vanilla demo

Serve the web/ directory with any static file server:

cd web && python3 -m http.server 8000

Run the Next.js example

All dev servers use portless to avoid hardcoded ports. Each app is served at a .localhost URL (e.g. nextjs-example.wterm.localhost).

cp web/wterm.wasm examples/nextjs/public/
pnpm --filter nextjs dev

Run Zig tests

zig build test

License

Apache-2.0

About

A terminal emulator for the web

Resources

Stars

3.4k stars

Watchers

8 watching

Forks

Releases

Packages

Used by

Contributors

Languages