wraithterm 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +313 -2
  3. package/css/xterm.css +285 -0
  4. package/dist/index.d.ts +88 -0
  5. package/dist/index.js +707 -0
  6. package/dist/keycodes.d.ts +1 -0
  7. package/dist/keycodes.js +179 -0
  8. package/dist/protocol.d.ts +117 -0
  9. package/dist/protocol.js +1 -0
  10. package/dist/types.d.ts +66 -0
  11. package/dist/types.js +19 -0
  12. package/dist/vite.d.ts +11 -0
  13. package/dist/vite.js +11 -0
  14. package/dist/worker.d.ts +1 -0
  15. package/dist/worker.js +302 -0
  16. package/dist/xterm-api.d.ts +1956 -0
  17. package/dist/xterm-atlas.d.ts +39 -0
  18. package/dist/xterm-atlas.js +176 -0
  19. package/dist/xterm-internals.d.ts +120 -0
  20. package/dist/xterm-internals.js +19 -0
  21. package/dist/xterm-renderer.d.ts +77 -0
  22. package/dist/xterm-renderer.js +540 -0
  23. package/dist/xterm.d.ts +17 -0
  24. package/dist/xterm.js +35 -0
  25. package/docs/ARCHITECTURE.md +179 -0
  26. package/docs/COMPATIBILITY.md +66 -0
  27. package/docs/PERFORMANCE.md +122 -0
  28. package/docs/TOP_TIER.md +124 -0
  29. package/docs/XTERM_API.md +163 -0
  30. package/docs/compatibility/xterm-chrome.json +34 -0
  31. package/licenses/Ghostty-MIT.txt +21 -0
  32. package/licenses/JetBrainsMono-OFL.txt +93 -0
  33. package/licenses/NOTICE.md +93 -0
  34. package/licenses/Zig-MIT.txt +21 -0
  35. package/licenses/rust/arrayvec-0.7.8/LICENSE-APACHE +201 -0
  36. package/licenses/rust/arrayvec-0.7.8/LICENSE-MIT +25 -0
  37. package/licenses/rust/autocfg-1.5.1/LICENSE-APACHE +201 -0
  38. package/licenses/rust/autocfg-1.5.1/LICENSE-MIT +25 -0
  39. package/licenses/rust/bit-set-0.10.0/LICENSE-APACHE +201 -0
  40. package/licenses/rust/bit-set-0.10.0/LICENSE-MIT +25 -0
  41. package/licenses/rust/bit-vec-0.9.1/LICENSE-APACHE +201 -0
  42. package/licenses/rust/bit-vec-0.9.1/LICENSE-MIT +25 -0
  43. package/licenses/rust/bitflags-2.13.2/LICENSE-APACHE +201 -0
  44. package/licenses/rust/bitflags-2.13.2/LICENSE-MIT +25 -0
  45. package/licenses/rust/bumpalo-3.20.3/LICENSE-APACHE +201 -0
  46. package/licenses/rust/bumpalo-3.20.3/LICENSE-MIT +25 -0
  47. package/licenses/rust/bytemuck-1.25.2/LICENSE-APACHE +61 -0
  48. package/licenses/rust/bytemuck-1.25.2/LICENSE-MIT +9 -0
  49. package/licenses/rust/bytemuck-1.25.2/LICENSE-ZLIB +11 -0
  50. package/licenses/rust/bytemuck_derive-1.12.1/LICENSE-APACHE +61 -0
  51. package/licenses/rust/bytemuck_derive-1.12.1/LICENSE-MIT +9 -0
  52. package/licenses/rust/bytemuck_derive-1.12.1/LICENSE-ZLIB +11 -0
  53. package/licenses/rust/cfg-if-1.0.5/LICENSE-APACHE +201 -0
  54. package/licenses/rust/cfg-if-1.0.5/LICENSE-MIT +25 -0
  55. package/licenses/rust/cfg_aliases-0.2.2/LICENSE +9 -0
  56. package/licenses/rust/codespan-reporting-0.13.1/LICENSE +201 -0
  57. package/licenses/rust/crunchy-0.2.4/LICENSE +21 -0
  58. package/licenses/rust/document-features-0.2.12/LICENSE-APACHE +73 -0
  59. package/licenses/rust/document-features-0.2.12/LICENSE-MIT +19 -0
  60. package/licenses/rust/equivalent-1.0.2/LICENSE-APACHE +201 -0
  61. package/licenses/rust/equivalent-1.0.2/LICENSE-MIT +25 -0
  62. package/licenses/rust/foldhash-0.2.0/LICENSE +19 -0
  63. package/licenses/rust/font-types-0.12.6/LICENSE-APACHE +67 -0
  64. package/licenses/rust/font-types-0.12.6/LICENSE-MIT +25 -0
  65. package/licenses/rust/futures-core-0.3.34/LICENSE-APACHE +202 -0
  66. package/licenses/rust/futures-core-0.3.34/LICENSE-MIT +26 -0
  67. package/licenses/rust/futures-task-0.3.34/LICENSE-APACHE +202 -0
  68. package/licenses/rust/futures-task-0.3.34/LICENSE-MIT +26 -0
  69. package/licenses/rust/futures-util-0.3.34/LICENSE-APACHE +202 -0
  70. package/licenses/rust/futures-util-0.3.34/LICENSE-MIT +26 -0
  71. package/licenses/rust/half-2.7.1/LICENSE-APACHE +176 -0
  72. package/licenses/rust/half-2.7.1/LICENSE-MIT +19 -0
  73. package/licenses/rust/harfrust-0.13.3/LICENSE +22 -0
  74. package/licenses/rust/hashbrown-0.17.1/LICENSE-APACHE +201 -0
  75. package/licenses/rust/hashbrown-0.17.1/LICENSE-MIT +25 -0
  76. package/licenses/rust/indexmap-2.14.2/LICENSE-APACHE +201 -0
  77. package/licenses/rust/indexmap-2.14.2/LICENSE-MIT +25 -0
  78. package/licenses/rust/js-sys-0.3.106/LICENSE-APACHE +201 -0
  79. package/licenses/rust/js-sys-0.3.106/LICENSE-MIT +25 -0
  80. package/licenses/rust/libc-0.2.190/LICENSE-APACHE +176 -0
  81. package/licenses/rust/libc-0.2.190/LICENSE-MIT +25 -0
  82. package/licenses/rust/libloading-0.8.9/LICENSE +12 -0
  83. package/licenses/rust/libm-0.2.16/LICENSE.txt +258 -0
  84. package/licenses/rust/litrs-1.0.0/LICENSE-APACHE +176 -0
  85. package/licenses/rust/litrs-1.0.0/LICENSE-MIT +25 -0
  86. package/licenses/rust/lock_api-0.4.14/LICENSE-APACHE +201 -0
  87. package/licenses/rust/lock_api-0.4.14/LICENSE-MIT +25 -0
  88. package/licenses/rust/log-0.4.34/LICENSE-APACHE +201 -0
  89. package/licenses/rust/log-0.4.34/LICENSE-MIT +25 -0
  90. package/licenses/rust/naga-30.0.1/LICENSE.APACHE +176 -0
  91. package/licenses/rust/naga-30.0.1/LICENSE.MIT +21 -0
  92. package/licenses/rust/naga-types-30.0.1/LICENSE.APACHE +176 -0
  93. package/licenses/rust/naga-types-30.0.1/LICENSE.MIT +21 -0
  94. package/licenses/rust/num-traits-0.2.19/LICENSE-APACHE +201 -0
  95. package/licenses/rust/num-traits-0.2.19/LICENSE-MIT +25 -0
  96. package/licenses/rust/once_cell-1.21.4/LICENSE-APACHE +201 -0
  97. package/licenses/rust/once_cell-1.21.4/LICENSE-MIT +23 -0
  98. package/licenses/rust/parking_lot-0.12.5/LICENSE-APACHE +201 -0
  99. package/licenses/rust/parking_lot-0.12.5/LICENSE-MIT +25 -0
  100. package/licenses/rust/parking_lot_core-0.9.12/LICENSE-APACHE +201 -0
  101. package/licenses/rust/parking_lot_core-0.9.12/LICENSE-MIT +25 -0
  102. package/licenses/rust/pin-project-lite-0.2.17/LICENSE-APACHE +177 -0
  103. package/licenses/rust/pin-project-lite-0.2.17/LICENSE-MIT +23 -0
  104. package/licenses/rust/portable-atomic-1.15.0/LICENSE-APACHE +177 -0
  105. package/licenses/rust/portable-atomic-1.15.0/LICENSE-MIT +23 -0
  106. package/licenses/rust/portable-atomic-util-0.2.8/LICENSE-APACHE +177 -0
  107. package/licenses/rust/portable-atomic-util-0.2.8/LICENSE-MIT +23 -0
  108. package/licenses/rust/proc-macro2-1.0.107/LICENSE-APACHE +176 -0
  109. package/licenses/rust/proc-macro2-1.0.107/LICENSE-MIT +23 -0
  110. package/licenses/rust/quote-1.0.47/LICENSE-APACHE +176 -0
  111. package/licenses/rust/quote-1.0.47/LICENSE-MIT +23 -0
  112. package/licenses/rust/raw-window-handle-0.6.2/LICENSE-APACHE.md +177 -0
  113. package/licenses/rust/raw-window-handle-0.6.2/LICENSE-MIT.md +21 -0
  114. package/licenses/rust/raw-window-handle-0.6.2/LICENSE-ZLIB.md +11 -0
  115. package/licenses/rust/read-fonts-0.41.0/LICENSE-APACHE +67 -0
  116. package/licenses/rust/read-fonts-0.41.0/LICENSE-MIT +25 -0
  117. package/licenses/rust/read-fonts-0.43.3/LICENSE-APACHE +67 -0
  118. package/licenses/rust/read-fonts-0.43.3/LICENSE-MIT +25 -0
  119. package/licenses/rust/redox_syscall-0.5.18/LICENSE +22 -0
  120. package/licenses/rust/renderdoc-sys-1.1.0/LICENSE-APACHE +201 -0
  121. package/licenses/rust/renderdoc-sys-1.1.0/LICENSE-MIT +25 -0
  122. package/licenses/rust/rustc-hash-1.1.0/LICENSE-APACHE +201 -0
  123. package/licenses/rust/rustc-hash-1.1.0/LICENSE-MIT +23 -0
  124. package/licenses/rust/rustversion-1.0.23/LICENSE-APACHE +176 -0
  125. package/licenses/rust/rustversion-1.0.23/LICENSE-MIT +23 -0
  126. package/licenses/rust/scopeguard-1.2.0/LICENSE-APACHE +201 -0
  127. package/licenses/rust/scopeguard-1.2.0/LICENSE-MIT +25 -0
  128. package/licenses/rust/serde-1.0.229/LICENSE-APACHE +176 -0
  129. package/licenses/rust/serde-1.0.229/LICENSE-MIT +23 -0
  130. package/licenses/rust/serde_core-1.0.229/LICENSE-APACHE +176 -0
  131. package/licenses/rust/serde_core-1.0.229/LICENSE-MIT +23 -0
  132. package/licenses/rust/serde_derive-1.0.229/LICENSE-APACHE +176 -0
  133. package/licenses/rust/serde_derive-1.0.229/LICENSE-MIT +23 -0
  134. package/licenses/rust/skrifa-0.44.0/LICENSE-APACHE +67 -0
  135. package/licenses/rust/skrifa-0.44.0/LICENSE-MIT +25 -0
  136. package/licenses/rust/slab-0.4.12/LICENSE +25 -0
  137. package/licenses/rust/smallvec-1.16.2/LICENSE-APACHE +201 -0
  138. package/licenses/rust/smallvec-1.16.2/LICENSE-MIT +25 -0
  139. package/licenses/rust/static_assertions-1.1.0/LICENSE-APACHE +202 -0
  140. package/licenses/rust/static_assertions-1.1.0/LICENSE-MIT +21 -0
  141. package/licenses/rust/swash-0.2.10/LICENSE-APACHE +201 -0
  142. package/licenses/rust/swash-0.2.10/LICENSE-MIT +25 -0
  143. package/licenses/rust/syn-2.0.119/LICENSE-APACHE +176 -0
  144. package/licenses/rust/syn-2.0.119/LICENSE-MIT +23 -0
  145. package/licenses/rust/syn-3.0.6/LICENSE-APACHE +176 -0
  146. package/licenses/rust/syn-3.0.6/LICENSE-MIT +23 -0
  147. package/licenses/rust/termcolor-1.4.1/COPYING +3 -0
  148. package/licenses/rust/termcolor-1.4.1/LICENSE-MIT +21 -0
  149. package/licenses/rust/termcolor-1.4.1/UNLICENSE +24 -0
  150. package/licenses/rust/thiserror-2.0.21/LICENSE-APACHE +176 -0
  151. package/licenses/rust/thiserror-2.0.21/LICENSE-MIT +23 -0
  152. package/licenses/rust/thiserror-impl-2.0.21/LICENSE-APACHE +176 -0
  153. package/licenses/rust/thiserror-impl-2.0.21/LICENSE-MIT +23 -0
  154. package/licenses/rust/tokio-1.53.2/LICENSE +21 -0
  155. package/licenses/rust/unicode-ident-1.0.26/LICENSE-APACHE +176 -0
  156. package/licenses/rust/unicode-ident-1.0.26/LICENSE-MIT +23 -0
  157. package/licenses/rust/unicode-ident-1.0.26/LICENSE-UNICODE +39 -0
  158. package/licenses/rust/unicode-width-0.2.2/LICENSE-APACHE +201 -0
  159. package/licenses/rust/unicode-width-0.2.2/LICENSE-MIT +25 -0
  160. package/licenses/rust/wasm-bindgen-0.2.129/LICENSE-APACHE +201 -0
  161. package/licenses/rust/wasm-bindgen-0.2.129/LICENSE-MIT +25 -0
  162. package/licenses/rust/wasm-bindgen-futures-0.4.79/LICENSE-APACHE +201 -0
  163. package/licenses/rust/wasm-bindgen-futures-0.4.79/LICENSE-MIT +25 -0
  164. package/licenses/rust/wasm-bindgen-macro-0.2.129/LICENSE-APACHE +201 -0
  165. package/licenses/rust/wasm-bindgen-macro-0.2.129/LICENSE-MIT +25 -0
  166. package/licenses/rust/wasm-bindgen-macro-support-0.2.129/LICENSE-APACHE +201 -0
  167. package/licenses/rust/wasm-bindgen-macro-support-0.2.129/LICENSE-MIT +25 -0
  168. package/licenses/rust/wasm-bindgen-shared-0.2.129/LICENSE-APACHE +201 -0
  169. package/licenses/rust/wasm-bindgen-shared-0.2.129/LICENSE-MIT +25 -0
  170. package/licenses/rust/web-sys-0.3.106/LICENSE-APACHE +201 -0
  171. package/licenses/rust/web-sys-0.3.106/LICENSE-MIT +25 -0
  172. package/licenses/rust/wgpu-30.0.1/LICENSE.APACHE +176 -0
  173. package/licenses/rust/wgpu-30.0.1/LICENSE.MIT +21 -0
  174. package/licenses/rust/wgpu-core-30.0.1/LICENSE.APACHE +176 -0
  175. package/licenses/rust/wgpu-core-30.0.1/LICENSE.MIT +21 -0
  176. package/licenses/rust/wgpu-core-deps-windows-linux-android-30.0.1/LICENSE.APACHE +176 -0
  177. package/licenses/rust/wgpu-core-deps-windows-linux-android-30.0.1/LICENSE.MIT +21 -0
  178. package/licenses/rust/wgpu-hal-30.0.1/LICENSE.APACHE +176 -0
  179. package/licenses/rust/wgpu-hal-30.0.1/LICENSE.MIT +21 -0
  180. package/licenses/rust/wgpu-naga-bridge-30.0.1/LICENSE.APACHE +176 -0
  181. package/licenses/rust/wgpu-naga-bridge-30.0.1/LICENSE.MIT +21 -0
  182. package/licenses/rust/wgpu-types-30.0.1/LICENSE.APACHE +176 -0
  183. package/licenses/rust/wgpu-types-30.0.1/LICENSE.MIT +21 -0
  184. package/licenses/rust/winapi-util-0.1.11/COPYING +3 -0
  185. package/licenses/rust/winapi-util-0.1.11/LICENSE-MIT +21 -0
  186. package/licenses/rust/winapi-util-0.1.11/UNLICENSE +24 -0
  187. package/licenses/rust/windows-link-0.2.1/license-apache-2.0 +201 -0
  188. package/licenses/rust/windows-link-0.2.1/license-mit +21 -0
  189. package/licenses/rust/windows-sys-0.61.2/license-apache-2.0 +201 -0
  190. package/licenses/rust/windows-sys-0.61.2/license-mit +21 -0
  191. package/licenses/rust/yazi-0.2.1/LICENSE-APACHE +201 -0
  192. package/licenses/rust/yazi-0.2.1/LICENSE-MIT +19 -0
  193. package/licenses/rust/zeno-0.3.3/LICENSE-APACHE +201 -0
  194. package/licenses/rust/zeno-0.3.3/LICENSE-MIT +25 -0
  195. package/licenses/rust/zerocopy-0.8.62/LICENSE-APACHE +202 -0
  196. package/licenses/rust/zerocopy-0.8.62/LICENSE-BSD +24 -0
  197. package/licenses/rust/zerocopy-0.8.62/LICENSE-MIT +26 -0
  198. package/licenses/rust/zerocopy-derive-0.8.62/LICENSE-APACHE +202 -0
  199. package/licenses/rust/zerocopy-derive-0.8.62/LICENSE-BSD +24 -0
  200. package/licenses/rust/zerocopy-derive-0.8.62/LICENSE-MIT +26 -0
  201. package/licenses/xterm-MIT.txt +21 -0
  202. package/package.json +69 -4
  203. package/wasm/Ghostty-MIT.txt +21 -0
  204. package/wasm/JetBrainsMono-Regular.ttf +0 -0
  205. package/wasm/OFL.txt +93 -0
  206. package/wasm/optimization.json +6 -0
  207. package/wasm/wraith_engine.d.ts +176 -0
  208. package/wasm/wraith_engine.js +2057 -0
  209. package/wasm/wraith_engine_bg.wasm +0 -0
  210. package/wasm/wraith_engine_bg.wasm.d.ts +71 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Wraith contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,314 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <a href="https://wraithterm.com">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/betterclever/wraithterm/main/.github/assets/logo-light.svg">
5
+ <img src="https://raw.githubusercontent.com/betterclever/wraithterm/main/.github/assets/logo.svg" alt="Wraith" width="560">
6
+ </picture>
7
+ </a>
8
+ </p>
2
9
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
10
+ <h3 align="center">Spooky fast web terminal.</h3>
11
+
12
+ <p align="center">
13
+ Ghostty's terminal engine and a Rust WebGPU renderer, compiled into one Wasm module.<br>
14
+ Drop it in where xterm.js was, or run Ghostty itself in a worker.
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="https://www.npmjs.com/package/wraithterm"><img alt="npm" src="https://img.shields.io/npm/v/wraithterm?style=flat-square&color=ffb86b&labelColor=0c0806"></a>
19
+ <a href="https://github.com/betterclever/wraithterm/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/betterclever/wraithterm/ci.yml?branch=main&style=flat-square&label=ci&color=ffd98a&labelColor=0c0806"></a>
20
+ <a href="LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-ff7f6e?style=flat-square&labelColor=0c0806"></a>
21
+ <img alt="xterm.js 6.0 compatible" src="https://img.shields.io/badge/xterm.js-6.0%20compatible-d9bbff?style=flat-square&labelColor=0c0806">
22
+ <img alt="WebGPU" src="https://img.shields.io/badge/WebGPU-Rust%20%2B%20Wasm-ffb86b?style=flat-square&labelColor=0c0806">
23
+ </p>
24
+
25
+ <p align="center">
26
+ <a href="https://wraithterm.com"><b>Website</b></a> ·
27
+ <a href="https://wraithterm.com/#race"><b>Race it in your browser</b></a> ·
28
+ <a href="docs/ARCHITECTURE.md"><b>Architecture</b></a> ·
29
+ <a href="docs/PERFORMANCE.md"><b>Performance</b></a> ·
30
+ <a href="CHANGELOG.md"><b>Changelog</b></a>
31
+ </p>
32
+
33
+ ## Why Wraith
34
+
35
+ <table>
36
+ <tr>
37
+ <td width="50%">
38
+
39
+ **Less CPU per update.** One dense, full-screen update (240×80 cells, about 4,800 style changes):
40
+
41
+ | Renderer | CPU per update |
42
+ | ---------------- | -------------: |
43
+ | xterm.js, DOM | 37.7 ms |
44
+ | xterm.js + WebGL | 9.8 ms |
45
+ | **Wraith** | **2.5 ms** |
46
+
47
+ That is **15× less** than xterm.js DOM and **3.9× less** than xterm.js + WebGL, and we are still climbing.
48
+
49
+ <sub>Medians of interleaved runs, Chrome 155, Apple M5 Max, GPU-completed updates ([report](docs/benchmarks/launch/REPORT.md)). Your machine will differ: [race it yourself](https://wraithterm.com/#race).</sub>
50
+
51
+ </td>
52
+ <td width="50%">
53
+
54
+ <img src="https://raw.githubusercontent.com/betterclever/wraithterm/main/.github/assets/numbers.jpg" alt="15× less CPU than xterm.js DOM, 3.9× less than xterm.js + WebGL" width="100%">
55
+
56
+ </td>
57
+ </tr>
58
+ </table>
59
+
60
+ - **Two ways in.** `wraithterm/xterm` is a complete xterm.js 6.0 `Terminal`: keep your code and addons, get a WebGPU renderer. `Wraith.mount()` runs Ghostty's own `libghostty-vt` in a worker.
61
+ - **Built for the GPU.** 20-byte cells, glyph quads sized to their ink, and row reuse: a one-cell edit uploads one row.
62
+ - **Off your main thread.** The native profile parses, snapshots and renders in a dedicated worker; your app keeps its frame budget.
63
+ - **One module, one allocator.** Zig owns the terminal model; Rust owns shaping, the glyph atlas and wgpu, in a single Wasm binary.
64
+
65
+ <p align="center">
66
+ <img src="https://raw.githubusercontent.com/betterclever/wraithterm/main/.github/assets/dashboard.jpg" alt="A btop-style dashboard rendered live by Wraith: CPU meters, a braille network graph, a process table, highlighted Rust, logs and a frame-time histogram." width="100%">
67
+ <br><sub>A full-screen dashboard rewritten every update, rendered live by Wraith on WebGPU.</sub>
68
+ </p>
69
+
70
+ ## Quick start
71
+
72
+ ```sh
73
+ npm i wraithterm
74
+ ```
75
+
76
+ ```ts
77
+ // Keep your xterm.js code: swap one import.
78
+ import { Terminal } from 'wraithterm/xterm';
79
+ import 'wraithterm/css/xterm.css';
80
+
81
+ const term = new Terminal({ fontSize: 14 });
82
+ term.open(document.getElementById('terminal')!);
83
+ term.write('hello from the other side\r\n');
84
+ ```
85
+
86
+ ```ts
87
+ // Or go native: Ghostty's terminal semantics in a worker.
88
+ import { Wraith } from 'wraithterm';
89
+
90
+ const term = await Wraith.mount(document.getElementById('terminal')!);
91
+ term.connect(new WebSocket(ptyUrl));
92
+ ```
93
+
94
+ ## About this repository
95
+
96
+ The `Wraith.mount()` profile is built around upstream
97
+ `libghostty-vt`. Zig owns the terminal model; Rust owns text shaping, glyph
98
+ rasterization, and the WebGPU renderer. Both live in **one Wasm module with one
99
+ allocator**, inside a dedicated worker. TypeScript handles browser input and the
100
+ public API.
101
+
102
+ The initial performance target is a **1 ms warm frame processing budget**, with
103
+ 120 Hz presentation on capable displays. GPU-completed render throughput is
104
+ measured separately from the screen's refresh rate. See [the measured results](docs/PERFORMANCE.md).
105
+
106
+ ## Run the playground
107
+
108
+ The prebuilt engine and font are included. Node 22.12+ is sufficient to run the
109
+ demo; Rust and Zig are needed only when changing the engine.
110
+
111
+ ```sh
112
+ npm ci
113
+ npm run build:sdk
114
+ npm run dev
115
+ ```
116
+
117
+ Open **http://127.0.0.1:5173** for the landing page and its in-browser race, or
118
+ **http://127.0.0.1:5173/playground.html** for the playground. In the playground,
119
+ try `help` or `colors`, start a stream, and run a benchmark. The playground's shell is an interactive demonstration; connect a PTY
120
+ backend to run actual programs.
121
+
122
+ ## Drop-in xterm API
123
+
124
+ Wraith 0.2 exports a complete xterm.js **6.0.0** `Terminal` with original public
125
+ methods, events, options, parser hooks, buffer views and addon contracts:
126
+
127
+ ```ts
128
+ import { Terminal } from 'wraithterm/xterm';
129
+ import 'wraithterm/css/xterm.css';
130
+ import { FitAddon } from '@xterm/addon-fit';
131
+
132
+ const terminal = new Terminal({ fontSize: 14, scrollback: 10_000 });
133
+ const fit = new FitAddon();
134
+ terminal.loadAddon(fit);
135
+ terminal.open(document.querySelector('#terminal')!);
136
+ fit.fit();
137
+ terminal.write('Hello, \x1b[36mworld\x1b[0m\r\n');
138
+ terminal.onData((data) => socket.send(data));
139
+ ```
140
+
141
+ This profile retains xterm's semantic core and uses Wraith's Rust/Wasm WebGPU
142
+ compositor. The `Wraith.mount()` profile below retains libghostty. Original Fit,
143
+ Search, Serialize, Attach and Unicode11 addons are verified. Some visual features
144
+ use automatic DOM fallback; [XTERM_API.md](docs/XTERM_API.md) gives the exact
145
+ contracts, fallback list, and instructions to retain **unchanged `@xterm/xterm`
146
+ imports** by installing the package under that dependency key.
147
+
148
+ Open **http://127.0.0.1:5173/xterm.html** for the compatibility playground.
149
+
150
+ ## Integrate
151
+
152
+ The package is `wraithterm`; it has not been published to npm. Install
153
+ the supplied `.tgz`, use the local package directory, or build your own package:
154
+
155
+ ```sh
156
+ npm run build:sdk
157
+ npm pack --workspace wraithterm
158
+ ```
159
+
160
+ Give the host an explicit height:
161
+
162
+ ```html
163
+ <div id="terminal" style="height: 420px"></div>
164
+ ```
165
+
166
+ ```ts
167
+ import { Wraith } from 'wraithterm';
168
+
169
+ const terminal = await Wraith.mount(document.querySelector('#terminal')!, {
170
+ fontSize: 14,
171
+ scrollback: 10_000,
172
+ });
173
+
174
+ await terminal.write('Hello, \x1b[36mworld\x1b[0m\r\n');
175
+ terminal.onData((input) => console.log(input));
176
+ terminal.focus();
177
+ ```
178
+
179
+ Connect a PTY transport:
180
+
181
+ ```ts
182
+ const socket = new WebSocket('wss://your-backend/terminal');
183
+ const connection = terminal.connect(socket);
184
+
185
+ // This control message is a convention for YOUR server, not terminal output.
186
+ const sendSize = () => {
187
+ if (socket.readyState === WebSocket.OPEN) {
188
+ socket.send(JSON.stringify({ type: 'resize', cols: terminal.cols, rows: terminal.rows }));
189
+ }
190
+ };
191
+ socket.addEventListener('open', sendSize);
192
+ terminal.onResize(sendSize);
193
+
194
+ // Cleanup:
195
+ connection.dispose();
196
+ await terminal.dispose();
197
+ ```
198
+
199
+ `connect()` sends input as binary WebSocket messages and accepts output as text,
200
+ ArrayBuffer, or Blob, preserving order. Your backend owns PTY creation, geometry,
201
+ authentication, and transport lifecycle.
202
+
203
+ For Vite, add the included adapter so dependency prebundling preserves the worker
204
+ and font URLs. Both dev mode and a production build are verified with the installed
205
+ npm archive:
206
+
207
+ ```ts
208
+ // vite.config.ts
209
+ import { defineConfig } from 'vite';
210
+ import { wraith } from 'wraithterm/vite';
211
+
212
+ export default defineConfig({ plugins: [wraith()] });
213
+ ```
214
+
215
+ Other bundlers must preserve the `new URL(..., import.meta.url)` worker and asset
216
+ references; they have not yet been certified.
217
+
218
+ ## API contracts
219
+
220
+ | Method / event | Contract |
221
+ | ----------------------------------------------------------- | ----------------------------------------------------------------------------------- |
222
+ | `Wraith.mount(element, options)` | Resolves after engine and pipeline initialization; fits by default. |
223
+ | `write(string \| Uint8Array)` | Resolves after parsing. Retains caller ownership of input buffers. |
224
+ | `flush()` | Renders pending state and waits for a GPU completion fence. |
225
+ | `resize(cols, rows)` / `fit()` | Preserves state through Ghostty's reflow. |
226
+ | `onBytes(listener)` | Byte-accurate PTY input and terminal query responses; preferred for transports. |
227
+ | `onData(listener)` | UTF-8 text view of output. Use `onBytes` for binary mouse protocols. |
228
+ | `onResize`, `onTitleChange`, `onBell`, `onStats`, `onError` | Return disposable subscriptions. |
229
+ | `paste(text)` | Removes terminal control characters and follows bracketed paste mode. |
230
+ | `scroll(lines)` | Negative moves toward history; positive moves toward the active area. |
231
+ | `getText()` | Plain text for the current viewport, with visual row breaks. |
232
+ | `getText(true)` | Ghostty's selection formatter; unwraps soft-wrapped lines. |
233
+ | `setTheme({ foreground, background, cursor })` | Colors use `#rrggbb`. |
234
+ | `benchmark({ workload, frames, warmup })` | Exclusive, warmed render benchmark; restores the main screen and cursor visibility. |
235
+ | `dispose()` | Rejects outstanding work and releases the worker, DOM, listeners, and engine. |
236
+
237
+ The default maximum unacknowledged input is **8 MiB**. `write()` rejects with
238
+ `BackpressureError` when full. Await writes to regulate a high-throughput producer.
239
+ `write()` resolves before presentation; `flush()` provides the stronger completion
240
+ contract.
241
+
242
+ The bundled JetBrains Mono font covers the demo. Supply `font` and `fallbackFonts`
243
+ as URLs or Uint8Arrays for other scripts or color emoji. Font size is in CSS pixels;
244
+ rasterization uses devicePixelRatio captured at mount. The accessible text mirror
245
+ is enabled with `screenReaderMode: true`.
246
+
247
+ ## Architecture and compatibility
248
+
249
+ Read [ARCHITECTURE.md](docs/ARCHITECTURE.md) for ownership, the frame path, and
250
+ failure handling. [COMPATIBILITY.md](docs/COMPATIBILITY.md) distinguishes verified
251
+ behavior from upstream capabilities and remaining renderer work.
252
+
253
+ This release implements a broad text-terminal path. **Kitty graphics / Sixel,
254
+ OSC 52 clipboard operations, cross-cell ligatures, contextual script runs, and
255
+ cross-browser certification remain release work.** This is not a claim of complete
256
+ terminal-spec conformance.
257
+
258
+ ## Build from source
259
+
260
+ Prerequisites: Rust 1.88+, the `wasm32-unknown-unknown` target, Node 22.12+, Git,
261
+ and tar. The bootstrap supports macOS and Linux on arm64 or x64. It downloads a
262
+ checksum-verified Zig 0.16.0 toolchain and the Ghostty commit in `upstream.json`.
263
+
264
+ ```sh
265
+ rustup target add wasm32-unknown-unknown
266
+ npm ci
267
+ npm run build
268
+ npm run test:native
269
+ npm run typecheck
270
+ npm test
271
+ npm run build:demo
272
+ ```
273
+
274
+ The distributed Wasm is optionally post-link optimized with Binaryen. Run
275
+ `npm run optimize` after a fresh engine build when `wasm-opt` is installed.
276
+
277
+ Build downloads and intermediates go under `.cache/`. Set `WRAITH_BUILD_DIR` to
278
+ use another build directory and `ZIG` to use an existing Zig 0.16.0 executable.
279
+ Consumers of the prebuilt package need neither compiler.
280
+
281
+ For real browser verification, run the demo server in another terminal:
282
+
283
+ ```sh
284
+ npm run test:browser
285
+ npm run test:xterm
286
+ npm run test:xterm-consumer
287
+ ```
288
+
289
+ Set `CHROME_PATH` when Chrome is outside its standard macOS path; on Linux, install
290
+ Playwright Chromium with `npx playwright install chromium`. `WRAITH_HEADFUL=1`
291
+ shows the test browser. The suite requires a working WebGPU adapter. The software
292
+ GPU test option is `WRAITH_SOFTWARE_GPU=1`; such results must be identified as
293
+ software results, not hardware performance.
294
+
295
+ ## License
296
+
297
+ Wraith is MIT licensed. Ghostty's MIT license, the font's SIL Open Font License,
298
+ and bundled Rust dependency notices accompany the package. See [licenses/](licenses/).
299
+
300
+ ## Renderer comparison
301
+
302
+ The [dense-scene benchmark](docs/benchmarks/comparison/REPORT.md) compares Wraith
303
+ with xterm DOM and WebGL on a 240×80 styled Unicode scene. Run
304
+ `npm run benchmark:compare` with the demo server active, or use `/compare.html`.
305
+ Raw measurements and a separate CPU profile are retained under
306
+ `docs/benchmarks/comparison`.
307
+
308
+ The [efficiency report](docs/benchmarks/efficiency/REPORT.md) has the current
309
+ before/after numbers for both profiles, with pixel-identical output. The
310
+ [engineering plan](docs/TOP_TIER.md) prioritizes GPU feature coverage, scrolling,
311
+ latency, recovery, memory, compatibility and integration for a stable release.
312
+ Earlier passes: [optimization](docs/benchmarks/optimization/REPORT.md),
313
+ [packing](docs/benchmarks/packing/REPORT.md) and
314
+ [utilization](docs/benchmarks/comparison/UTILIZATION.md).
package/css/xterm.css ADDED
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Copyright (c) 2014 The xterm.js authors. All rights reserved.
3
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
4
+ * https://github.com/chjj/term.js
5
+ * @license MIT
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ *
25
+ * Originally forked from (with the author's permission):
26
+ * Fabrice Bellard's javascript vt100 for jslinux:
27
+ * http://bellard.org/jslinux/
28
+ * Copyright (c) 2011 Fabrice Bellard
29
+ * The original design remains. The terminal itself
30
+ * has been extended to include xterm CSI codes, among
31
+ * other features.
32
+ */
33
+
34
+ /**
35
+ * Default styles for xterm.js
36
+ */
37
+
38
+ .xterm {
39
+ cursor: text;
40
+ position: relative;
41
+ user-select: none;
42
+ -ms-user-select: none;
43
+ -webkit-user-select: none;
44
+ }
45
+
46
+ .xterm.focus,
47
+ .xterm:focus {
48
+ outline: none;
49
+ }
50
+
51
+ .xterm .xterm-helpers {
52
+ position: absolute;
53
+ top: 0;
54
+ /**
55
+ * The z-index of the helpers must be higher than the canvases in order for
56
+ * IMEs to appear on top.
57
+ */
58
+ z-index: 5;
59
+ }
60
+
61
+ .xterm .xterm-helper-textarea {
62
+ padding: 0;
63
+ border: 0;
64
+ margin: 0;
65
+ /* Move textarea out of the screen to the far left, so that the cursor is not visible */
66
+ position: absolute;
67
+ opacity: 0;
68
+ left: -9999em;
69
+ top: 0;
70
+ width: 0;
71
+ height: 0;
72
+ z-index: -5;
73
+ /** Prevent wrapping so the IME appears against the textarea at the correct position */
74
+ white-space: nowrap;
75
+ overflow: hidden;
76
+ resize: none;
77
+ }
78
+
79
+ .xterm .composition-view {
80
+ /* TODO: Composition position got messed up somewhere */
81
+ background: #000;
82
+ color: #FFF;
83
+ display: none;
84
+ position: absolute;
85
+ white-space: nowrap;
86
+ z-index: 1;
87
+ }
88
+
89
+ .xterm .composition-view.active {
90
+ display: block;
91
+ }
92
+
93
+ .xterm .xterm-viewport {
94
+ /* On OS X this is required in order for the scroll bar to appear fully opaque */
95
+ background-color: #000;
96
+ overflow-y: scroll;
97
+ cursor: default;
98
+ position: absolute;
99
+ right: 0;
100
+ left: 0;
101
+ top: 0;
102
+ bottom: 0;
103
+ }
104
+
105
+ .xterm .xterm-screen {
106
+ position: relative;
107
+ }
108
+
109
+ .xterm .xterm-screen canvas {
110
+ position: absolute;
111
+ left: 0;
112
+ top: 0;
113
+ }
114
+
115
+ .xterm-char-measure-element {
116
+ display: inline-block;
117
+ visibility: hidden;
118
+ position: absolute;
119
+ top: 0;
120
+ left: -9999em;
121
+ line-height: normal;
122
+ }
123
+
124
+ .xterm.enable-mouse-events {
125
+ /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
126
+ cursor: default;
127
+ }
128
+
129
+ .xterm.xterm-cursor-pointer,
130
+ .xterm .xterm-cursor-pointer {
131
+ cursor: pointer;
132
+ }
133
+
134
+ .xterm.column-select.focus {
135
+ /* Column selection mode */
136
+ cursor: crosshair;
137
+ }
138
+
139
+ .xterm .xterm-accessibility:not(.debug),
140
+ .xterm .xterm-message {
141
+ position: absolute;
142
+ left: 0;
143
+ top: 0;
144
+ bottom: 0;
145
+ right: 0;
146
+ z-index: 10;
147
+ color: transparent;
148
+ pointer-events: none;
149
+ }
150
+
151
+ .xterm .xterm-accessibility-tree:not(.debug) *::selection {
152
+ color: transparent;
153
+ }
154
+
155
+ .xterm .xterm-accessibility-tree {
156
+ font-family: monospace;
157
+ user-select: text;
158
+ white-space: pre;
159
+ }
160
+
161
+ .xterm .xterm-accessibility-tree > div {
162
+ transform-origin: left;
163
+ width: fit-content;
164
+ }
165
+
166
+ .xterm .live-region {
167
+ position: absolute;
168
+ left: -9999px;
169
+ width: 1px;
170
+ height: 1px;
171
+ overflow: hidden;
172
+ }
173
+
174
+ .xterm-dim {
175
+ /* Dim should not apply to background, so the opacity of the foreground color is applied
176
+ * explicitly in the generated class and reset to 1 here */
177
+ opacity: 1 !important;
178
+ }
179
+
180
+ .xterm-underline-1 { text-decoration: underline; }
181
+ .xterm-underline-2 { text-decoration: double underline; }
182
+ .xterm-underline-3 { text-decoration: wavy underline; }
183
+ .xterm-underline-4 { text-decoration: dotted underline; }
184
+ .xterm-underline-5 { text-decoration: dashed underline; }
185
+
186
+ .xterm-overline {
187
+ text-decoration: overline;
188
+ }
189
+
190
+ .xterm-overline.xterm-underline-1 { text-decoration: overline underline; }
191
+ .xterm-overline.xterm-underline-2 { text-decoration: overline double underline; }
192
+ .xterm-overline.xterm-underline-3 { text-decoration: overline wavy underline; }
193
+ .xterm-overline.xterm-underline-4 { text-decoration: overline dotted underline; }
194
+ .xterm-overline.xterm-underline-5 { text-decoration: overline dashed underline; }
195
+
196
+ .xterm-strikethrough {
197
+ text-decoration: line-through;
198
+ }
199
+
200
+ .xterm-screen .xterm-decoration-container .xterm-decoration {
201
+ z-index: 6;
202
+ position: absolute;
203
+ }
204
+
205
+ .xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer {
206
+ z-index: 7;
207
+ }
208
+
209
+ .xterm-decoration-overview-ruler {
210
+ z-index: 8;
211
+ position: absolute;
212
+ top: 0;
213
+ right: 0;
214
+ pointer-events: none;
215
+ }
216
+
217
+ .xterm-decoration-top {
218
+ z-index: 2;
219
+ position: relative;
220
+ }
221
+
222
+
223
+
224
+ /* Derived from vs/base/browser/ui/scrollbar/media/scrollbar.css */
225
+
226
+ /* xterm.js customization: Override xterm's cursor style */
227
+ .xterm .xterm-scrollable-element > .scrollbar {
228
+ cursor: default;
229
+ }
230
+
231
+ /* Arrows */
232
+ .xterm .xterm-scrollable-element > .scrollbar > .scra {
233
+ cursor: pointer;
234
+ font-size: 11px !important;
235
+ }
236
+
237
+ .xterm .xterm-scrollable-element > .visible {
238
+ opacity: 1;
239
+
240
+ /* Background rule added for IE9 - to allow clicks on dom node */
241
+ background:rgba(0,0,0,0);
242
+
243
+ transition: opacity 100ms linear;
244
+ /* In front of peek view */
245
+ z-index: 11;
246
+ }
247
+ .xterm .xterm-scrollable-element > .invisible {
248
+ opacity: 0;
249
+ pointer-events: none;
250
+ }
251
+ .xterm .xterm-scrollable-element > .invisible.fade {
252
+ transition: opacity 800ms linear;
253
+ }
254
+
255
+ /* Scrollable Content Inset Shadow */
256
+ .xterm .xterm-scrollable-element > .shadow {
257
+ position: absolute;
258
+ display: none;
259
+ }
260
+ .xterm .xterm-scrollable-element > .shadow.top {
261
+ display: block;
262
+ top: 0;
263
+ left: 3px;
264
+ height: 3px;
265
+ width: 100%;
266
+ box-shadow: var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset;
267
+ }
268
+ .xterm .xterm-scrollable-element > .shadow.left {
269
+ display: block;
270
+ top: 3px;
271
+ left: 0;
272
+ height: 100%;
273
+ width: 3px;
274
+ box-shadow: var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset;
275
+ }
276
+ .xterm .xterm-scrollable-element > .shadow.top-left-corner {
277
+ display: block;
278
+ top: 0;
279
+ left: 0;
280
+ height: 3px;
281
+ width: 3px;
282
+ }
283
+ .xterm .xterm-scrollable-element > .shadow.top.left {
284
+ box-shadow: var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset;
285
+ }