cmux-remote は iPhone から cmux ワークスペースをリモート監視・制御するための PWA。現在 xterm.js をターミナル描画に使用している。
wterm は Vercel Labs が公開した DOM ベースのターミナルエミュレータ。Zig → 12KB WASM という軽量さが特徴。
本稿では xterm.js を wterm に置き換える実現性とメリット・リスクを整理する。
iPhone PWA (React 19 + xterm.js)
↕ WebSocket
Bridge Server (Bun + Hono)
↕ Unix Domain Socket
cmux (~/.../cmux.sock)
| ファイル | サイズ | 役割 |
|---|---|---|
client/src/components/Terminal.tsx |
~2KB | xterm.js によるターミナル描画 |
client/src/hooks/useWebSocket.ts |
~2.5KB | WebSocket 接続管理 |
client/src/hooks/useCmux.ts |
~5.5KB | cmux コア機能 |
server/src/ws.ts |
~4.6KB | WebSocket サーバー実装 |
- クライアント: React 19, TypeScript, Vite, xterm.js, Hammer.js
- サーバー: Bun, Hono
- バンドルサイズ: gzip 時 約 144KB
| 項目 | 内容 |
|---|---|
| レンダリング | DOM ベース(Canvas ではない) |
| コアサイズ | ~12KB WASM(Zig 製) |
| パッケージ構成 | @wterm/core, @wterm/dom, @wterm/react, @wterm/just-bash, @wterm/markdown |
| API | write(data) で出力、onData(cb) でユーザー入力取得 |
| WebSocket | @wterm/core にトランスポート内蔵 |
| テーマ | Default, Solarized Dark, Monokai, Light 等ビルトイン |
| 自動リサイズ | ResizeObserver 対応 |
両方とも基本的なインターフェースは同じ概念:
// xterm.js
const term = new Terminal();
term.write(data);
term.onData((input) => { /* send to server */ });
// wterm (@wterm/react)
<Terminal
ref={ref}
cols={80}
rows={24}
wasmUrl="/wterm.wasm"
onData={(input) => { /* send to server */ }}
onReady={(api) => { api.write(data); }}
/>
ドロップイン置換ではないが、概念マッピングは 1:1 で対応する。
| 項目 | xterm.js | wterm | 影響 |
|---|---|---|---|
| バンドルサイズ | 大 | ~12KB | PWA の初回ロードが大幅改善 |
| テキスト選択 | Canvas 上の独自実装 | ネイティブ DOM | iPhone Safari での UX 向上 |
| コピー/ペースト | 追加実装が必要 | ネイティブ対応 | モバイルの長押しメニューがそのまま動く |
| CSS カスタマイズ | 制限的 | 通常の CSS | テーマ・レスポンシブ対応が容易 |
| アクセシビリティ | 追加実装が必要 | DOM 標準対応 | スクリーンリーダー等が自然に動作 |
| 自動リサイズ | FitAddon が必要 | ResizeObserver 内蔵 | 依存が減る |
特に cmux-remote は iPhone PWA であるため、DOM ベースのネイティブなテキスト選択・コピペは UX に直結する大きなメリット。
| リスク | 詳細 | 対策 |
|---|---|---|
| プロジェクトの成熟度 | wterm はまだ若い。エッジケースの対応が不十分な可能性 | cmux の出力パターンで事前テスト |
| ANSI エスケープシーケンス網羅度 | cmux が使う全シーケンスをサポートしているか未検証 | VT100/VT220/xterm は対応。256色・24bit RGB 対応済み |
| Addon エコシステム | xterm.js の FitAddon, WebLinksAddon 等に相当する機能がない | FitAddon → ResizeObserver で代替可。リンクは DOM なので CSS/JS で対応可能 |
| API 互換性 | ドロップイン置換ではない | 書き換え対象が小さい(Terminal.tsx ~2KB) |
| モバイルブラウザ対応 | iPhone Safari での動作実績が不明 | DOM ベースなので Canvas より Safari との相性は良いはず |
-
client/src/components/Terminal.tsx(~2KB)- xterm.js の
Terminal→@wterm/reactの<Terminal>に差し替え - FitAddon の削除(ResizeObserver で代替)
- xterm.js の
-
client/src/hooks/useWebSocket.ts(~2.5KB)@wterm/coreの WebSocket トランスポートで簡素化できる可能性- もしくは既存のロジックをそのまま活かし、
write()/onData()の接続点だけ変更
-
package.jsonxterm→@wterm/react,@wterm/coreに依存を差し替えxterm-addon-fit等の Addon 依存を削除
- コード変更量: 100〜200行程度
- 所要時間: 数時間〜1日
- 難易度: 低〜中(API の概念が似ているため)
wterm の発表は大きな注目を集めている:
- Chris Tate(Vercel, 作者)の発表ツイートが 1,182 いいね / 13万ビュー
- 「12KB WASM で DOM レンダリング」という軽量さとアクセシビリティが評価ポイント
- xterm.js の Canvas ベースの制約を DOM で解決するアプローチに好意的な反応
cmux-remote と wterm の組み合わせは相性が良い:
- PWA + 12KB WASM → バンドルサイズ大幅削減
- iPhone + DOM レンダリング → ネイティブなテキスト操作
- React + @wterm/react → フレームワーク一致
- WebSocket + @wterm/core → トランスポート層の簡素化
リスクは wterm の成熟度だが、cmux-remote の用途(ターミナル出力の表示と基本的な入力)であれば、wterm の現時点の機能で十分カバーできると考えられる。