Ghostty Core
The @wterm/ghostty package provides a full-featured terminal emulation core powered by libghostty built directly from upstream source. It implements the same TerminalCore interface as wterm's built-in Zig core, so it's a drop-in replacement.
Why use it?
wterm ships with a lightweight built-in core (~12 KB WASM) that covers basic VT100/VT220/xterm escape sequences. For apps that need comprehensive terminal emulation — full Unicode grapheme clusters, all SGR attributes, terminal modes, and more — @wterm/ghostty provides all of that via Ghostty's battle-tested VT parser (~400 KB WASM).
Install
npm install @wterm/ghosttyUsage
Load the Ghostty core and pass it to WTerm via the core option. Everything else stays the same.
Vanilla JS
import { WTerm } from "@wterm/dom";
import { GhosttyCore } from "@wterm/ghostty";
import "@wterm/dom/css";
const core = await GhosttyCore.load();
const term = new WTerm(document.getElementById("terminal"), { core });
await term.init();React
import { Terminal } from "@wterm/react";
import { GhosttyCore } from "@wterm/ghostty";
import "@wterm/dom/css";
const core = await GhosttyCore.load();
function App() {
return <Terminal core={core} />;
}Vue
<script setup lang="ts">
import { Terminal } from "@wterm/vue";
import { GhosttyCore } from "@wterm/ghostty";
const core = await GhosttyCore.load();
</script>
<template>
<Terminal :core="core" />
</template>Options
GhosttyCore.load() accepts an optional options object:
| Option | Type | Description |
|---|---|---|
wasmPath | string | Custom path to the ghostty-vt WASM binary. By default it resolves to the committed binary inside the package. |
scrollbackLimit | number | Maximum scrollback lines (default: 10000). |
How it works
@wterm/ghostty builds libghostty directly from ghostty-org/ghostty source — no third-party npm packages or pre-built binaries from other projects. The architecture:
- Zig package dependency: ghostty v1.3.1 is declared as a URL dependency in
zig/build.zig.zon. Zig's package manager fetches it automatically. - WASM compatibility patches: ghostty's
Terminalusesposix.mmapand Mach VM allocators internally, which don't exist onwasm32-freestanding. The build script applies small, targeted patches to replace these withstd.heap.wasm_allocatorbehind comptimeisWasm()checks. The patches only touchpage.zigandPageList.zig. - Thin WASM export layer:
zig/src/wasm_api.zig(~300 lines) imports ghostty'sTerminalandRenderStateAPIs and exports ~20 functions to JavaScript. - Committed WASM binary: The built
wasm/ghostty-vt.wasmis checked into the repo so consumers never need Zig installed. - TypeScript bindings:
wasm-bindings.tsloads the WASM module and provides typed accessors for the exported functions. - TerminalCore adapter:
ghostty-core.tsimplements theTerminalCoreinterface by calling the WASM bindings, converting ghostty's pre-resolved 24-bit RGB colors to wterm'sCellDataformat via thefgRgb/bgRgbfields.
The TerminalCore interface means the DOM renderer, input handler, and framework bindings don't need to know which core they're talking to.
Rebuilding the WASM
Only needed by maintainers. Requires Zig 0.15.x (ghostty's required Zig version, separate from wterm's Zig 0.16.x):
pnpm --filter @wterm/ghostty rebuild-wasmComparison
| Built-in (default) | @wterm/ghostty | |
|---|---|---|
| Bundle size | ~12 KB WASM (inlined) | ~400 KB WASM (fetched) |
| VT compliance | Basic VT100/VT220/xterm | Comprehensive |
| Unicode | Single codepoints | Full grapheme clusters |
| Color model | 256-color palette indices | Pre-resolved 24-bit RGB |
| Dependencies | None | None (WASM built from source) |
| Setup | Zero-config | Requires @wterm/ghostty install |