diff --git a/INSTALL.md b/INSTALL.md deleted file mode 100644 index a5bd18a..0000000 --- a/INSTALL.md +++ /dev/null @@ -1,181 +0,0 @@ -# Installation & Usage - -## Installation - -```bash -npm install @coder/ghostty-web -# or -bun add @coder/ghostty-web -# or -yarn add @coder/ghostty-web -``` - -### Installing from Git - -You can install directly from GitHub: - -```bash -npm install github:coder/ghostty-web -# or -bun add github:coder/ghostty-web -``` - -**Note:** Git installs require manually building the package first. See [Local Development](#local-development) for build instructions. - -## Basic Usage - -```typescript -import { Terminal } from '@coder/ghostty-web'; - -const term = new Terminal({ - cols: 80, - rows: 24, - cursorBlink: true, - theme: { - background: '#1e1e1e', - foreground: '#d4d4d4', - }, -}); - -// Mount to DOM -await term.open(document.getElementById('terminal')); - -// Write output -term.write('Hello, World!\r\n'); -term.write('\x1b[1;32mGreen text\x1b[0m\r\n'); - -// Handle user input -term.onData((data) => { - console.log('User typed:', data); - // Send to backend, echo, etc. -}); -``` - -## With FitAddon (Responsive Sizing) - -```typescript -import { Terminal, FitAddon } from '@coder/ghostty-web'; - -const term = new Terminal(); -const fitAddon = new FitAddon(); -term.loadAddon(fitAddon); - -await term.open(document.getElementById('terminal')); -fitAddon.fit(); // Resize to container - -// Resize on window resize -window.addEventListener('resize', () => fitAddon.fit()); -``` - -## WebSocket Integration - -```typescript -import { Terminal } from '@coder/ghostty-web'; - -const term = new Terminal(); -await term.open(document.getElementById('terminal')); - -const ws = new WebSocket('ws://localhost:3001/ws'); - -// Send user input to backend -term.onData((data) => { - ws.send(JSON.stringify({ type: 'input', data })); -}); - -// Display backend output -ws.onmessage = (event) => { - const msg = JSON.parse(event.data); - term.write(msg.data); -}; -``` - -## WASM File Handling - -The library requires the `ghostty-vt.wasm` file at runtime. When installing from npm, the WASM is pre-built and included in the package. - -### Local Development - -After cloning: - -```bash -./scripts/build-wasm.sh -``` - -The script will automatically initialize the submodule if needed. The WASM file is generated locally and gitignored. - -### Vite (Recommended) - -Vite handles WASM automatically. No extra config needed: - -```javascript -// vite.config.js -export default { - // WASM works out of the box -}; -``` - -### Webpack - -Configure WASM as an asset: - -```javascript -// webpack.config.js -module.exports = { - module: { - rules: [ - { - test: /\.wasm$/, - type: 'asset/resource', - }, - ], - }, -}; -``` - -### Manual Import (Advanced) - -```typescript -import wasmUrl from '@coder/ghostty-web/ghostty-vt.wasm?url'; -import { Ghostty } from '@coder/ghostty-web'; - -const ghostty = await Ghostty.load(wasmUrl); -``` - -## TypeScript Support - -Full TypeScript definitions are included: - -```typescript -import { Terminal, ITerminalOptions, ITheme } from '@coder/ghostty-web'; - -const options: ITerminalOptions = { - cols: 80, - rows: 24, - cursorBlink: true, -}; - -const theme: ITheme = { - background: '#1e1e1e', - foreground: '#d4d4d4', - cursor: '#ffffff', -}; -``` - -## API Documentation - -See [API.md](https://github.com/coder/ghostty-web/blob/main/packaging/docs/API.md) for complete API reference. - -## Migration from xterm.js - -This library follows xterm.js conventions: - -```typescript -// Before (xterm.js) -import { Terminal } from 'xterm'; -import { FitAddon } from 'xterm-addon-fit'; - -// After (@coder/ghostty-web) -import { Terminal, FitAddon } from '@coder/ghostty-web'; -``` - -Most xterm.js code works with minimal changes. See [API.md](https://github.com/coder/ghostty-web/blob/main/packaging/docs/API.md) for differences. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bd8d593 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Coder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 48b3e92..24f52f7 100644 --- a/README.md +++ b/README.md @@ -1,331 +1,138 @@ -# Ghostty Web +# ghostty-web -A web-based terminal emulator that integrates [Ghostty's](https://github.com/ghostty-org/ghostty) VT100 parser via WebAssembly. + -## Installation +`ghostty-web` is a fully-featured web terminal built on [Ghostty's](https://github.com/ghostty-org/ghostty) +terminal emulation core compiled to WebAssembly. By leveraging Ghostty's production-tested VT100 parser +and state machine, `ghostty-web` delivers fast, robust terminal emulation in the browser. For many use +cases it is a drop-in replacement for xterm.js. -```bash -npm install @coder/ghostty-web -``` +## Live Demo -Or install from GitHub: +You can try ghostty-web yourself: -```bash -npm install github:coder/ghostty-web -``` +> [!NOTE] +> Requires Zig and Bun, see [Development](#development) -## Quick Start +```bash +git clone https://github.com/coder/ghostty-web +cd ghostty-web +bun install +bun run build # Builds the WASM module and library -```typescript -import { Terminal } from '@coder/ghostty-web'; +# Terminal 1: Start PTY Server +cd demo/server +bun install +bun run start -const term = new Terminal({ cols: 80, rows: 24 }); -await term.open(document.getElementById('terminal')); -term.write('Hello, World!\r\n'); +# Terminal 2: Start web server +bun run start # http://localhost:8000 ``` -See [INSTALL.md](./INSTALL.md) for complete usage guide. +## Getting Started -## Features - -- ✅ Full xterm.js-compatible API -- ✅ Production-tested VT100 parser (via Ghostty) -- ✅ ANSI colors (16, 256, RGB true color) -- ✅ Canvas rendering at 60 FPS -- ✅ Scrollback buffer -- ✅ Text selection & clipboard -- ✅ FitAddon for responsive sizing -- ✅ TypeScript declarations included - -## Development & Demos - -### Shell Terminal Demo - -**Requires server** +Install the module via npm ```bash -# Terminal 1: Start PTY shell server -cd demo/server -bun install -bun run start +npm install ghostty-web +``` -# Terminal 2: Start web server (from project root) -bun run dev +After install, using `ghostty-web` is as simple as -# Open: http://localhost:8000/demo/ +```html + + +
+ + + + ``` -This provides a **real persistent shell session**! You can: +## Features -- Use `cd` and it persists between commands -- Run interactive programs like `vim`, `nano`, `top`, `htop` -- Use tab completion and command history (↑/↓) -- Use pipes, redirects, and background jobs -- Access all your shell aliases and environment +`ghostty-web` compiles Ghostty's core terminal emulation engine (parser, state +machine, and screen buffer) to WebAssembly, providing: -**Alternative: Command-by-Command Mode** +**Core Terminal:** -For the original file browser (executes each command separately): +- Full VT100/ANSI escape sequence support +- True color (24-bit RGB) + 256 color + 16 ANSI colors +- Text styles: bold, italic, underline, strikethrough, dim, reverse +- Alternate screen buffer (for vim, htop, less, etc.) +- Scrollback buffer with mouse wheel support -```bash -cd demo/server -bun run file-browser -``` +**Input & Interaction:** -**Remote Access:** If you're accessing via a forwarded hostname (e.g., `mux.coder`), make sure to forward both ports: +- Text selection and clipboard integration +- Mouse tracking modes +- Kitty keyboard protocol support +- Custom key/wheel event handlers -- Port 8000 (web server - Vite) -- Port 3001 (WebSocket server) +**API & Integration:** -The terminal will automatically connect to the WebSocket using the same hostname you're accessing the page from. +- xterm.js-compatible API (drop-in replacement for many use cases) +- FitAddon for responsive terminal sizing +- Event system (onData, onResize, onBell, onScroll, etc.) -**Colors Demo** (no server needed) +**Performance:** -```bash -bun run dev -# Open: http://localhost:8000/demo/colors-demo.html -``` +- Canvas-based rendering at 60 FPS +- Zero runtime dependencies (just ghostty-web + bundled WASM) +- Parser/state machine from Ghostty + +## Why ghostty-web? -See all ANSI colors (16, 256, RGB) and text styles in action. +- **Don't reimplement VT100 parsing** – it's thousands of edge cases refined over years. Instead, leverage Ghostty's battle-tested terminal emulator that's proven by thousands of daily users. +- **Drop-in xterm.js replacement** – for many use cases, ghostty-web can replace xterm.js with minimal code changes +- **Modern & maintained** – Built on Ghostty, an actively developed modern terminal emulator, ensuring continued improvements and bug fixes. -## Usage +## Usage Examples ### Basic Terminal ```typescript -import { Terminal } from './lib/index.ts'; -import { FitAddon } from './lib/addons/fit.ts'; +import { Terminal, FitAddon } from 'ghostty-web'; -// Create terminal const term = new Terminal({ - cols: 80, - rows: 24, cursorBlink: true, + fontSize: 14, theme: { background: '#1e1e1e', foreground: '#d4d4d4', }, }); -// Add FitAddon for responsive sizing const fitAddon = new FitAddon(); term.loadAddon(fitAddon); -// Open in container await term.open(document.getElementById('terminal')); fitAddon.fit(); -// Write output (supports ANSI colors) -term.write('Hello, World!\r\n'); -term.write('\x1b[1;32mGreen bold text\x1b[0m\r\n'); - // Handle user input term.onData((data) => { + // Send to backend/PTY console.log('User typed:', data); - // Send to backend, echo, etc. }); ``` -### WebSocket Integration - -```typescript -const ws = new WebSocket('ws://localhost:3001/ws'); - -// Send user input to backend -term.onData((data) => { - ws.send(JSON.stringify({ type: 'input', data })); -}); - -// Display backend output -ws.onmessage = (event) => { - const msg = JSON.parse(event.data); - term.write(msg.data); -}; -``` - -### URL Detection - -Ghostty-web automatically detects and makes clickable: - -- **OSC 8 hyperlinks** - Explicit terminal escape sequences (e.g., from `ls --hyperlink`) -- **Plain text URLs** - Common protocols detected via regex (https, http, mailto, ssh, git, ftp, tel, magnet) - -URLs are detected on hover and can be opened with Ctrl/Cmd+Click. - -```typescript -// URL detection works automatically after opening terminal -await term.open(container); - -// URLs in output become clickable automatically -term.write('Visit https://github.com for code\r\n'); -term.write('Contact mailto:support@example.com\r\n'); -``` - -**Custom Link Providers** - -Register custom providers to detect additional link types: - -```typescript -import { UrlRegexProvider } from '@coder/ghostty-web'; - -// Create custom provider -const myProvider = { - provideLinks(y, callback) { - // Your detection logic here - const links = detectCustomLinks(y); - callback(links); - }, -}; - -// Register after opening terminal -term.registerLinkProvider(myProvider); -``` - -See [AGENTS.md](AGENTS.md) for development guide and code patterns. - -## Why This Approach? - -**DON'T** re-implement VT100 parsing from scratch (years of work, thousands of edge cases). - -**DO** use Ghostty's proven parser: - -- ✅ Battle-tested by thousands of users -- ✅ Handles all VT100/ANSI quirks correctly -- ✅ Modern features (RGB colors, Kitty keyboard protocol) -- ✅ Get bug fixes and updates for free - -**You build**: Screen buffer, rendering, UI (the "easy" parts in TypeScript) -**Ghostty handles**: VT100 parsing (the hard part via WASM) - -## Architecture - -``` -┌─────────────────────────────────────────┐ -│ Terminal (lib/terminal.ts) │ -│ - Public xterm.js-compatible API │ -│ - Event handling (onData, onResize) │ -└───────────┬─────────────────────────────┘ - │ - ├─► ScreenBuffer (lib/buffer.ts) - │ - 2D grid, cursor, scrollback - │ - ├─► VTParser (lib/vt-parser.ts) - │ - ANSI escape sequence parsing - │ └─► Ghostty WASM (SGR parser) - │ - ├─► CanvasRenderer (lib/renderer.ts) - │ - Canvas-based rendering - │ - 60 FPS, supports all colors - │ - └─► InputHandler (lib/input-handler.ts) - - Keyboard events → escape codes - └─► Ghostty WASM (Key encoder) - -WebSocket Server (server/file-browser-server.ts) -└─► Executes shell commands (ls, cd, cat, etc.) -``` - -## Project Structure - -``` -├── lib/ -│ ├── terminal.ts - Main Terminal class (xterm.js-compatible) -│ ├── buffer.ts - Screen buffer with scrollback -│ ├── vt-parser.ts - VT100/ANSI escape sequence parser -│ ├── renderer.ts - Canvas-based renderer -│ ├── input-handler.ts - Keyboard input handling -│ ├── ghostty.ts - Ghostty WASM wrapper -│ ├── types.ts - TypeScript type definitions -│ ├── interfaces.ts - xterm.js-compatible interfaces -│ └── addons/ -│ └── fit.ts - FitAddon for responsive sizing -│ -├── demo/ -│ ├── index.html - File browser terminal -│ ├── colors-demo.html - ANSI colors showcase -│ └── server/ -│ ├── file-browser-server.ts - WebSocket server -│ ├── package.json -│ └── start.sh - Startup script (auto-kills port conflicts) -│ -├── docs/ -│ └── API.md - Complete API documentation -│ -└── ghostty-vt.wasm - Ghostty VT100 parser (122 KB) -``` - -## Building WASM +## Development -The WASM binary is built from source, not committed to the repo. +### Prerequisites -**Requirements:** +- [bun](https://bun.com/docs/installation) +- [zig](https://ziglang.org/download/) -- Zig 0.15.2+ -- Git submodules initialized +### Building WASM -**Build:** +`ghostty-web` builds a custom WASM binary from Ghostty's source with patches to expose additional +browser-specific functionality ```bash -# Initialize submodule (first time only) -git submodule update --init --recursive - -# Build WASM -./scripts/build-wasm.sh -# or -bun run build:wasm +bun run build ``` - -**What it does:** - -1. Initializes `ghostty/` submodule (ghostty-org/ghostty) -2. Applies patches from `patches/ghostty-wasm-api.patch` -3. Builds WASM with Zig (takes ~20 seconds) -4. Outputs `ghostty-vt.wasm` (404 KB) -5. Reverts patch to keep submodule clean - -**Updating Ghostty:** - -```bash -cd ghostty -git fetch origin -git checkout