@xincli/opentui-core 0.4.6

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 (476) hide show
  1. package/README.md +63 -0
  2. package/dev/keypress-debug-renderer.ts +148 -0
  3. package/dev/keypress-debug.ts +43 -0
  4. package/dev/print-env-vars.ts +32 -0
  5. package/dev/test-tmux-graphics-334.sh +68 -0
  6. package/dev/test-tmux-theme-queries.sh +151 -0
  7. package/dev/thai-debug-test.ts +68 -0
  8. package/dev/theme-mode.ts +290 -0
  9. package/docs/development.md +144 -0
  10. package/package.json +102 -0
  11. package/prebuilt/aarch64-android/libopentui.so +0 -0
  12. package/scripts/build-android.ts +226 -0
  13. package/scripts/build-native-termux.sh +525 -0
  14. package/scripts/build.ts +530 -0
  15. package/scripts/dist-test.ts +312 -0
  16. package/scripts/package-prebuilt.ts +110 -0
  17. package/scripts/publish.ts +60 -0
  18. package/scripts/test-node-hook.mjs +16 -0
  19. package/scripts/test-node.ts +241 -0
  20. package/scripts/vendor-deps.sh +73 -0
  21. package/src/NativeSpanFeed.ts +375 -0
  22. package/src/Renderable.ts +1878 -0
  23. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  24. package/src/animation/Timeline.test.ts +2709 -0
  25. package/src/animation/Timeline.ts +598 -0
  26. package/src/ansi.ts +22 -0
  27. package/src/audio.ts +479 -0
  28. package/src/benchmark/attenuation-benchmark.ts +81 -0
  29. package/src/benchmark/audio-playback-benchmark.ts +344 -0
  30. package/src/benchmark/box-draw-benchmark.ts +1042 -0
  31. package/src/benchmark/colormatrix-benchmark.ts +123 -0
  32. package/src/benchmark/gain-benchmark.ts +80 -0
  33. package/src/benchmark/latest-all-bench-run.json +707 -0
  34. package/src/benchmark/latest-async-bench-run.json +336 -0
  35. package/src/benchmark/latest-default-bench-run.json +657 -0
  36. package/src/benchmark/latest-large-bench-run.json +707 -0
  37. package/src/benchmark/latest-quick-bench-run.json +207 -0
  38. package/src/benchmark/layout-benchmark.ts +2547 -0
  39. package/src/benchmark/markdown-benchmark.ts +1796 -0
  40. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  41. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  42. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  43. package/src/benchmark/native-span-feed-compare.ts +280 -0
  44. package/src/benchmark/render-traversal-benchmark.ts +928 -0
  45. package/src/benchmark/text-buffer-render-benchmark.ts +874 -0
  46. package/src/benchmark/text-table-benchmark.ts +948 -0
  47. package/src/buffer.test.ts +292 -0
  48. package/src/buffer.ts +564 -0
  49. package/src/console.test.ts +629 -0
  50. package/src/console.ts +1253 -0
  51. package/src/edit-buffer.test.ts +1852 -0
  52. package/src/edit-buffer.ts +417 -0
  53. package/src/editor-view.test.ts +1056 -0
  54. package/src/editor-view.ts +290 -0
  55. package/src/index.ts +25 -0
  56. package/src/lib/KeyHandler.integration.test.ts +292 -0
  57. package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
  58. package/src/lib/KeyHandler.test.ts +662 -0
  59. package/src/lib/KeyHandler.ts +222 -0
  60. package/src/lib/RGBA.test.ts +60 -0
  61. package/src/lib/RGBA.ts +343 -0
  62. package/src/lib/ascii.font.ts +330 -0
  63. package/src/lib/border.test.ts +83 -0
  64. package/src/lib/border.ts +170 -0
  65. package/src/lib/bunfs.test.ts +27 -0
  66. package/src/lib/bunfs.ts +18 -0
  67. package/src/lib/clipboard.test.ts +63 -0
  68. package/src/lib/clipboard.ts +41 -0
  69. package/src/lib/clock.ts +35 -0
  70. package/src/lib/data-paths.test.ts +133 -0
  71. package/src/lib/data-paths.ts +109 -0
  72. package/src/lib/debounce.ts +106 -0
  73. package/src/lib/detect-links.test.ts +98 -0
  74. package/src/lib/detect-links.ts +56 -0
  75. package/src/lib/env.test.ts +228 -0
  76. package/src/lib/env.ts +209 -0
  77. package/src/lib/extmarks-history.ts +51 -0
  78. package/src/lib/extmarks-multiwidth.test.ts +324 -0
  79. package/src/lib/extmarks.test.ts +3547 -0
  80. package/src/lib/extmarks.ts +861 -0
  81. package/src/lib/fonts/block.json +405 -0
  82. package/src/lib/fonts/grid.json +265 -0
  83. package/src/lib/fonts/huge.json +741 -0
  84. package/src/lib/fonts/pallet.json +314 -0
  85. package/src/lib/fonts/shade.json +591 -0
  86. package/src/lib/fonts/slick.json +321 -0
  87. package/src/lib/fonts/tiny.json +69 -0
  88. package/src/lib/hast-styled-text.ts +59 -0
  89. package/src/lib/index.ts +22 -0
  90. package/src/lib/keybinding.internal.test.ts +342 -0
  91. package/src/lib/keybinding.internal.ts +182 -0
  92. package/src/lib/objects-in-viewport.test.ts +789 -0
  93. package/src/lib/objects-in-viewport.ts +153 -0
  94. package/src/lib/output.capture.ts +58 -0
  95. package/src/lib/parse.keypress-kitty.protocol.test.ts +347 -0
  96. package/src/lib/parse.keypress-kitty.test.ts +712 -0
  97. package/src/lib/parse.keypress-kitty.ts +470 -0
  98. package/src/lib/parse.keypress.test.ts +2020 -0
  99. package/src/lib/parse.keypress.ts +480 -0
  100. package/src/lib/parse.mouse.test.ts +552 -0
  101. package/src/lib/parse.mouse.ts +232 -0
  102. package/src/lib/paste.ts +18 -0
  103. package/src/lib/queue.ts +65 -0
  104. package/src/lib/render-geometry.ts +36 -0
  105. package/src/lib/renderable.validations.test.ts +87 -0
  106. package/src/lib/renderable.validations.ts +83 -0
  107. package/src/lib/scroll-acceleration.ts +98 -0
  108. package/src/lib/selection.ts +261 -0
  109. package/src/lib/singleton.ts +34 -0
  110. package/src/lib/stdin-parser.test.ts +2439 -0
  111. package/src/lib/stdin-parser.ts +2007 -0
  112. package/src/lib/styled-text.ts +178 -0
  113. package/src/lib/terminal-capability-detection.test.ts +226 -0
  114. package/src/lib/terminal-capability-detection.ts +98 -0
  115. package/src/lib/terminal-palette.test.ts +954 -0
  116. package/src/lib/terminal-palette.ts +441 -0
  117. package/src/lib/tree-sitter/assets/README.md +119 -0
  118. package/src/lib/tree-sitter/assets/javascript/highlights.scm +205 -0
  119. package/src/lib/tree-sitter/assets/javascript/tree-sitter-javascript.wasm +0 -0
  120. package/src/lib/tree-sitter/assets/markdown/highlights.scm +150 -0
  121. package/src/lib/tree-sitter/assets/markdown/injections.scm +27 -0
  122. package/src/lib/tree-sitter/assets/markdown/tree-sitter-markdown.wasm +0 -0
  123. package/src/lib/tree-sitter/assets/markdown_inline/highlights.scm +115 -0
  124. package/src/lib/tree-sitter/assets/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  125. package/src/lib/tree-sitter/assets/typescript/highlights.scm +604 -0
  126. package/src/lib/tree-sitter/assets/typescript/tree-sitter-typescript.wasm +0 -0
  127. package/src/lib/tree-sitter/assets/update.ts +360 -0
  128. package/src/lib/tree-sitter/assets/zig/highlights.scm +284 -0
  129. package/src/lib/tree-sitter/assets/zig/tree-sitter-zig.wasm +0 -0
  130. package/src/lib/tree-sitter/assets.d.ts +9 -0
  131. package/src/lib/tree-sitter/cache.test.ts +291 -0
  132. package/src/lib/tree-sitter/client.test.ts +1434 -0
  133. package/src/lib/tree-sitter/client.ts +847 -0
  134. package/src/lib/tree-sitter/default-parsers.ts +133 -0
  135. package/src/lib/tree-sitter/download-utils.ts +148 -0
  136. package/src/lib/tree-sitter/index.ts +75 -0
  137. package/src/lib/tree-sitter/parser.worker.ts +1098 -0
  138. package/src/lib/tree-sitter/parsers-config.ts +81 -0
  139. package/src/lib/tree-sitter/resolve-ft.test.ts +55 -0
  140. package/src/lib/tree-sitter/resolve-ft.ts +189 -0
  141. package/src/lib/tree-sitter/types.ts +132 -0
  142. package/src/lib/tree-sitter/update-assets.ts +10 -0
  143. package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
  144. package/src/lib/tree-sitter-styled-text.ts +314 -0
  145. package/src/lib/validate-dir-name.ts +55 -0
  146. package/src/lib/yoga.options.test.ts +628 -0
  147. package/src/lib/yoga.options.ts +346 -0
  148. package/src/native-event-worker-repro.test.ts +48 -0
  149. package/src/native-event-worker-repro.worker.ts +9 -0
  150. package/src/native-handle.test.ts +221 -0
  151. package/src/platform/ffi.test.ts +516 -0
  152. package/src/platform/ffi.ts +653 -0
  153. package/src/platform/runtime.test.ts +52 -0
  154. package/src/platform/runtime.ts +121 -0
  155. package/src/platform/test.ts +45 -0
  156. package/src/platform/worker-handler-cleanup.fixture.ts +12 -0
  157. package/src/platform/worker-onmessage-startup.fixture.ts +10 -0
  158. package/src/platform/worker-startup.fixture.ts +9 -0
  159. package/src/platform/worker.node-test.ts +153 -0
  160. package/src/platform/worker.ts +425 -0
  161. package/src/plugins/core-slot.ts +579 -0
  162. package/src/plugins/registry.ts +402 -0
  163. package/src/plugins/types.ts +46 -0
  164. package/src/post/effects.ts +948 -0
  165. package/src/post/filters.ts +512 -0
  166. package/src/post/matrices.ts +288 -0
  167. package/src/renderables/ASCIIFont.ts +219 -0
  168. package/src/renderables/Box.test.ts +474 -0
  169. package/src/renderables/Box.ts +353 -0
  170. package/src/renderables/Code.test.ts +2388 -0
  171. package/src/renderables/Code.ts +555 -0
  172. package/src/renderables/Diff.regression.test.ts +381 -0
  173. package/src/renderables/Diff.test.ts +3212 -0
  174. package/src/renderables/Diff.ts +1278 -0
  175. package/src/renderables/EditBufferRenderable.test.ts +288 -0
  176. package/src/renderables/EditBufferRenderable.ts +1152 -0
  177. package/src/renderables/FrameBuffer.ts +47 -0
  178. package/src/renderables/Input.test.ts +1310 -0
  179. package/src/renderables/Input.ts +273 -0
  180. package/src/renderables/LineNumberRenderable.ts +725 -0
  181. package/src/renderables/Markdown.ts +2144 -0
  182. package/src/renderables/ScrollBar.ts +423 -0
  183. package/src/renderables/ScrollBox.ts +903 -0
  184. package/src/renderables/Select.test.ts +1134 -0
  185. package/src/renderables/Select.ts +535 -0
  186. package/src/renderables/Slider.test.ts +456 -0
  187. package/src/renderables/Slider.ts +342 -0
  188. package/src/renderables/TabSelect.test.ts +238 -0
  189. package/src/renderables/TabSelect.ts +447 -0
  190. package/src/renderables/Text.selection-buffer.test.ts +118 -0
  191. package/src/renderables/Text.test.ts +2662 -0
  192. package/src/renderables/Text.ts +147 -0
  193. package/src/renderables/TextBufferRenderable.ts +504 -0
  194. package/src/renderables/TextNode.test.ts +1137 -0
  195. package/src/renderables/TextNode.ts +379 -0
  196. package/src/renderables/TextTable.test.ts +1411 -0
  197. package/src/renderables/TextTable.ts +1434 -0
  198. package/src/renderables/Textarea.ts +425 -0
  199. package/src/renderables/TimeToFirstDraw.ts +89 -0
  200. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  201. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  202. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  203. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  204. package/src/renderables/__tests__/Code.test.ts +55 -0
  205. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  206. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +827 -0
  207. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1906 -0
  208. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  209. package/src/renderables/__tests__/Markdown.code-colors.test.ts +288 -0
  210. package/src/renderables/__tests__/Markdown.test.ts +4175 -0
  211. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  212. package/src/renderables/__tests__/Textarea.buffer.test.ts +683 -0
  213. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  214. package/src/renderables/__tests__/Textarea.editing.test.ts +2120 -0
  215. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  216. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  217. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  218. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3275 -0
  219. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  220. package/src/renderables/__tests__/Textarea.rendering.test.ts +1927 -0
  221. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  222. package/src/renderables/__tests__/Textarea.selection.test.ts +1589 -0
  223. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  224. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  225. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  226. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  227. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  228. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  229. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  230. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  231. package/src/renderables/__tests__/markdown-parser.test.ts +241 -0
  232. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  233. package/src/renderables/composition/README.md +8 -0
  234. package/src/renderables/composition/VRenderable.ts +32 -0
  235. package/src/renderables/composition/constructs.ts +127 -0
  236. package/src/renderables/composition/vnode.ts +277 -0
  237. package/src/renderables/index.ts +23 -0
  238. package/src/renderables/markdown-parser.ts +79 -0
  239. package/src/renderer-theme-mode.ts +199 -0
  240. package/src/renderer.ts +4975 -0
  241. package/src/runtime-plugin-support-configure.ts +63 -0
  242. package/src/runtime-plugin-support.ts +13 -0
  243. package/src/runtime-plugin.ts +626 -0
  244. package/src/specs/terminal-startup.md +64 -0
  245. package/src/syntax-style.test.ts +841 -0
  246. package/src/syntax-style.ts +274 -0
  247. package/src/testing/README.md +219 -0
  248. package/src/testing/bun-test-node.ts +880 -0
  249. package/src/testing/capture-spans.test.ts +216 -0
  250. package/src/testing/integration.test.ts +276 -0
  251. package/src/testing/manual-clock.ts +117 -0
  252. package/src/testing/mock-keys.test.ts +1378 -0
  253. package/src/testing/mock-keys.ts +457 -0
  254. package/src/testing/mock-mouse.test.ts +218 -0
  255. package/src/testing/mock-mouse.ts +247 -0
  256. package/src/testing/mock-tree-sitter-client.ts +81 -0
  257. package/src/testing/spy.ts +13 -0
  258. package/src/testing/terminal-capabilities.ts +47 -0
  259. package/src/testing/test-recorder.test.ts +410 -0
  260. package/src/testing/test-recorder.ts +133 -0
  261. package/src/testing/test-renderer.ts +375 -0
  262. package/src/testing/test-renderer.wait.test.ts +278 -0
  263. package/src/testing/test-streams.ts +31 -0
  264. package/src/testing.ts +9 -0
  265. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  266. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  267. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  268. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  269. package/src/tests/allocator-stats.test.ts +53 -0
  270. package/src/tests/audio.test.ts +303 -0
  271. package/src/tests/destroy-during-render.test.ts +200 -0
  272. package/src/tests/destroy-on-exit.fixture.ts +36 -0
  273. package/src/tests/destroy-on-exit.test.ts +62 -0
  274. package/src/tests/ffi-borrowed-pointer-callsites.test.ts +153 -0
  275. package/src/tests/hover-cursor.test.ts +98 -0
  276. package/src/tests/native-backed-measurement-lifecycle.test.ts +133 -0
  277. package/src/tests/native-backed-measurement-parity.test.ts +322 -0
  278. package/src/tests/native-span-feed-async.test.ts +173 -0
  279. package/src/tests/native-span-feed-close.test.ts +120 -0
  280. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  281. package/src/tests/native-span-feed-edge-cases.test.ts +384 -0
  282. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  283. package/src/tests/opacity.test.ts +123 -0
  284. package/src/tests/renderable.snapshot.test.ts +524 -0
  285. package/src/tests/renderable.test.ts +1851 -0
  286. package/src/tests/renderer.clock.test.ts +270 -0
  287. package/src/tests/renderer.console-startup.test.ts +2151 -0
  288. package/src/tests/renderer.control.test.ts +458 -0
  289. package/src/tests/renderer.core-slot-binding.test.ts +962 -0
  290. package/src/tests/renderer.cursor.test.ts +26 -0
  291. package/src/tests/renderer.custom-stdout.test.ts +1112 -0
  292. package/src/tests/renderer.destroy-during-render.test.ts +147 -0
  293. package/src/tests/renderer.focus-restore.test.ts +257 -0
  294. package/src/tests/renderer.focus.test.ts +329 -0
  295. package/src/tests/renderer.idle.test.ts +219 -0
  296. package/src/tests/renderer.input.test.ts +2615 -0
  297. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  298. package/src/tests/renderer.lifecycle.test.ts +34 -0
  299. package/src/tests/renderer.mouse.test.ts +1315 -0
  300. package/src/tests/renderer.notifications.test.ts +27 -0
  301. package/src/tests/renderer.palette.test.ts +1199 -0
  302. package/src/tests/renderer.remote.test.ts +247 -0
  303. package/src/tests/renderer.render-stats.test.ts +146 -0
  304. package/src/tests/renderer.scrollback-surface.test.ts +474 -0
  305. package/src/tests/renderer.selection.test.ts +138 -0
  306. package/src/tests/renderer.slot-registry.test.ts +684 -0
  307. package/src/tests/renderer.tracker.test.ts +202 -0
  308. package/src/tests/renderer.useMouse.test.ts +83 -0
  309. package/src/tests/runtime-plugin-node-modules-cycle.fixture.ts +76 -0
  310. package/src/tests/runtime-plugin-node-modules-import-like-string.fixture.ts +48 -0
  311. package/src/tests/runtime-plugin-node-modules-mjs.fixture.ts +43 -0
  312. package/src/tests/runtime-plugin-node-modules-no-bare-rewrite.fixture.ts +67 -0
  313. package/src/tests/runtime-plugin-node-modules-package-type-cache.fixture.ts +72 -0
  314. package/src/tests/runtime-plugin-node-modules-runtime-specifier.fixture.ts +44 -0
  315. package/src/tests/runtime-plugin-node-modules-scoped-package-bare-rewrite.fixture.ts +85 -0
  316. package/src/tests/runtime-plugin-path-alias.fixture.ts +43 -0
  317. package/src/tests/runtime-plugin-resolve-roots.fixture.ts +65 -0
  318. package/src/tests/runtime-plugin-support-configure.fixture.ts +31 -0
  319. package/src/tests/runtime-plugin-support-late-addition.fixture.ts +17 -0
  320. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  321. package/src/tests/runtime-plugin-support.test.ts +54 -0
  322. package/src/tests/runtime-plugin-windows-file-url.fixture.ts +30 -0
  323. package/src/tests/runtime-plugin.fixture.ts +40 -0
  324. package/src/tests/runtime-plugin.test.ts +369 -0
  325. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  326. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  327. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  328. package/src/tests/scrollbox.test.ts +1895 -0
  329. package/src/tests/wrap-resize-perf.test.ts +276 -0
  330. package/src/tests/yoga-api-coverage.test.ts +409 -0
  331. package/src/tests/yoga-callback-stress.test.ts +122 -0
  332. package/src/tests/yoga-ffi.test.ts +117 -0
  333. package/src/tests/yoga-setters.test.ts +921 -0
  334. package/src/tests/yoga-upstream/YGAlignBaselineTest.test.ts +124 -0
  335. package/src/tests/yoga-upstream/YGComputedBorderTest.test.ts +27 -0
  336. package/src/tests/yoga-upstream/YGComputedMarginTest.test.ts +27 -0
  337. package/src/tests/yoga-upstream/YGComputedPaddingTest.test.ts +27 -0
  338. package/src/tests/yoga-upstream/YGDirtiedTest.test.ts +157 -0
  339. package/src/tests/yoga-upstream/YGErrataTest.test.ts +40 -0
  340. package/src/tests/yoga-upstream/YGFlexBasisAuto.test.ts +23 -0
  341. package/src/tests/yoga-upstream/YGHasNewLayout.test.ts +81 -0
  342. package/src/tests/yoga-upstream/YGMeasureCacheTest.test.ts +31 -0
  343. package/src/tests/yoga-upstream/YGMeasureTest.test.ts +70 -0
  344. package/src/tests/yoga-upstream/generated/YGAbsolutePositionTest.test.ts +1864 -0
  345. package/src/tests/yoga-upstream/generated/YGAlignContentTest.test.ts +5829 -0
  346. package/src/tests/yoga-upstream/generated/YGAlignItemsTest.test.ts +2444 -0
  347. package/src/tests/yoga-upstream/generated/YGAlignSelfTest.test.ts +293 -0
  348. package/src/tests/yoga-upstream/generated/YGAndroidNewsFeed.test.ts +315 -0
  349. package/src/tests/yoga-upstream/generated/YGAspectRatioTest.test.ts +231 -0
  350. package/src/tests/yoga-upstream/generated/YGAutoTest.test.ts +347 -0
  351. package/src/tests/yoga-upstream/generated/YGBorderTest.test.ts +256 -0
  352. package/src/tests/yoga-upstream/generated/YGBoxSizingTest.test.ts +2747 -0
  353. package/src/tests/yoga-upstream/generated/YGDimensionTest.test.ts +129 -0
  354. package/src/tests/yoga-upstream/generated/YGDisplayContentsTest.test.ts +109 -0
  355. package/src/tests/yoga-upstream/generated/YGDisplayTest.test.ts +1097 -0
  356. package/src/tests/yoga-upstream/generated/YGFlexDirectionTest.test.ts +4562 -0
  357. package/src/tests/yoga-upstream/generated/YGFlexTest.test.ts +677 -0
  358. package/src/tests/yoga-upstream/generated/YGFlexWrapTest.test.ts +2071 -0
  359. package/src/tests/yoga-upstream/generated/YGGapTest.test.ts +3303 -0
  360. package/src/tests/yoga-upstream/generated/YGIntrinsicSizeTest.test.ts +582 -0
  361. package/src/tests/yoga-upstream/generated/YGJustifyContentTest.test.ts +2150 -0
  362. package/src/tests/yoga-upstream/generated/YGMarginTest.test.ts +1963 -0
  363. package/src/tests/yoga-upstream/generated/YGMinMaxDimensionTest.test.ts +1446 -0
  364. package/src/tests/yoga-upstream/generated/YGPaddingTest.test.ts +354 -0
  365. package/src/tests/yoga-upstream/generated/YGPercentageTest.test.ts +1760 -0
  366. package/src/tests/yoga-upstream/generated/YGRoundingTest.test.ts +1161 -0
  367. package/src/tests/yoga-upstream/generated/YGSizeOverflowTest.test.ts +207 -0
  368. package/src/tests/yoga-upstream/generated/YGStaticPositionTest.test.ts +6338 -0
  369. package/src/tests/yoga-upstream/tools/MeasureCounter.ts +54 -0
  370. package/src/tests/yoga-upstream/tools/utils.ts +81 -0
  371. package/src/text-buffer-view.test.ts +722 -0
  372. package/src/text-buffer-view.ts +193 -0
  373. package/src/text-buffer.test.ts +512 -0
  374. package/src/text-buffer.ts +250 -0
  375. package/src/types.ts +199 -0
  376. package/src/utils.ts +88 -0
  377. package/src/yoga.ts +1146 -0
  378. package/src/zig/ansi.zig +502 -0
  379. package/src/zig/audio.zig +1206 -0
  380. package/src/zig/bench/README.md +50 -0
  381. package/src/zig/bench/buffer-color-blending_bench.zig +350 -0
  382. package/src/zig/bench/buffer-draw-box_bench.zig +786 -0
  383. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +894 -0
  384. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  385. package/src/zig/bench/editor-view_bench.zig +169 -0
  386. package/src/zig/bench/native-span-feed_bench.zig +107 -0
  387. package/src/zig/bench/rope-markers_bench.zig +713 -0
  388. package/src/zig/bench/rope_bench.zig +514 -0
  389. package/src/zig/bench/styled-text_bench.zig +476 -0
  390. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  391. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  392. package/src/zig/bench/text-chunk-graphemes_bench.zig +272 -0
  393. package/src/zig/bench/utf8_bench.zig +799 -0
  394. package/src/zig/bench-utils.zig +431 -0
  395. package/src/zig/bench.zig +223 -0
  396. package/src/zig/buffer-methods.zig +215 -0
  397. package/src/zig/buffer.zig +2515 -0
  398. package/src/zig/build.zig +700 -0
  399. package/src/zig/build.zig.zon +19 -0
  400. package/src/zig/edit-buffer.zig +900 -0
  401. package/src/zig/editor-view.zig +812 -0
  402. package/src/zig/event-bus.zig +28 -0
  403. package/src/zig/event-emitter.zig +65 -0
  404. package/src/zig/file-logger.zig +92 -0
  405. package/src/zig/grapheme.zig +838 -0
  406. package/src/zig/handles.zig +267 -0
  407. package/src/zig/lib.zig +2813 -0
  408. package/src/zig/link.zig +349 -0
  409. package/src/zig/logger.zig +43 -0
  410. package/src/zig/mem-registry.zig +126 -0
  411. package/src/zig/miniaudio_shim.c +21 -0
  412. package/src/zig/native-renderable.zig +112 -0
  413. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  414. package/src/zig/native-span-feed.zig +747 -0
  415. package/src/zig/renderer-output.zig +677 -0
  416. package/src/zig/renderer.zig +2106 -0
  417. package/src/zig/rope.zig +1220 -0
  418. package/src/zig/split-scrollback.zig +88 -0
  419. package/src/zig/syntax-style.zig +174 -0
  420. package/src/zig/terminal.zig +1652 -0
  421. package/src/zig/test.zig +82 -0
  422. package/src/zig/tests/README.md +18 -0
  423. package/src/zig/tests/ansi_test.zig +18 -0
  424. package/src/zig/tests/audio_test.zig +439 -0
  425. package/src/zig/tests/buffer-methods_test.zig +1111 -0
  426. package/src/zig/tests/buffer_test.zig +2926 -0
  427. package/src/zig/tests/edit-buffer-history_test.zig +299 -0
  428. package/src/zig/tests/edit-buffer_test.zig +1688 -0
  429. package/src/zig/tests/editor-view_test.zig +3454 -0
  430. package/src/zig/tests/event-emitter_test.zig +249 -0
  431. package/src/zig/tests/grapheme_test.zig +1329 -0
  432. package/src/zig/tests/handles_test.zig +123 -0
  433. package/src/zig/tests/link_test.zig +220 -0
  434. package/src/zig/tests/mem-registry_test.zig +473 -0
  435. package/src/zig/tests/memory_leak_regression_test.zig +234 -0
  436. package/src/zig/tests/native-renderable_test.zig +16 -0
  437. package/src/zig/tests/native-span-feed_test.zig +1266 -0
  438. package/src/zig/tests/renderer_test.zig +2604 -0
  439. package/src/zig/tests/rope-nested_test.zig +712 -0
  440. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  441. package/src/zig/tests/rope_test.zig +2362 -0
  442. package/src/zig/tests/segment-merge.test.zig +148 -0
  443. package/src/zig/tests/split-scrollback_test.zig +70 -0
  444. package/src/zig/tests/syntax-style_test.zig +558 -0
  445. package/src/zig/tests/terminal_test.zig +1489 -0
  446. package/src/zig/tests/test-renderer.zig +126 -0
  447. package/src/zig/tests/text-buffer-drawing_test.zig +3291 -0
  448. package/src/zig/tests/text-buffer-highlights_test.zig +706 -0
  449. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  450. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  451. package/src/zig/tests/text-buffer-selection_test.zig +1056 -0
  452. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  453. package/src/zig/tests/text-buffer-view_test.zig +3672 -0
  454. package/src/zig/tests/text-buffer_test.zig +2191 -0
  455. package/src/zig/tests/unicode-width-map.zon +3909 -0
  456. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  457. package/src/zig/tests/utf8_test.zig +4060 -0
  458. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  459. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  460. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  461. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  462. package/src/zig/tests/yoga_test.zig +65 -0
  463. package/src/zig/text-buffer-iterators.zig +496 -0
  464. package/src/zig/text-buffer-segment.zig +403 -0
  465. package/src/zig/text-buffer-view.zig +1428 -0
  466. package/src/zig/text-buffer.zig +1272 -0
  467. package/src/zig/utf8.zig +1954 -0
  468. package/src/zig/utils.zig +12 -0
  469. package/src/zig/uucode-stub.zig +76 -0
  470. package/src/zig/vendor/miniaudio/miniaudio.h +93468 -0
  471. package/src/zig/yoga.zig +658 -0
  472. package/src/zig-structs.ts +381 -0
  473. package/src/zig.ts +5260 -0
  474. package/tsconfig.build.json +17 -0
  475. package/tsconfig.json +27 -0
  476. package/tsconfig.node-test.json +138 -0
@@ -0,0 +1,512 @@
1
+ import type { OptimizedBuffer } from "../buffer.js"
2
+
3
+ function toU8(value: number): number {
4
+ return Math.round(Math.max(0, Math.min(1, Number.isFinite(value) ? value : 0)) * 255)
5
+ }
6
+
7
+ function channel(buffer: Uint16Array, index: number): number {
8
+ return (buffer[index] & 0xff) / 255
9
+ }
10
+
11
+ function setRgb(buffer: Uint16Array, base: number, r: number, g: number, b: number): void {
12
+ const a = buffer[base + 3] & 0xff
13
+ buffer[base] = toU8(r)
14
+ buffer[base + 1] = toU8(g)
15
+ buffer[base + 2] = toU8(b)
16
+ buffer[base + 3] = a
17
+ }
18
+
19
+ /**
20
+ * Applies a scanline effect by darkening every nth row using native color matrix.
21
+ * Only affects the background buffer to maintain text readability.
22
+ */
23
+ export function applyScanlines(buffer: OptimizedBuffer, strength: number = 0.8, step: number = 2): void {
24
+ if (strength === 1.0 || step < 1) return
25
+
26
+ const width = buffer.width
27
+ const height = buffer.height
28
+
29
+ // Calculate number of affected rows
30
+ const affectedRows = Math.ceil(height / step)
31
+ const cellCount = width * affectedRows
32
+ const cellMask = new Float32Array(cellCount * 3)
33
+
34
+ let maskIdx = 0
35
+ for (let y = 0; y < height; y += step) {
36
+ for (let x = 0; x < width; x++) {
37
+ cellMask[maskIdx++] = x
38
+ cellMask[maskIdx++] = y
39
+ cellMask[maskIdx++] = 1.0 // full strength
40
+ }
41
+ }
42
+
43
+ // Gain matrix to scale down background colors
44
+ const s = strength
45
+ const matrix = new Float32Array([
46
+ s,
47
+ 0,
48
+ 0,
49
+ 0, // Row 0: Red output
50
+ 0,
51
+ s,
52
+ 0,
53
+ 0, // Row 1: Green output
54
+ 0,
55
+ 0,
56
+ s,
57
+ 0, // Row 2: Blue output
58
+ 0,
59
+ 0,
60
+ 0,
61
+ 1, // Row 3: Alpha output (identity)
62
+ ])
63
+
64
+ // Apply only to background buffer (target = 2)
65
+ buffer.colorMatrix(matrix, cellMask, 1.0, 2)
66
+ }
67
+
68
+ /**
69
+ * Inverts the colors in the buffer using native color matrix.
70
+ * Uses negative matrix with alpha offset: output = 1.0 - input for each RGB channel.
71
+ */
72
+ export function applyInvert(buffer: OptimizedBuffer, strength: number = 1.0): void {
73
+ if (strength === 0.0) return
74
+
75
+ // Invert matrix: output = -1*input + 1*alpha = 1.0 - input (assuming alpha=1.0)
76
+ // Row format: [R_coeff, G_coeff, B_coeff, A_coeff]
77
+ const matrix = new Float32Array([
78
+ -1,
79
+ 0,
80
+ 0,
81
+ 1, // Row 0: Red output = -1*R + 0*G + 0*B + 1*A = 1 - R
82
+ 0,
83
+ -1,
84
+ 0,
85
+ 1, // Row 1: Green output = 1 - G
86
+ 0,
87
+ 0,
88
+ -1,
89
+ 1, // Row 2: Blue output = 1 - B
90
+ 0,
91
+ 0,
92
+ 0,
93
+ 1, // Row 3: Alpha output = A
94
+ ])
95
+
96
+ buffer.colorMatrixUniform(matrix, strength, 3)
97
+ }
98
+
99
+ /**
100
+ * Adds random noise to the buffer colors using colorMatrix with brightness matrix.
101
+ * Uses per-pixel random strength values to dim/brighten each cell.
102
+ */
103
+ export function applyNoise(buffer: OptimizedBuffer, strength: number = 0.1): void {
104
+ const width = buffer.width
105
+ const height = buffer.height
106
+ const size = width * height
107
+
108
+ // Skip if no effect
109
+ if (strength === 0) return
110
+
111
+ // Generate random cellMask with per-pixel strength values
112
+ // Each pixel gets [x, y, random_strength] where random_strength ranges from -1 to 1
113
+ const cellMask = new Float32Array(size * 3)
114
+ let cellMaskIndex = 0
115
+
116
+ for (let y = 0; y < height; y++) {
117
+ for (let x = 0; x < width; x++) {
118
+ cellMask[cellMaskIndex++] = x
119
+ cellMask[cellMaskIndex++] = y
120
+ // Random strength from -1 to 1
121
+ cellMask[cellMaskIndex++] = (Math.random() - 0.5) * 2
122
+ }
123
+ }
124
+
125
+ // Brightness matrix: scales all channels by (1 + strength)
126
+ // With cellMask strength S, result = original * (1 + (B - 1) * S)
127
+ // where B = 1 + strength
128
+ // So: S=1 → original * (1 + strength), S=-1 → original * (1 - strength)
129
+ const b = 1.0 + strength
130
+ const matrix = new Float32Array([
131
+ b,
132
+ 0,
133
+ 0,
134
+ 0, // Row 0 (Red output)
135
+ 0,
136
+ b,
137
+ 0,
138
+ 0, // Row 1 (Green output)
139
+ 0,
140
+ 0,
141
+ b,
142
+ 0, // Row 2 (Blue output)
143
+ 0,
144
+ 0,
145
+ 0,
146
+ 1, // Row 3 (Alpha output - identity)
147
+ ])
148
+
149
+ buffer.colorMatrix(matrix, cellMask, 1.0, 3)
150
+ }
151
+
152
+ /**
153
+ * Applies a simplified chromatic aberration effect.
154
+ */
155
+ export function applyChromaticAberration(buffer: OptimizedBuffer, strength: number = 1): void {
156
+ const width = buffer.width
157
+ const height = buffer.height
158
+ const srcFg = Uint16Array.from(buffer.buffers.fg) // Copy original fg data
159
+ const destFg = buffer.buffers.fg
160
+ const centerX = width / 2
161
+ const centerY = height / 2
162
+
163
+ for (let y = 0; y < height; y++) {
164
+ for (let x = 0; x < width; x++) {
165
+ const dx = x - centerX
166
+ const dy = y - centerY
167
+ const offset = Math.round((Math.sqrt(dx * dx + dy * dy) / Math.max(centerX, centerY)) * strength)
168
+
169
+ const rX = Math.max(0, Math.min(width - 1, x - offset))
170
+ const bX = Math.max(0, Math.min(width - 1, x + offset))
171
+
172
+ const rIndex = (y * width + rX) * 4
173
+ const gIndex = (y * width + x) * 4 // Green from original position
174
+ const bIndex = (y * width + bX) * 4
175
+ const destIndex = (y * width + x) * 4
176
+
177
+ setRgb(destFg, destIndex, channel(srcFg, rIndex), channel(srcFg, gIndex + 1), channel(srcFg, bIndex + 2))
178
+ }
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Converts the buffer to ASCII art based on background brightness.
184
+ * Uses native colorMatrix for efficient color corrections.
185
+ */
186
+ export function applyAsciiArt(
187
+ buffer: OptimizedBuffer,
188
+ ramp: string = ' .\'`^"",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$',
189
+ fgColor: { r: number; g: number; b: number } = { r: 1.0, g: 1.0, b: 1.0 },
190
+ bgColor: { r: number; g: number; b: number } = { r: 0.0, g: 0.0, b: 0.0 },
191
+ ): void {
192
+ const width = buffer.width
193
+ const height = buffer.height
194
+ const chars = buffer.buffers.char
195
+ const bg = buffer.buffers.bg
196
+ const rampLength = ramp.length
197
+
198
+ // Set ASCII characters based on background luminance
199
+ for (let y = 0; y < height; y++) {
200
+ for (let x = 0; x < width; x++) {
201
+ const index = y * width + x
202
+ const colorIndex = index * 4
203
+ const bgR = channel(bg, colorIndex)
204
+ const bgG = channel(bg, colorIndex + 1)
205
+ const bgB = channel(bg, colorIndex + 2)
206
+ const lum = 0.299 * bgR + 0.587 * bgG + 0.114 * bgB // Luminance
207
+ const rampIndex = Math.min(rampLength - 1, Math.floor(lum * rampLength))
208
+ chars[index] = ramp[rampIndex].charCodeAt(0)
209
+ }
210
+ }
211
+
212
+ // Create color matrix that sets all pixels to the target color
213
+ // Matrix: output = target_color * input (where input is 1.0 from alpha)
214
+ const fgMatrix = new Float32Array([
215
+ 0,
216
+ 0,
217
+ 0,
218
+ fgColor.r, // Red output
219
+ 0,
220
+ 0,
221
+ 0,
222
+ fgColor.g, // Green output
223
+ 0,
224
+ 0,
225
+ 0,
226
+ fgColor.b, // Blue output
227
+ 0,
228
+ 0,
229
+ 0,
230
+ 1, // Alpha output (identity)
231
+ ])
232
+
233
+ const bgMatrix = new Float32Array([
234
+ 0,
235
+ 0,
236
+ 0,
237
+ bgColor.r, // Red output
238
+ 0,
239
+ 0,
240
+ 0,
241
+ bgColor.g, // Green output
242
+ 0,
243
+ 0,
244
+ 0,
245
+ bgColor.b, // Blue output
246
+ 0,
247
+ 0,
248
+ 0,
249
+ 1, // Alpha output (identity)
250
+ ])
251
+
252
+ // Apply uniform color transformation to foreground (target = 1)
253
+ buffer.colorMatrixUniform(fgMatrix, 1.0, 1)
254
+ // Apply uniform color transformation to background (target = 2)
255
+ buffer.colorMatrixUniform(bgMatrix, 1.0, 2)
256
+ }
257
+
258
+ /**
259
+ * Adjusts the brightness of the buffer using color matrix transformation.
260
+ * Brightness adds the brightness value to all RGB channels (additive brightness).
261
+ * If not provided, applies uniform brightness to entire buffer.
262
+ */
263
+ export function applyBrightness(buffer: OptimizedBuffer, brightness: number = 0.0, cellMask?: Float32Array): void {
264
+ // No need to process if brightness is 0 (no change)
265
+ if (brightness === 0.0) return
266
+
267
+ const b = brightness
268
+ // Additive brightness matrix: adds brightness to all channels via alpha column
269
+ const matrix = new Float32Array([
270
+ 1,
271
+ 0,
272
+ 0,
273
+ b, // Row 0 (Red output = R + brightness*A)
274
+ 0,
275
+ 1,
276
+ 0,
277
+ b, // Row 1 (Green output = G + brightness*A)
278
+ 0,
279
+ 0,
280
+ 1,
281
+ b, // Row 2 (Blue output = B + brightness*A)
282
+ 0,
283
+ 0,
284
+ 0,
285
+ 1, // Row 3 (Alpha output = A)
286
+ ])
287
+
288
+ if (!cellMask || cellMask.length === 0) {
289
+ buffer.colorMatrixUniform(matrix, 1.0, 3)
290
+ } else {
291
+ buffer.colorMatrix(matrix, cellMask, 1.0, 3)
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Adjusts the gain of the buffer using color matrix transformation.
297
+ * Gain multiplies all RGB channels by the gain factor (no clamping).
298
+ * If not provided, applies uniform gain to entire buffer.
299
+ */
300
+ export function applyGain(buffer: OptimizedBuffer, gain: number = 1.0, cellMask?: Float32Array): void {
301
+ // No need to process if gain is 1 (no change)
302
+ if (gain === 1.0) return
303
+
304
+ const g = Math.max(0, gain)
305
+ const matrix = new Float32Array([
306
+ g,
307
+ 0,
308
+ 0,
309
+ 0, // Row 0 (Red output)
310
+ 0,
311
+ g,
312
+ 0,
313
+ 0, // Row 1 (Green output)
314
+ 0,
315
+ 0,
316
+ g,
317
+ 0, // Row 2 (Blue output)
318
+ 0,
319
+ 0,
320
+ 0,
321
+ 1, // Row 3 (Alpha output - identity)
322
+ ])
323
+
324
+ if (!cellMask || cellMask.length === 0) {
325
+ buffer.colorMatrixUniform(matrix, 1.0, 3)
326
+ } else {
327
+ buffer.colorMatrix(matrix, cellMask, 1.0, 3)
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Generates a saturation color matrix (4x4 RGBA with alpha identity).
333
+ */
334
+ function createSaturationMatrix(saturation: number): Float32Array {
335
+ const s = Math.max(0, saturation)
336
+ const sr = 0.299 * (1 - s)
337
+ const sg = 0.587 * (1 - s)
338
+ const sb = 0.114 * (1 - s)
339
+
340
+ // Row 0 (Red output)
341
+ const m00 = sr + s // 0.299 + 0.701*s
342
+ const m01 = sg // 0.587 * (1 - s)
343
+ const m02 = sb // 0.114 * (1 - s)
344
+
345
+ // Row 1 (Green output)
346
+ const m10 = sr // 0.299 * (1 - s)
347
+ const m11 = sg + s // 0.587 + 0.413*s
348
+ const m12 = sb // 0.114 * (1 - s)
349
+
350
+ // Row 2 (Blue output)
351
+ const m20 = sr // 0.299 * (1 - s)
352
+ const m21 = sg // 0.587 * (1 - s)
353
+ const m22 = sb + s // 0.114 + 0.886*s
354
+
355
+ // 4x4 matrix with alpha identity
356
+ return new Float32Array([
357
+ m00,
358
+ m01,
359
+ m02,
360
+ 0, // Red output row
361
+ m10,
362
+ m11,
363
+ m12,
364
+ 0, // Green output row
365
+ m20,
366
+ m21,
367
+ m22,
368
+ 0, // Blue output row
369
+ 0,
370
+ 0,
371
+ 0,
372
+ 1, // Alpha output row (identity)
373
+ ])
374
+ }
375
+
376
+ /**
377
+ * Applies a saturation adjustment to the buffer.
378
+ */
379
+ export function applySaturation(buffer: OptimizedBuffer, cellMask?: Float32Array, strength: number = 1.0): void {
380
+ // No need to process if saturation is 1 (no change) or strength is 0
381
+ if (strength === 1.0 || strength === 0) {
382
+ return
383
+ }
384
+
385
+ const matrix = createSaturationMatrix(strength)
386
+
387
+ // If no cellMask provided, use uniform saturation (much faster)
388
+ if (!cellMask || cellMask.length === 0) {
389
+ buffer.colorMatrixUniform(matrix, 1.0, 3)
390
+ } else {
391
+ buffer.colorMatrix(matrix, cellMask, 1.0, 3)
392
+ }
393
+ }
394
+
395
+ /**
396
+ * Applies a bloom effect based on bright areas (Simplified).
397
+ */
398
+ export class BloomEffect {
399
+ private _threshold: number
400
+ private _strength: number
401
+ private _radius: number
402
+
403
+ constructor(threshold: number = 0.8, strength: number = 0.2, radius: number = 2) {
404
+ this._threshold = Math.max(0, Math.min(1, threshold))
405
+ this._strength = Math.max(0, strength)
406
+ this._radius = Math.max(0, Math.round(radius))
407
+ }
408
+
409
+ public set threshold(newThreshold: number) {
410
+ this._threshold = Math.max(0, Math.min(1, newThreshold))
411
+ }
412
+ public get threshold(): number {
413
+ return this._threshold
414
+ }
415
+
416
+ public set strength(newStrength: number) {
417
+ this._strength = Math.max(0, newStrength)
418
+ }
419
+ public get strength(): number {
420
+ return this._strength
421
+ }
422
+
423
+ public set radius(newRadius: number) {
424
+ this._radius = Math.max(0, Math.round(newRadius))
425
+ }
426
+ public get radius(): number {
427
+ return this._radius
428
+ }
429
+
430
+ public apply(buffer: OptimizedBuffer): void {
431
+ const threshold = this._threshold
432
+ const strength = this._strength
433
+ const radius = this._radius
434
+
435
+ if (strength <= 0 || radius <= 0) return // No bloom if strength or radius is non-positive
436
+
437
+ const width = buffer.width
438
+ const height = buffer.height
439
+ // Operate directly on the buffer's data for bloom, but need a source copy temporarily
440
+ const srcFg = Uint16Array.from(buffer.buffers.fg)
441
+ const srcBg = Uint16Array.from(buffer.buffers.bg)
442
+ const destFg = buffer.buffers.fg
443
+ const destBg = buffer.buffers.bg
444
+
445
+ const brightPixels: { x: number; y: number; intensity: number }[] = []
446
+
447
+ // 1. Find bright pixels based on original data
448
+ for (let y = 0; y < height; y++) {
449
+ for (let x = 0; x < width; x++) {
450
+ const index = (y * width + x) * 4
451
+ // Consider max component brightness, or luminance? Using luminance.
452
+ const fgLum =
453
+ 0.299 * channel(srcFg, index) + 0.587 * channel(srcFg, index + 1) + 0.114 * channel(srcFg, index + 2)
454
+ const bgLum =
455
+ 0.299 * channel(srcBg, index) + 0.587 * channel(srcBg, index + 1) + 0.114 * channel(srcBg, index + 2)
456
+ const lum = Math.max(fgLum, bgLum)
457
+ if (lum > threshold) {
458
+ const intensity = (lum - threshold) / (1 - threshold + 1e-6) // Add epsilon to avoid div by zero
459
+ brightPixels.push({ x, y, intensity: Math.max(0, intensity) })
460
+ }
461
+ }
462
+ }
463
+
464
+ // If no bright pixels found, exit early
465
+ if (brightPixels.length === 0) return
466
+
467
+ // Initialize destination buffers by copying original state before applying bloom
468
+ // This prevents bloom from compounding on itself within one frame pass
469
+ destFg.set(srcFg)
470
+ destBg.set(srcBg)
471
+
472
+ // 2. Apply bloom spread from bright pixels onto the destination buffers
473
+ for (const bright of brightPixels) {
474
+ for (let ky = -radius; ky <= radius; ky++) {
475
+ for (let kx = -radius; kx <= radius; kx++) {
476
+ if (kx === 0 && ky === 0) continue // Don't bloom self
477
+
478
+ const sampleX = bright.x + kx
479
+ const sampleY = bright.y + ky
480
+
481
+ if (sampleX >= 0 && sampleX < width && sampleY >= 0 && sampleY < height) {
482
+ const distSq = kx * kx + ky * ky // Use squared distance for falloff calculation
483
+ const radiusSq = radius * radius
484
+ if (distSq <= radiusSq) {
485
+ // Simple linear falloff based on squared distance
486
+ const falloff = 1 - distSq / radiusSq
487
+ const bloomAmount = bright.intensity * strength * falloff
488
+ const destIndex = (sampleY * width + sampleX) * 4
489
+
490
+ // Add bloom to both fg and bg, clamping at 1.0
491
+ setRgb(
492
+ destFg,
493
+ destIndex,
494
+ Math.min(1.0, channel(destFg, destIndex) + bloomAmount),
495
+ Math.min(1.0, channel(destFg, destIndex + 1) + bloomAmount),
496
+ Math.min(1.0, channel(destFg, destIndex + 2) + bloomAmount),
497
+ )
498
+
499
+ setRgb(
500
+ destBg,
501
+ destIndex,
502
+ Math.min(1.0, channel(destBg, destIndex) + bloomAmount),
503
+ Math.min(1.0, channel(destBg, destIndex + 1) + bloomAmount),
504
+ Math.min(1.0, channel(destBg, destIndex + 2) + bloomAmount),
505
+ )
506
+ }
507
+ }
508
+ }
509
+ }
510
+ }
511
+ }
512
+ }