Breaking Changes
- Reworked the public configuration shape around explicit
surface,terminal, andservicessections. Terminal rendering/input options now live underterminal, pane shell behavior lives undersurface, and PTY/hooks/callbacks live underservices. - Replaced raw pane/runtime escape hatches in app-facing APIs with stable
ResttyPaneHandlemethods and active-pane convenience methods onRestty. Low-level modules are still available throughrestty/internal,restty/internal/runtime, andrestty/internal/surface, but those subpaths are intentionally unstable. - Replaced legacy font source shapes with the new
terminal.fontsinput model. OldappOptions.fontSourcesandfontPresetstyle configuration is no longer accepted.
Migration
-
Move flat runtime options into the new grouped config:
// Before new Restty({ root, renderer: "auto", fontSize: 16, ptyTransport, }); // After new Restty({ root, terminal: { renderer: "auto", fontSize: 16, }, services: { ptyTransport, }, });
-
Move pane shell options into
surface:new Restty({ root, surface: { searchUi: true, shortcuts: true, defaultContextMenu: true, }, });
-
Move font configuration to
terminal.fonts:new Restty({ root, terminal: { fonts: [ { family: "JetBrains Mono", local: "prefer", fallback: "/fonts/JetBrainsMono-Regular.ttf" }, "/fonts/SymbolsNerdFont-Regular.ttf", ], }, });
-
Prefer
restty.panes(),restty.activePane(),restty.focusedPane(), andrestty.pane(id)for pane handles. Use active-pane convenience methods such asrestty.connectPty(...),restty.setFontSize(...),restty.openSearch(...), andrestty.sendInput(...)when you only need to target the active pane. -
Use
restty/headlessfor DOM-free terminal state, replay, and backend-owned sessions. If a browser pane passively renders a backend-owned/headless session, setterminal.forwardTerminalRepliestofalse. -
Use
restty/esmonly when you need the standalone single-file browser ESM bundle. Normal bundler users should keep importing fromrestty.
Features
- Added the new native
Restty/createResttysurface API with multi-pane layout, pane handles, active-pane helpers, pane style controls, default context menus, and lifecycle events. - Added
restty/headlessfor DOM-free WASM terminal usage with snapshots, bounded replay journals, resize/write replay, terminal reply draining, Kitty state inspection, and WASM search controls. - Added built-in pane search UI and pane-local search APIs, including active-pane helpers, pane-handle methods, callbacks, themed match colors, and WASM-backed search state.
- Added a plugin runtime with manifest loading, plugin diagnostics, lifecycle hooks, input/output interceptors, render hooks, and managed shader stage handles.
- Added standalone browser ESM output at
restty/esm; the package now ships the normal library entrypoints plus one self-contained ESM bundle for direct browser/CDN usage. - Added programming ligatures, runtime ligature toggles, font hinting controls,
fontSizeMode, Local Font Access inputs, richer fallback font inputs, and shared font resource reuse across panes. - Added configurable scrollback limits through
maxScrollbackBytes. - Added desktop multi-click selection, word/line selection, touch selection modes, and drag selection behavior for longer scrollback selections.
- Added xterm-style compatibility improvements, including buffered writes before
open(...), callbacks, resize events, addon activation/disposal, and nativeResttyaccess for gradual migration.
Fixes
- Auto-scroll the viewport while drag-selecting text past the top or bottom terminal edge, matching Ghostty-style long selection across scrollback.
- Support common shell navigation keys in the default keyboard mapper: Ctrl+A/E and Home/End are covered by regression tests, and Ctrl/Cmd+Left/Right now emit readline-compatible word-jump sequences outside Kitty keyboard protocol mode.
- Updated the Ghostty/libvt Kitty runtime reference and rebuilt the embedded WASM so Kitty graphics and terminal protocol behavior track current upstream more closely.
- Reworked Kitty graphics handling for file-medium rewrites, direct-medium placement, unicode placeholder placement, chunk boundaries, echoed response filtering, and invalid control sanitization.
- Render symbol/nerd fallback fonts at the primary font's em size, matching Ghostty's same-point-size rule instead of normalizing each fallback by its own line height.
- Fix the
fit_cover1glyph constraint's multi-cell upscale cap double-applyingrelative_width/relative_height, which undersized icons whose constraint defines a relative scale group. - Switch the default symbols fallback to
SymbolsNerdFont-Regular.ttf(the non-Mono variant Ghostty embeds); the Mono variant draws icons larger within the em, diverging from Ghostty's icon sizing. - Broaden emoji and symbol fallback classification, including concatenated font filename labels and emoji-like symbol ranges.
- Feed PTY output to the terminal as it arrives instead of coalescing through 10ms/40ms flush timers; presentation now coalesces in the render loop, removing the ~25fps ceiling during sustained output.
- Hold presentation at frame time while synchronized output (mode 2026) is active instead of dropping frames whose data ended mid-update; the frame right after the end sequence now presents immediately.
- Accumulate mouse wheel deltas by cell size for app mouse reporting, emitting one report per scrolled cell instead of one per DOM wheel event, and add horizontal wheel reports.
- Present dirty foreground frames on every animation frame; the previous elapsed-time FPS budget quantized against vsync and skipped frames on high-refresh displays.
- Fix pointer mapping when canvas CSS scale differs from device pixel ratio.
- Use the native Cmd+V paste path with IME input while keeping macOS Ctrl+V available for TUI bindings.
- Keep IME preedit overlays readable and avoid hiding the focused IME textarea from accessibility APIs.
- Stabilize pane initialization, cursor reporting, resize timing, hyperlink resize handling, terminal reply routing, and queued runtime IO before lifecycle readiness.
Internal
- Updated the publish workflow to be tag-driven, validate package/changelog consistency, require annotated release tags, publish with npm provenance, and create or update the GitHub Release from
CHANGELOG.md. - Reduced package distribution size by keeping React, React DOM, React Router, Fumadocs, and playground-only shell dependencies in
devDependencies;text-shaperremains the runtime dependency. - Reworked the embedded WASM packaging path and removed dead generated asset paths.
- Split runtime and surface internals into narrower modules and contracts, with architecture tests guarding module boundaries and public export ownership.
- Curated unstable internal exports under
restty/internal,restty/internal/runtime, andrestty/internal/surface.
Playground
- Replaced the legacy playground shell with the React Router and Fumadocs docs app used by the hosted documentation.
- Default the playground to the Just Bash backend and lazy-load WebContainer only when selected.
- Restore and expand terminal demos, bundled fonts, shader presets, split dividers, theme backgrounds, and pane/search controls.
- Bundle
SymbolsNerdFont-Regular.ttf(non-Mono) as the symbols fallback font instead ofSymbolsNerdFontMono-Regular.ttf. - Document Cloudflare Pages build settings for the hosted playground/docs.
Docs
- Rebuilt the README around the new public API, entrypoints, and canonical hosted docs.
- Added or refreshed docs for getting started, configuration, API surface, surface and panes, PTY backends, headless mode, search, fonts, themes and shaders, plugins, xterm compatibility, troubleshooting, architecture, and runnable examples.