Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3ddfd42
feat: Bump ghostty to upstream main; drop now-upstreamed WASM patches
neomantra Apr 28, 2026
3869ca6
feat: Wire terminal new/vt_write/resize to upstream C ABI
neomantra Apr 28, 2026
1631242
feat: Rewire render state onto upstream's key/value API
neomantra Apr 28, 2026
bd59e4b
Rewire terminal_get family onto upstream's key/value API
neomantra Apr 28, 2026
2e329b2
feat: Wire getViewport / isRowDirty onto the row iterator API
neomantra Apr 28, 2026
669a4d9
Fill in style flags, isRowWrapped, and getGrapheme
neomantra Apr 28, 2026
219c5a4
feat: Get to 331/331: scrollback, markClean, config apply
neomantra Apr 28, 2026
c4c0044
Reinstate hasResponse / readResponse via WRITE_PTY trampoline
neomantra Apr 28, 2026
f22c7ac
fix: Mirror isDefaultBg fallback for foreground rendering
neomantra Apr 28, 2026
aa807ef
Restore cell.width for CJK and wide emoji
neomantra Apr 29, 2026
9125434
Restore cell pixel dims and CSI 14/16/18 t responses
neomantra Apr 29, 2026
a9dc722
Wire kitty graphics: WASM enable patch + C ABI bindings
neomantra Apr 29, 2026
8aa9aeb
Composite kitty graphics placements onto the canvas
neomantra Apr 29, 2026
b63e587
Demo: thread cell pixel dims through to the PTY winsize
neomantra Apr 29, 2026
3e2dc55
Wire a JS PNG decoder via ghostty_sys_set(DECODE_PNG)
neomantra Apr 29, 2026
3b4a9ab
Substitute U+10EEEE cells with kitty graphics image slices
neomantra Apr 29, 2026
074b2a1
Restore scrollback cell styling — fg/bg/flags/width
neomantra Apr 29, 2026
642b936
Encoding choice: 0/1, not a unique id
neomantra Apr 29, 2026
d3714d1
fix: Replace banned `Function` types in trampoline exports
neomantra Apr 29, 2026
6d00a1d
Damage-track kitty placements + plumb pixel dims in npx demo
neomantra Apr 29, 2026
319eeba
Strengthen kitty cache key + reapply pixel size on reset
neomantra Apr 29, 2026
62228d7
Update GitHub Action versions and Node to 24
neomantra Apr 29, 2026
1004aed
chore: bun run lint:fix
neomantra Apr 29, 2026
d308f56
chore: run prettier
neomantra Apr 29, 2026
e781419
ci: raise WASM size limit to 768 KB
neomantra Apr 29, 2026
1569b9f
fix: Distinguish default fg/bg from explicit RGB(0,0,0)
neomantra May 6, 2026
0822d6e
fix: tile-edge seams in kitty placeholder slice rendering
neomantra May 6, 2026
4a0ae7c
feat(render): Replace perpetual rAF loop with event-driven render sch…
neomantra May 7, 2026
b6ef353
feat(render): Render block elements as fillRect instead of font glyphs
neomantra May 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/setup-zig/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ runs:
using: 'composite'
steps:
- name: Cache Zig
uses: actions/cache@v4
uses: actions/cache@v5
id: cache-zig
with:
path: |
Expand Down
24 changes: 12 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ jobs:
name: fmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- uses: oven-sh/setup-bun@v1
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

Expand All @@ -27,9 +27,9 @@ jobs:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- uses: oven-sh/setup-bun@v1
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

Expand All @@ -43,9 +43,9 @@ jobs:
name: type check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- uses: oven-sh/setup-bun@v1
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

Expand All @@ -59,11 +59,11 @@ jobs:
name: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: recursive

- uses: oven-sh/setup-bun@v1
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

Expand All @@ -84,11 +84,11 @@ jobs:
name: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: recursive

- uses: oven-sh/setup-bun@v1
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

Expand All @@ -103,8 +103,8 @@ jobs:
run: |
SIZE=$(stat -c%s ghostty-vt.wasm)
echo "WASM size: $SIZE bytes"
if [ "$SIZE" -gt 524288 ]; then
echo "❌ Error: WASM exceeds 512 KB limit"
if [ "$SIZE" -gt 786432 ]; then
echo "❌ Error: WASM exceeds 768 KB limit"
exit 1
fi

Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ jobs:
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'push' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ github.ref }}
fetch-depth: 0 # Required for git describe to find tags
submodules: recursive

- name: Setup Bun
uses: oven-sh/setup-bun@v1
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

Expand Down Expand Up @@ -61,9 +61,9 @@ jobs:
run: bun run build

- name: Setup Node.js for npm
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: '24'
registry-url: 'https://registry.npmjs.org'

# Ensure npm 11.5.1 or later for trusted publishing
Expand Down Expand Up @@ -159,15 +159,15 @@ jobs:
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'push' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ github.ref }}
fetch-depth: 0

- name: Setup Node.js for npm
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: '24'
registry-url: 'https://registry.npmjs.org'

- run: npm install -g npm@latest
Expand Down
11 changes: 11 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 47 additions & 4 deletions demo/bin/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ import { homedir } from 'os';
import path from 'path';
import { fileURLToPath } from 'url';

// Node-pty for cross-platform PTY support
import pty from '@lydell/node-pty';
// Node-pty for cross-platform PTY support. The 1.2.0-beta.x line adds a
// `pixelSize` argument to resize(), which sets ws_xpixel / ws_ypixel in
// the slave PTY's winsize struct so kitty kittens (icat etc.) can detect
// graphics support via TIOCGWINSZ instead of falling back to terminal
// queries. Lydell's fork is based on 1.1.0-beta14 (pre-pixelSize), so we
// use upstream's beta directly.
import pty from 'node-pty';
// WebSocket server
import { WebSocketServer } from 'ws';

Expand Down Expand Up @@ -243,12 +248,32 @@ const HTML_TEMPLATE = `<!doctype html>
const wsUrl = protocol + '//' + window.location.host + '/ws?cols=' + term.cols + '&rows=' + term.rows;
let ws;

// Read total canvas pixel dims (CSS pixels). The server stuffs these
// into ws_xpixel / ws_ypixel via node-pty's resize(cols, rows, pixelSize)
// so kittens like icat see non-zero TIOCGWINSZ pixel fields.
function getPixelSize() {
const canvas = container.querySelector('canvas');
return canvas
? { xpixel: canvas.clientWidth, ypixel: canvas.clientHeight }
: { xpixel: 0, ypixel: 0 };
}

function connect() {
setStatus('connecting', 'Connecting...');
ws = new WebSocket(wsUrl);

ws.onopen = () => {
setStatus('connected', 'Connected');
// Push initial pixel dims so TIOCGWINSZ-gated tools see them
// before the first resize event.
const px = getPixelSize();
ws.send(JSON.stringify({
type: 'resize',
cols: term.cols,
rows: term.rows,
xpixel: px.xpixel,
ypixel: px.ypixel,
}));
};

ws.onmessage = (event) => {
Expand Down Expand Up @@ -278,7 +303,14 @@ const HTML_TEMPLATE = `<!doctype html>
// Handle resize - notify PTY when terminal dimensions change
term.onResize(({ cols, rows }) => {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'resize', cols, rows }));
const px = getPixelSize();
ws.send(JSON.stringify({
type: 'resize',
cols,
rows,
xpixel: px.xpixel,
ypixel: px.ypixel,
}));
}
});

Expand Down Expand Up @@ -463,7 +495,18 @@ wss.on('connection', (ws, req) => {
try {
const msg = JSON.parse(message);
if (msg.type === 'resize') {
ptyProcess.resize(msg.cols, msg.rows);
// node-pty 1.2.0+ accepts a third pixelSize arg that sets
// ws_xpixel / ws_ypixel in the PTY winsize struct. Without it,
// kitty kittens (icat, etc.) read zeros via TIOCGWINSZ and
// refuse to render images.
if (msg.xpixel > 0 && msg.ypixel > 0) {
ptyProcess.resize(msg.cols, msg.rows, {
width: msg.xpixel,
height: msg.ypixel,
});
} else {
ptyProcess.resize(msg.cols, msg.rows);
}
return;
}
} catch (e) {
Expand Down
18 changes: 4 additions & 14 deletions demo/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 37 additions & 2 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,20 @@
let ws;
let fitAddon;

// Read total canvas pixel dimensions (CSS pixels). Used so the
// server can stuff ws_xpixel / ws_ypixel into the PTY winsize via
// node-pty's resize(cols, rows, pixelSize) — kitty kittens (icat
// etc.) read those fields from their stdin and bail "doesn't
// support reporting screen sizes in pixels" if they're zero.
// Module-scope so both initTerminal and connectWebSocket can call it.
function getPixelSize() {
const container = document.getElementById('terminal-container');
const canvas = container?.querySelector('canvas');
return canvas
? { xpixel: canvas.clientWidth, ypixel: canvas.clientHeight }
: { xpixel: 0, ypixel: 0 };
}

async function initTerminal() {
// Initialize WASM
await init();
Expand Down Expand Up @@ -168,8 +182,16 @@
// Handle terminal resize
term.onResize((size) => {
if (ws && ws.readyState === WebSocket.OPEN) {
// Send resize as control sequence (server expects this format)
ws.send(JSON.stringify({ type: 'resize', cols: size.cols, rows: size.rows }));
const px = getPixelSize();
ws.send(
JSON.stringify({
type: 'resize',
cols: size.cols,
rows: size.rows,
xpixel: px.xpixel,
ypixel: px.ypixel,
})
);
}
});

Expand Down Expand Up @@ -200,6 +222,19 @@
ws.onopen = () => {
console.log('WebSocket connected');
updateConnectionStatus(true);
// Push initial pixel dims into the PTY winsize so tools that
// gate on TIOCGWINSZ (e.g. kitten icat) can detect graphics
// support without falling back to terminal queries.
const px = getPixelSize();
ws.send(
JSON.stringify({
type: 'resize',
cols: term.cols,
rows: term.rows,
xpixel: px.xpixel,
ypixel: px.ypixel,
})
);
};

ws.onmessage = (event) => {
Expand Down
2 changes: 1 addition & 1 deletion demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"dev": "node bin/demo.js --dev"
},
"dependencies": {
"@lydell/node-pty": "^1.0.1",
"node-pty": "1.2.0-beta.12",
"ghostty-web": "latest",
"ws": "^8.18.0"
},
Expand Down
2 changes: 1 addition & 1 deletion ghostty
Submodule ghostty updated 4883 files
Loading