Full Code of anomalyco/opentui for AI

main 8cb2a5ae0023 cached
663 files
8.0 MB
2.1M tokens
4327 symbols
1 requests
Download .txt
Showing preview only (8,475K chars total). Download the full file or copy to clipboard to get everything.
Repository: anomalyco/opentui
Branch: main
Commit: 8cb2a5ae0023
Files: 663
Total size: 8.0 MB

Directory structure:
gitextract_ou224iei/

├── .editorconfig
├── .github/
│   ├── CODEOWNERS
│   └── workflows/
│       ├── build-core.yml
│       ├── build-examples.yml
│       ├── build-native.yml
│       ├── build-react.yml
│       ├── build-solid.yml
│       ├── deploy.yml
│       ├── npm-latest-release.yml
│       ├── npm-release.yml
│       ├── opencode.yml
│       ├── pkg-pr-new.yml
│       ├── prettier.yml
│       ├── release.yml
│       └── review.yml
├── .gitignore
├── .prettierignore
├── .zig-version
├── AGENTS.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── opentui.pc.in
├── package.json
├── packages/
│   ├── core/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── dev/
│   │   │   ├── keypress-debug-renderer.ts
│   │   │   ├── keypress-debug.ts
│   │   │   ├── print-env-vars.ts
│   │   │   ├── test-tmux-graphics-334.sh
│   │   │   └── thai-debug-test.ts
│   │   ├── docs/
│   │   │   └── development.md
│   │   ├── package.json
│   │   ├── scripts/
│   │   │   ├── build.ts
│   │   │   └── publish.ts
│   │   ├── src/
│   │   │   ├── 3d/
│   │   │   │   ├── SpriteResourceManager.ts
│   │   │   │   ├── SpriteUtils.ts
│   │   │   │   ├── TextureUtils.ts
│   │   │   │   ├── ThreeRenderable.ts
│   │   │   │   ├── WGPURenderer.ts
│   │   │   │   ├── animation/
│   │   │   │   │   ├── ExplodingSpriteEffect.ts
│   │   │   │   │   ├── PhysicsExplodingSpriteEffect.ts
│   │   │   │   │   ├── SpriteAnimator.ts
│   │   │   │   │   └── SpriteParticleGenerator.ts
│   │   │   │   ├── canvas.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── physics/
│   │   │   │   │   ├── PlanckPhysicsAdapter.ts
│   │   │   │   │   ├── RapierPhysicsAdapter.ts
│   │   │   │   │   └── physics-interface.ts
│   │   │   │   └── shaders/
│   │   │   │       └── supersampling.wgsl
│   │   │   ├── 3d.ts
│   │   │   ├── NativeSpanFeed.ts
│   │   │   ├── Renderable.ts
│   │   │   ├── __snapshots__/
│   │   │   │   └── buffer.test.ts.snap
│   │   │   ├── animation/
│   │   │   │   ├── Timeline.test.ts
│   │   │   │   └── Timeline.ts
│   │   │   ├── ansi.ts
│   │   │   ├── benchmark/
│   │   │   │   ├── .gitignore
│   │   │   │   ├── attenuation-benchmark.ts
│   │   │   │   ├── colormatrix-benchmark.ts
│   │   │   │   ├── gain-benchmark.ts
│   │   │   │   ├── latest-all-bench-run.json
│   │   │   │   ├── latest-async-bench-run.json
│   │   │   │   ├── latest-default-bench-run.json
│   │   │   │   ├── latest-large-bench-run.json
│   │   │   │   ├── latest-quick-bench-run.json
│   │   │   │   ├── markdown-benchmark.ts
│   │   │   │   ├── native-span-feed-async-benchmark.ts
│   │   │   │   ├── native-span-feed-benchmark.md
│   │   │   │   ├── native-span-feed-benchmark.ts
│   │   │   │   ├── native-span-feed-compare.ts
│   │   │   │   ├── renderer-benchmark.ts
│   │   │   │   └── text-table-benchmark.ts
│   │   │   ├── buffer.test.ts
│   │   │   ├── buffer.ts
│   │   │   ├── console.test.ts
│   │   │   ├── console.ts
│   │   │   ├── edit-buffer.test.ts
│   │   │   ├── edit-buffer.ts
│   │   │   ├── editor-view.test.ts
│   │   │   ├── editor-view.ts
│   │   │   ├── examples/
│   │   │   │   ├── ascii-font-selection-demo.ts
│   │   │   │   ├── assets/
│   │   │   │   │   └── hast-example.json
│   │   │   │   ├── build.ts
│   │   │   │   ├── code-demo.ts
│   │   │   │   ├── console-demo.ts
│   │   │   │   ├── core-plugin-slots-demo.ts
│   │   │   │   ├── diff-demo.ts
│   │   │   │   ├── draggable-three-demo.ts
│   │   │   │   ├── editor-demo.ts
│   │   │   │   ├── extmarks-demo.ts
│   │   │   │   ├── focus-restore-demo.ts
│   │   │   │   ├── fonts.ts
│   │   │   │   ├── fractal-shader-demo.ts
│   │   │   │   ├── framebuffer-demo.ts
│   │   │   │   ├── full-unicode-demo.ts
│   │   │   │   ├── golden-star-demo.ts
│   │   │   │   ├── grayscale-buffer-demo.ts
│   │   │   │   ├── hast-syntax-highlighting-demo.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── input-demo.ts
│   │   │   │   ├── input-select-layout-demo.ts
│   │   │   │   ├── install.sh
│   │   │   │   ├── keypress-debug-demo.ts
│   │   │   │   ├── lib/
│   │   │   │   │   ├── HexList.ts
│   │   │   │   │   ├── PaletteGrid.ts
│   │   │   │   │   ├── standalone-keys.ts
│   │   │   │   │   └── tab-controller.ts
│   │   │   │   ├── lights-phong-demo.ts
│   │   │   │   ├── link-demo.ts
│   │   │   │   ├── live-state-demo.ts
│   │   │   │   ├── markdown-demo.ts
│   │   │   │   ├── mouse-interaction-demo.ts
│   │   │   │   ├── nested-zindex-demo.ts
│   │   │   │   ├── opacity-example.ts
│   │   │   │   ├── opentui-demo.ts
│   │   │   │   ├── physx-planck-2d-demo.ts
│   │   │   │   ├── physx-rapier-2d-demo.ts
│   │   │   │   ├── relative-positioning-demo.ts
│   │   │   │   ├── scroll-example.ts
│   │   │   │   ├── scrollbox-mouse-test.ts
│   │   │   │   ├── scrollbox-overlay-hit-test.ts
│   │   │   │   ├── select-demo.ts
│   │   │   │   ├── shader-cube-demo.ts
│   │   │   │   ├── simple-layout-example.ts
│   │   │   │   ├── slider-demo.ts
│   │   │   │   ├── split-mode-demo.ts
│   │   │   │   ├── sprite-animation-demo.ts
│   │   │   │   ├── sprite-particle-generator-demo.ts
│   │   │   │   ├── static-sprite-demo.ts
│   │   │   │   ├── sticky-scroll-example.ts
│   │   │   │   ├── styled-text-demo.ts
│   │   │   │   ├── tab-select-demo.ts
│   │   │   │   ├── terminal-title.ts
│   │   │   │   ├── terminal.ts
│   │   │   │   ├── text-node-demo.ts
│   │   │   │   ├── text-selection-demo.ts
│   │   │   │   ├── text-table-demo.ts
│   │   │   │   ├── text-truncation-demo.ts
│   │   │   │   ├── text-wrap.ts
│   │   │   │   ├── texture-loading-demo.ts
│   │   │   │   ├── timeline-example.ts
│   │   │   │   ├── transparency-demo.ts
│   │   │   │   └── vnode-composition-demo.ts
│   │   │   ├── index.ts
│   │   │   ├── lib/
│   │   │   │   ├── KeyHandler.integration.test.ts
│   │   │   │   ├── KeyHandler.stopPropagation.test.ts
│   │   │   │   ├── KeyHandler.test.ts
│   │   │   │   ├── KeyHandler.ts
│   │   │   │   ├── RGBA.test.ts
│   │   │   │   ├── RGBA.ts
│   │   │   │   ├── ascii.font.ts
│   │   │   │   ├── border.test.ts
│   │   │   │   ├── border.ts
│   │   │   │   ├── bunfs.test.ts
│   │   │   │   ├── bunfs.ts
│   │   │   │   ├── clipboard.test.ts
│   │   │   │   ├── clipboard.ts
│   │   │   │   ├── clock.ts
│   │   │   │   ├── data-paths.test.ts
│   │   │   │   ├── data-paths.ts
│   │   │   │   ├── debounce.ts
│   │   │   │   ├── detect-links.test.ts
│   │   │   │   ├── detect-links.ts
│   │   │   │   ├── env.test.ts
│   │   │   │   ├── env.ts
│   │   │   │   ├── extmarks-history.ts
│   │   │   │   ├── extmarks-multiwidth.test.ts
│   │   │   │   ├── extmarks.test.ts
│   │   │   │   ├── extmarks.ts
│   │   │   │   ├── fonts/
│   │   │   │   │   ├── block.json
│   │   │   │   │   ├── grid.json
│   │   │   │   │   ├── huge.json
│   │   │   │   │   ├── pallet.json
│   │   │   │   │   ├── shade.json
│   │   │   │   │   ├── slick.json
│   │   │   │   │   └── tiny.json
│   │   │   │   ├── hast-styled-text.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── keymapping.test.ts
│   │   │   │   ├── keymapping.ts
│   │   │   │   ├── objects-in-viewport.test.ts
│   │   │   │   ├── objects-in-viewport.ts
│   │   │   │   ├── output.capture.ts
│   │   │   │   ├── parse.keypress-kitty.protocol.test.ts
│   │   │   │   ├── parse.keypress-kitty.test.ts
│   │   │   │   ├── parse.keypress-kitty.ts
│   │   │   │   ├── parse.keypress.test.ts
│   │   │   │   ├── parse.keypress.ts
│   │   │   │   ├── parse.mouse.test.ts
│   │   │   │   ├── parse.mouse.ts
│   │   │   │   ├── paste.ts
│   │   │   │   ├── queue.ts
│   │   │   │   ├── renderable.validations.test.ts
│   │   │   │   ├── renderable.validations.ts
│   │   │   │   ├── scroll-acceleration.ts
│   │   │   │   ├── selection.ts
│   │   │   │   ├── singleton.ts
│   │   │   │   ├── stdin-parser.test.ts
│   │   │   │   ├── stdin-parser.ts
│   │   │   │   ├── styled-text.ts
│   │   │   │   ├── terminal-capability-detection.test.ts
│   │   │   │   ├── terminal-capability-detection.ts
│   │   │   │   ├── terminal-palette.test.ts
│   │   │   │   ├── terminal-palette.ts
│   │   │   │   ├── tree-sitter/
│   │   │   │   │   ├── assets/
│   │   │   │   │   │   ├── README.md
│   │   │   │   │   │   ├── javascript/
│   │   │   │   │   │   │   ├── highlights.scm
│   │   │   │   │   │   │   └── tree-sitter-javascript.wasm
│   │   │   │   │   │   ├── markdown/
│   │   │   │   │   │   │   ├── highlights.scm
│   │   │   │   │   │   │   ├── injections.scm
│   │   │   │   │   │   │   └── tree-sitter-markdown.wasm
│   │   │   │   │   │   ├── markdown_inline/
│   │   │   │   │   │   │   ├── highlights.scm
│   │   │   │   │   │   │   └── tree-sitter-markdown_inline.wasm
│   │   │   │   │   │   ├── typescript/
│   │   │   │   │   │   │   ├── highlights.scm
│   │   │   │   │   │   │   └── tree-sitter-typescript.wasm
│   │   │   │   │   │   ├── update.ts
│   │   │   │   │   │   └── zig/
│   │   │   │   │   │       ├── highlights.scm
│   │   │   │   │   │       └── tree-sitter-zig.wasm
│   │   │   │   │   ├── assets.d.ts
│   │   │   │   │   ├── cache.test.ts
│   │   │   │   │   ├── client.test.ts
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── default-parsers.ts
│   │   │   │   │   ├── download-utils.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── parser.worker.ts
│   │   │   │   │   ├── parsers-config.ts
│   │   │   │   │   ├── resolve-ft.test.ts
│   │   │   │   │   ├── resolve-ft.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── tree-sitter-styled-text.test.ts
│   │   │   │   ├── tree-sitter-styled-text.ts
│   │   │   │   ├── validate-dir-name.ts
│   │   │   │   ├── yoga.options.test.ts
│   │   │   │   └── yoga.options.ts
│   │   │   ├── plugins/
│   │   │   │   ├── core-slot.ts
│   │   │   │   ├── registry.ts
│   │   │   │   └── types.ts
│   │   │   ├── post/
│   │   │   │   ├── effects.ts
│   │   │   │   ├── filters.ts
│   │   │   │   └── matrices.ts
│   │   │   ├── renderables/
│   │   │   │   ├── ASCIIFont.ts
│   │   │   │   ├── Box.test.ts
│   │   │   │   ├── Box.ts
│   │   │   │   ├── Code.test.ts
│   │   │   │   ├── Code.ts
│   │   │   │   ├── Diff.regression.test.ts
│   │   │   │   ├── Diff.test.ts
│   │   │   │   ├── Diff.ts
│   │   │   │   ├── EditBufferRenderable.ts
│   │   │   │   ├── FrameBuffer.ts
│   │   │   │   ├── Input.test.ts
│   │   │   │   ├── Input.ts
│   │   │   │   ├── LineNumberRenderable.ts
│   │   │   │   ├── Markdown.ts
│   │   │   │   ├── ScrollBar.ts
│   │   │   │   ├── ScrollBox.ts
│   │   │   │   ├── Select.test.ts
│   │   │   │   ├── Select.ts
│   │   │   │   ├── Slider.test.ts
│   │   │   │   ├── Slider.ts
│   │   │   │   ├── TabSelect.test.ts
│   │   │   │   ├── TabSelect.ts
│   │   │   │   ├── Text.selection-buffer.test.ts
│   │   │   │   ├── Text.test.ts
│   │   │   │   ├── Text.ts
│   │   │   │   ├── TextBufferRenderable.ts
│   │   │   │   ├── TextNode.test.ts
│   │   │   │   ├── TextNode.ts
│   │   │   │   ├── TextTable.test.ts
│   │   │   │   ├── TextTable.ts
│   │   │   │   ├── Textarea.ts
│   │   │   │   ├── TimeToFirstDraw.ts
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   ├── Code.test.ts.snap
│   │   │   │   │   ├── Diff.test.ts.snap
│   │   │   │   │   ├── Text.test.ts.snap
│   │   │   │   │   └── TextTable.test.ts.snap
│   │   │   │   ├── __tests__/
│   │   │   │   │   ├── LineNumberRenderable.scrollbox-simple.test.ts
│   │   │   │   │   ├── LineNumberRenderable.scrollbox.test.ts
│   │   │   │   │   ├── LineNumberRenderable.test.ts
│   │   │   │   │   ├── LineNumberRenderable.wrapping.test.ts
│   │   │   │   │   ├── Markdown.code-colors.test.ts
│   │   │   │   │   ├── Markdown.test.ts
│   │   │   │   │   ├── MultiRenderable.selection.test.ts
│   │   │   │   │   ├── Textarea.buffer.test.ts
│   │   │   │   │   ├── Textarea.destroyed-events.test.ts
│   │   │   │   │   ├── Textarea.editing.test.ts
│   │   │   │   │   ├── Textarea.error-handling.test.ts
│   │   │   │   │   ├── Textarea.events.test.ts
│   │   │   │   │   ├── Textarea.highlights.test.ts
│   │   │   │   │   ├── Textarea.keybinding.test.ts
│   │   │   │   │   ├── Textarea.paste.test.ts
│   │   │   │   │   ├── Textarea.rendering.test.ts
│   │   │   │   │   ├── Textarea.scroll.test.ts
│   │   │   │   │   ├── Textarea.selection.test.ts
│   │   │   │   │   ├── Textarea.stress.test.ts
│   │   │   │   │   ├── Textarea.undo-redo.test.ts
│   │   │   │   │   ├── Textarea.visual-lines.test.ts
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   ├── LineNumberRenderable.code.test.ts.snap
│   │   │   │   │   │   ├── LineNumberRenderable.scrollbox-simple.test.ts.snap
│   │   │   │   │   │   ├── LineNumberRenderable.scrollbox.test.ts.snap
│   │   │   │   │   │   ├── LineNumberRenderable.test.ts.snap
│   │   │   │   │   │   └── Textarea.rendering.test.ts.snap
│   │   │   │   │   ├── markdown-parser.test.ts
│   │   │   │   │   └── renderable-test-utils.ts
│   │   │   │   ├── composition/
│   │   │   │   │   ├── README.md
│   │   │   │   │   ├── VRenderable.ts
│   │   │   │   │   ├── constructs.ts
│   │   │   │   │   └── vnode.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── markdown-parser.ts
│   │   │   ├── renderer.ts
│   │   │   ├── runtime-plugin-support.ts
│   │   │   ├── runtime-plugin.ts
│   │   │   ├── syntax-style.test.ts
│   │   │   ├── syntax-style.ts
│   │   │   ├── testing/
│   │   │   │   ├── README.md
│   │   │   │   ├── capture-spans.test.ts
│   │   │   │   ├── integration.test.ts
│   │   │   │   ├── manual-clock.ts
│   │   │   │   ├── mock-keys.test.ts
│   │   │   │   ├── mock-keys.ts
│   │   │   │   ├── mock-mouse.test.ts
│   │   │   │   ├── mock-mouse.ts
│   │   │   │   ├── mock-tree-sitter-client.ts
│   │   │   │   ├── spy.ts
│   │   │   │   ├── test-recorder.test.ts
│   │   │   │   ├── test-recorder.ts
│   │   │   │   └── test-renderer.ts
│   │   │   ├── testing.ts
│   │   │   ├── tests/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   ├── absolute-positioning.snapshot.test.ts.snap
│   │   │   │   │   ├── renderable.snapshot.test.ts.snap
│   │   │   │   │   └── scrollbox.test.ts.snap
│   │   │   │   ├── absolute-positioning.snapshot.test.ts
│   │   │   │   ├── allocator-stats.test.ts
│   │   │   │   ├── destroy-during-render.test.ts
│   │   │   │   ├── hover-cursor.test.ts
│   │   │   │   ├── native-span-feed-async.test.ts
│   │   │   │   ├── native-span-feed-close.test.ts
│   │   │   │   ├── native-span-feed-coverage.test.ts
│   │   │   │   ├── native-span-feed-edge-cases.test.ts
│   │   │   │   ├── native-span-feed-use-after-free.test.ts
│   │   │   │   ├── opacity.test.ts
│   │   │   │   ├── renderable.snapshot.test.ts
│   │   │   │   ├── renderable.test.ts
│   │   │   │   ├── renderer.clock.test.ts
│   │   │   │   ├── renderer.console-startup.test.ts
│   │   │   │   ├── renderer.control.test.ts
│   │   │   │   ├── renderer.core-slot-binding.test.ts
│   │   │   │   ├── renderer.cursor.test.ts
│   │   │   │   ├── renderer.destroy-during-render.test.ts
│   │   │   │   ├── renderer.focus-restore.test.ts
│   │   │   │   ├── renderer.focus.test.ts
│   │   │   │   ├── renderer.idle.test.ts
│   │   │   │   ├── renderer.input.test.ts
│   │   │   │   ├── renderer.kitty-flags.test.ts
│   │   │   │   ├── renderer.mouse.test.ts
│   │   │   │   ├── renderer.palette.test.ts
│   │   │   │   ├── renderer.selection.test.ts
│   │   │   │   ├── renderer.slot-registry.test.ts
│   │   │   │   ├── renderer.useMouse.test.ts
│   │   │   │   ├── runtime-plugin-resolve-roots.fixture.ts
│   │   │   │   ├── runtime-plugin-support.fixture.ts
│   │   │   │   ├── runtime-plugin-support.test.ts
│   │   │   │   ├── runtime-plugin.fixture.ts
│   │   │   │   ├── runtime-plugin.test.ts
│   │   │   │   ├── scrollbox-culling-bug.test.ts
│   │   │   │   ├── scrollbox-hitgrid-resize.test.ts
│   │   │   │   ├── scrollbox-hitgrid.test.ts
│   │   │   │   ├── scrollbox.test.ts
│   │   │   │   ├── wrap-resize-perf.test.ts
│   │   │   │   └── yoga-setters.test.ts
│   │   │   ├── text-buffer-view.test.ts
│   │   │   ├── text-buffer-view.ts
│   │   │   ├── text-buffer.test.ts
│   │   │   ├── text-buffer.ts
│   │   │   ├── types.ts
│   │   │   ├── utils.ts
│   │   │   ├── zig/
│   │   │   │   ├── ansi.zig
│   │   │   │   ├── bench/
│   │   │   │   │   ├── README.md
│   │   │   │   │   ├── buffer-draw-text-buffer_bench.zig
│   │   │   │   │   ├── edit-buffer_bench.zig
│   │   │   │   │   ├── native-span-feed_bench.zig
│   │   │   │   │   ├── rope-markers_bench.zig
│   │   │   │   │   ├── rope_bench.zig
│   │   │   │   │   ├── styled-text_bench.zig
│   │   │   │   │   ├── text-buffer-coords_bench.zig
│   │   │   │   │   ├── text-buffer-view_bench.zig
│   │   │   │   │   ├── text-chunk-graphemes_bench.zig
│   │   │   │   │   └── utf8_bench.zig
│   │   │   │   ├── bench-utils.zig
│   │   │   │   ├── bench.zig
│   │   │   │   ├── buffer-methods.zig
│   │   │   │   ├── buffer.zig
│   │   │   │   ├── build.zig
│   │   │   │   ├── build.zig.zon
│   │   │   │   ├── edit-buffer.zig
│   │   │   │   ├── editor-view.zig
│   │   │   │   ├── event-bus.zig
│   │   │   │   ├── event-emitter.zig
│   │   │   │   ├── file-logger.zig
│   │   │   │   ├── grapheme.zig
│   │   │   │   ├── lib.zig
│   │   │   │   ├── link.zig
│   │   │   │   ├── logger.zig
│   │   │   │   ├── mem-registry.zig
│   │   │   │   ├── native-span-feed-bench-lib.zig
│   │   │   │   ├── native-span-feed.zig
│   │   │   │   ├── renderer.zig
│   │   │   │   ├── rope.zig
│   │   │   │   ├── syntax-style.zig
│   │   │   │   ├── terminal.zig
│   │   │   │   ├── test.zig
│   │   │   │   ├── tests/
│   │   │   │   │   ├── README.md
│   │   │   │   │   ├── buffer-methods_test.zig
│   │   │   │   │   ├── buffer_test.zig
│   │   │   │   │   ├── edit-buffer-history_test.zig
│   │   │   │   │   ├── edit-buffer_test.zig
│   │   │   │   │   ├── editor-view_test.zig
│   │   │   │   │   ├── event-emitter_test.zig
│   │   │   │   │   ├── grapheme_test.zig
│   │   │   │   │   ├── link_test.zig
│   │   │   │   │   ├── mem-registry_test.zig
│   │   │   │   │   ├── memory_leak_regression_test.zig
│   │   │   │   │   ├── native-span-feed_test.zig
│   │   │   │   │   ├── renderer_test.zig
│   │   │   │   │   ├── rope-nested_test.zig
│   │   │   │   │   ├── rope_fuzz_test.zig
│   │   │   │   │   ├── rope_test.zig
│   │   │   │   │   ├── segment-merge.test.zig
│   │   │   │   │   ├── syntax-style_test.zig
│   │   │   │   │   ├── terminal_test.zig
│   │   │   │   │   ├── text-buffer-drawing_test.zig
│   │   │   │   │   ├── text-buffer-highlights_test.zig
│   │   │   │   │   ├── text-buffer-iterators_test.zig
│   │   │   │   │   ├── text-buffer-segment_test.zig
│   │   │   │   │   ├── text-buffer-selection_test.zig
│   │   │   │   │   ├── text-buffer-selection_viewport_test.zig
│   │   │   │   │   ├── text-buffer-view_test.zig
│   │   │   │   │   ├── text-buffer_test.zig
│   │   │   │   │   ├── unicode-width-map.zon
│   │   │   │   │   ├── utf8_no_zwj_test.zig
│   │   │   │   │   ├── utf8_test.zig
│   │   │   │   │   ├── utf8_wcwidth_cursor_test.zig
│   │   │   │   │   ├── utf8_wcwidth_test.zig
│   │   │   │   │   ├── word-wrap-editing_test.zig
│   │   │   │   │   └── wrap-cache-perf_test.zig
│   │   │   │   ├── text-buffer-iterators.zig
│   │   │   │   ├── text-buffer-segment.zig
│   │   │   │   ├── text-buffer-view.zig
│   │   │   │   ├── text-buffer.zig
│   │   │   │   ├── utf8.zig
│   │   │   │   └── utils.zig
│   │   │   ├── zig-structs.ts
│   │   │   └── zig.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── react/
│   │   ├── README.md
│   │   ├── docs/
│   │   │   └── EXTEND.md
│   │   ├── examples/
│   │   │   ├── .plugin/
│   │   │   │   ├── index.tsx
│   │   │   │   └── slot-components.tsx
│   │   │   ├── animation.tsx
│   │   │   ├── ascii.tsx
│   │   │   ├── basic.tsx
│   │   │   ├── borders.tsx
│   │   │   ├── box.tsx
│   │   │   ├── build.ts
│   │   │   ├── counter.tsx
│   │   │   ├── diff.tsx
│   │   │   ├── extend-example.tsx
│   │   │   ├── external-plugin-slots-demo.tsx
│   │   │   ├── flush-sync.tsx
│   │   │   ├── index.tsx
│   │   │   ├── line-number.tsx
│   │   │   ├── opacity.tsx
│   │   │   ├── plugin-slots-errors.tsx
│   │   │   ├── scroll.tsx
│   │   │   ├── text.tsx
│   │   │   └── tsconfig.json
│   │   ├── jsx-dev-runtime.d.ts
│   │   ├── jsx-dev-runtime.js
│   │   ├── jsx-namespace.d.ts
│   │   ├── jsx-runtime.d.ts
│   │   ├── jsx-runtime.js
│   │   ├── package.json
│   │   ├── scripts/
│   │   │   ├── build.ts
│   │   │   ├── publish.ts
│   │   │   └── runtime-plugin-support.ts
│   │   ├── src/
│   │   │   ├── components/
│   │   │   │   ├── app.tsx
│   │   │   │   ├── error-boundary.tsx
│   │   │   │   ├── index.ts
│   │   │   │   └── text.ts
│   │   │   ├── hooks/
│   │   │   │   ├── index.ts
│   │   │   │   ├── use-event.ts
│   │   │   │   ├── use-keyboard.ts
│   │   │   │   ├── use-renderer.ts
│   │   │   │   ├── use-resize.ts
│   │   │   │   ├── use-terminal-dimensions.ts
│   │   │   │   └── use-timeline.ts
│   │   │   ├── index.ts
│   │   │   ├── plugins/
│   │   │   │   └── slot.tsx
│   │   │   ├── reconciler/
│   │   │   │   ├── devtools-polyfill.ts
│   │   │   │   ├── devtools.ts
│   │   │   │   ├── host-config.ts
│   │   │   │   ├── reconciler.ts
│   │   │   │   └── renderer.ts
│   │   │   ├── test-utils.ts
│   │   │   ├── time-to-first-draw.tsx
│   │   │   ├── types/
│   │   │   │   ├── components.ts
│   │   │   │   └── host.ts
│   │   │   └── utils/
│   │   │       ├── id.ts
│   │   │       └── index.ts
│   │   ├── tests/
│   │   │   ├── __snapshots__/
│   │   │   │   └── layout.test.tsx.snap
│   │   │   ├── destroy-crash.test.tsx
│   │   │   ├── layout.test.tsx
│   │   │   ├── link.test.tsx
│   │   │   ├── runtime-plugin-support.fixture.ts
│   │   │   ├── runtime-plugin-support.test.ts
│   │   │   └── slot.test.tsx
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── solid/
│   │   ├── README.md
│   │   ├── bunfig.toml
│   │   ├── examples/
│   │   │   ├── .plugin/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── package.json
│   │   │   │   └── slot-components.tsx
│   │   │   ├── build.ts
│   │   │   ├── components/
│   │   │   │   ├── ExampleSelector.tsx
│   │   │   │   ├── animation-demo.tsx
│   │   │   │   ├── autocomplete-demo.tsx
│   │   │   │   ├── code-demo.tsx
│   │   │   │   ├── custom-scroll-accel-demo.tsx
│   │   │   │   ├── diff-demo.tsx
│   │   │   │   ├── extend-demo.tsx
│   │   │   │   ├── external-plugin-path.test.ts
│   │   │   │   ├── external-plugin-path.ts
│   │   │   │   ├── external-plugin-runtime.ts
│   │   │   │   ├── external-plugin-slots-demo.tsx
│   │   │   │   ├── input-demo.tsx
│   │   │   │   ├── line-number-demo.tsx
│   │   │   │   ├── mouse-demo.tsx
│   │   │   │   ├── plugin-slots-demo.tsx
│   │   │   │   ├── scroll-demo.tsx
│   │   │   │   ├── tab-select-demo.tsx
│   │   │   │   ├── text-selection-demo.tsx
│   │   │   │   ├── text-style-demo.tsx
│   │   │   │   ├── text-truncation-demo.tsx
│   │   │   │   ├── textarea-demo.tsx
│   │   │   │   ├── textarea-keybindings.ts
│   │   │   │   └── textarea-minimal-demo.tsx
│   │   │   ├── index.tsx
│   │   │   ├── package.json
│   │   │   ├── repro-empty-styled-text.tsx
│   │   │   ├── repro-filter-list.tsx
│   │   │   ├── repro-onSubmit.tsx
│   │   │   ├── session.tsx
│   │   │   └── tsconfig.json
│   │   ├── index.ts
│   │   ├── jsx-runtime.d.ts
│   │   ├── package.json
│   │   ├── scripts/
│   │   │   ├── build.ts
│   │   │   ├── preload.ts
│   │   │   ├── publish.ts
│   │   │   ├── runtime-plugin-support.ts
│   │   │   └── solid-plugin.ts
│   │   ├── src/
│   │   │   ├── elements/
│   │   │   │   ├── extras.ts
│   │   │   │   ├── hooks.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── slot.ts
│   │   │   ├── plugins/
│   │   │   │   └── slot.tsx
│   │   │   ├── reconciler.ts
│   │   │   ├── renderer/
│   │   │   │   ├── index.ts
│   │   │   │   ├── universal.d.ts
│   │   │   │   └── universal.js
│   │   │   ├── time-to-first-draw.tsx
│   │   │   ├── types/
│   │   │   │   └── elements.ts
│   │   │   └── utils/
│   │   │       ├── id-counter.ts
│   │   │       └── log.ts
│   │   ├── tests/
│   │   │   ├── __snapshots__/
│   │   │   │   ├── control-flow.test.tsx.snap
│   │   │   │   ├── dynamic-collections.test.tsx.snap
│   │   │   │   ├── dynamic-portal.test.tsx.snap
│   │   │   │   ├── layout.test.tsx.snap
│   │   │   │   ├── line-number-debug.test.tsx.snap
│   │   │   │   ├── line-number-scrollbox.test.tsx.snap
│   │   │   │   └── textarea.test.tsx.snap
│   │   │   ├── box.test.tsx
│   │   │   ├── control-flow.test.tsx
│   │   │   ├── cursor-behavior.test.tsx
│   │   │   ├── destroy-crash.test.tsx
│   │   │   ├── destroy-race-repro.test.ts
│   │   │   ├── destroy-race.fixture.tsx
│   │   │   ├── diff.test.tsx
│   │   │   ├── dynamic-collections.test.tsx
│   │   │   ├── dynamic-portal.test.tsx
│   │   │   ├── events.test.tsx
│   │   │   ├── layout.test.tsx
│   │   │   ├── line-number-scrollbox.test.tsx
│   │   │   ├── line-number.test.tsx
│   │   │   ├── link.test.tsx
│   │   │   ├── runtime-plugin-support-preload.fixture.ts
│   │   │   ├── runtime-plugin-support-preload.test.ts
│   │   │   ├── runtime-plugin-support.fixture.ts
│   │   │   ├── runtime-plugin-support.test.ts
│   │   │   ├── scrollbox-cleanchildren.test.tsx
│   │   │   ├── scrollbox-content.test.tsx
│   │   │   ├── slot.test.tsx
│   │   │   ├── solid-plugin.fixture.ts
│   │   │   ├── solid-plugin.test.ts
│   │   │   ├── sticky-scroll.test.tsx
│   │   │   └── textarea.test.tsx
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   └── web/
│       ├── .gitignore
│       ├── astro.config.mjs
│       ├── package.json
│       ├── scripts/
│       │   ├── test-doc-examples.ts
│       │   └── verify-doc-examples.ts
│       ├── src/
│       │   ├── components/
│       │   │   └── TuiSurface.astro
│       │   ├── content/
│       │   │   ├── config.ts
│       │   │   └── docs/
│       │   │       ├── bindings/
│       │   │       │   ├── react.mdx
│       │   │       │   └── solid.mdx
│       │   │       ├── components/
│       │   │       │   ├── ascii-font.mdx
│       │   │       │   ├── box.mdx
│       │   │       │   ├── code.mdx
│       │   │       │   ├── diff.mdx
│       │   │       │   ├── frame-buffer.mdx
│       │   │       │   ├── input.mdx
│       │   │       │   ├── line-number.mdx
│       │   │       │   ├── markdown.mdx
│       │   │       │   ├── scrollbar.mdx
│       │   │       │   ├── scrollbox.mdx
│       │   │       │   ├── select.mdx
│       │   │       │   ├── slider.mdx
│       │   │       │   ├── tab-select.mdx
│       │   │       │   ├── text.mdx
│       │   │       │   └── textarea.mdx
│       │   │       ├── core-concepts/
│       │   │       │   ├── colors.mdx
│       │   │       │   ├── console.mdx
│       │   │       │   ├── constructs.mdx
│       │   │       │   ├── keyboard.mdx
│       │   │       │   ├── layout.mdx
│       │   │       │   ├── lifecycle.mdx
│       │   │       │   ├── renderables-vs-constructs.mdx
│       │   │       │   ├── renderables.mdx
│       │   │       │   └── renderer.mdx
│       │   │       ├── getting-started.mdx
│       │   │       ├── plugins/
│       │   │       │   ├── core.mdx
│       │   │       │   ├── react.mdx
│       │   │       │   ├── slots.mdx
│       │   │       │   └── solid.mdx
│       │   │       └── reference/
│       │   │           ├── env-vars.mdx
│       │   │           └── tree-sitter.mdx
│       │   ├── layouts/
│       │   │   ├── Base.astro
│       │   │   └── Docs.astro
│       │   ├── pages/
│       │   │   ├── 404.astro
│       │   │   ├── docs/
│       │   │   │   └── [...slug].astro
│       │   │   └── index.astro
│       │   └── styles/
│       │       └── global.css
│       └── tsconfig.json
└── scripts/
    ├── create-snapshot.sh
    ├── link-opentui-dev.sh
    ├── pre-publish.ts
    └── prepare-release.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
insert_final_newline = true
end_of_line = lf
indent_style = space
indent_size = 2
max_line_length = 120

================================================
FILE: .github/CODEOWNERS
================================================
*                   @kommander @msmps @Hona @simonklee
/packages/react/    @msmps @Adictya @fezproof @kommander @Hona @simonklee
/packages/solid/    @Adictya @fezproof @msmps @kommander @Hona @simonklee


================================================
FILE: .github/workflows/build-core.yml
================================================
name: Build Core

on:
  push:
  pull_request:
    branches: [main]

env:
  ZIG_VERSION: 0.15.2
  # Workaround for bug in Zig 0.15.2 (fixed in next version)
  # https://github.com/ziglang/zig/issues/25805
  ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-global-cache

jobs:
  build:
    name: Build Native Libraries
    runs-on: macos-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Setup Zig
        uses: goto-bus-stop/setup-zig@v2
        with:
          version: ${{ env.ZIG_VERSION }}

      - name: Install dependencies
        run: bun install

      - name: Build native libraries (cross-compile all platforms)
        run: |
          cd packages/core
          bun run build:native --all

      - name: Upload native artifacts
        uses: actions/upload-artifact@v4
        with:
          name: native-libraries
          path: packages/core/node_modules/@opentui/
          retention-days: 1

  test:
    name: Test (${{ matrix.os }})
    needs: build
    strategy:
      matrix:
        include:
          - os: macos-latest
            platform: darwin-arm64
          - os: ubuntu-latest
            platform: linux-x64
          - os: windows-latest
            platform: win32-x64
    runs-on: ${{ matrix.os }}
    defaults:
      run:
        shell: bash
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Setup Zig
        uses: goto-bus-stop/setup-zig@v2
        with:
          version: ${{ env.ZIG_VERSION }}

      - name: Install dependencies
        run: bun install

      - name: Download native artifacts
        uses: actions/download-artifact@v4
        with:
          name: native-libraries
          path: packages/core/node_modules/@opentui/

      - name: Verify native library
        run: |
          echo "Checking for ${{ matrix.platform }} native library..."
          ls -la packages/core/node_modules/@opentui/
          ls -la packages/core/node_modules/@opentui/core-${{ matrix.platform }}/

      - name: Run native tests
        run: |
          cd packages/core/src/zig
          zig build test --summary all

      - name: Build TypeScript library
        run: |
          cd packages/core
          bun run build:lib

      - name: Run TypeScript tests
        run: |
          cd packages/core
          bun run test:js

  # Gate job for branch protection
  build-complete:
    name: Core - Build and Test
    needs: [test]
    runs-on: ubuntu-latest
    if: always()
    steps:
      - name: Check test results
        run: |
          if [ "${{ needs.test.result }}" != "success" ]; then
            echo "Tests failed"
            exit 1
          fi
          echo "All tests passed"


================================================
FILE: .github/workflows/build-examples.yml
================================================
name: Build Examples

on:
  workflow_call:
    inputs:
      version:
        description: "Version being released"
        required: true
        type: string
      isDryRun:
        description: "Whether this is a dry run release"
        required: false
        type: boolean
        default: false

jobs:
  build-examples:
    name: Build Example Executables
    runs-on: macos-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Install dependencies FIRST (before copying built packages)
        run: |
          echo "Installing base dependencies..."
          bun install

          echo ""
          echo "✅ Base dependencies installed"
          echo "Note: bun-webgpu will be installed by the build script (src/examples/build.ts) for all platforms"

      - name: Download npm packages artifact
        uses: actions/download-artifact@v4
        with:
          name: npm-packages-${{ inputs.version }}

      - name: Extract and install npm packages
        run: |
          set -e
          echo "Extracting npm packages..."
          test -f npm-packages.zip || (echo "❌ npm-packages.zip not found!" && exit 1)
          unzip -q npm-packages.zip

          # Create node_modules structure
          mkdir -p node_modules/@opentui
          mkdir -p packages/core/node_modules/@opentui

          # Copy core dist (required)
          echo "Copying core dist..."
          test -d "npm-packages/core-dist" || (echo "❌ core-dist not found in artifact!" && exit 1)
          cp -r npm-packages/core-dist packages/core/dist
          test -f packages/core/dist/package.json || (echo "❌ core dist/package.json missing after copy!" && exit 1)
          echo "✅ Core dist copied"

          # Copy native packages to core's node_modules (required - these OVERRIDE the npm versions)
          echo "Copying built native packages (overriding any npm versions)..."
          test -d "npm-packages/core-native-packages" || (echo "❌ core-native-packages not found in artifact!" && exit 1)
          cp -r npm-packages/core-native-packages/* packages/core/node_modules/@opentui/
          test -n "$(ls -A packages/core/node_modules/@opentui/)" || (echo "❌ No native packages copied!" && exit 1)
          echo "✅ Native packages copied"

          # Copy other package dists (optional)
          if [ -d "npm-packages/react-dist" ]; then
            cp -r npm-packages/react-dist packages/react/dist
            echo "✅ React dist copied"
          fi

          if [ -d "npm-packages/solid-dist" ]; then
            cp -r npm-packages/solid-dist packages/solid/dist
            echo "✅ Solid dist copied"
          fi

          echo ""
          echo "Package extraction complete:"
          ls -lah packages/core/dist/
          ls -lah packages/core/node_modules/@opentui/

      - name: Verify bun-webgpu is available for build
        run: |
          echo "Checking bun-webgpu installation..."

          # Check root node_modules first
          if [ -d node_modules/bun-webgpu ]; then
            echo "✅ bun-webgpu found in root node_modules"
          # Check packages/core/node_modules
          elif [ -d packages/core/node_modules/bun-webgpu ]; then
            echo "✅ bun-webgpu found in packages/core/node_modules"
          else
            echo "❌ bun-webgpu not found in root or packages/core/node_modules!"
            echo "Note: The build script will install it, but it should already be present"
            exit 1
          fi

          # Check for platform-specific packages in .bun cache (where bun install --os="*" --cpu="*" puts them)
          echo ""
          echo "Checking for platform-specific bun-webgpu packages in cache..."
          if [ -d node_modules/.bun/bun-webgpu-darwin-arm64@0.1.4 ]; then
            echo "✅ bun-webgpu-darwin-arm64 found in cache"
          else
            echo "⚠️  bun-webgpu-darwin-arm64 not found (will be installed during build)"
          fi

          if [ -d node_modules/.bun/bun-webgpu-darwin-x64@0.1.4 ]; then
            echo "✅ bun-webgpu-darwin-x64 found in cache"
          else
            echo "⚠️  bun-webgpu-darwin-x64 not found (will be installed during build)"
          fi

          if [ -d node_modules/.bun/bun-webgpu-linux-x64@0.1.4 ]; then
            echo "✅ bun-webgpu-linux-x64 found in cache"
          else
            echo "⚠️  bun-webgpu-linux-x64 not found (will be installed during build)"
          fi

          if [ -d node_modules/.bun/bun-webgpu-win32-x64@0.1.4 ]; then
            echo "✅ bun-webgpu-win32-x64 found in cache"
          else
            echo "⚠️  bun-webgpu-win32-x64 not found (will be installed during build)"
          fi

          echo ""
          echo "✅ bun-webgpu ready for bundling"

      - name: Build examples
        run: |
          set -e
          cd packages/core
          bun src/examples/build.ts

      - name: Verify example builds
        run: |
          set -e
          echo "Verifying example executables..."
          test -f "packages/core/src/examples/dist/darwin-x64/opentui-examples" || (echo "❌ darwin-x64 example missing!" && exit 1)
          test -f "packages/core/src/examples/dist/darwin-arm64/opentui-examples" || (echo "❌ darwin-arm64 example missing!" && exit 1)
          test -f "packages/core/src/examples/dist/linux-x64/opentui-examples" || (echo "❌ linux-x64 example missing!" && exit 1)
          test -f "packages/core/src/examples/dist/windows-x64/opentui-examples.exe" || (echo "❌ windows-x64 example missing!" && exit 1)

          echo "✅ All example executables verified"
          echo ""
          ls -lah packages/core/src/examples/dist/*/

      # Create separate zips for each platform's examples
      - name: Package examples - darwin-x64
        run: |
          set -e
          mkdir -p artifacts/examples-darwin-x64
          cp packages/core/src/examples/dist/darwin-x64/opentui-examples artifacts/examples-darwin-x64/
          cd artifacts
          zip -r examples-darwin-x64.zip examples-darwin-x64/
          test -f examples-darwin-x64.zip || (echo "❌ Failed to create darwin-x64 zip" && exit 1)
          test -s examples-darwin-x64.zip || (echo "❌ darwin-x64 zip is empty" && exit 1)
          echo "✅ darwin-x64 packaged successfully ($(du -h examples-darwin-x64.zip | cut -f1))"

      - name: Package examples - darwin-arm64
        run: |
          set -e
          mkdir -p artifacts/examples-darwin-arm64
          cp packages/core/src/examples/dist/darwin-arm64/opentui-examples artifacts/examples-darwin-arm64/
          cd artifacts
          zip -r examples-darwin-arm64.zip examples-darwin-arm64/
          test -f examples-darwin-arm64.zip || (echo "❌ Failed to create darwin-arm64 zip" && exit 1)
          test -s examples-darwin-arm64.zip || (echo "❌ darwin-arm64 zip is empty" && exit 1)
          echo "✅ darwin-arm64 packaged successfully ($(du -h examples-darwin-arm64.zip | cut -f1))"

      - name: Package examples - linux-x64
        run: |
          set -e
          mkdir -p artifacts/examples-linux-x64
          cp packages/core/src/examples/dist/linux-x64/opentui-examples artifacts/examples-linux-x64/
          cd artifacts
          zip -r examples-linux-x64.zip examples-linux-x64/
          test -f examples-linux-x64.zip || (echo "❌ Failed to create linux-x64 zip" && exit 1)
          test -s examples-linux-x64.zip || (echo "❌ linux-x64 zip is empty" && exit 1)
          echo "✅ linux-x64 packaged successfully ($(du -h examples-linux-x64.zip | cut -f1))"

      - name: Package examples - windows-x64
        run: |
          set -e
          mkdir -p artifacts/examples-windows-x64
          cp packages/core/src/examples/dist/windows-x64/opentui-examples.exe artifacts/examples-windows-x64/
          cd artifacts
          zip -r examples-windows-x64.zip examples-windows-x64/
          test -f examples-windows-x64.zip || (echo "❌ Failed to create windows-x64 zip" && exit 1)
          test -s examples-windows-x64.zip || (echo "❌ windows-x64 zip is empty" && exit 1)
          echo "✅ windows-x64 packaged successfully ($(du -h examples-windows-x64.zip | cut -f1))"

      - name: Verify all artifacts before upload
        run: |
          set -e
          echo "Verifying all artifacts exist..."
          test -f artifacts/examples-darwin-x64.zip || (echo "❌ examples-darwin-x64.zip missing!" && exit 1)
          test -f artifacts/examples-darwin-arm64.zip || (echo "❌ examples-darwin-arm64.zip missing!" && exit 1)
          test -f artifacts/examples-linux-x64.zip || (echo "❌ examples-linux-x64.zip missing!" && exit 1)
          test -f artifacts/examples-windows-x64.zip || (echo "❌ examples-windows-x64.zip missing!" && exit 1)

          echo ""
          echo "✅ All artifacts verified. Ready to upload:"
          ls -lah artifacts/*.zip

      - name: Upload example executables
        uses: actions/upload-artifact@v4
        with:
          name: example-executables-${{ inputs.version }}
          path: |
            artifacts/examples-darwin-x64.zip
            artifacts/examples-darwin-arm64.zip
            artifacts/examples-linux-x64.zip
            artifacts/examples-windows-x64.zip
          if-no-files-found: error
          retention-days: 30


================================================
FILE: .github/workflows/build-native.yml
================================================
name: Build Native

on:
  workflow_call:
    inputs:
      version:
        description: "Version being released"
        required: true
        type: string
      isDryRun:
        description: "Whether this is a dry run release"
        required: false
        type: boolean
        default: false

env:
  ZIG_VERSION: 0.15.2

jobs:
  build-native:
    name: Build Native Libraries
    runs-on: macos-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Setup Zig
        uses: goto-bus-stop/setup-zig@v2
        with:
          version: ${{ env.ZIG_VERSION }}

      - name: Install dependencies
        run: bun install

      - name: Build packages (cross-compile for all platforms)
        run: |
          cd packages/core
          bun run build:native --all
          bun run build:lib
          cd ../react
          bun run build
          cd ../solid
          bun run build

      - name: Verify build outputs
        run: |
          set -e
          echo "Checking for native binary packages..."
          ls -lah packages/core/node_modules/@opentui/
          echo "Checking for dist packages..."
          ls -lah packages/*/dist/

          # Verify critical files exist (all 6 platforms)
          echo ""
          echo "Verifying native binaries exist..."
          test -f packages/core/node_modules/@opentui/core-darwin-x64/libopentui.dylib || (echo "❌ darwin-x64 binary missing!" && exit 1)
          test -f packages/core/node_modules/@opentui/core-darwin-arm64/libopentui.dylib || (echo "❌ darwin-arm64 binary missing!" && exit 1)
          test -f packages/core/node_modules/@opentui/core-linux-x64/libopentui.so || (echo "❌ linux-x64 binary missing!" && exit 1)
          test -f packages/core/node_modules/@opentui/core-linux-arm64/libopentui.so || (echo "❌ linux-arm64 binary missing!" && exit 1)
          test -f packages/core/node_modules/@opentui/core-win32-x64/opentui.dll || (echo "❌ windows-x64 binary missing!" && exit 1)
          test -f packages/core/node_modules/@opentui/core-win32-arm64/opentui.dll || (echo "❌ windows-arm64 binary missing!" && exit 1)

          echo "Verifying dist packages exist..."
          test -d packages/core/dist || (echo "❌ core dist missing!" && exit 1)
          test -f packages/core/dist/package.json || (echo "❌ core dist/package.json missing!" && exit 1)

          echo "✅ All required build outputs verified (6 platforms)"

      # Create separate zips for each platform's native binaries
      - name: Package native binaries - darwin-x64
        run: |
          set -e
          mkdir -p artifacts/native-darwin-x64
          cp packages/core/node_modules/@opentui/core-darwin-x64/libopentui.dylib artifacts/native-darwin-x64/
          cd artifacts
          zip -r native-darwin-x64.zip native-darwin-x64/
          test -f native-darwin-x64.zip || (echo "❌ Failed to create darwin-x64 zip" && exit 1)
          test -s native-darwin-x64.zip || (echo "❌ darwin-x64 zip is empty" && exit 1)
          echo "✅ darwin-x64 packaged successfully ($(du -h native-darwin-x64.zip | cut -f1))"

      - name: Package native binaries - darwin-arm64
        run: |
          set -e
          mkdir -p artifacts/native-darwin-arm64
          cp packages/core/node_modules/@opentui/core-darwin-arm64/libopentui.dylib artifacts/native-darwin-arm64/
          cd artifacts
          zip -r native-darwin-arm64.zip native-darwin-arm64/
          test -f native-darwin-arm64.zip || (echo "❌ Failed to create darwin-arm64 zip" && exit 1)
          test -s native-darwin-arm64.zip || (echo "❌ darwin-arm64 zip is empty" && exit 1)
          echo "✅ darwin-arm64 packaged successfully ($(du -h native-darwin-arm64.zip | cut -f1))"

      - name: Package native binaries - linux-x64
        run: |
          set -e
          mkdir -p artifacts/native-linux-x64
          cp packages/core/node_modules/@opentui/core-linux-x64/libopentui.so artifacts/native-linux-x64/
          cd artifacts
          zip -r native-linux-x64.zip native-linux-x64/
          test -f native-linux-x64.zip || (echo "❌ Failed to create linux-x64 zip" && exit 1)
          test -s native-linux-x64.zip || (echo "❌ linux-x64 zip is empty" && exit 1)
          echo "✅ linux-x64 packaged successfully ($(du -h native-linux-x64.zip | cut -f1))"

      - name: Package native binaries - windows-x64
        run: |
          set -e
          mkdir -p artifacts/native-windows-x64
          cp packages/core/node_modules/@opentui/core-win32-x64/opentui.dll artifacts/native-windows-x64/
          cd artifacts
          zip -r native-windows-x64.zip native-windows-x64/
          test -f native-windows-x64.zip || (echo "❌ Failed to create windows-x64 zip" && exit 1)
          test -s native-windows-x64.zip || (echo "❌ windows-x64 zip is empty" && exit 1)
          echo "✅ windows-x64 packaged successfully ($(du -h native-windows-x64.zip | cut -f1))"

      - name: Package native binaries - linux-arm64
        run: |
          set -e
          mkdir -p artifacts/native-linux-arm64
          cp packages/core/node_modules/@opentui/core-linux-arm64/libopentui.so artifacts/native-linux-arm64/
          cd artifacts
          zip -r native-linux-arm64.zip native-linux-arm64/
          test -f native-linux-arm64.zip || (echo "❌ Failed to create linux-arm64 zip" && exit 1)
          test -s native-linux-arm64.zip || (echo "❌ linux-arm64 zip is empty" && exit 1)
          echo "✅ linux-arm64 packaged successfully ($(du -h native-linux-arm64.zip | cut -f1))"

      - name: Package native binaries - windows-arm64
        run: |
          set -e
          mkdir -p artifacts/native-windows-arm64
          cp packages/core/node_modules/@opentui/core-win32-arm64/opentui.dll artifacts/native-windows-arm64/
          cd artifacts
          zip -r native-windows-arm64.zip native-windows-arm64/
          test -f native-windows-arm64.zip || (echo "❌ Failed to create windows-arm64 zip" && exit 1)
          test -s native-windows-arm64.zip || (echo "❌ windows-arm64 zip is empty" && exit 1)
          echo "✅ windows-arm64 packaged successfully ($(du -h native-windows-arm64.zip | cut -f1))"

      # Package the built npm packages (for use by build-examples and npm-publish)
      - name: Package npm packages
        run: |
          set -e
          mkdir -p artifacts/npm-packages

          # Copy core package dist and native packages
          echo "Packaging core dist..."
          cp -r packages/core/dist artifacts/npm-packages/core-dist
          test -f artifacts/npm-packages/core-dist/package.json || (echo "❌ core dist/package.json missing after copy!" && exit 1)

          echo "Packaging core native packages..."
          cp -r packages/core/node_modules/@opentui artifacts/npm-packages/core-native-packages

          # Copy other package dists (optional - don't fail if missing)
          echo "Packaging other packages..."
          if [ -d packages/react/dist ]; then
            cp -r packages/react/dist artifacts/npm-packages/react-dist
            echo "✅ React dist packaged"
          else
            echo "⚠️  React dist not found (skipping)"
          fi

          if [ -d packages/solid/dist ]; then
            cp -r packages/solid/dist artifacts/npm-packages/solid-dist
            echo "✅ Solid dist packaged"
          else
            echo "⚠️  Solid dist not found (skipping)"
          fi

          cd artifacts
          zip -r npm-packages.zip npm-packages/
          test -f npm-packages.zip || (echo "❌ Failed to create npm-packages zip" && exit 1)
          test -s npm-packages.zip || (echo "❌ npm-packages zip is empty" && exit 1)
          echo "✅ npm packages packaged successfully ($(du -h npm-packages.zip | cut -f1))"

      - name: Verify all artifacts before upload
        run: |
          set -e
          echo "Verifying all artifacts exist..."
          test -f artifacts/native-darwin-x64.zip || (echo "❌ native-darwin-x64.zip missing!" && exit 1)
          test -f artifacts/native-darwin-arm64.zip || (echo "❌ native-darwin-arm64.zip missing!" && exit 1)
          test -f artifacts/native-linux-x64.zip || (echo "❌ native-linux-x64.zip missing!" && exit 1)
          test -f artifacts/native-linux-arm64.zip || (echo "❌ native-linux-arm64.zip missing!" && exit 1)
          test -f artifacts/native-windows-x64.zip || (echo "❌ native-windows-x64.zip missing!" && exit 1)
          test -f artifacts/native-windows-arm64.zip || (echo "❌ native-windows-arm64.zip missing!" && exit 1)
          test -f artifacts/npm-packages.zip || (echo "❌ npm-packages.zip missing!" && exit 1)

          echo ""
          echo "✅ All 6 platform artifacts verified. Ready to upload:"
          ls -lah artifacts/*.zip

      - name: Upload native binaries artifacts
        uses: actions/upload-artifact@v4
        with:
          name: native-binaries-${{ inputs.version }}
          path: |
            artifacts/native-darwin-x64.zip
            artifacts/native-darwin-arm64.zip
            artifacts/native-linux-x64.zip
            artifacts/native-linux-arm64.zip
            artifacts/native-windows-x64.zip
            artifacts/native-windows-arm64.zip
          if-no-files-found: error
          retention-days: 30

      - name: Upload npm packages artifact
        uses: actions/upload-artifact@v4
        with:
          name: npm-packages-${{ inputs.version }}
          path: artifacts/npm-packages.zip
          if-no-files-found: error
          retention-days: 30


================================================
FILE: .github/workflows/build-react.yml
================================================
name: Build React

on:
  push:
  pull_request:
    branches: [main]

env:
  # Workaround for bug in Zig 0.15.2 (fixed in next version)
  # https://github.com/ziglang/zig/issues/25805
  ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-global-cache

jobs:
  test:
    name: Test (${{ matrix.os }})
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    defaults:
      run:
        shell: bash
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Setup Zig
        uses: goto-bus-stop/setup-zig@v2
        with:
          version: 0.15.2

      - name: Install dependencies
        run: bun install

      - name: Build core
        run: |
          cd packages/core
          bun run build

      - name: Build
        run: |
          cd packages/react
          bun run build --ci

      - name: Run tests
        run: |
          cd packages/react
          bun run test

  # Gate job for branch protection
  build-complete:
    name: React - Build and Test
    needs: [test]
    runs-on: ubuntu-latest
    if: always()
    steps:
      - name: Check test results
        run: |
          if [ "${{ needs.test.result }}" != "success" ]; then
            echo "Tests failed"
            exit 1
          fi
          echo "All tests passed"


================================================
FILE: .github/workflows/build-solid.yml
================================================
name: Build Solid

on:
  push:
  pull_request:
    branches: [main]

env:
  # Workaround for bug in Zig 0.15.2 (fixed in next version)
  # https://github.com/ziglang/zig/issues/25805
  ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-global-cache

jobs:
  test:
    name: Test (${{ matrix.os }})
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    defaults:
      run:
        shell: bash
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Setup Zig
        uses: goto-bus-stop/setup-zig@v2
        with:
          version: 0.15.2

      - name: Install dependencies
        run: bun install

      - name: Build core
        run: |
          cd packages/core
          bun run build

      - name: Build
        run: |
          cd packages/solid
          bun run build --ci

      - name: Run tests
        run: |
          cd packages/solid
          bun run test

  # Gate job for branch protection
  build-complete:
    name: Solid - Build and Test
    needs: [test]
    runs-on: ubuntu-latest
    if: always()
    steps:
      - name: Check test results
        run: |
          if [ "${{ needs.test.result }}" != "success" ]; then
            echo "Tests failed"
            exit 1
          fi
          echo "All tests passed"


================================================
FILE: .github/workflows/deploy.yml
================================================
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout your repository using git
        uses: actions/checkout@v6
      - name: Install, build, and upload your site
        uses: withastro/action@v5
        with:
          path: ./packages/web
          package-manager: bun@latest

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4


================================================
FILE: .github/workflows/npm-latest-release.yml
================================================
name: NPM Publish

on:
  workflow_call:
    inputs:
      version:
        description: "Version being published"
        required: true
        type: string
      isDryRun:
        description: "Whether this is a dry run (npm publish --dry-run)"
        required: false
        type: boolean
        default: false
    secrets:
      NPM_TOKEN:
        required: true

permissions:
  contents: write
  pull-requests: write

jobs:
  publish:
    runs-on: macos-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

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

      - name: Install dependencies
        run: bun install

      - name: Download npm packages artifact
        uses: actions/download-artifact@v4
        with:
          name: npm-packages-${{ inputs.version }}

      - name: Extract npm packages
        run: |
          echo "Extracting npm packages..."
          unzip -q npm-packages.zip

          # Copy core dist
          if [ -d "npm-packages/core-dist" ]; then
            cp -r npm-packages/core-dist packages/core/dist
            echo "Copied core dist"
          fi

          # Copy native packages to core's node_modules
          if [ -d "npm-packages/core-native-packages" ]; then
            mkdir -p packages/core/node_modules/@opentui
            cp -r npm-packages/core-native-packages/* packages/core/node_modules/@opentui/
            echo "Copied native packages"
          fi

          # Copy other package dists
          if [ -d "npm-packages/react-dist" ]; then
            cp -r npm-packages/react-dist packages/react/dist
            echo "Copied react dist"
          fi

          if [ -d "npm-packages/solid-dist" ]; then
            cp -r npm-packages/solid-dist packages/solid/dist
            echo "Copied solid dist"
          fi

          echo "Package extraction complete"

      - name: Publish packages (dry-run)
        if: ${{ inputs.isDryRun }}
        run: |
          echo "=========================================="
          echo "DRY RUN MODE - Not publishing to npm"
          echo "=========================================="
          echo ""
          echo "Skipping pre-publish validation (npm version check would fail for dry-runs)"
          echo ""

          # Show what would be published (just check if packages can be packed)
          echo "Packages that would be published:"
          echo ""

          echo "📦 Checking @opentui/core..."
          cd packages/core/dist && npm pack --dry-run

          echo ""
          echo "📦 Checking @opentui/react..."
          cd ../../react/dist && npm pack --dry-run

          echo ""
          echo "📦 Checking @opentui/solid..."
          cd ../../solid/dist && npm pack --dry-run

          echo ""
          echo "=========================================="
          echo "DRY RUN COMPLETE - All packages validated"
          echo "=========================================="
        env:
          NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
          CI: true

      - name: Publish packages (production)
        if: ${{ !inputs.isDryRun }}
        run: |
          echo "=========================================="
          echo "PRODUCTION MODE - Publishing to npm"
          echo "=========================================="

          # Run pre-publish validation
          bun run pre-publish

          # Publish packages
          bun run publish

          echo ""
          echo "=========================================="
          echo "PUBLISH COMPLETE"
          echo "=========================================="
        env:
          NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
          CI: true


================================================
FILE: .github/workflows/npm-release.yml
================================================
name: NPM Snapshot Release

on:
  push:
    tags:
      - "*snapshot*"

permissions:
  contents: write
  pull-requests: write

jobs:
  release:
    runs-on: macos-latest

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

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

      - name: Setup Zig
        uses: goto-bus-stop/setup-zig@v2
        with:
          version: 0.15.2

      - name: Extract version from tag
        id: extract_version
        run: |
          TAG=${GITHUB_REF#refs/tags/v}
          echo "version=$TAG" >> $GITHUB_OUTPUT
          echo "Extracted version: $TAG"

      - name: Generate snapshot version
        id: version_scheme
        run: |
          TAG_VERSION="${{ steps.extract_version.outputs.version }}"
          COMMIT_SHA=$(git rev-parse --short=8 HEAD)

          # Pre-release snapshot
          VERSION="0.0.0-$(date +%Y%m%d)-${COMMIT_SHA}"
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "Using snapshot version: $VERSION"

      - name: Install dependencies
        run: bun i

      - name: Prepare release versions
        run: bun run prepare-release "${{ steps.version_scheme.outputs.version }}"

      - name: Build packages (cross-compile for all platforms)
        run: |
          cd packages/core
          bun run build:native --all
          bun run build:lib
          cd ../solid && bun run build
          cd ../react && bun run build

      - name: Publish packages
        run: bun run publish
        env:
          NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
          CI: true


================================================
FILE: .github/workflows/opencode.yml
================================================
name: opencode

on:
  issue_comment:
    types: [created]

jobs:
  opencode:
    if: |
      contains(github.event.comment.body, ' /oc') ||
      startsWith(github.event.comment.body, '/oc') ||
      contains(github.event.comment.body, ' /opencode') ||
      startsWith(github.event.comment.body, '/opencode')
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Run opencode
        uses: sst/opencode/github@latest
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        with:
          model: anthropic/claude-sonnet-4-20250514


================================================
FILE: .github/workflows/pkg-pr-new.yml
================================================
name: Publish Preview Packages

on:
  issue_comment:
    types: [created]

permissions: {}

jobs:
  publish:
    name: Publish Preview
    if: |
      github.event.issue.pull_request &&
      github.event.issue.state == 'open' &&
      (contains(github.event.comment.body, ' /pkg-preview') ||
        startsWith(github.event.comment.body, '/pkg-preview')) &&
      contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout PR branch
        uses: actions/checkout@v4
        with:
          ref: refs/pull/${{ github.event.issue.number }}/head

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

      - name: Setup Zig
        uses: goto-bus-stop/setup-zig@v2
        with:
          version: 0.15.2

      - name: Install dependencies
        run: bun install

      - name: Build core (all platforms via cross-compilation)
        run: bun scripts/build.ts --native --all && bun scripts/build.ts --lib
        working-directory: packages/core

      - name: Get native package directories
        id: native-packages
        run: |
          NATIVE_DIRS=$(find ./packages/core/node_modules/@opentui -maxdepth 1 -type d -name 'core-*' -printf '%p ' | sed 's/ $//')
          echo "dirs=$NATIVE_DIRS" >> $GITHUB_OUTPUT
          echo "Found native packages: $NATIVE_DIRS"

      - name: Build react
        run: bun run build --ci
        working-directory: packages/react

      - name: Build solid
        run: bun run build --ci
        working-directory: packages/solid

      - name: Publish preview packages
        run: |
          npx pkg-pr-new publish --no-template --commentWithSha --bun \
            './packages/core/dist' \
            ${{ steps.native-packages.outputs.dirs }} \
            './packages/react/dist' \
            './packages/solid/dist'


================================================
FILE: .github/workflows/prettier.yml
================================================
name: Format

on:
  pull_request:
    branches: [main]

jobs:
  prettier-core:
    name: Prettier Check
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Check Prettier formatting
        run: |
          PRETTIER_VERSION=$(bun -e 'console.log(require("./package.json").devDependencies.prettier)')
          bunx prettier@$PRETTIER_VERSION --check --log-level warn .

      - name: Show formatting differences
        if: failure()
        run: |
          echo "=== Showing differences for each file ==="
          PRETTIER_VERSION=$(bun -e 'console.log(require("./package.json").devDependencies.prettier)')
          bunx prettier@$PRETTIER_VERSION --write .
          git diff --color=always


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  push:
    tags:
      - "v*"

permissions:
  contents: write
  pull-requests: write

jobs:
  # Extract version and check if it's a dry run
  prepare:
    name: Prepare Release
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.extract.outputs.version }}
      fullTag: ${{ steps.extract.outputs.fullTag }}
      isDryRun: ${{ steps.extract.outputs.isDryRun }}
      releaseTitle: ${{ steps.extract.outputs.releaseTitle }}

    steps:
      - name: Extract version and dry-run flag
        id: extract
        run: |
          TAG=${GITHUB_REF#refs/tags/v}
          echo "Full tag: $TAG"

          # Check if this is a dry run (contains -dry.)
          if [[ "$TAG" =~ -dry\. ]]; then
            IS_DRY_RUN=true
            # Extract base version (remove -dry.X suffix for validation)
            VERSION=$(echo "$TAG" | sed -E 's/-dry\.[0-9]+$//')
            RELEASE_TITLE="Release v$TAG (DRY RUN)"
            echo "This is a DRY RUN release"
          else
            IS_DRY_RUN=false
            VERSION="$TAG"
            RELEASE_TITLE="Release v$TAG"
            echo "This is a PRODUCTION release"
          fi

          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "fullTag=$TAG" >> $GITHUB_OUTPUT
          echo "isDryRun=$IS_DRY_RUN" >> $GITHUB_OUTPUT
          echo "releaseTitle=$RELEASE_TITLE" >> $GITHUB_OUTPUT

          echo "Version (for validation): $VERSION"
          echo "Full Tag (for artifacts): $TAG"
          echo "Is Dry Run: $IS_DRY_RUN"
          echo "Release Title: $RELEASE_TITLE"

  # Version validation check
  validate-version:
    name: Validate Version
    needs: prepare
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Check version matches package.json files
        run: |
          TAG_VERSION="${{ needs.prepare.outputs.version }}"
          echo "Validating version: $TAG_VERSION"

          # Check package.json versions (exclude web, not published to npm)
          FAILED=false
          for pkg in packages/*/; do
            if [ -f "$pkg/package.json" ]; then
              if [ "$(basename "$pkg")" = "web" ]; then
                echo "INFO: Skipping $pkg (not published to npm)"
                continue
              fi
              PKG_VERSION=$(node -p "require('./$pkg/package.json').version")
              if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then
                echo "❌ Package $pkg version ($PKG_VERSION) does not match tag version ($TAG_VERSION)"
                FAILED=true
              else
                echo "✅ Package $pkg version matches: $PKG_VERSION"
              fi
            fi
          done

          if [ "$FAILED" = true ]; then
            echo ""
            echo "Version validation FAILED!"
            echo "Please update package.json versions to match the tag version: $TAG_VERSION"
            exit 1
          fi

          echo ""
          echo "✅ All package versions match tag version: $TAG_VERSION"

  # Build native libraries and packages
  build-native:
    name: Build Native
    needs: [prepare, validate-version]
    uses: ./.github/workflows/build-native.yml
    with:
      version: ${{ needs.prepare.outputs.fullTag }}
      isDryRun: ${{ needs.prepare.outputs.isDryRun == 'true' }}

  # Build example executables
  build-examples:
    name: Build Examples
    needs: [prepare, validate-version, build-native]
    uses: ./.github/workflows/build-examples.yml
    with:
      version: ${{ needs.prepare.outputs.fullTag }}
      isDryRun: ${{ needs.prepare.outputs.isDryRun == 'true' }}

  # Publish to npm
  npm-publish:
    name: NPM Publish
    needs: [prepare, validate-version, build-native]
    uses: ./.github/workflows/npm-latest-release.yml
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
    with:
      version: ${{ needs.prepare.outputs.fullTag }}
      isDryRun: ${{ needs.prepare.outputs.isDryRun == 'true' }}

  # Create GitHub release with assets
  github-release:
    name: Create GitHub Release
    needs: [prepare, build-native, build-examples, npm-publish]
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts

      - name: Organize release assets
        run: |
          set -e
          WORK_DIR=$(pwd)
          mkdir -p "$WORK_DIR/release-assets"

          FULL_TAG="${{ needs.prepare.outputs.fullTag }}"
          echo "Organizing release assets for tag: $FULL_TAG"
          echo "Working directory: $WORK_DIR"

          # Verify artifact directories exist
          test -d "artifacts/native-binaries-$FULL_TAG" || (echo "❌ native-binaries artifact directory not found!" && exit 1)
          test -d "artifacts/example-executables-$FULL_TAG" || (echo "❌ example-executables artifact directory not found!" && exit 1)

          # Copy native binaries (unzip and rezip with versioned names)
          echo "Processing native binaries..."
          cd "artifacts/native-binaries-$FULL_TAG"

          for zip_file in native-*.zip; do
            if [ -f "$zip_file" ]; then
              platform=$(echo "$zip_file" | sed 's/native-//' | sed 's/.zip//')
              echo "  Processing $platform..."
              unzip -q "$zip_file"
              
              # Repackage with versioned name
              dir_name=$(echo "$zip_file" | sed 's/.zip//')
              if [ -d "$dir_name" ]; then
                cd "$dir_name"
                zip -r "$WORK_DIR/release-assets/opentui-native-v${FULL_TAG}-${platform}.zip" .
                cd ..
                
                # Verify the output
                test -f "$WORK_DIR/release-assets/opentui-native-v${FULL_TAG}-${platform}.zip" || (echo "❌ Failed to create native $platform release asset!" && exit 1)
                echo "  ✅ opentui-native-v${FULL_TAG}-${platform}.zip created"
              else
                echo "❌ Directory $dir_name not found after unzip!" && exit 1
              fi
            fi
          done

          cd "$WORK_DIR"

          # Copy example executables (unzip and rezip with versioned names)
          echo "Processing example executables..."
          cd "artifacts/example-executables-$FULL_TAG"

          for zip_file in examples-*.zip; do
            if [ -f "$zip_file" ]; then
              platform=$(echo "$zip_file" | sed 's/examples-//' | sed 's/.zip//')
              echo "  Processing $platform..."
              unzip -q "$zip_file"
              
              # Repackage with versioned name
              dir_name=$(echo "$zip_file" | sed 's/.zip//')
              if [ -d "$dir_name" ]; then
                cd "$dir_name"
                zip -r "$WORK_DIR/release-assets/opentui-examples-v${FULL_TAG}-${platform}.zip" .
                cd ..
                
                # Verify the output
                test -f "$WORK_DIR/release-assets/opentui-examples-v${FULL_TAG}-${platform}.zip" || (echo "❌ Failed to create examples $platform release asset!" && exit 1)
                echo "  ✅ opentui-examples-v${FULL_TAG}-${platform}.zip created"
              else
                echo "❌ Directory $dir_name not found after unzip!" && exit 1
              fi
            fi
          done

          cd "$WORK_DIR"

          # Verify all expected release assets exist
          echo ""
          echo "Verifying all release assets..."
          EXPECTED_ASSETS=10  # 6 native (darwin-x64, darwin-arm64, linux-x64, linux-arm64, windows-x64, windows-arm64) + 4 examples (no linux-arm64, no windows-arm64)
          ACTUAL_ASSETS=$(ls -1 release-assets/*.zip 2>/dev/null | wc -l | tr -d ' ')

          if [ "$ACTUAL_ASSETS" -ne "$EXPECTED_ASSETS" ]; then
            echo "❌ Expected $EXPECTED_ASSETS release assets, found $ACTUAL_ASSETS"
            ls -lah release-assets/ || echo "No release assets found"
            exit 1
          fi

          echo "✅ All $ACTUAL_ASSETS release assets prepared:"
          echo "   - 6 native binaries (all platforms)"
          echo "   - 4 example executables (darwin-x64, darwin-arm64, linux-x64, windows-x64)"
          ls -lah release-assets/

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          name: ${{ needs.prepare.outputs.releaseTitle }}
          files: release-assets/*.zip
          generate_release_notes: true
          draft: false
          prerelease: ${{ needs.prepare.outputs.isDryRun == 'true' }}
          token: ${{ secrets.GITHUB_TOKEN }}
          fail_on_unmatched_files: true


================================================
FILE: .github/workflows/review.yml
================================================
name: Guidelines Check

on:
  issue_comment:
    types: [created]

jobs:
  check-guidelines:
    if: |
      github.event.issue.pull_request &&
      startsWith(github.event.comment.body, '/review') &&
      contains(fromJson('["OWNER","MEMBER"]'), github.event.comment.author_association)
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - name: Get PR number
        id: pr-number
        run: |
          if [ "${{ github.event_name }}" = "pull_request_target" ]; then
            echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
          else
            echo "number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT
          fi

      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Install opencode
        run: curl -fsSL https://opencode.ai/install | bash

      - name: Get PR details
        id: pr-details
        run: |
          gh api /repos/${{ github.repository }}/pulls/${{ steps.pr-number.outputs.number }} > pr_data.json
          echo "title=$(jq -r .title pr_data.json)" >> $GITHUB_OUTPUT
          echo "sha=$(jq -r .head.sha pr_data.json)" >> $GITHUB_OUTPUT
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Check PR guidelines compliance
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          OPENCODE_PERMISSION: '{ "bash": { "gh*": "allow", "gh pr review*": "deny", "*": "deny" } }'
        run: |
          PR_BODY=$(jq -r .body pr_data.json)
          opencode run -m anthropic/claude-sonnet-4-5 "A new pull request has been created: '${{ steps.pr-details.outputs.title }}'

          <pr-number>
          ${{ steps.pr-number.outputs.number }}
          </pr-number>

          <pr-description>
          $PR_BODY
          </pr-description>

          Please check all the code changes in this pull request against the style guide, also look for any bugs if they exist. Diffs are important but make sure you read the entire file to get proper context. Make it clear the suggestions are merely suggestions and the human can decide what to do

          When critiquing code against the style guide, be sure that the code is ACTUALLY in violation, don't complain about else statements if they already use early returns there. You may complain about excessive nesting though, regardless of else statement usage.
          When critiquing code style don't be a zealot, we don't like "let" statements but sometimes they are the simpliest option, if someone does a bunch of nesting with let, they should consider using iife (see packages/opencode/src/util.iife.ts)

          Use the gh cli to create comments on the files for the violations. Try to leave the comment on the exact line number. If you have a suggested fix include it in a suggestion code block.

          Command MUST be like this.
          \`\`\`
          gh api \
            --method POST \
            -H \"Accept: application/vnd.github+json\" \
            -H \"X-GitHub-Api-Version: 2022-11-28\" \
            /repos/${{ github.repository }}/pulls/${{ steps.pr-number.outputs.number }}/comments \
            -f 'body=[summary of issue]' -f 'commit_id=${{ steps.pr-details.outputs.sha }}' -f 'path=[path-to-file]' -F \"line=[line]\" -f 'side=RIGHT'
          \`\`\`

          Only create comments for actual violations. If the code follows all guidelines, comment 'lgtm' AND NOTHING ELSE!!!!."


================================================
FILE: .gitignore
================================================
# dependencies (bun install)
node_modules

Session.vim

# output
out
dist
packed
*.tgz
*.log
*.txt

# code coverage
coverage
*.lcov

# logs
logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# caches
.eslintcache
.cache
*.tsbuildinfo

# IntelliJ based IDEs
.idea

# Finder (MacOS) folder config
.DS_Store

screenshot-*.png


================================================
FILE: .prettierignore
================================================
**/.zig-cache/**
packages/core/src/lib/tree-sitter/default-parsers.ts


================================================
FILE: .zig-version
================================================
0.15.2


================================================
FILE: AGENTS.md
================================================
# Agent Guidelines for opentui

Default to using Bun instead of Node.js.

- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
- Use `bun test` instead of `jest` or `vitest`
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
- Bun automatically loads .env, so don't use dotenv.

NOTE: When only changing typescript, you do NOT need to run the build script.
The build is only needed when changing native code.

## APIs

Don't use bun-specific APIs. Generated code should work in Bun, Node.js and Deno runtimes.

## Testing

Use `bun test` to run tests from the packages directories for a specific package.

```ts#index.test.ts
import { test, expect } from "bun:test";

test("hello world", () => {
  expect(1).toBe(1);
});
```

For more information, read the Bun API docs in `node_modules/bun-types/docs/**.md`.

## Build/Test Commands

To build the project (before running typescript tests), run
`bun run build`
FROM THE REPO ROOT to make sure all packages are built correctly.

To run native tests for `packages/core`, run
`bun run test:native`
FROM THE `packages/core` DIRECTORY.

To filter native tests, use:
`bun run test:native -Dtest-filter="test name"`
FROM THE `packages/core` DIRECTORY.

## Typescript Code Style

- **Runtime**: Bun with TypeScript
- **Formatting**: Prettier (semi: false, printWidth: 120)
- **Imports**: Use explicit imports, group by: built-ins, external deps, internal modules
- **Types**: Strict TypeScript, use interfaces for options/configs, explicit return types for public APIs
- **Naming**: camelCase for variables/functions, PascalCase for classes/interfaces, UPPER_CASE for constants
- **Error Handling**: Use proper Error objects, avoid silent failures
- **Async**: Prefer async/await over Promises, handle errors explicitly
- **Comments**: Minimal comments, NO JSDoc
- **File Structure**: Index files for clean exports, group related functionality
- **Testing**: Bun test framework, descriptive test names, use beforeEach/afterEach for setup

## Debugging

- NOTE this is a terminal UI lib and when running examples or apps built with it,
  you cannot currently see log output like console.log. Ask the user to run the example/app and provide the output.
- Reproduce the issue in a test case. Do NOT start fixing without a reproducible test case.
  Use debug logs to see what is actually happening. DO NOT GUESS.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Opentui

Bug fixes and feature suggestions are always welcome. For bug fixes, open a PR
for reviews. Feature suggestions are subject to discussion via issues.

## Code style

Reference existing [AGENTS.md](https://github.com/anomalyco/opentui/blob/main/AGENTS.md) or project conventions if applicable.

## Code of conduct

- Treat everyone with respect and empathy. We do not tolerate harassment, discrimination, or personal attacks.
- Be kind, constructive, and assume good intent.
- Keep feedback specific and actionable; critique code, not people.
- No unsolicited DMs for support unless invited.
- Follow project guidelines and maintainers’ decisions.


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2025 opentui

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
# OpenTUI

<div align="center">
    <a href="https://www.npmjs.com/package/@opentui/core"><img alt="npm" src="https://img.shields.io/npm/v/@opentui/core?style=flat-square" /></a>
    <a href="https://github.com/anomalyco/opentui/actions/workflows/build-core.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/anomalyco/opentui/build-core.yml?style=flat-square&branch=main" /></a>
    <a href="https://github.com/msmps/awesome-opentui"><img alt="awesome opentui list" src="https://awesome.re/badge-flat.svg" /></a>
</div>

OpenTUI is a native terminal UI core written in Zig with TypeScript bindings. The native core exposes a C ABI and can be used from any language. OpenTUI powers [OpenCode](https://opencode.ai) in production today and will also power [terminal.shop](https://terminal.shop). It is an extensible core with a focus on correctness, stability, and high performance. It provides a component-based architecture with flexible layout capabilities, allowing you to create complex terminal applications.

Docs: https://opentui.com/docs/getting-started

Quick start with [bun](https://bun.sh) and [create-tui](https://github.com/msmps/create-tui):

```bash
bun create tui
```

This monorepo contains the following packages:

- [`@opentui/core`](packages/core) - TypeScript bindings for OpenTUI's native Zig core, with an imperative API and all primitives.
- [`@opentui/solid`](packages/solid) - The SolidJS reconciler for OpenTUI.
- [`@opentui/react`](packages/react) - The React reconciler for OpenTUI.

## Install

NOTE: You must have [Zig](https://ziglang.org/learn/getting-started/) installed on your system to build the packages.

### TypeScript/JavaScript

```bash
bun install @opentui/core
```

## AI Agent Skill

Teach your AI coding assistant OpenTUI's APIs and patterns.

**For [OpenCode](https://opencode.ai) (includes `/opentui` command):**

```bash
curl -fsSL https://raw.githubusercontent.com/msmps/opentui-skill/main/install.sh | bash
```

**For other AI coding assistants:**

```bash
npx skills add msmps/opentui-skill
```

## Try Examples

You can quickly try out OpenTUI examples without cloning the repository:

**For macOS, Linux, WSL, Git Bash:**

```bash
curl -fsSL https://raw.githubusercontent.com/anomalyco/opentui/main/packages/core/src/examples/install.sh | sh
```

**For Windows (PowerShell/CMD):**

Download the latest release directly from [GitHub Releases](https://github.com/anomalyco/opentui/releases/latest)

## Running Examples (from the repo root)

### TypeScript Examples

```bash
bun install
cd packages/core
bun run src/examples/index.ts
```

## Development

See the [Development Guide](packages/core/docs/development.md) for building, testing, debugging, and local development linking.

### Documentation

- [Website docs](https://opentui.com/docs/getting-started) - Guides and API references
- [Development Guide](packages/core/docs/development.md) - Building, testing, and local dev linking
- [Getting Started](packages/core/docs/getting-started.md) - API and usage guide
- [Environment Variables](packages/core/docs/env-vars.md) - Configuration options

## Showcase

Consider showcasing your work on the [awesome-opentui](https://github.com/msmps/awesome-opentui) list. A curated list of awesome resources and terminal user interfaces built with OpenTUI.


================================================
FILE: opentui.pc.in
================================================
prefix=@PREFIX@
libdir=${prefix}/lib
includedir=${prefix}/include

Name: OpenTUI
Description: High-performance terminal user interface library
Version: @VERSION@
Libs: -L${libdir} -lopentui -Wl,-rpath,${libdir}
Cflags: -I${includedir}

================================================
FILE: package.json
================================================
{
  "name": "@opentui",
  "private": true,
  "workspaces": [
    "packages/*",
    "packages/solid/examples"
  ],
  "scripts": {
    "build": "cd packages/core && bun run build && cd ../solid && bun run build && cd ../react && bun run build",
    "pre-publish": "bun scripts/pre-publish.ts",
    "publish": "bun run pre-publish && bun run publish:core && bun run publish:react && bun run publish:solid",
    "publish:core": "cd packages/core && bun run publish",
    "publish:react": "cd packages/react && bun run publish",
    "publish:solid": "cd packages/solid && bun run publish",
    "prepare-release": "bun scripts/prepare-release.ts",
    "prettier:write": "prettier --write .",
    "test": "bun run --filter '@opentui/core' --filter '@opentui/solid' --filter '@opentui/react' --if-present test"
  },
  "devDependencies": {
    "prettier": "3.6.2"
  },
  "prettier": {
    "semi": false,
    "printWidth": 120
  }
}


================================================
FILE: packages/core/.gitignore
================================================
# Zig build cache
.zig-cache
zig-out
src/zig/lib


================================================
FILE: packages/core/README.md
================================================
# OpenTUI Core

OpenTUI is a native terminal UI core written in Zig with TypeScript bindings. The native core exposes a C ABI and can be used from any language. OpenTUI powers OpenCode in production today and will also power terminal.shop. It is an extensible core with a focus on correctness, stability, and high performance. It provides a component-based architecture with flexible layout capabilities, allowing you to create complex terminal applications.

## Documentation

- [Getting Started](docs/getting-started.md) - API and usage guide
- [Development Guide](docs/development.md) - Building, testing, and contributing
- [Tree-Sitter](docs/tree-sitter.md) - Syntax highlighting integration
- [Renderables vs Constructs](docs/renderables-vs-constructs.md) - Understanding the component model
- [Environment Variables](docs/env-vars.md) - Configuration options

## Install

```bash
bun install @opentui/core
```

## Build

```bash
bun run build
```

This creates platform-specific libraries that are automatically loaded by the TypeScript layer.

## Examples

```bash
bun install
bun run src/examples/index.ts
```

## Benchmarks

Run native performance benchmarks:

```bash
bun run bench:native
```

See [src/zig/bench.zig](src/zig/bench.zig) for available options like `--filter` and `--mem`.

NativeSpanFeed TypeScript benchmarks:

- [src/benchmark/native-span-feed-benchmark.md](src/benchmark/native-span-feed-benchmark.md)

## CLI Renderer

### Renderables

Renderables are hierarchical objects that can be positioned, nested, styled and rendered to the terminal:

```typescript
import { createCliRenderer, TextRenderable } from "@opentui/core"

const renderer = await createCliRenderer()

const obj = new TextRenderable(renderer, { id: "my-obj", content: "Hello, world!" })

renderer.root.add(obj)
```


================================================
FILE: packages/core/dev/keypress-debug-renderer.ts
================================================
#!/usr/bin/env bun
import { BoxRenderable, type CliRenderer, createCliRenderer, CodeRenderable, addDefaultParsers } from "../src/index.js"
import { ScrollBoxRenderable } from "../src/renderables/ScrollBox.js"
import { SyntaxStyle } from "../src/syntax-style.js"
import { parseColor } from "../src/lib/RGBA.js"

const parsers = [
  {
    filetype: "json",
    wasm: "https://github.com/tree-sitter/tree-sitter-json/releases/download/v0.24.8/tree-sitter-json.wasm",
    queries: {
      highlights: [
        "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/json/highlights.scm",
      ],
    },
  },
]
addDefaultParsers(parsers)
let scrollBox: ScrollBoxRenderable | null = null
let renderer: CliRenderer | null = null
let syntaxStyle: SyntaxStyle | null = null
let eventCount = 0

function addEvent(eventType: string, event: object) {
  if (!renderer || !scrollBox || !syntaxStyle) return

  eventCount++

  const eventData = {
    type: eventType,
    timestamp: new Date().toISOString(),
    ...event,
  }

  const eventBox = new BoxRenderable(renderer, {
    id: `event-${eventCount}`,
    width: "auto",
    marginBottom: 1,
    padding: 1,
    backgroundColor: "#1f2937",
  })

  const codeDisplay = new CodeRenderable(renderer, {
    id: `event-code-${eventCount}`,
    content: JSON.stringify(eventData, null, 2),
    filetype: "json",
    conceal: false,
    syntaxStyle,
    bg: "#1f2937",
  })

  eventBox.add(codeDisplay)
  scrollBox.add(eventBox)

  const children = scrollBox.getChildren()
  if (children.length > 50) {
    const oldest = children[0]
    if (oldest) {
      scrollBox.remove(oldest.id)
      oldest.destroyRecursively()
    }
  }
}

async function main() {
  const usePrepend = process.argv.includes("--prepend")
  const prependInputHandlers = usePrepend
    ? [
        (sequence: string) => {
          addEvent("raw-input-before", { sequence })
          return false
        },
      ]
    : []
  renderer = await createCliRenderer({
    exitOnCtrlC: true,
    targetFps: 60,
    useKittyKeyboard: { events: true },
    prependInputHandlers,
  })

  renderer.setBackgroundColor("#0D1117")

  const mainContainer = new BoxRenderable(renderer, {
    id: "main-container",
    flexGrow: 1,
    flexDirection: "column",
  })

  renderer.root.add(mainContainer)

  scrollBox = new ScrollBoxRenderable(renderer, {
    id: "event-scroll-box",
    stickyScroll: true,
    stickyStart: "bottom",
    border: true,
    borderColor: "#6BCF7F",
    title: `Keypress Debug${usePrepend ? " (prepend mode)" : ""} (Ctrl+C to exit)`,
    titleAlignment: "center",
    contentOptions: {
      paddingLeft: 1,
      paddingRight: 1,
      paddingTop: 1,
    },
  })

  mainContainer.add(scrollBox)

  syntaxStyle = SyntaxStyle.fromStyles({
    string: { fg: parseColor("#A5D6FF") },
    number: { fg: parseColor("#79C0FF") },
    boolean: { fg: parseColor("#79C0FF") },
    keyword: { fg: parseColor("#FF7B72") },
    default: { fg: parseColor("#E6EDF3") },
  })

  addEvent("capabilities", renderer.capabilities)

  renderer.addInputHandler((sequence) => {
    addEvent("raw-input-after", { sequence })
    return true
  })

  renderer.keyInput.on("keypress", (event) => {
    addEvent("keypress", event)

    if (event.name === "c" && event.shift) {
      if (renderer) {
        addEvent("capabilities", renderer.capabilities)
      }
    }
  })

  renderer.keyInput.on("keyrelease", (event) => {
    addEvent("keyrelease", event)
  })

  renderer.keyInput.on("paste", (event) => {
    addEvent("paste", event)
  })

  renderer.requestRender()
}

main().catch((err) => {
  console.error("Error:", err)
  process.exit(1)
})


================================================
FILE: packages/core/dev/keypress-debug.ts
================================================
#!/usr/bin/env bun
import { parseKeypress } from "../src/lib/parse.keypress.ts"

console.log("Keypress Debug Tool")
console.log("Press keys to see their parsed output. Press Ctrl+C to exit.\n")

// Set stdin to raw mode to capture individual keypresses
process.stdin.setRawMode(true)
process.stdin.resume()

// Listen for keypress data
process.stdin.on("data", (data: Buffer) => {
  // Check for Ctrl+C to exit
  if (data.toString() === "\x03") {
    console.log("\nExiting keypress debug tool...")
    process.stdin.setRawMode(false)
    process.exit(0)
  }

  const parsed = parseKeypress(data)

  console.log("Input data:", JSON.stringify(data.toString()))
  console.log("Raw:", JSON.stringify(parsed?.raw))
  console.log("Parsed:", {
    name: parsed?.name,
    ctrl: parsed?.ctrl,
    meta: parsed?.meta,
    shift: parsed?.shift,
    option: parsed?.option,
    number: parsed?.number,
    sequence: parsed?.sequence,
    code: parsed?.code,
    buffer: data,
  })
  console.log("---")
})

// Handle Ctrl+C gracefully
process.on("SIGINT", () => {
  console.log("\nExiting keypress debug tool...")
  process.stdin.setRawMode(false)
  process.exit(0)
})


================================================
FILE: packages/core/dev/print-env-vars.ts
================================================
#!/usr/bin/env bun

/**
 * Development script to print all registered environment variables
 *
 * Usage:
 *   bun dev/print-env-vars.ts          # Colored output (default)
 *   bun dev/print-env-vars.ts --markdown  # Markdown output
 *   bun dev/print-env-vars.ts --update   # Update docs/env-vars.md
 */

import { generateEnvColored, generateEnvMarkdown } from "../src/index.js"
import { join } from "path"

const args = process.argv.slice(2)
const useMarkdown = args.includes("--markdown")
const updateDocs = args.includes("--update")

const generateMarkdownContent = () => {
  return `# Environment Variables\n\n${generateEnvMarkdown()}---\n\n_generated via packages/core/dev/print-env-vars.ts_\n`
}

if (updateDocs) {
  const docsPath = join(import.meta.dir, "../docs/env-vars.md")
  const content = generateMarkdownContent()
  await Bun.write(docsPath, content)
  console.log(`✓ Updated ${docsPath}`)
} else if (useMarkdown) {
  console.log(`${generateEnvMarkdown()}\n---\n_generated via packages/core/dev/print-env-vars.ts_`)
} else {
  console.log(generateEnvColored())
}


================================================
FILE: packages/core/dev/test-tmux-graphics-334.sh
================================================
#!/bin/bash
# Test script for issue #334: Kitty Graphics Protocol query leaks into tmux pane title
#
# This script verifies that the kitty graphics query doesn't corrupt tmux pane titles.
# Run this inside tmux to test.
#
# Usage: ./test-tmux-graphics-334.sh
#
# Expected results:
#   - Test 1 (Direct query): FAIL - demonstrates the bug
#   - Test 2 (DCS passthrough): PASS - demonstrates the fix
#   - Test 3 (No query): PASS - control test

set -e

SESSION_NAME="opentui-test-334-$$"
EXPECTED_TITLE="test-title"

cleanup() {
    tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
}
trap cleanup EXIT

run_test() {
    local test_name="$1"
    local query_cmd="$2"
    
    cleanup
    tmux new-session -d -s "$SESSION_NAME" -x 80 -y 24
    tmux select-pane -t "$SESSION_NAME" -T "$EXPECTED_TITLE"
    
    if [ -n "$query_cmd" ]; then
        tmux send-keys -t "$SESSION_NAME" "$query_cmd" Enter
        sleep 0.5
    fi
    
    local after_title
    after_title=$(tmux display-message -t "$SESSION_NAME" -p '#{pane_title}')
    
    if [[ "$after_title" == *"Gi=31337"* ]] || [[ "$after_title" == *"i=31337"* ]]; then
        echo "FAIL: $test_name - pane title corrupted: '$after_title'"
        return 1
    elif [[ "$after_title" != "$EXPECTED_TITLE" ]]; then
        echo "WARN: $test_name - pane title changed: '$after_title'"
        return 1
    else
        echo "PASS: $test_name"
        return 0
    fi
}

echo "=== Issue #334 Test: Kitty Graphics Query in tmux ==="
echo "tmux version: $(tmux -V)"
echo ""

echo "Test 1: Direct query (demonstrates bug)"
run_test "Direct kitty graphics query" \
    "printf '\\x1b_Gi=31337,s=1,v=1,a=q,t=d,f=24;AAAA\\x1b\\\\\\x1b[c'" || true

echo "Test 2: DCS passthrough wrapped query (demonstrates fix)"
run_test "DCS passthrough wrapped" \
    "printf '\\x1bPtmux;\\x1b\\x1b_Gi=31337,s=1,v=1,a=q,t=d,f=24;AAAA\\x1b\\x1b\\\\\\x1b\\x1b[c\\x1b\\\\'"

echo "Test 3: No query (control)"
run_test "No query" ""

echo ""
echo "If Test 1 fails and Test 2 passes, the fix is working correctly."


================================================
FILE: packages/core/dev/thai-debug-test.ts
================================================
#!/usr/bin/env bun
import { TextRenderable, createCliRenderer } from "../src/index.js"
import { ScrollBoxRenderable } from "../src/renderables/ScrollBox.js"
async function main() {
  const renderer = await createCliRenderer({ exitOnCtrlC: true })
  console.log("capabilities:", renderer.capabilities)
  const scrollBox = new ScrollBoxRenderable(renderer, {
    id: "scroll-box",
    border: true,
    height: 20,
    title: "Thai Render Debug (Up/Down to scroll, Ctrl+C to exit)",
    titleAlignment: "center",
  })
  const thaiLorem = `ภาษาไทยเป็นภาษาที่มีความสวยงามและซับซ้อนมาก มีพยัญชนะ 44 ตัว สระ 32 รูป และวรรณยุกต์ 4 รูป
มอญเป็นชนชาติที่มีอิทธิพลต่อภาษาไทยมาก คำว่า "มอ" เป็นพยัญชนะที่ใช้บ่อยในภาษาไทย
ตัวอย่างคำที่มี มอ: มา มี มือ มอง มัว มอบ มวย มอม มอด มอก
การเขียนภาษาไทยต้องใส่ใจเรื่องวรรณยุกต์ เช่น ม่า ม้า หม่า หม้า
สระลอยและสระเปลี่ยนรูปทำให้ภาษาไทยมีความพิเศษ เช่น เมือง แมว ไม้ ใหม่
คำผสมที่น่าสนใจ: มอมแมม มอดมอด มอมเมา มืดมอม มอมดำ
ภาษาไทยมีระบบการเขียนที่ไม่เว้นวรรคระหว่างคำ ทำให้การอ่านต้องอาศัยความเข้าใจ
ตัวอักษรไทยมีสามระดับ: บน กลาง ล่าง เช่น ก็ ปี่ ฎุ ฏู ญ ฐ ฑ
วรรณยุกต์ไทยมี 5 เสียง: สามัญ เอก โท ตรี จัตวา
ตัวอย่างเสียงวรรณยุกต์: มา ม่า ม้า หมา หม่า หม้า
การสะกดคำในภาษาไทยมีกฎเกณฑ์ที่ซับซ้อน มีทั้งตัวสะกดมาตราแม่ ก กา และตัวสะกดไม่ตรงมาตรา
คำยืมจากภาษาบาลีสันสกฤต: กรรม ธรรม สงฆ์ ศาสนา พระ มหา
คำยืมจากภาษาเขมร: ถนน เสวย ขนม ตำรวจ ทหาร
คำยืมจากภาษาจีน: ก๋วยเตี๋ยว เต้าหู้ บะหมี่ เกี๊ยว ซาลาเปา
ภาษาไทยถิ่นมีหลายภาษา: ภาษาเหนือ ภาษาอีสาน ภาษาใต้ ภาษากลาง
มอญกับไทยมีความสัมพันธ์ทางวัฒนธรรมมายาวนาน
ตัวเลขไทย: ๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙
เครื่องหมายวรรคตอน: ฯ ๆ ฯลฯ « » ๏
อักษรไทยมีต้นกำเนิดจากอักษรเขมร ซึ่งมาจากอักษรปัลลวะของอินเดียใต้
พ่อขุนรามคำแหงมหาราชทรงประดิษฐ์อักษรไทยเมื่อ พ.ศ. 1826
ภาษาไทยเป็นภาษาที่มีวรรณยุกต์ การออกเสียงผิดวรรณยุกต์ทำให้ความหมายเปลี่ยน
ตัวอย่าง: ขาว (สีขาว) ข่าว (news) ข้าว (rice) เข้า (enter)
มอเตอร์ไซค์ มอนิเตอร์ มอลต์ มอร์ฟีน เป็นคำทับศัพท์ที่มี มอ
สำนวนไทยที่มี มอ: มอมเมา หมอมหมาม มืดมอม มอดไหม้
คำกริยาที่มี มอ: มอง มอบ มอม มอด มอก
คำนามที่มี มอ: มอญ มอด หมอ มอเตอร์
การผันวรรณยุกต์ของ มอ: มอ ม่อ ม้อ หมอ หม่อ หม้อ
ภาษาไทยมีคำควบกล้ำ: กร กล กว ขร ขล ขว คร คล คว
ตัวอย่างคำควบกล้ำ: กราบ กลาง กวาง ครู คลอง ความ
อักษรสูง กลาง ต่ำ มีผลต่อการผันวรรณยุกต์
อักษรสูง: ข ฃ ฉ ฐ ถ ผ ฝ ศ ษ ส ห
อักษรกลาง: ก จ ฎ ฏ ด ต บ ป อ
อักษรต่ำ: ค ฅ ฆ ง ช ซ ฌ ญ ฑ ฒ ณ ท ธ น พ ฟ ภ ม ย ร ล ว ฬ ฮ`
  const text = new TextRenderable(renderer, {
    id: "thai-text",
    content: thaiLorem,
  })
  scrollBox.add(text)
  renderer.root.add(scrollBox)
  renderer.keyInput.on("keypress", (event) => {
    if (event.name === "down") scrollBox.scrollDown()
    if (event.name === "up") scrollBox.scrollUp()
  })
  renderer.requestRender()

  renderer.keyInput.on("keypress", (event) => {
    if (event.name === "`") {
      renderer.console.toggle()
    }
  })
}
main().catch((err) => {
  console.error("Error:", err)
  process.exit(1)
})


================================================
FILE: packages/core/docs/development.md
================================================
# Development Guide

## Prerequisites

- [Bun](https://bun.sh) - JavaScript runtime and package manager
- [Zig](https://ziglang.org/learn/getting-started/) - Required for building native modules

## Setup

```bash
git clone https://github.com/anomalyco/opentui.git
cd opentui
bun install
```

## Building

```bash
bun run build
```

**Note:** Only needed when changing native Zig code. TypeScript changes don't require rebuilding.

## Running Examples

```bash
cd packages/core
bun run src/examples/index.ts
```

## Testing

```bash
# TypeScript tests
cd packages/core
bun test

# Native tests
bun run test:native

# Filter native tests
bun run test:native -Dtest-filter="test name"

# Benchmarks
bun run bench:native
```

## Local Development Linking

Link your local OpenTUI to another project:

```bash
./scripts/link-opentui-dev.sh /path/to/your/project
```

**Options:**

- `--react` - Also link `@opentui/react` and React dependencies
- `--solid` - Also link `@opentui/solid` and SolidJS dependencies
- `--dist` - Link built `dist` directories instead of source
- `--copy` - Copy instead of symlink (requires `--dist`)
- `--subdeps` - Find and link packages that depend on opentui (e.g., `opentui-spinner`)

**Examples:**

```bash
# Link core only
./scripts/link-opentui-dev.sh /path/to/your/project

# Link core and solid with subdependency discovery
./scripts/link-opentui-dev.sh /path/to/your/project --solid --subdeps

# Link built artifacts
./scripts/link-opentui-dev.sh /path/to/your/project --react --dist

# Copy for Docker/Windows
./scripts/link-opentui-dev.sh /path/to/your/project --dist --copy
```

The script automatically links:

- Main packages: `@opentui/core`, `@opentui/solid`, `@opentui/react`
- Peer dependencies: `yoga-layout`, `solid-js`, `react`, `react-dom`, `react-reconciler`
- Subdependencies (with `--subdeps`): Packages like `opentui-spinner` that depend on opentui

**Requirements:** Target project must have `node_modules` (run `bun install` first).

## Debugging

OpenTUI captures `console.log` output. Toggle the built-in console with backtick or use [Environment Variables](./env-vars.md) for debugging.

## Terminal Compatibility

### OSC 66 Artifacts on Older Terminals

**Problem:** If you see weird artifacts containing "66" in your terminal when running OpenTUI applications, your terminal emulator doesn't support OSC 66 escape sequences (used for explicit character width detection).

**Affected Terminals:**

- GNOME Terminal
- Konsole (older versions)
- xterm (older versions)
- Many VT100/VT220 emulators

**Solution:** Disable OSC 66 queries by setting an environment variable:

```bash
export OPENTUI_FORCE_EXPLICIT_WIDTH=false
```

Or run your application with:

```bash
OPENTUI_FORCE_EXPLICIT_WIDTH=false your-app
```

**For Application Developers:**

Set it in your code before creating the renderer:

```typescript
process.env.OPENTUI_FORCE_EXPLICIT_WIDTH = "false"

const renderer = new CliRenderer()
// ... rest of your app
```

Or add to your `.env` file:

```bash
OPENTUI_FORCE_EXPLICIT_WIDTH=false
```

**What This Does:**

- Prevents OSC 66 detection queries from being sent
- Disables the explicit width feature
- Falls back to standard width calculation
- No visual artifacts on unsupported terminals

**Modern Terminals:** If your terminal supports OSC 66 (Kitty, Ghostty, WezTerm, Alacritty, iTerm2), you don't need this setting - they work correctly by default.


================================================
FILE: packages/core/package.json
================================================
{
  "name": "@opentui/core",
  "description": "OpenTUI is a TypeScript library on a native Zig core for building terminal user interfaces (TUIs)",
  "repository": {
    "type": "git",
    "url": "https://github.com/anomalyco/opentui",
    "directory": "packages/core"
  },
  "types": "src/index.ts",
  "module": "src/index.ts",
  "main": "src/index.ts",
  "version": "0.1.90",
  "type": "module",
  "scripts": {
    "build": "bun run build:native && bun run build:lib",
    "build:dev": "bun run build:native:dev && bun run build:lib",
    "build:lib": "bun scripts/build.ts --lib",
    "build:native": "bun scripts/build.ts --native",
    "build:native:dev": "bun scripts/build.ts --native --dev",
    "build:examples": "bun src/examples/build.ts",
    "test:native": "cd src/zig && zig build test --summary all",
    "bench:native": "cd src/zig && zig build bench -Dbench-optimize=ReleaseFast --",
    "bench:text-table": "bun src/benchmark/text-table-benchmark.ts",
    "bench:ts": "bun src/benchmark/native-span-feed-benchmark.ts --suite=quick --json=src/benchmark/latest-quick-bench-run.json && bun src/benchmark/native-span-feed-benchmark.ts --suite=default --json=src/benchmark/latest-default-bench-run.json && bun src/benchmark/native-span-feed-benchmark.ts --suite=large --json=src/benchmark/latest-large-bench-run.json && bun src/benchmark/native-span-feed-benchmark.ts --suite=all --json=src/benchmark/latest-all-bench-run.json && bun src/benchmark/native-span-feed-async-benchmark.ts --json=src/benchmark/latest-async-bench-run.json",
    "publish": "bun scripts/publish.ts",
    "test:js": "bun test",
    "test": "bun run test:native && bun run test:js"
  },
  "license": "MIT",
  "devDependencies": {
    "@types/bun": "latest",
    "@types/node": "^24.0.0",
    "@types/three": "0.177.0",
    "commander": "^13.1.0",
    "typescript": "^5",
    "web-tree-sitter": "0.25.10"
  },
  "dependencies": {
    "bun-ffi-structs": "0.1.2",
    "diff": "8.0.2",
    "jimp": "1.6.0",
    "marked": "17.0.1",
    "yoga-layout": "3.2.1"
  },
  "peerDependencies": {
    "web-tree-sitter": "0.25.10"
  },
  "optionalDependencies": {
    "@dimforge/rapier2d-simd-compat": "^0.17.3",
    "bun-webgpu": "0.1.5",
    "planck": "^1.4.2",
    "three": "0.177.0",
    "@opentui/core-darwin-x64": "0.1.90",
    "@opentui/core-darwin-arm64": "0.1.90",
    "@opentui/core-linux-x64": "0.1.90",
    "@opentui/core-linux-arm64": "0.1.90",
    "@opentui/core-win32-x64": "0.1.90",
    "@opentui/core-win32-arm64": "0.1.90"
  },
  "exports": {
    ".": {
      "types": "./src/index.ts",
      "import": "./src/index.ts"
    },
    "./3d": {
      "types": "./src/3d.ts",
      "import": "./src/3d.ts"
    },
    "./testing": {
      "types": "./src/testing.ts",
      "import": "./src/testing.ts"
    },
    "./runtime-plugin": {
      "types": "./src/runtime-plugin.ts",
      "import": "./src/runtime-plugin.ts"
    },
    "./runtime-plugin-support": {
      "types": "./src/runtime-plugin-support.ts",
      "import": "./src/runtime-plugin-support.ts"
    },
    "./parser.worker": {
      "types": "./src/lib/tree-sitter/parser.worker.ts",
      "import": "./src/lib/tree-sitter/parser.worker.ts"
    }
  },
  "engines": {
    "bun": ">=1.3.0"
  }
}


================================================
FILE: packages/core/scripts/build.ts
================================================
import { spawnSync, type SpawnSyncReturns } from "node:child_process"
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs"
import { dirname, join, resolve } from "path"
import { fileURLToPath } from "url"
import process from "process"
import path from "path"

interface Variant {
  platform: string
  arch: string
}

interface PackageJson {
  name: string
  version: string
  license?: string
  repository?: any
  description?: string
  homepage?: string
  author?: string
  bugs?: any
  keywords?: string[]
  module?: string
  main?: string
  types?: string
  type?: string
  dependencies?: Record<string, string>
  devDependencies?: Record<string, string>
  optionalDependencies?: Record<string, string>
  peerDependencies?: Record<string, string>
}

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const rootDir = resolve(__dirname, "..")
const licensePath = path.resolve(__dirname, "../../../LICENSE")
const packageJson: PackageJson = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"))

const args = process.argv.slice(2)
const buildLib = args.find((arg) => arg === "--lib")
const buildNative = args.find((arg) => arg === "--native")
const isDev = args.includes("--dev")
const buildAll = args.includes("--all") // Build for all platforms
const gpaSafeStats = args.includes("--gpa-safe-stats")

const variants: Variant[] = [
  { platform: "darwin", arch: "x64" },
  { platform: "darwin", arch: "arm64" },
  { platform: "linux", arch: "x64" },
  { platform: "linux", arch: "arm64" },
  { platform: "win32", arch: "x64" },
  { platform: "win32", arch: "arm64" },
]

if (!buildLib && !buildNative) {
  console.error("Error: Please specify --lib, --native, or both")
  process.exit(1)
}

const getZigTarget = (platform: string, arch: string): string => {
  const platformMap: Record<string, string> = { darwin: "macos", win32: "windows", linux: "linux" }
  const archMap: Record<string, string> = { x64: "x86_64", arm64: "aarch64" }
  return `${archMap[arch] ?? arch}-${platformMap[platform] ?? platform}`
}

const replaceLinks = (text: string): string => {
  return packageJson.homepage
    ? text.replace(
        /(\[.*?\]\()(\.\/.*?\))/g,
        (_, p1: string, p2: string) => `${p1}${packageJson.homepage}/blob/HEAD/${p2.replace("./", "")}`,
      )
    : text
}

const requiredFields: (keyof PackageJson)[] = ["name", "version", "license", "repository", "description"]
const missingRequired = requiredFields.filter((field) => !packageJson[field])
if (missingRequired.length > 0) {
  console.error(`Error: Missing required fields in package.json: ${missingRequired.join(", ")}`)
  process.exit(1)
}

if (buildNative) {
  console.log(`Building native ${isDev ? "dev" : "prod"} binaries${buildAll ? " for all platforms" : ""}...`)

  const zigArgs = ["build", `-Doptimize=${isDev ? "Debug" : "ReleaseFast"}`]
  if (buildAll) {
    zigArgs.push("-Dall")
  }
  if (gpaSafeStats) {
    zigArgs.push("-Dgpa-safe-stats=true")
  }

  const zigBuild: SpawnSyncReturns<Buffer> = spawnSync("zig", zigArgs, {
    cwd: join(rootDir, "src", "zig"),
    stdio: "inherit",
  })

  if (zigBuild.error) {
    console.error("Error: Zig is not installed or not in PATH")
    process.exit(1)
  }

  if (zigBuild.status !== 0) {
    console.error("Error: Zig build failed")
    process.exit(1)
  }

  for (const { platform, arch } of variants) {
    const nativeName = `${packageJson.name}-${platform}-${arch}`
    const nativeDir = join(rootDir, "node_modules", nativeName)
    const libDir = join(rootDir, "src", "zig", "lib", getZigTarget(platform, arch))

    rmSync(nativeDir, { recursive: true, force: true })
    mkdirSync(nativeDir, { recursive: true })

    let copiedFiles = 0
    let libraryFileName: string | null = null
    for (const name of ["libopentui", "opentui"]) {
      for (const ext of [".so", ".dll", ".dylib"]) {
        const src = join(libDir, `${name}${ext}`)
        if (existsSync(src)) {
          const fileName = `${name}${ext}`
          copyFileSync(src, join(nativeDir, fileName))
          copiedFiles++
          if (!libraryFileName) {
            libraryFileName = fileName
          }
        }
      }
    }

    if (copiedFiles === 0) {
      // Skip platforms that weren't built
      console.log(`Skipping ${platform}-${arch}: no libraries found`)
      rmSync(nativeDir, { recursive: true, force: true })
      continue
    }

    const indexTsContent = `const module = await import("./${libraryFileName}", { with: { type: "file" } })
const path = module.default
export default path;
`
    writeFileSync(join(nativeDir, "index.ts"), indexTsContent)

    writeFileSync(
      join(nativeDir, "package.json"),
      JSON.stringify(
        {
          name: nativeName,
          version: packageJson.version,
          description: `Prebuilt ${platform}-${arch} binaries for ${packageJson.name}`,
          main: "index.ts",
          types: "index.ts",
          license: packageJson.license,
          author: packageJson.author,
          homepage: packageJson.homepage,
          repository: packageJson.repository,
          bugs: packageJson.bugs,
          keywords: [...(packageJson.keywords ?? []), "prebuild", "prebuilt"],
          os: [platform],
          cpu: [arch],
        },
        null,
        2,
      ),
    )

    writeFileSync(
      join(nativeDir, "README.md"),
      replaceLinks(`## ${nativeName}\n\n> Prebuilt ${platform}-${arch} binaries for \`${packageJson.name}\`.`),
    )

    if (existsSync(licensePath)) copyFileSync(licensePath, join(nativeDir, "LICENSE"))
    console.log("Built:", nativeName)
  }
}

if (buildLib) {
  console.log("Building library...")

  const distDir = join(rootDir, "dist")
  rmSync(distDir, { recursive: true, force: true })
  mkdirSync(distDir, { recursive: true })

  const externalDeps: string[] = [
    ...Object.keys(packageJson.optionalDependencies || {}),
    ...Object.keys(packageJson.peerDependencies || {}),
  ]

  // Build main entry point
  if (!packageJson.module) {
    console.error("Error: 'module' field not found in package.json")
    process.exit(1)
  }

  const entryPoints: string[] = [
    packageJson.module,
    "src/3d.ts",
    "src/testing.ts",
    "src/runtime-plugin.ts",
    "src/runtime-plugin-support.ts",
  ]

  // Build main entry points with code splitting
  // External patterns to prevent bundling tree-sitter assets and default-parsers
  // to allow standalone executables to work
  const externalPatterns = [
    ...externalDeps,
    "*.wasm",
    "*.scm",
    "./lib/tree-sitter/assets/*",
    "./lib/tree-sitter/default-parsers",
    "./lib/tree-sitter/default-parsers.ts",
  ]

  spawnSync(
    "bun",
    [
      "build",
      "--target=bun",
      "--splitting",
      "--outdir=dist",
      "--sourcemap",
      ...externalPatterns.flatMap((dep) => ["--external", dep]),
      ...entryPoints,
    ],
    {
      cwd: rootDir,
      stdio: "inherit",
    },
  )

  // Build parser worker as standalone bundle (no splitting) so it can be loaded as a Worker
  // Make web-tree-sitter external so it loads from node_modules with its WASM file
  spawnSync(
    "bun",
    [
      "build",
      "--target=bun",
      "--outdir=dist",
      "--sourcemap",
      ...externalDeps.flatMap((dep) => ["--external", dep]),
      "--external",
      "web-tree-sitter",
      "src/lib/tree-sitter/parser.worker.ts",
    ],
    {
      cwd: rootDir,
      stdio: "inherit",
    },
  )

  // Post-process to fix Bun's duplicate export issue
  // See: https://github.com/oven-sh/bun/issues/5344
  // and: https://github.com/oven-sh/bun/issues/10631
  console.log("Post-processing bundled files to fix duplicate exports...")
  const bundledFiles = [
    "dist/index.js",
    "dist/3d.js",
    "dist/testing.js",
    "dist/runtime-plugin.js",
    "dist/runtime-plugin-support.js",
    "dist/lib/tree-sitter/parser.worker.js",
  ]
  for (const filePath of bundledFiles) {
    const fullPath = join(rootDir, filePath)
    if (existsSync(fullPath)) {
      let content = readFileSync(fullPath, "utf8")
      const helperExportPattern = /^export\s*\{([^}]*(?:__toESM|__commonJS|__export|__require)[^}]*)\};\s*$/gm

      let modified = false
      content = content.replace(helperExportPattern, (match, exports) => {
        const exportsList = exports.split(",").map((e: string) => e.trim())
        const helpers = ["__toESM", "__commonJS", "__export", "__require"]
        const nonHelpers = exportsList.filter((e: string) => !helpers.includes(e))

        if (nonHelpers.length > 0) {
          modified = true
          const helperExports = exportsList.filter((e: string) => helpers.includes(e))
          return `export { ${helperExports.join(", ")} };`
        }
        return match
      })

      if (modified) {
        writeFileSync(fullPath, content)
        console.log(`  Fixed duplicate exports in ${filePath}`)
      }
    }
  }

  console.log("Generating TypeScript declarations...")

  const tsconfigBuildPath = join(rootDir, "tsconfig.build.json")

  const tscResult: SpawnSyncReturns<Buffer> = spawnSync("bunx", ["tsc", "-p", tsconfigBuildPath], {
    cwd: rootDir,
    stdio: "inherit",
  })

  if (tscResult.status !== 0) {
    console.error("Error: TypeScript declaration generation failed")
    process.exit(1)
  } else {
    console.log("TypeScript declarations generated")
  }

  const treeSitterSrcDir = join(rootDir, "src", "lib", "tree-sitter")

  const copyAssets = (src: string, dest: string) => {
    mkdirSync(dest, { recursive: true })
    const entries = readdirSync(src, { withFileTypes: true })
    for (const entry of entries) {
      const srcPath = join(src, entry.name)
      const destPath = join(dest, entry.name)
      if (entry.isDirectory()) {
        copyAssets(srcPath, destPath)
      } else if (entry.isFile() && (entry.name.endsWith(".wasm") || entry.name.endsWith(".scm"))) {
        copyFileSync(srcPath, destPath)
      }
    }
  }

  copyAssets(join(treeSitterSrcDir, "assets"), join(distDir, "assets"))
  console.log("  Copied tree-sitter assets (*.wasm, *.scm) to dist/assets/")

  // Configure exports for multiple entry points
  const exports = {
    ".": {
      import: "./index.js",
      require: "./index.js",
      types: "./index.d.ts",
    },
    "./3d": {
      import: "./3d.js",
      require: "./3d.js",
      types: "./3d.d.ts",
    },
    "./testing": {
      import: "./testing.js",
      require: "./testing.js",
      types: "./testing.d.ts",
    },
    "./runtime-plugin": {
      import: "./runtime-plugin.js",
      require: "./runtime-plugin.js",
      types: "./runtime-plugin.d.ts",
    },
    "./runtime-plugin-support": {
      import: "./runtime-plugin-support.js",
      require: "./runtime-plugin-support.js",
      types: "./runtime-plugin-support.d.ts",
    },
    "./parser.worker": {
      import: "./lib/tree-sitter/parser.worker.js",
      require: "./lib/tree-sitter/parser.worker.js",
      types: "./lib/tree-sitter/parser.worker.d.ts",
    },
  }

  const optionalDeps: Record<string, string> = Object.fromEntries(
    variants.map(({ platform, arch }) => [`${packageJson.name}-${platform}-${arch}`, packageJson.version]),
  )

  writeFileSync(
    join(distDir, "package.json"),
    JSON.stringify(
      {
        name: packageJson.name,
        module: "index.js",
        main: "index.js",
        types: "index.d.ts",
        type: packageJson.type,
        version: packageJson.version,
        description: packageJson.description,
        keywords: packageJson.keywords,
        license: packageJson.license,
        author: packageJson.author,
        homepage: packageJson.homepage,
        repository: packageJson.repository,
        bugs: packageJson.bugs,
        exports,
        dependencies: packageJson.dependencies,
        devDependencies: packageJson.devDependencies,
        peerDependencies: packageJson.peerDependencies,
        optionalDependencies: {
          ...packageJson.optionalDependencies,
          ...optionalDeps,
        },
      },
      null,
      2,
    ),
  )

  writeFileSync(join(distDir, "README.md"), replaceLinks(readFileSync(join(rootDir, "README.md"), "utf8")))
  if (existsSync(licensePath)) copyFileSync(licensePath, join(distDir, "LICENSE"))

  console.log("Library built at:", distDir)
}


================================================
FILE: packages/core/scripts/publish.ts
================================================
import { spawnSync, type SpawnSyncReturns } from "node:child_process"
import { existsSync, readFileSync } from "node:fs"
import { dirname, join, resolve } from "node:path"
import process from "node:process"
import { fileURLToPath } from "node:url"

interface PackageJson {
  name: string
  version: string
  optionalDependencies?: Record<string, string>
}

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const rootDir = resolve(__dirname, "..")

const packageJson: PackageJson = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"))

console.log(`Publishing @opentui/core@${packageJson.version}...`)
console.log("Make sure you've run the pre-publish validation script first!")

const libDir = join(rootDir, "dist")
const packageJsons: Record<string, PackageJson> = {
  [libDir]: JSON.parse(readFileSync(join(libDir, "package.json"), "utf8")),
}

// Load all native package.json files
for (const pkgName of Object.keys(packageJsons[libDir].optionalDependencies!).filter((x) =>
  x.startsWith(packageJson.name),
)) {
  const nativeDir = join(rootDir, "node_modules", pkgName)
  packageJsons[nativeDir] = JSON.parse(readFileSync(join(nativeDir, "package.json"), "utf8"))
}

// Publish all packages (main + native packages)
Object.entries(packageJsons).forEach(([dir, { name, version }]) => {
  console.log(`\nPublishing ${name}@${version}...`)

  const isSnapshot = version.includes("-snapshot") || /^0\.0\.0-\d{8}-[a-f0-9]{8}$/.test(version)
  const publishArgs = ["publish", "--access=public"]

  if (isSnapshot) {
    publishArgs.push("--tag", "snapshot")
    console.log(`  Publishing as snapshot (--tag snapshot)`)
  }

  const publish: SpawnSyncReturns<Buffer> = spawnSync("npm", publishArgs, {
    cwd: dir,
    stdio: "inherit",
  })

  if (publish.status !== 0) {
    console.error(`Failed to publish '${name}@${version}'.`)
    process.exit(1)
  }

  console.log(`Successfully published '${name}@${version}'`)
})

console.log(`\nAll @opentui/core packages published successfully!`)


================================================
FILE: packages/core/src/3d/SpriteResourceManager.ts
================================================
import * as THREE from "three"
import { TextureUtils } from "./TextureUtils.js"
import type { Scene } from "three"

export interface ResourceConfig {
  imagePath: string
  sheetNumFrames: number
}

export interface SheetProperties {
  imagePath: string
  sheetTilesetWidth: number
  sheetTilesetHeight: number
  sheetNumFrames: number
}

export interface InstanceManagerOptions {
  maxInstances: number
  renderOrder?: number
  depthWrite?: boolean
  name?: string
  frustumCulled?: boolean
  matrix?: THREE.Matrix4
}

export interface MeshPoolOptions {
  geometry: () => THREE.BufferGeometry
  material: THREE.Material
  maxInstances: number
  name?: string
}

const HIDDEN_MATRIX = new THREE.Matrix4().scale(new THREE.Vector3(0, 0, 0))

export class MeshPool {
  private pools: Map<string, THREE.InstancedMesh[]> = new Map()

  public acquireMesh(poolId: string, options: MeshPoolOptions): THREE.InstancedMesh {
    const poolArray = this.pools.get(poolId) ?? []
    this.pools.set(poolId, poolArray)

    if (poolArray.length > 0) {
      const mesh = poolArray.pop()!
      mesh.material = options.material
      mesh.count = options.maxInstances
      return mesh
    }

    const mesh = new THREE.InstancedMesh(options.geometry(), options.material, options.maxInstances)

    if (options.name) {
      mesh.name = options.name
    }

    return mesh
  }

  public releaseMesh(poolId: string, mesh: THREE.InstancedMesh): void {
    const poolArray = this.pools.get(poolId) ?? []
    poolArray.push(mesh)
    this.pools.set(poolId, poolArray)
  }

  public fill(poolId: string, options: MeshPoolOptions, count: number): void {
    const poolArray = this.pools.get(poolId) ?? []
    this.pools.set(poolId, poolArray)

    for (let i = 0; i < count; i++) {
      const mesh = new THREE.InstancedMesh(options.geometry(), options.material, options.maxInstances)

      if (options.name) {
        mesh.name = `${options.name}_${i}`
      }

      poolArray.push(mesh)
    }
  }

  public clearPool(poolId: string): void {
    const poolArray = this.pools.get(poolId)
    if (poolArray) {
      poolArray.forEach((mesh) => {
        mesh.geometry.dispose()
        if (Array.isArray(mesh.material)) {
          mesh.material.forEach((mat) => mat.dispose())
        } else {
          mesh.material.dispose()
        }
      })
      poolArray.length = 0
    }
  }

  public clearAllPools(): void {
    for (const poolId of this.pools.keys()) {
      this.clearPool(poolId)
    }
    this.pools.clear()
  }
}

export class InstanceManager {
  private scene: Scene
  private instancedMesh: THREE.InstancedMesh
  private material: THREE.Material
  private maxInstances: number
  private _freeIndices: number[] = []
  private instanceCount: number = 0
  private _matrix: THREE.Matrix4

  constructor(scene: Scene, geometry: THREE.BufferGeometry, material: THREE.Material, options: InstanceManagerOptions) {
    this.scene = scene
    this.material = material
    this.maxInstances = options.maxInstances
    this._matrix = options.matrix ?? HIDDEN_MATRIX

    this.instancedMesh = new THREE.InstancedMesh(geometry, material, this.maxInstances)
    this.instancedMesh.renderOrder = options.renderOrder ?? 0
    this.instancedMesh.frustumCulled = options.frustumCulled ?? false
    this.instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage)

    if (options.name) {
      this.instancedMesh.name = options.name
    }

    for (let i = 0; i < this.maxInstances; i++) {
      this._freeIndices.push(i)
      this.instancedMesh.setMatrixAt(i, this._matrix)
    }
    this.instancedMesh.instanceMatrix.needsUpdate = true

    this.scene.add(this.instancedMesh)
  }

  acquireInstanceSlot(): number {
    if (this._freeIndices.length === 0) {
      throw new Error(`[InstanceManager] Max instances (${this.maxInstances}) reached. Cannot acquire slot.`)
    }
    const instanceIndex = this._freeIndices.pop()!
    this.instanceCount++
    return instanceIndex
  }

  releaseInstanceSlot(instanceIndex: number): void {
    if (instanceIndex >= 0 && instanceIndex < this.maxInstances) {
      this.instancedMesh.setMatrixAt(instanceIndex, this._matrix)
      this.instancedMesh.instanceMatrix.needsUpdate = true

      if (!this._freeIndices.includes(instanceIndex)) {
        this._freeIndices.push(instanceIndex)
        this._freeIndices.sort((a, b) => a - b)
        this.instanceCount--
      }
    } else {
      console.warn(`[InstanceManager] Attempted to release invalid instanceIndex ${instanceIndex}`)
    }
  }

  getInstanceCount(): number {
    return this.instanceCount
  }

  getMaxInstances(): number {
    return this.maxInstances
  }

  get hasFreeIndices(): boolean {
    return this._freeIndices.length > 0
  }

  get mesh(): THREE.InstancedMesh {
    return this.instancedMesh
  }

  dispose(): void {
    this.scene.remove(this.instancedMesh)
    this.instancedMesh.geometry.dispose()
    if (Array.isArray(this.material)) {
      this.material.forEach((mat) => mat.dispose())
    } else {
      this.material.dispose()
    }
  }
}

export class SpriteResource {
  private _texture: THREE.DataTexture
  private _sheetProperties: SheetProperties
  private scene: Scene
  private _meshPool: MeshPool

  constructor(texture: THREE.DataTexture, sheetProperties: SheetProperties, scene: Scene) {
    this._texture = texture
    this._sheetProperties = sheetProperties
    this.scene = scene
    this._meshPool = new MeshPool()
  }

  public get texture(): THREE.DataTexture {
    return this._texture
  }

  public get sheetProperties(): SheetProperties {
    return this._sheetProperties
  }

  public get meshPool(): MeshPool {
    return this._meshPool
  }

  public createInstanceManager(
    geometry: THREE.BufferGeometry,
    material: THREE.Material,
    options: InstanceManagerOptions,
  ): InstanceManager {
    const managerOptions = {
      ...options,
      name: options.name ?? `InstancedSprites_${this._sheetProperties.imagePath.replace(/[^a-zA-Z0-9_]/g, "_")}`,
    }

    return new InstanceManager(this.scene, geometry, material, managerOptions)
  }

  public get uvTileSize(): THREE.Vector2 {
    const uvTileWidth = 1.0 / this._sheetProperties.sheetNumFrames
    const uvTileHeight = 1.0
    return new THREE.Vector2(uvTileWidth, uvTileHeight)
  }

  public dispose(): void {
    this._meshPool.clearAllPools()
  }
}

export class SpriteResourceManager {
  private resources: Map<string, SpriteResource> = new Map()
  private textureCache: Map<string, THREE.DataTexture> = new Map()
  private scene: Scene

  constructor(scene: Scene) {
    this.scene = scene
  }

  private getResourceKey(sheetProps: SheetProperties): string {
    return sheetProps.imagePath
  }

  public async getOrCreateResource(texture: THREE.DataTexture, sheetProps: SheetProperties): Promise<SpriteResource> {
    const resourceKey = this.getResourceKey(sheetProps)
    let resource = this.resources.get(resourceKey)

    if (!resource) {
      resource = new SpriteResource(texture, sheetProps, this.scene)
      this.resources.set(resourceKey, resource)
    }

    return resource
  }

  public async createResource(config: ResourceConfig): Promise<SpriteResource> {
    let texture = this.textureCache.get(config.imagePath)
    if (!texture) {
      const loadedTexture = await TextureUtils.fromFile(config.imagePath)
      if (!loadedTexture) {
        throw new Error(`[SpriteResourceManager] Failed to load texture for ${config.imagePath}`)
      }
      loadedTexture.needsUpdate = true
      texture = loadedTexture
      this.textureCache.set(config.imagePath, texture)
    }

    const sheetProps: SheetProperties = {
      imagePath: config.imagePath,
      sheetTilesetWidth: texture.image.width,
      sheetTilesetHeight: texture.image.height,
      sheetNumFrames: config.sheetNumFrames,
    }

    return await this.getOrCreateResource(texture, sheetProps)
  }

  public clearCache(): void {
    this.resources.clear()
    this.textureCache.clear()
  }
}


================================================
FILE: packages/core/src/3d/SpriteUtils.ts
================================================
import { TextureUtils } from "./TextureUtils.js"
import { Sprite, SpriteMaterial, DataTexture, type SpriteMaterialParameters } from "three"

export class SheetSprite extends Sprite {
  private _frameIndex: number = 0
  private _numFrames: number = 0

  constructor(material: SpriteMaterial, numFrames: number) {
    super(material)
    this._numFrames = numFrames
    this.setIndex(0)
  }

  setIndex = (index: number) => {
    this._frameIndex = index
    this.material.map?.repeat.set(1 / this._numFrames, 1)
    this.material.map?.offset.set(this._frameIndex / this._numFrames, 0)
  }
}

export class SpriteUtils {
  static async fromFile(
    path: string,
    {
      materialParameters = {
        alphaTest: 0.1,
        depthWrite: true,
      },
    }: {
      materialParameters?: Omit<SpriteMaterialParameters, "map">
    } = {},
  ): Promise<Sprite> {
    const texture = await TextureUtils.fromFile(path)
    if (!texture) {
      throw new Error(`Failed to load sprite texture from ${path}`)
    }

    const spriteMaterial = new SpriteMaterial({ map: texture, ...materialParameters })
    const sprite = new Sprite(spriteMaterial)

    const textureAspectRatio = texture.image.width / texture.image.height

    sprite.updateMatrix = function () {
      this.matrix.compose(this.position, this.quaternion, this.scale.clone().setX(this.scale.x * textureAspectRatio))
    }

    return sprite
  }

  static async sheetFromFile(path: string, numFrames: number): Promise<SheetSprite> {
    const spriteTexture = await TextureUtils.fromFile(path)

    if (!spriteTexture) {
      console.error("Failed to load sprite texture, exiting.")
      process.exit(1)
    }

    const spriteMaterial = new SpriteMaterial({ map: spriteTexture })
    const sprite = new SheetSprite(spriteMaterial, numFrames)

    const singleFrameWidth = spriteTexture.image.width / numFrames
    const singleFrameHeight = spriteTexture.image.height
    const frameAspectRatio = singleFrameWidth / singleFrameHeight

    sprite.updateMatrix = function () {
      this.matrix.compose(this.position, this.quaternion, this.scale.clone().setX(this.scale.x * frameAspectRatio))
    }

    return sprite
  }
}


================================================
FILE: packages/core/src/3d/TextureUtils.ts
================================================
import { readFile } from "node:fs/promises"
import { Color, Texture, DataTexture, NearestFilter, ClampToEdgeWrapping, RGBAFormat, UnsignedByteType } from "three"
import { Jimp } from "jimp"

interface SimpleImageData {
  data: Uint8ClampedArray
  width: number
  height: number
}

// Utility class for loading and generating THREE.Texture instances
export class TextureUtils {
  /**
   * Loads a texture from a file path using sharp.
   * Returns a THREE.Texture with ImageData attached to its .image property.
   */
  static async loadTextureFromFile(path: string): Promise<DataTexture | null> {
    try {
      const buffer = await readFile(path)
      const image = await Jimp.read(buffer)

      image.flip({ horizontal: false, vertical: true })

      const texture = new DataTexture(
        image.bitmap.data,
        image.bitmap.width,
        image.bitmap.height,
        RGBAFormat,
        UnsignedByteType,
      )
      texture.needsUpdate = true
      texture.format = RGBAFormat
      texture.magFilter = NearestFilter
      texture.minFilter = NearestFilter
      texture.wrapS = ClampToEdgeWrapping
      texture.wrapT = ClampToEdgeWrapping
      texture.flipY = false // Usually true for webGL, but our sampler flips V

      return texture
    } catch (error) {
      console.error(`Failed to load texture from ${path}:`, error)
      return null
    }
  }

  /**
   * Alias for loadTextureFromFile for convenience.
   */
  static async fromFile(path: string): Promise<DataTexture | null> {
    return this.loadTextureFromFile(path)
  }

  /**
   * Creates a THREE.Texture with a checkerboard pattern.
   */
  static createCheckerboard(
    size: number = 256,
    color1: Color = new Color(1.0, 1.0, 1.0),
    color2: Color = new Color(0.0, 0.0, 0.0),
    checkSize: number = 32,
  ): Texture {
    const data = new Uint8ClampedArray(size * size * 4)

    for (let y = 0; y < size; y++) {
      for (let x = 0; x < size; x++) {
        const isEvenX = Math.floor(x / checkSize) % 2 === 0
        const isEvenY = Math.floor(y / checkSize) % 2 === 0
        const color = (isEvenX && isEvenY) || (!isEvenX && !isEvenY) ? color1 : color2

        const index = (y * size + x) * 4
        data[index] = Math.floor(color.r * 255)
        data[index + 1] = Math.floor(color.g * 255)
        data[index + 2] = Math.floor(color.b * 255)
        data[index + 3] = 255 // Alpha
      }
    }

    const imageData: SimpleImageData = { data, width: size, height: size }
    const texture = new DataTexture(data, size, size, RGBAFormat, UnsignedByteType)
    texture.needsUpdate = true
    texture.format = RGBAFormat
    texture.magFilter = NearestFilter
    texture.minFilter = NearestFilter
    texture.wrapS = ClampToEdgeWrapping
    texture.wrapT = ClampToEdgeWrapping
    texture.flipY = false

    return texture
  }

  /**
   * Creates a THREE.Texture with a gradient pattern.
   */
  static createGradient(
    size: number = 256,
    startColor: Color = new Color(1.0, 0.0, 0.0),
    endColor: Color = new Color(0.0, 0.0, 1.0),
    direction: "horizontal" | "vertical" | "radial" = "vertical",
  ): Texture {
    const data = new Uint8ClampedArray(size * size * 4)

    for (let y = 0; y < size; y++) {
      for (let x = 0; x < size; x++) {
        let t = 0

        if (direction === "horizontal") {
          t = x / (size - 1)
        } else if (direction === "vertical") {
          t = y / (size - 1)
        } else if (direction === "radial") {
          const dx = x - size / 2
          const dy = y - size / 2
          t = Math.min(1, Math.sqrt(dx * dx + dy * dy) / (size / 2))
        }

        const r = startColor.r * (1 - t) + endColor.r * t
        const g = startColor.g * (1 - t) + endColor.g * t
        const b = startColor.b * (1 - t) + endColor.b * t

        const index = (y * size + x) * 4
        data[index] = Math.floor(r * 255)
        data[index + 1] = Math.floor(g * 255)
        data[index + 2] = Math.floor(b * 255)
        data[index + 3] = 255 // Alpha
      }
    }

    const imageData: SimpleImageData = { data, width: size, height: size }
    const texture = new DataTexture(data, size, size, RGBAFormat, UnsignedByteType)
    texture.needsUpdate = true
    texture.format = RGBAFormat
    texture.magFilter = NearestFilter
    texture.minFilter = NearestFilter
    texture.wrapS = ClampToEdgeWrapping
    texture.wrapT = ClampToEdgeWrapping
    texture.flipY = false

    return texture
  }

  /**
   * Creates a THREE.Texture with a procedural noise pattern.
   */
  static createNoise(
    size: number = 256,
    scale: number = 1,
    octaves: number = 1,
    color1: Color = new Color(1.0, 1.0, 1.0),
    color2: Color = new Color(0.0, 0.0, 0.0),
  ): Texture {
    const data = new Uint8ClampedArray(size * size * 4)

    for (let y = 0; y < size; y++) {
      for (let x = 0; x < size; x++) {
        let noise = 0
        let amplitude = 1
        let frequency = 1

        for (let o = 0; o < octaves; o++) {
          const nx = (x * frequency * scale) / size
          const ny = (y * frequency * scale) / size
          const sampleX = Math.sin(nx * 12.9898) * 43758.5453
          const sampleY = Math.cos(ny * 78.233) * 43758.5453
          const sample = Math.sin(sampleX + sampleY) * 0.5 + 0.5
          noise += sample * amplitude
          amplitude *= 0.5
          frequency *= 2
        }

        noise = Math.min(1, Math.max(0, noise)) // Normalize

        const r = color1.r * noise + color2.r * (1 - noise)
        const g = color1.g * noise + color2.g * (1 - noise)
        const b = color1.b * noise + color2.b * (1 - noise)

        const index = (y * size + x) * 4
        data[index] = Math.floor(r * 255)
        data[index + 1] = Math.floor(g * 255)
        data[index + 2] = Math.floor(b * 255)
        data[index + 3] = 255 // Alpha
      }
    }

    const imageData: SimpleImageData = { data, width: size, height: size }
    const texture = new DataTexture(data, size, size, RGBAFormat, UnsignedByteType)
    texture.needsUpdate = true
    texture.format = RGBAFormat
    texture.magFilter = NearestFilter
    texture.minFilter = NearestFilter
    texture.wrapS = ClampToEdgeWrapping
    texture.wrapT = ClampToEdgeWrapping
    texture.flipY = false

    return texture
  }
}


================================================
FILE: packages/core/src/3d/ThreeRenderable.ts
================================================
import { OrthographicCamera, PerspectiveCamera, Scene } from "three"

import { OptimizedBuffer } from "../buffer.js"
import { RGBA } from "../lib/RGBA.js"
import { Renderable, type RenderableOptions } from "../Renderable.js"
import type { CliRenderer } from "../renderer.js"
import type { RenderContext } from "../types.js"
import { ThreeCliRenderer, type ThreeCliRendererOptions } from "./WGPURenderer.js"

export interface ThreeRenderableOptions extends RenderableOptions<ThreeRenderable> {
  scene?: Scene | null
  camera?: PerspectiveCamera | OrthographicCamera
  renderer?: Omit<ThreeCliRendererOptions, "width" | "height" | "autoResize">
  autoAspect?: boolean
}

export class ThreeRenderable extends Renderable {
  private engine: ThreeCliRenderer
  private scene: Scene | null
  private autoAspect: boolean
  private initPromise: Promise<boolean> | null = null
  private initFailed: boolean = false
  private drawInFlight: boolean = false
  private frameCallback: ((deltaTime: number) => Promise<void>) | null = null
  private frameCallbackRegistered: boolean = false
  private cliRenderer: CliRenderer
  private clearColor: RGBA

  constructor(ctx: RenderContext, options: ThreeRenderableOptions) {
    const { scene = null, camera, renderer, autoAspect = true, ...renderableOptions } = options
    super(ctx, { ...renderableOptions, buffered: true, live: options.live ?? true })

    const cliRenderer = ctx as CliRenderer
    if (typeof cliRenderer.setFrameCallback !== "function" || typeof cliRenderer.removeFrameCallback !== "function") {
      throw new Error("ThreeRenderable requires a CliRenderer context")
    }

    this.cliRenderer = cliRenderer
    this.scene = scene
    this.autoAspect = autoAspect
    this.clearColor = renderer?.backgroundColor ?? RGBA.fromValues(0, 0, 0, 1)

    const { width, height } = this.getRenderSize()
    this.engine = new ThreeCliRenderer(cliRenderer, {
      width,
      height,
      autoResize: false,
      ...renderer,
    })

    if (camera) {
      this.engine.setActiveCamera(camera)
    }
    this.updateCameraAspect(width, height)

    this.registerFrameCallback()
  }

  public get aspectRatio(): number {
    return this.getAspectRatio(this.width, this.height)
  }

  public get renderer(): ThreeCliRenderer {
    return this.engine
  }

  public getScene(): Scene | null {
    return this.scene
  }

  public setScene(scene: Scene | null): void {
    this.scene = scene
    this.requestRender()
  }

  public getActiveCamera(): PerspectiveCamera | OrthographicCamera {
    return this.engine.getActiveCamera()
  }

  public setActiveCamera(camera: PerspectiveCamera | OrthographicCamera): void {
    this.engine.setActiveCamera(camera)
    this.updateCameraAspect(this.width, this.height)
    this.requestRender()
  }

  public setAutoAspect(autoAspect: boolean): void {
    if (this.autoAspect === autoAspect) return
    this.autoAspect = autoAspect
    if (autoAspect) {
      this.updateCameraAspect(this.width, this.height)
    }
  }

  protected onResize(width: number, height: number): void {
    if (width > 0 && height > 0) {
      this.engine.setSize(width, height, true)
      this.updateCameraAspect(width, height)
    }
    super.onResize(width, height)
  }

  protected renderSelf(buffer: OptimizedBuffer, deltaTime: number): void {
    if (!this.visible || this.isDestroyed) return
    if (this.frameCallbackRegistered) return
    if (this.buffered && !this.frameBuffer) return
    void this.renderToBuffer(buffer, deltaTime / 1000)
  }

  protected destroySelf(): void {
    if (this.frameCallback && this.frameCallbackRegistered) {
      this.cliRenderer.removeFrameCallback(this.frameCallback)
      this.frameCallbackRegistered = false
      this.frameCallback = null
    }

    this.engine.destroy()
    super.destroySelf()
  }

  private registerFrameCallback(): void {
    if (this.frameCallbackRegistered) return

    this.frameCallback = async (deltaTime: number) => {
      if (this.isDestroyed || !this.visible || !this.parent) return
      if (!this.scene || !this.frameBuffer) return
      await this.renderToBuffer(this.frameBuffer, deltaTime / 1000)
    }

    this.cliRenderer.setFrameCallback(this.frameCallback)
    this.frameCallbackRegistered = true
  }

  private async renderToBuffer(buffer: OptimizedBuffer, deltaTime: number): Promise<void> {
    if (!this.scene || this.isDestroyed || this.drawInFlight) return

    this.drawInFlight = true
    try {
      const initialized = await this.ensureInitialized()
      if (!initialized || !this.scene) return

      if (buffer === this.frameBuffer) {
        buffer.clear(this.clearColor)
      }

      await this.engine.drawScene(this.scene, buffer, deltaTime)
    } finally {
      this.drawInFlight = false
    }
  }

  private async ensureInitialized(): Promise<boolean> {
    if (this.initFailed) return false
    if (!this.initPromise) {
      this.initPromise = this.engine
        .init()
        .then(() => true)
        .catch((error) => {
          this.initFailed = true
          console.error("ThreeRenderable init failed:", error)
          return false
        })
    }
    return this.initPromise
  }

  private updateCameraAspect(width: number, height: number): void {
    if (!this.autoAspect || width <= 0 || height <= 0) return

    const camera = this.engine.getActiveCamera()
    if (camera instanceof PerspectiveCamera) {
      camera.aspect = this.getAspectRatio(width, height)
      camera.updateProjectionMatrix()
    }
  }

  private getAspectRatio(width: number, height: number): number {
    if (width <= 0 || height <= 0) return 1

    const resolution = this.cliRenderer.resolution
    if (resolution && this.cliRenderer.terminalWidth > 0 && this.cliRenderer.terminalHeight > 0) {
      const cellWidth = resolution.width / this.cliRenderer.terminalWidth
      const cellHeight = resolution.height / this.cliRenderer.terminalHeight
      if (cellHeight > 0) {
        return (width * cellWidth) / (height * cellHeight)
      }
    }

    return width / (height * 2)
  }

  private getRenderSize(): { width: number; height: number } {
    return {
      width: Math.max(1, this.width),
      height: Math.max(1, this.height),
    }
  }
}


================================================
FILE: packages/core/src/3d/WGPURenderer.ts
================================================
import { PerspectiveCamera, OrthographicCamera, Color, NoToneMapping, LinearSRGBColorSpace, Scene } from "three"
import { WebGPURenderer } from "three/webgpu"
import type { OptimizedBuffer } from "../buffer.js"
import { RGBA } from "../lib/RGBA.js"
import { createWebGPUDevice, setupGlobals } from "bun-webgpu"
import { CLICanvas, SuperSampleAlgorithm } from "./canvas.js"
import { CliRenderEvents, type CliRenderer } from "../renderer.js"

export enum SuperSampleType {
  NONE = "none",
  GPU = "gpu",
  CPU = "cpu",
}

export interface ThreeCliRendererOptions {
  width: number
  height: number
  focalLength?: number
  backgroundColor?: RGBA
  superSample?: SuperSampleType
  alpha?: boolean
  autoResize?: boolean
  libPath?: string
}

export class ThreeCliRenderer {
  private outputWidth: number
  private outputHeight: number
  private renderWidth: number
  private renderHeight: number
  private superSample: SuperSampleType
  private backgroundColor: RGBA = RGBA.fromValues(0, 0, 0, 1)
  private alpha: boolean = false
  private threeRenderer?: WebGPURenderer
  private canvas?: CLICanvas
  private device: GPUDevice | null = null

  private activeCamera: PerspectiveCamera | OrthographicCamera
  private _aspectRatio: number | null = null
  private doRenderStats: boolean = false

  private resizeHandler: (width: number, height: number) => void
  private debugToggleHandler: (enabled: boolean) => void
  private destroyHandler: () => void

  // Stats tracking
  private renderTimeMs: number = 0
  private readbackTimeMs: number = 0
  private totalDrawTimeMs: number = 0

  private renderMethod: (
    root: Scene,
    camera: PerspectiveCamera | OrthographicCamera,
    buffer: OptimizedBuffer,
    deltaTime: number,
  ) => Promise<void> = () => Promise.resolve()

  public get aspectRatio(): number {
    if (this._aspectRatio) return this._aspectRatio
    if (this.cliRenderer.resolution) {
      const pixelAspectRatio = this.cliRenderer.resolution.width / this.cliRenderer.resolution.height
      return pixelAspectRatio
    }
    const terminalWidth = process.stdout.columns
    const terminalHeight = process.stdout.rows
    return terminalWidth / (terminalHeight * 2)
  }

  constructor(
    private readonly cliRenderer: CliRenderer,
    options: ThreeCliRendererOptions,
  ) {
    this.outputWidth = options.width
    this.outputHeight = options.height
    this.superSample = options.superSample ?? SuperSampleType.GPU

    this.renderWidth = this.outputWidth * (this.superSample !== SuperSampleType.NONE ? 2 : 1)
    this.renderHeight = this.outputHeight * (this.superSample !== SuperSampleType.NONE ? 2 : 1)

    this.backgroundColor = options.backgroundColor ?? RGBA.fromValues(0, 0, 0, 1)
    this.alpha = options.alpha ?? false

    if (process.env.CELL_ASPECT_RATIO) {
      this._aspectRatio = parseFloat(process.env.CELL_ASPECT_RATIO)
    }

    // Create a default active camera
    const fov = options.focalLength ? 2 * Math.atan(this.outputHeight / (2 * options.focalLength)) * (180 / Math.PI) : 1 // Default FOV if focal length not provided
    this.activeCamera = new PerspectiveCamera(
      fov,
      this.aspectRatio,
      0.1, // near plane
      1000, // far plane
    )
    this.activeCamera.position.set(0, 0, 3)
    this.activeCamera.up.set(0, 1, 0)
    this.activeCamera.lookAt(0, 0, 0)
    this.activeCamera.updateMatrixWorld()

    this.resizeHandler = (width: number, height: number) => {
      this.setSize(width, height, true)
    }

    this.debugToggleHandler = (enabled: boolean) => {
      this.doRenderStats = enabled
    }

    this.destroyHandler = () => {
      this.destroy()
    }

    if (options.autoResize !== false) {
      this.cliRenderer.on("resize", this.resizeHandler)
    }

    this.cliRenderer.on(CliRenderEvents.DEBUG_OVERLAY_TOGGLE, this.debugToggleHandler)
    this.cliRenderer.on(CliRenderEvents.DESTROY, this.destroyHandler)

    setupGlobals({ libPath: options.libPath })
  }

  public toggleDebugStats(): void {
    this.doRenderStats = !this.doRenderStats
  }

  async init(): Promise<void> {
    this.device = await createWebGPUDevice()
    this.canvas = new CLICanvas(this.device, this.renderWidth, this.renderHeight, this.superSample)

    try {
      this.threeRenderer = new WebGPURenderer({
        canvas: this.canvas as unknown as HTMLCanvasElement,
        device: this.device,
        alpha: this.alpha,
      })

      this.setBackgroundColor(this.backgroundColor)

      this.threeRenderer.toneMapping = NoToneMapping
      this.threeRenderer.outputColorSpace = LinearSRGBColorSpace

      this.threeRenderer.setSize(this.renderWidth, this.renderHeight, false)
    } catch (error) {
      console.error("Error creating THREE.WebGPURenderer:", error)
      throw error
    }

    await this.threeRenderer.init().then(() => {
      this.renderMethod = this.doDrawScene.bind(this)
    })
  }

  public getSuperSampleAlgorithm(): SuperSampleAlgorithm {
    return this.canvas!.getSuperSampleAlgorithm()
  }

  public setSuperSampleAlgorithm(superSampleAlgorithm: SuperSampleAlgorithm): void {
    this.canvas!.setSuperSampleAlgorithm(superSampleAlgorithm)
  }

  public saveToFile(filePath: string): Promise<void> {
    return this.canvas!.saveToFile(filePath)
  }

  setActiveCamera(camera: PerspectiveCamera | OrthographicCamera): void {
    this.activeCamera = camera
  }

  getActiveCamera(): PerspectiveCamera | OrthographicCamera {
    return this.activeCamera
  }

  public setBackgroundColor(color: RGBA): void {
    this.backgroundColor = color
    const clearColor = new Color(this.backgroundColor.r, this.backgroundColor.g, this.backgroundColor.b)
    const clearAlpha = this.alpha ? this.backgroundColor.a : 1.0
    this.threeRenderer!.setClearColor(clearColor, clearAlpha)
  }

  setSize(width: number, height: number, forceUpdate: boolean = false): void {
    // Check against OUTPUT dimensions
    if (!forceUpdate && this.outputWidth === width && this.outputHeight === height) return

    this.outputWidth = width
    this.outputHeight = height

    this.renderWidth = this.outputWidth * (this.superSample !== SuperSampleType.NONE ? 2 : 1)
    this.renderHeight = this.outputHeight * (this.superSample !== SuperSampleType.NONE ? 2 : 1)

    this.canvas?.setSize(this.renderWidth, this.renderHeight)

    this.threeRenderer?.setSize(this.renderWidth, this.renderHeight, false)
    this.threeRenderer?.setViewport(0, 0, this.renderWidth, this.renderHeight)

    if (this.activeCamera instanceof PerspectiveCamera) {
      this.activeCamera.aspect = this.aspectRatio
    }
    this.activeCamera.updateProjectionMatrix()
  }

  public async drawScene(root: Scene, buffer: OptimizedBuffer, deltaTime: number): Promise<void> {
    await this.renderMethod(root, this.activeCamera, buffer, deltaTime)

    if (this.doRenderStats) {
      this.renderStats(buffer)
    }
  }

  private rendering: boolean = false
  private destroyed: boolean = false
  async doDrawScene(
    root: Scene,
    camera: PerspectiveCamera | OrthographicCamera,
    buffer: OptimizedBuffer,
    deltaTime: number,
  ): Promise<void> {
    if (this.rendering) {
      console.warn("ThreeCliRenderer.drawScene was called concurrently, which is not supported.")
      return
    }
    if (this.destroyed) {
      return
    }
    try {
      this.rendering = true

      const totalStart = performance.now()
      const renderStart = performance.now()
      await this.threeRenderer!.render(root, camera)
      this.renderTimeMs = performance.now() - renderStart

      const readbackStart = performance.now()
      await this.canvas!.readPixelsIntoBuffer(buffer)
      this.readbackTimeMs = performance.now() - readbackStart

      this.totalDrawTimeMs = performance.now() - totalStart
    } finally {
      this.rendering = false
    }
  }

  public toggleSuperSampling(): void {
    if (this.superSample === SuperSampleType.NONE) {
      this.superSample = SuperSampleType.CPU
    } else if (this.superSample === SuperSampleType.CPU) {
      this.superSample = SuperSampleType.GPU
    } else {
      this.superSample = SuperSampleType.NONE
    }
    this.canvas!.setSuperSample(this.superSample)
    this.setSize(this.outputWidth, this.outputHeight, true)
  }

  public renderStats(buffer: OptimizedBuffer): void {
    const stats = [
      `WebGPU Renderer Stats:`,
      ` Render: ${this.renderTimeMs.toFixed(2)}ms`,
      ` Readback: ${this.readbackTimeMs.toFixed(2)}ms`,
      `  ├ MapAsync: ${this.canvas!.mapAsyncTimeMs.toFixed(2)}ms`,
      `  └ SS Draw: ${this.canvas!.superSampleDrawTimeMs.toFixed(2)}ms`,
      ` Total Draw: ${this.totalDrawTimeMs.toFixed(2)}ms`,
      ` SuperSample: ${this.superSample}`,
      ` SuperSample Algorithm: ${this.getSuperSampleAlgorithm()}`,
    ]
    const startY = 4
    const startX = 2
    const fg = RGBA.fromValues(0.9, 0.9, 0.9, 1.0)
    const bg = RGBA.fromValues(0.1, 0.1, 0.1, 1.0)

    stats.forEach((line, index) => {
      buffer.drawText(line, startX + 1, startY + index, fg, bg)
    })
  }

  public destroy(): void {
    this.destroyed = true

    this.cliRenderer.off("resize", this.resizeHandler)
    this.cliRenderer.off(CliRenderEvents.DEBUG_OVERLAY_TOGGLE, this.debugToggleHandler)

    if (this.canvas) {
      this.canvas.destroy()
    }

    if (this.threeRenderer) {
      this.threeRenderer.dispose()
      this.threeRenderer = undefined
    }

    this.canvas = undefined
    this.device = null
    this.renderMethod = () => Promise.resolve()
  }
}


================================================
FILE: packages/core/src/3d/animation/ExplodingSpriteEffect.ts
================================================
import * as THREE from "three"
import {
  uniform,
  attribute,
  texture as tslTexture,
  uv,
  float,
  vec2,
  vec3,
  vec4,
  step,
  max,
  sin,
  cos,
  positionLocal,
  mat3,
} from "three/tsl"
import { MeshBasicNodeMaterial, NodeMaterial } from "three/webgpu"
import type { TiledSprite, SpriteDefinition, SpriteAnimator } from "./SpriteAnimator.js"
import type { SpriteResource } from "../SpriteResourceManager.js"

export interface ExplosionEffectParameters {
  numRows: number
  numCols: number
  durationMs: number
  strength: number
  strengthVariation: number
  gravity: number
  gravityScale: number
  fadeOut: boolean
  angularVelocityMin: THREE.Vector3
  angularVelocityMax: THREE.Vector3
  initialVelocityYBoost: number
  zVariationStrength: number
  materialFactory: () => NodeMaterial
}

export const DEFAULT_EXPLOSION_PARAMETERS: ExplosionEffectParameters = {
  numRows: 5,
  numCols: 5,
  durationMs: 2000,
  strength: 5,
  strengthVariation: 0.5,
  gravity: 9.8,
  gravityScale: 0.15,
  fadeOut: true,
  angularVelocityMin: new THREE.Vector3(-Math.PI, -Math.PI, -Math.PI),
  angularVelocityMax: new THREE.Vector3(Math.PI, Math.PI, Math.PI),
  initialVelocityYBoost: 1.0,
  zVariationStrength: 0.3,
  materialFactory: () =>
    new MeshBasicNodeMaterial({
      transparent: true,
      alphaTest: 0.01,
      side: THREE.DoubleSide,
      depthWrite: true,
    }),
}

export interface ExplosionCreationData {
  resource: SpriteResource
  frameUvOffset: THREE.Vector2
  frameUvSize: THREE.Vector2
  spriteWorldTransform: THREE.Matrix4
}

export interface SpriteRecreationData {
  definition: SpriteDefinition
  currentTransform: {
    position: THREE.Vector3
    quaternion: THREE.Quaternion
    scale: THREE.Vector3
  }
}

export interface ExplosionHandle {
  readonly effect: ExplodingSpriteEffect
  readonly recreationData: SpriteRecreationData
  hasBeenRestored: boolean
  restoreSprite: (spriteAnimator: SpriteAnimator) => Promise<TiledSprite | null>
}

export class ExplodingSpriteEffect {
  private static baseMaterialCache: Map<string, NodeMaterial> = new Map()
  private scene: THREE.Scene
  private resource: SpriteResource
  private frameUvOffset: THREE.Vector2
  private frameUvSize: THREE.Vector2
  private spriteWorldTransform: THREE.Matrix4
  private params: ExplosionEffectParameters

  private instancedMesh!: THREE.InstancedMesh
  private material!: NodeMaterial
  private numParticles: number

  private uniformRefs!: { time: any; duration: any; gravity: any }

  public isActive: boolean = true
  private timeElapsedMs: number = 0

  constructor(
    scene: THREE.Scene,
    resource: SpriteResource,
    frameUvOffset: THREE.Vector2,
    frameUvSize: THREE.Vector2,
    spriteWorldTransform: THREE.Matrix4,
    userParams?: Partial<ExplosionEffectParameters>,
  ) {
    this.scene = scene
    this.resource = resource
    this.frameUvOffset = frameUvOffset
    this.frameUvSize = frameUvSize
    this.spriteWorldTransform = spriteWorldTransform
    this.params = { ...DEFAULT_EXPLOSION_PARAMETERS, ...userParams }

    this.numParticles = this.params.numRows * this.params.numCols
    const materialFactory = userParams?.materialFactory ?? DEFAULT_EXPLOSION_PARAMETERS.materialFactory

    this._createGPUParticles(materialFactory)
  }

  private _createGPUParticles(materialFactory: () => NodeMaterial): void {
    if (this.numParticles === 0) return

    const particleUnitWidth = 1.0 / this.params.numCols
    const particleUnitHeight = 1.0 / this.params.numRows

    const poolKey = `${this.params.numRows}x${this.params.numCols}`

    this._createGPUMaterial(materialFactory)

    this.instancedMesh = this.resource.meshPool.acquireMesh(poolKey, {
      geometry: () => {
        const geometry = new THREE.PlaneGeometry(particleUnitWidth, particleUnitHeight)
        geometry.setAttribute(
          "a_particleData",
          new THREE.InstancedBufferAttribute(new Float32Array(this.numParticles * 4), 4),
        )
        geometry.setAttribute(
          "a_velocity",
          new THREE.InstancedBufferAttribute(new Float32Array(this.numParticles * 4), 4),
        )
        geometry.setAttribute(
          "a_angularVel",
          new THREE.InstancedBufferAttribute(new Float32Array(this.numParticles * 4), 4),
        )
        geometry.setAttribute(
          "a_uvOffset",
          new THREE.InstancedBufferAttribute(new Float32Array(this.numParticles * 4), 4),
        )
        return geometry
      },
      material: this.material,
      maxInstances: this.numParticles,
      name: `ExplodingSprite_${poolKey}`,
    })

    const particleData: Float32Array = this.instancedMesh.geometry.getAttribute("a_particleData").array as Float32Array
    const velocityData: Float32Array = this.instancedMesh.geometry.getAttribute("a_velocity").array as Float32Array
    const angularVelData: Float32Array = this.instancedMesh.geometry.getAttribute("a_angularVel").array as Float32Array
    const uvOffsetData: Float32Array = this.instancedMesh.geometry.getAttribute("a_uvOffset").array as Float32Array

    const spriteWorldCenter = new THREE.Vector3().setFromMatrixPosition(this.spriteWorldTransform)

    let particleIndex = 0
    for (let r = 0; r < this.params.numRows; r++) {
      for (let c = 0; c < this.params.numCols; c++) {
        const localParticlePosX = (c + 0.5) * particleUnitWidth - 0.5
        const localParticlePosY = (r + 0.5) * particleUnitHeight - 0.5

        const initialLocalPosition = new THREE.Vector3(localParticlePosX, localParticlePosY, 0)
        const worldPosition = initialLocalPosition.clone().applyMatrix4(this.spriteWorldTransform)

        let velocityDir = worldPosition.clone().sub(spriteWorldCenter)
        if (velocityDir.lengthSq() < 0.0001) {
          velocityDir.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5)
        }
        velocityDir.normalize()

        const strengthVariationRange = this.params.strengthVariation
        const minStrengthFactor = 1.0 - strengthVariationRange * 0.5
        const maxStrengthFactor = 1.0 + strengthVariationRange * 0.5
        const strengthFactor = minStrengthFactor + Math.random() * (maxStrengthFactor - minStrengthFactor)
        const strength = this.params.strength * strengthFactor * 0.1
        const velocity = velocityDir.multiplyScalar(strength)

        if (
          Math.abs(this.spriteWorldTransform.elements[10]) < 0.1 &&
          Math.abs(this.spriteWorldTransform.elements[11]) < 0.1
        ) {
          velocity.z += (Math.random() - 0.5) * strength * this.params.zVariationStrength
        }

        velocity.y += this.params.strength * this.params.initialVelocityYBoost * Math.random()

        const angularVelocity = new THREE.Vector3(
          THREE.MathUtils.randFloat(this.params.angularVelocityMin.x, this.params.angularVelocityMax.x),
          THREE.MathUtils.randFloat(this.params.angularVelocityMin.y, this.params.angularVelocityMax.y),
          THREE.MathUtils.randFloat(this.params.angularVelocityMin.z, this.params.angularVelocityMax.z),
        )

        const lifeVariation = 0.8 + Math.random() * 0.4
        const randomSeed = Math.random()

        const u0 = this.frameUvOffset.x + (c / this.params.numCols) * this.frameUvSize.x
        const v0 = this.frameUvOffset.y + (r / this.params.numRows) * this.frameUvSize.y
        const uSize = this.frameUvSize.x / this.params.numCols
        const vSize = this.frameUvSize.y / this.params.numRows

        const baseIndex = particleIndex * 4

        particleData[baseIndex] = localParticlePosX
        particleData[baseIndex + 1] = localParticlePosY
        particleData[baseIndex + 2] = randomSeed
        particleData[baseIndex + 3] = lifeVariation

        velocityData[baseIndex] = velocity.x
        velocityData[baseIndex + 1] = velocity.y
        velocityData[baseIndex + 2] = velocity.z
        velocityData[baseIndex + 3] = 0.0

        angularVelData[baseIndex] = angularVelocity.x
        angularVelData[baseIndex + 1] = angularVelocity.y
        angularVelData[baseIndex + 2] = angularVelocity.z
        angularVelData[baseIndex + 3] = 0.0

        uvOffsetData[baseIndex] = u0
        uvOffsetData[baseIndex + 1] = v0
        uvOffsetData[baseIndex + 2] = uSize
        uvOffsetData[baseIndex + 3] = vSize

        particleIndex++
      }
    }

    this.instancedMesh.onBeforeRender = () => {
      this.uniformRefs.time.value = this.timeElapsedMs / 1000
    }

    this.timeElapsedMs = 0

    this.instancedMesh.geometry.getAttribute("a_particleData").needsUpdate = true
    this.instancedMesh.geometry.getAttribute("a_velocity").needsUpdate = true
    this.instancedMesh.geometry.getAttribute("a_angularVel").needsUpdate = true
    this.instancedMesh.geometry.getAttribute("a_uvOffset").needsUpdate = true

    this.instancedMesh.frustumCulled = false

    for (let i = 0; i < this.numParticles; i++) {
      this.instancedMesh.setMatrixAt(i, this.spriteWorldTransform)
    }
    this.instancedMesh.instanceMatrix.needsUpdate = true

    this.scene.add(this.instancedMesh)
  }

  private _createGPUMaterial(materialFactory: () => NodeMaterial): void {
    const key = `${this.resource.texture.uuid}_${this.params.numRows}x${this.params.numCols}_${this.params.fadeOut ? 1 : 0}`

    let template = ExplodingSpriteEffect.baseMaterialCache.get(key)
    if (!template) {
      template = ExplodingSpriteEffect._buildTemplateMaterial(this.resource.texture, this.params, materialFactory)
      ExplodingSpriteEffect.baseMaterialCache.set(key, template)
    }

    this.material = template
    this.uniformRefs = template.userData.uniformRefs as { time: any; duration: any; gravity: any }
  }

  public static _buildTemplateMaterial(
    texture: THREE.DataTexture,
    params: ExplosionEffectParameters,
    materialFactory: () => NodeMaterial,
  ): NodeMaterial {
    const timeUniformNode = uniform(0)
    ;(timeUniformNode as any).name = "timeUniform"
    const durationUniformNode = uniform(params.durationMs / 1000)
    ;(durationUniformNode as any).name = "durationUniform"
    const gravityUniformNode = uniform(params.gravity * params.gravityScale)
    ;(gravityUniformNode as any).name = "gravityUniform"

    const a_particleData = attribute("a_particleData", "vec4")
    const a_velocity = attribute("a_velocity", "vec4")
    const a_angularVel = attribute("a_angularVel", "vec4")
    const a_uvOffset = attribute("a_uvOffset", "vec4")

    const localPos = vec2(a_particleData.x, a_particleData.y)
    const lifeVariation = a_particleData.w

    const initialVelocity = vec3(a_velocity.x, a_velocity.y, a_velocity.z)
    const angularVelocity = vec3(a_angularVel.x, a_angularVel.y, a_angularVel.z)

    const uvOffset = vec2(a_uvOffset.x, a_uvOffset.y)
    const uvSize = vec2(a_uvOffset.z, a_uvOffset.w)

    const particleLifetime = durationUniformNode.mul(lifeVariation)
    const normalizedTime = timeUniformNode.div(particleLifetime)
    const isAlive = step(normalizedTime, float(1.0))

    const deltaTime = timeUniformNode
    const gravity = vec3(float(0), gravityUniformNode.negate(), float(0))

    const velocityContribution = initialVelocity.mul(deltaTime)
    const gravityContribution = gravity.mul(deltaTime).mul(deltaTime).mul(float(0.5))
    const positionOffset = velocityContribution.add(gravityContribution)

    const rotationAmount = angularVelocity.mul(deltaTime)
    const cosX = cos(rotationAmount.x)
    const sinX = sin(rotationAmount.x)
    const cosY = cos(rotationAmount.y)
    const sinY = sin(rotationAmount.y)
    const cosZ = cos(rotationAmount.z)
    const sinZ = sin(rotationAmount.z)

    const rotationMatrix = mat3(
      cosY.mul(cosZ),
      cosY.mul(sinZ).negate(),
      sinY,
      sinX.mul(sinY).mul(cosZ).add(cosX.mul(sinZ)),
      sinX.mul(sinY).mul(sinZ).negate().add(cosX.mul(cosZ)),
      sinX.mul(cosY).negate(),
      cosX.mul(sinY).mul(cosZ).negate().add(sinX.mul(sinZ)),
      cosX.mul(sinY).mul(sinZ).add(sinX.mul(cosZ)),
      cosX.mul(cosY),
    )

    const rotatedVertexPosition = rotationMatrix.mul(positionLocal)
    const finalOffset = vec3(localPos.x, localPos.y, float(0)).add(positionOffset)

    let opacity = float(1.0)
    if (params.fadeOut) {
      const fadeStart = float(0.7)
      const fadeProgress = max(float(0), normalizedTime.sub(fadeStart).div(float(1.0).sub(fadeStart)))
      opacity = float(1.0).sub(fadeProgress)
    }
    opacity = opacity.mul(isAlive)

    const baseUV = uv()
    const finalUV = baseUV.mul(uvSize).add(uvOffset)

    const mapNode = tslTexture(texture)
    const sampledColor = mapNode.sample(finalUV)

    const material = materialFactory()

    const finalColor = vec4(sampledColor.rgb, sampledColor.a.mul(opacity))
    material.colorNode = finalColor
    material.positionNode = rotatedVertexPosition.add(finalOffset)

    material.userData.uniformRefs = {
      time: timeUniformNode,
      duration: durationUniformNode,
      gravity: gravityUniformNode,
    }

    return material
  }

  update(deltaTimeMs: number): void {
    if (!this.isActive) return

    this.timeElapsedMs += deltaTimeMs

    if (this.timeElapsedMs >= this.params.durationMs) {
      this.dispose()
    }
  }

  dispose(): void {
    if (!this.isActive) return
    this.isActive = false

    if (this.instancedMesh) {
      this.scene.remove(this.instancedMesh)

      const poolKey = `${this.params.numRows}x${this.params.numCols}`

      this.resource.meshPool.releaseMesh(poolKey, this.instancedMesh)
    }
  }
}

export class ExplosionManager {
  private scene: THREE.Scene
  private activeExplosions: ExplodingSpriteEffect[] = []

  constructor(scene: THREE.Scene) {
    this.scene = scene
  }

  public fillPool(resource: SpriteResource, count: number, params: Partial<ExplosionEffectParameters> = {}): void {
    const effectParams = { ...DEFAULT_EXPLOSION_PARAMETERS, ...params }
    const poolKey = `${effectParams.numRows}x${effectParams.numCols}`
    const particleUnitWidth = 1.0 / effectParams.numCols
    const particleUnitHeight = 1.0 / effectParams.numRows
    const numParticles = effectParams.numRows * effectParams.numCols
    const materialFactory = params.materialFactory ?? DEFAULT_EXPLOSION_PARAMETERS.materialFactory

    const material = ExplodingSpriteEffect._buildTemplateMaterial(resource.texture, effectParams, materialFactory)

    resource.meshPool.fill(
      poolKey,
      {
        geometry: () => {
          const geometry = new THREE.PlaneGeometry(particleUnitWidth, particleUnitHeight)
          const particleData = new Float32Array(numParticles * 4)
          const velocityData = new Float32Array(numParticles * 4)
          const angularVelData = new Float32Array(numParticles * 4)
          const uvOffsetData = new Float32Array(numParticles * 4)
          const particleDataAttribute = new THREE.InstancedBufferAttribute(particleData, 4)
          const velocityAttribute = new THREE.InstancedBufferAttribute(velocityData, 4)
          const angularVelAttribute = new THREE.InstancedBufferAttribute(angularVelData, 4)
          const uvOffsetAttribute = new THREE.InstancedBufferAttribute(uvOffsetData, 4)

          geometry.setAttribute("a_particleData", particleDataAttribute)
          geometry.setAttribute("a_velocity", velocityAttribute)
          geometry.setAttribute("a_angularVel", angularVelAttribute)
          geometry.setAttribute("a_uvOffset", uvOffsetAttribute)

          particleDataAttribute.needsUpdate = true
          velocityAttribute.needsUpdate = true
          angularVelAttribute.needsUpdate = true
          uvOffsetAttribute.needsUpdate = true

          return geometry
        },
        material,
        maxInstances: numParticles,
        name: `ExplodingSprite_${poolKey}`,
      },
      count,
    )
  }

  private _createEffectCreationData(sprite: TiledSprite): ExplosionCreationData {
    const animState = sprite.currentAnimation.state
    const resource = sprite.currentAnimation.getResource()
    const currentAbsoluteFrame = animState.animFrameOffset + sprite.currentAnimation.currentLocalFrame
    const frameUOffset = currentAbsoluteFrame * resource.uvTileSize.x
    return {
      resource: resource,
      frameUvOffset: new THREE.Vector2(frameUOffset, 0),
      frameUvSize: resource.uvTileSize.clone(),
      spriteWorldTransform: sprite.getWorldTransform(),
    }
  }

  public createExplosionForSprite(
    spriteToExplode: TiledSprite,
    userParams?: Partial<ExplosionEffectParameters>,
  ): ExplosionHandle | null {
    const effectCreationData = this._createEffectCreationData(spriteToExplode)
    const definition = spriteToExplode.definition
    const transform = spriteToExplode.currentTransform

    let spriteRecreationData: SpriteRecreationData = {
      definition: definition,
      currentTransform: transform,
    }

    spriteToExplode.destroy()

    const effect = new ExplodingSpriteEffect(
      this.scene,
      effectCreationData.resource,
      effectCreationData.frameUvOffset,
      effectCreationData.frameUvSize,
      effectCreationData.spriteWorldTransform,
      userParams,
    )
    this.activeExplosions.push(effect)

    const handle: ExplosionHandle = {
      effect: effect,
      recreationData: spriteRecreationData,
      hasBeenRestored: false,
      restoreSprite: async (spriteAnimator: SpriteAnimator): Promise<TiledSprite | null> => {
        if (handle.hasBeenRestored) {
          return null
        }

        handle.effect.dispose()

        const newSprite = await spriteAnimator.createSprite(handle.recreationData.definition)
        const currentSpriteTransform = handle.recreationData.currentTransform
        newSprite.setTransform(
          currentSpriteTransform.position,
          currentSpriteTransform.quaternion,
          currentSpriteTransform.scale,
        )
        handle.hasBeenRestored = true

        return newSprite
      },
    }
    return handle
  }

  public update(deltaTimeMs: number): void {
    for (let i = this.activeExplosions.length - 1; i >= 0; i--) {
      const explosion = this.activeExplosions[i]
      explosion.update(deltaTimeMs)
      if (!explosion.isActive) {
        this.activeExplosions.splice(i, 1)
      }
    }
  }

  public disposeAll(): void {
    this.activeExplosions.forEach((exp) => exp.dispose())
    this.activeExplosions = []
  }
}


================================================
FILE: packages/core/src/3d/animation/PhysicsExplodingSpriteEffect.ts
================================================
import * as THREE from "three"
import { texture as tslTexture, uv, vec2, attribute } from "three/tsl"
import { MeshBasicNodeMaterial, NodeMaterial } from "three/webgpu"
import type { TiledSprite, SpriteDefinition, SpriteAnimator } from "./SpriteAnimator.js"
import type {
  PhysicsRigidBody,
  PhysicsWorld,
  PhysicsRigidBodyDesc,
  PhysicsColliderDesc,
  PhysicsVector2,
} from "../physics/physics-interface.js"
import type { SpriteResource } from "../SpriteResourceManager.js"

export interface PhysicsExplosionEffectParameters {
  numRows: number
  numCols: number
  durationMs: number
  explosionForce: number
  forceVariation: number
  torqueStrength: number
  gravityScale: number
  fadeOut: boolean
  linearDamping: number
  angularDamping: number
  restitution: number
  friction: number
  density: number
  materialFactory: () => NodeMaterial
}

export const DEFAULT_PHYSICS_EXPLOSION_PARAMETERS: PhysicsExplosionEffectParameters = {
  numRows: 5,
  numCols: 5,
  durationMs: 3000,
  explosionForce: 25.0,
  forceVariation: 0.4,
  torqueStrength: 15.0,
  gravityScale: 1.0,
  fadeOut: true,
  linearDamping: 0.8,
  angularDamping: 0.5,
  restitution: 0.3,
  friction: 0.7,
  density: 1.0,
  materialFactory: () =>
    new MeshBasicNodeMaterial({
      transparent: true,
      alphaTest: 0.01,
      // side: THREE.DoubleSide,
      depthWrite: false,
    }),
}

export interface PhysicsExplosionCreationData {
  resource: SpriteResource
  frameUvOffset: THREE.Vector2
  frameUvSize: THREE.Vector2
  spriteWorldTransform: THREE.Matrix4
}

export interface PhysicsSpriteRecreationData {
  definition: SpriteDefinition
  currentTransform: {
    position: THREE.Vector3
    quaternion: THREE.Quaternion
    scale: THREE.Vector3
  }
}

export interface PhysicsExplosionHandle {
  readonly effect: PhysicsExplodingSpriteEffect
  readonly recreationData: PhysicsSpriteRecreationData
  hasBeenRestored: boolean
  restoreSprite: (spriteAnimator: SpriteAnimator) => Promise<TiledSprite | null>
}

interface ExplosionParticle {
  rigidBody: PhysicsRigidBody
  instanceIndex: number
  uvOffset: THREE.Vector2
  uvSize: THREE.Vector2
  initialOpacity: number
  lifeVariation: number
  id: string
}

export class PhysicsExplodingSpriteEffect {
  private static materialCache: Map<string, NodeMaterial> = new Map()

  private scene: THREE.Scene
  private physicsWorld: PhysicsWorld
  private resource: SpriteResource
  private frameUvOffset: THREE.Vector2
  private frameUvSize: THREE.Vector2
  private spriteWorldTransform: THREE.Matrix4
  private params: PhysicsExplosionEffectParameters

  private particles: ExplosionParticle[] = []
  private numParticles: number

  private instancedMesh!: THREE.InstancedMesh
  private material!: NodeMaterial
  private uvOffsetAttribute!: THREE.InstancedBufferAttribute

  public isActive: boolean = true
  private timeElapsedMs: number = 0
  private particleIdCounter: number = 0

  constructor(
    scene: THREE.Scene,
    physicsWorld: PhysicsWorld,
    resource: SpriteResource,
    frameUvOffset: THREE.Vector2,
    frameUvSize: THREE.Vector2,
    spriteWorldTransform: THREE.Matrix4,
    userParams?: Partial<PhysicsExplosionEffectParameters>,
  ) {
    this.scene = scene
    this.physicsWorld = physicsWorld
    this.resource = resource
    this.frameUvOffset = frameUvOffset
    this.frameUvSize = frameUvSize
    this.spriteWorldTransform = spriteWorldTransform
    this.params = { ...DEFAULT_PHYSICS_EXPLOSION_PARAMETERS, ...userParams }

    this.numParticles = this.params.numRows * this.params.numCols
    const materialFactory = userParams?.materialFactory ?? DEFAULT_PHYSICS_EXPLOSION_PARAMETERS.materialFactory

    this._createPhysicsParticles(materialFactory)
  }

  private _createPhysicsParticles(materialFactory: () => NodeMaterial): void {
    if (this.numParticles === 0) return

    const particleUnitWidth = 1.0 / this.params.numCols
    const particleUnitHeight = 1.0 / this.params.numRows

    const spriteWorldCenter = new THREE.Vector3().setFromMatrixPosition(this.spriteWorldTransform)
    const spriteScale = new THREE.Vector3().setFromMatrixScale(this.spriteWorldTransform)
    const avgScale = (spriteScale.x + spriteScale.y) * 0.5
    const uvOffsetData = new Float32Array(this.numParticles * 4)

    let particleIndex = 0
    for (let r = 0; r < this.params.numRows; r++) {
      for (let c = 0; c < this.params.numCols; c++) {
        const localParticlePosX = (c + 0.5) * particleUnitWidth - 0.5
        const localParticlePosY = (r + 0.5) * particleUnitHeight - 0.5

        const initialLocalPosition = new THREE.Vector3(localParticlePosX, localParticlePosY, 0)
        const worldPosition = initialLocalPosition.clone().applyMatrix4(this.spriteWorldTransform)

        const rigidBodyDesc: PhysicsRigidBodyDesc = {
          translation: { x: worldPosition.x, y: worldPosition.y },
          linearDamping: this.params.linearDamping,
          angularDamping: this.params.angularDamping,
        }

        const rigidBody = this.physicsWorld.createRigidBody(rigidBodyDesc)

        const particlePhysicsWidth = particleUnitWidth * avgScale * 0.8
        const particlePhysicsHeight = particleUnitHeight * avgScale * 0.8
        const colliderDesc: PhysicsColliderDesc = {
          width: particlePhysicsWidth,
          height: particlePhysicsHeight,
          restitution: this.params.restitution,
          friction: this.params.friction,
          density: this.params.density,
        }

        this.physicsWorld.createCollider(colliderDesc, rigidBody)

        let explosionDir = worldPosition.clone().sub(spriteWorldCenter)
        if (explosionDir.lengthSq() < 0.0001) {
          explosionDir.set(Math.random() - 0.5, Math.random() - 0.5, 0)
        }
        explosionDir.normalize()

        const forceVariationRange = this.params.forceVariation
        const minForceFactor = 1.0 - forceVariationRange * 0.5
        const maxForceFactor = 1.0 + forceVariationRange * 0.5
        const forceFactor = minForceFactor + Math.random() * (maxForceFactor - minForceFactor)
        const explosionForce = this.params.explosionForce * forceFactor

        const forceVector: PhysicsVector2 = {
          x: explosionDir.x * explosionForce,
          y: explosionDir.y * explosionForce + explosionForce * 0.3, // Add upward bias
        }

        rigidBody.applyImpulse(forceVector)

        const torque = (Math.random() - 0.5) * this.params.torqueStrength
        rigidBody.applyTorqueImpulse(torque)

        const u0 = this.frameUvOffset.x + (c / this.params.numCols) * this.frameUvSize.x
        const v0 = this.frameUvOffset.y + (r / this.params.numRows) * this.frameUvSize.y
        const uSize = this.frameUvSize.x / this.params.numCols
        const vSize = this.frameUvSize.y / this.params.numRows

        const baseIndex = particleIndex * 4
        uvOffsetData[baseIndex] = u0
        uvOffsetData[baseIndex + 1] = v0
        uvOffsetData[baseIndex + 2] = uSize
        uvOffsetData[baseIndex + 3] = vSize

        const particleId = `explosion_particle_${this.particleIdCounter++}`
        const lifeVariation = 0.8 + Math.random() * 0.4

        const particle: ExplosionParticle = {
          rigidBody,
          instanceIndex: particleIndex,
          uvOffset: new THREE.Vector2(u0, v0),
          uvSize: new THREE.Vector2(uSize, vSize),
          initialOpacity: 1.0,
          lifeVariation,
          id: particleId,
        }

        this.particles.push(particle)
        particleIndex++
      }
    }

    this.uvOffsetAttribute = new THREE.InstancedBufferAttribute(uvOffsetData, 4)
    this.material = PhysicsExplodingSpriteEffect.getSharedMaterial(this.resource.texture, materialFactory)

    const poolKey = `${this.params.numRows}x${this.params.numCols}`

    this.instancedMesh = this.resource.meshPool.acquireMesh(poolKey, {
      geometry: () => new THREE.PlaneGeometry(particleUnitWidth, particleUnitHeight),
      material: this.material,
      maxInstances: this.numParticles,
      name: `PhysicsExplodingSprite_${poolKey}`,
    })

    this.instancedMesh.geometry.setAttribute("a_uvOffset", this.uvOffsetAttribute)

    this.instancedMesh.frustumCulled = false

    for (let i = 0; i < this.numParticles; i++) {
      this.instancedMesh.setMatrixAt(i, this.spriteWorldTransform)
    }
    this.instancedMesh.instanceMatrix.needsUpdate = true

    this.scene.add(this.instancedMesh)
  }

  public static getSharedMaterial(texture: THREE.DataTexture, materialFactory: () => NodeMaterial): NodeMaterial {
    const key = texture.uuid
    const cached = PhysicsExplodingSpriteEffect.materialCache.get(key)
    if (cached) return cached

    const a_uvOffset = attribute("a_uvOffset", "vec4")
    const uvOffset = vec2(a_uvOffset.x, a_uvOffset.y)
    const uvSize = vec2(a_uvOffset.z, a_uvOffset.w)

    const baseUV = uv()
    const finalUV = baseUV.mul(uvSize).add(uvOffset)

    const mapNode = tslTexture(texture)
    const sampledColor = mapNode.sample(finalUV)

    const material = materialFactory()
    material.colorNode = sampledColor

    PhysicsExplodingSpriteEffect.materialCache.set(key, material)
    return material
  }

  update(deltaTimeMs: number): void {
    if (!this.isActive) return

    this.timeElapsedMs += deltaTimeMs

    const tempMatrix = new THREE.Matrix4()
    const tempScale = new THREE.Vector3()
    this.spriteWorldTransform.decompose(new THREE.Vector3(), new THREE.Quaternion(), tempScale)

    const axis = new THREE.Vector3(0, 0, 1)
    for (const particle of this.particles) {
      const position = particle.rigidBody.getTranslation()
      const rotation = particle.rigidBody.getRotation()
      const quaternion = new THREE.Quaternion().setFromAxisAngle(axis, rotation)

      tempMatrix.compose(new THREE.Vector3(position.x, position.y, 0), quaternion, tempScale)

      this.instancedMesh.setMatrixAt(particle.instanceIndex, tempMatrix)
    }

    this.instancedMesh.instanceMatrix.needsUpdate = true

    if (this.timeElapsedMs >= this.params.durationMs) {
      this.dispose()
    }
  }

  dispose(): void {
    if (!this.isActive) return
    this.isActive = false

    if (this.instancedMesh) {
      this.scene.remove(this.instancedMesh)

      const poolKey = `${this.params.numRows}x${this.params.numCols}`
      this.resource.meshPool.releaseMesh(poolKey, this.instancedMesh)
    }

    for (const particle of this.particles) {
      this.physicsWorld.removeRigidBody(particle.rigidBody)
    }
    this.particles = []
  }
}

export class PhysicsExplosionManager {
  private scene: THREE.Scene
  private physicsWorld: PhysicsWorld
  private activeExplosions: PhysicsExplodingSpriteEffect[] = []

  constructor(scene: THREE.Scene, physicsWorld: PhysicsWorld) {
    this.scene = scene
    this.physicsWorld = physicsWorld
  }

  public fillPool(
    resource: SpriteResource,
    count: number,
    params: Partial<PhysicsExplosionEffectParameters> = {},
  ): void {
    const effectParams = { ...DEFAULT_PHYSICS_EXPLOSION_PARAMETERS, ...params }
    const poolKey = `${effectParams.numRows}x${effectParams.numCols}`
    const particleUnitWidth = 1.0 / effectParams.numCols
    const particleUnitHeight = 1.0 / effectParams.numRows
    const numParticles = effectParams.numRows * effectParams.numCols

    const materialFactory = params.materialFactory ?? DEFAULT_PHYSICS_EXPLOSION_PARAMETERS.materialFactory
    const material = PhysicsExplodingSpriteEffect.getSharedMaterial(resource.texture, materialFactory)
    const geometry = new THREE.PlaneGeometry(particleUnitWidth, particleUnitHeight)

    resource.meshPool.fill(
      poolKey,
      {
        geometry: () => geometry,
        material,
        maxInstances: numParticles,
        name: `PhysicsExplodingSprite_${poolKey}`,
      },
      count,
    )
  }

  private _createEffectCreationData(sprite: TiledSprite): PhysicsExplosionCreationData {
    const animState = sprite.currentAnimation.state
    const resource = sprite.currentAnimation.getResource()
    const currentAbsoluteFrame = animState.animFrameOffset + sprite.currentAnimation.currentLocalFrame
    const frameUOffset = currentAbsoluteFrame * resource.uvTileSize.x
    return {
      resource: resource,
      frameUvOffset: new THREE.Vector2(frameUOffset, 0),
      frameUvSize: resource.uvTileSize.clone(),
      spriteWorldTransform: sprite.getWorldTransform(),
    }
  }

  public async createExplosionForSprite(
    spriteToExplode: TiledSprite,
    userParams?: Partial<PhysicsExplosionEffectParameters>,
  ): Promise<PhysicsExplosionHandle | null> {
    const effectCreationData = this._createEffectCreationData(spriteToExplode)
    const definition = spriteToExplode.definition
    const transform = spriteToExplode.currentTransform
    const spriteRecreationData: PhysicsSpriteRecreationData = {
      definition: definition,
      currentTransform: transform,
    }

    spriteToExplode.destroy()

    const effect = new PhysicsExplodingSpriteEffect(
      this.scene,
      this.physicsWorld,
      effectCreationData.resource,
      effectCreationData.frameUvOffset,
      effectCreationData.frameUvSize,
      effectCreationData.spriteWorldTransform,
      userParams,
    )
    this.activeExplosions.push(effect)

    const handle: PhysicsExplosionHandle = {
      effect: effect,
      recreationData: spriteRecreationData,
      hasBeenRestored: false,
      restoreSprite: async (spriteAnimator: SpriteAnimator): Promise<TiledSprite | null> => {
        if (handle.hasBeenRestored) {
          return null
        }

        handle.effect.dispose()

        const newSprite = await spriteAnimator.createSprite(handle.recreationData.definition)
        const currentSpriteTransform = handle.recreationData.currentTransform
        newSprite.setTransform(
          currentSpriteTransform.position,
          currentSpriteTransform.quaternion,
          currentSpriteTransform.scale,
        )
        handle.hasBeenRestored = true

        return newSprite
      },
    }
    return handle
  }

  public update(deltaTimeMs: number): void {
    for (let i = this.activeExplosions.length - 1; i >= 0; i--) {
      const explosion = this.activeExplosions[i]
      explosion.update(deltaTimeMs)
      if (!explosion.isActive) {
        this.activeExplosions.splice(i, 1)
      }
    }
  }

  public disposeAll(): void {
    this.activeExplosions.forEach((exp) => exp.dispose())
    this.activeExplosions = []
  }
}


================================================
FILE: packages/core/src/3d/animation/SpriteAnimator.ts
================================================
import * as THREE from "three"
import { uniform, texture as tslTexture, uv, float, vec2, bufferAttribute, mix } from "three/tsl"
import { MeshBasicNodeMaterial, NodeMaterial } from "three/webgpu"
import type { Scene } from "three"
import { type SpriteResource, InstanceManager } from "../SpriteResourceManager.js"

export interface AnimationStateConfig {
  imagePath: string
  sheetNumFrames: number

  animNumFrames: number
  animFrameOffset: number

  frameDuration?: number
  loop?: boolean
  initialFrame?: number
  flipX?: boolean
  flipY?: boolean
}

export type ResolvedAnimationState = Required<AnimationStateConfig> & {
  sheetTilesetWidth: number
  sheetTilesetHeight: number
  texture: THREE.DataTexture
}

export interface AnimationDefinition {
  resource: SpriteResource
  animNumFrames?: number
  animFrameOffset?: number
  frameDuration?: number
  loop?: boolean
  initialFrame?: number
  flipX?: boolean
  flipY?: boolean
}

export interface SpriteDefinition {
  id?: string
  renderOrder?: number
  depthWrite?: boolean
  maxInstances?: number
  scale?: number
  initialAnimation: string
  animations: Record<string, AnimationDefinition>
}

const HIDDEN_MATRIX = new THREE.Matrix4().scale(new THREE.Vector3(0, 0, 0))

const DEFAULT_FRAME_DURATION = 100
const DEFAULT_INITIAL_FRAME = 0
const DEFAULT_SCALE = 1.0
const DEFAULT_FLIP_X = false
const DEFAULT_FLIP_Y = false

class Animation {
  public readonly name: string
  public state: ResolvedAnimationState
  private resource: SpriteResource
  public instanceIndex: number
  private instanceManager: InstanceManager
  private frameAttribute: THREE.InstancedBufferAttribute
  private flipAttribute: THREE.InstancedBufferAttribute

  public currentLocalFrame: number
  public timeAccumulator: number
  public isPlaying: boolean
  private _isActive: boolean = false

  constructor(
    name: string,
    state: ResolvedAnimationState,
    resource: SpriteResource,
    instanceIndex: number,
    instanceManager: InstanceManager,
    frameAttribute: THREE.InstancedBufferAttribute,
    flipAttribute: THREE.InstancedBufferAttribute,
  ) {
    this.name = name
    this.state = state
    this.resource = resource
    this.instanceIndex = instanceIndex
    this.instanceManager = instanceManager
    this.frameAttribute = frameAttribute
    this.flipAttribute = flipAttribute

    this.currentLocalFrame = state.initialFrame
    this.timeAccumulator = 0
    this.isPlaying = true

    this.instanceManager.mesh.setMatrixAt(this.instanceIndex, HIDDEN_MATRIX)
    const absoluteFrame = this.state.animFrameOffset + this.currentLocalFrame
    this.frameAttribute.setX(this.instanceIndex, absoluteFrame)
    this.flipAttribute.setXY(this.instanceIndex, this.state.flipX ? 1.0 : 0.0, this.state.flipY ? 1.0 : 0.0)
  }

  activate(worldTransform: THREE.Matrix4): void {
    this._isActive = true
    this.isPlaying = true // Start playing when activated
    this.currentLocalFrame = this.state.initialFrame // Reset to initial frame
    this.timeAccumulator = 0
    this.updateVisuals(worldTransform) // Apply transform and set frame
    // Ensure frame attribute is updated upon activation
    const absoluteFrame = this.state.animFrameOffset + this.currentLocalFrame
    this.frameAttribute.setX(this.instanceIndex, absoluteFrame)
    this.frameAttribute.needsUpdate = true // Mark manager for update
    this.flipAttribute.setXY(this.instanceIndex, this.state.flipX ? 1.0 : 0.0, this.state.flipY ? 1.0 : 0.0)
    this.flipAttribute.needsUpdate = true
  }

  deactivate(): void {
    this._isActive = false
    this.isPlaying = false
    this.instanceManager.mesh.setMatrixAt(this.instanceIndex, HIDDEN_MATRIX)
  }

  updateVisuals(worldTransform: THREE.Matrix4): void {
    if (!this._isActive) return
    this.instanceManager.mesh.setMatrixAt(this.instanceIndex, worldTransform)
  }

  updateTime(deltaTimeMs: number): boolean {
    // Returns true if frame attribute was updated
    if (!this.isPlaying || !this._isActive) return false

    this.timeAccumulator += deltaTimeMs
    let needsFrameAttributeUpdate = false

    if (this.timeAccumulator >= this.state.frameDuration) {
      const framesToAdvance = Math.floor(this.timeAccumulator / this.state.frameDuration)
      this.timeAccumulator %= this.state.frameDuration

      const oldLocalFrame = this.currentLocalFrame
      let nextLocalFrame = this.currentLocalFrame + framesToAdvance

      if (nextLocalFrame >= this.state.animNumFrames) {
        if (this.state.loop) {
          this.currentLocalFrame = nextLocalFrame % this.state.animNumFrames
        } else {
          this.currentLocalFrame = this.state.animNumFrames - 1
          this.isPlaying = false
        }
      } else {
        this.currentLocalFrame = nextLocalFrame
      }

      if (this.currentLocalFrame !== oldLocalFrame || !this.isPlaying) {
        const absoluteFrame = this.state.animFrameOffset + this.currentLocalFrame
        this.frameAttribute.setX(this.instanceIndex, absoluteFrame)
        this.frameAttribute.needsUpdate = true
        needsFrameAttributeUpdate = true
      }
    }
    return needsFrameAttributeUpdate
  }

  play(): void {
    if (!this._isActive) return
    this.isPlaying = true
  }

  stop(): void {
    this.isPlaying = false
  }

  goToFrame(localFrame: number): void {
    if (!this._isActive) return
    const targetLocalFrame = Math.max(0, Math.min(localFrame, this.state.animNumFrames - 1))
    if (this.currentLocalFrame !== targetLocalFrame) {
      this.currentLocalFrame = targetLocalFrame
      this.timeAccumulator = 0
      const absoluteFrame = this.state.animFrameOffset + this.currentLocalFrame
      this.frameAttribute.setX(this.instanceIndex, absoluteFrame)
      this.frameAttribute.needsUpdate = true // Mark manager for update
    }
  }

  setFrameDuration(newFrameDuration: number): void {
    if (newFrameDuration > 0) {
      this.state = { ...this.state, frameDuration: newFrameDuration }
    }
  }

  getResource(): SpriteResource {
    return this.resource
  }

  releaseInstanceSlot(): void {
    this.instanceManager.releaseInstanceSlot(this.instanceIndex)
  }
}

export class TiledSprite {
  public readonly id: string
  private animator: SpriteAnimator
  private _animations: Map<string, Animation>
  private _currentAnimation: Animation
  private _transformObject: THREE.Object3D

  private _reusableMatrix: THREE.Matrix4
  private _reusableAnimGeomScale: THREE.Vector3
  private _isVisibleState: boolean = true
  private originalDefinition: SpriteDefinition

  constructor(
    id: string,
    userSpriteDefinition: SpriteDefinition,
    animator: SpriteAnimator,
    animationInstanceParams: Array<{
      name: string
      state: ResolvedAnimationState
      resource: SpriteResource
      index: number
      instanceManager: InstanceManager
      frameAttribute: THREE.InstancedBufferAttribute
      flipAttribute: THREE.InstancedBufferAttribute
    }>,
  ) {
    this.id = id
    this.originalDefinition = userSpriteDefinition
    this.animator = animator
    this._transformObject = new THREE.Object3D()
    this._reusableMatrix = new THREE.Matrix4()
    this._reusableAnimGeomScale = new THREE.Vector3()

    const initialScale = userSpriteDefinition.scale ?? DEFAULT_SCALE
    this._transformObject.scale.set(initialScale, initialScale, initialScale)

    this._animations = new Map()
    for (const params of animationInstanceParams) {
      const anim = new Animation(
        params.name,
        params.state,
        params.resource,
        params.index,
        params.instanceManager,
        params.frameAttribute,
        params.flipAttribute,
      )
      this._animations.set(params.name, anim)
    }

    const initialAnim = this._animations.get(userSpriteDefinition.initialAnimation)
    if (!initialAnim) {
      throw new Error(
        `[TiledSprite] Initial animation "${userSpriteDefinition.initialAnimation}" not found for sprite "${this.id}".`,
      )
    }
    this._currentAnimation = initialAnim
    const initialWorldMatrix = this._calculateAnimationWorldMatrix(this._currentAnimation.state)
    this._currentAnimation.activate(initialWorldMatrix)
    this._isVisibleState = true
  }

  private _calculateAnimationWorldMatrix(animState: ResolvedAnimationState): THREE.Matrix4 {
    const matrix = this._reusableMatrix
    const animGeomScale = this._reusableAnimGeomScale
    const worldHeight = this._transformObject.scale.y
    const frameAspectRatio = animState.sheetTilesetWidth / animState.sheetNumFrames / animState.sheetTilesetHeight
    const worldWidth = worldHeight * frameAspectRatio
    animGeomScale.set(worldWidth, worldHeight, this._transformObject.scale.z)
    matrix.compose(this._transformObject.position, this._transformObject.quaternion, animGeomScale)
    return matrix
  }

  public get currentAnimation(): Animation {
    return this._currentAnimation
  }

  private updateCurrentAnimationVisuals(): void {
    if (this._isVisibleState) {
      const currentAnim = this.currentAnimation
      if (currentAnim) {
        const finalMatrix = this._calculateAnimationWorldMatrix(currentAnim.state)
        currentAnim.updateVisuals(finalMatrix)
      }
    }
  }

  setPosition(position: THREE.Vector3): void {
    this._transformObject.position.copy(position)
    this.updateCurrentAnimationVisuals()
  }

  setRotation(rotation: THREE.Quaternion): void {
    this._transformObject.quaternion.copy(rotation)
    this.updateCurrentAnimationVisuals()
  }

  setScale(scale: THREE.Vector3): void {
    this._transformObject.scale.copy(scale)
    this.updateCurrentAnimationVisuals()
  }

  getScale(): THREE.Vector3 {
    return this._transformObject.scale.clone()
  }

  setTransform(position: THREE.Vector3, rotation: THREE.Quaternion, newScale: THREE.Vector3): void {
    this._transformObject.position.copy(position)
    this._transformObject.quaternion.copy(rotation)
    this._transformObject.scale.copy(newScale)
    this.updateCurrentAnimationVisuals()
  }

  play(): void {
    this.currentAnimation.play()
  }
  stop(): void {
    this.currentAnimation.stop()
  }
  goToFrame(frame: number): void {
    this.currentAnimation.goToFrame(frame)
  }
  setFrameDuration(newFrameDuration: number): void {
    this.currentAnimation.setFrameDuration(newFrameDuration)
  }

  isPlaying(): boolean {
    return this.currentAnimation.isPlaying
  }

  async setAnimation(animationName: string): Promise<void> {
    const newAnim = this._animations.get(animationName)
    if (!newAnim) {
      throw new Error(`[TiledSprite] Animation "${animationName}" not found for sprite "${this.id}".`)
    }

    const switchingToSameAnimation = this._currentAnimation.name === animationName
    const oldAnim = this._currentAnimation

    if (!switchingToSameAnimation || !this._isVisibleState) {
      oldAnim?.deactivate()
    }

    this._currentAnimation = newAnim

    if (this._isVisibleState) {
      const finalMatrix = this._calculateAnimationWorldMatrix(newAnim.state)
      newAnim.activate(finalMatrix)
    } else {
      newAnim.deactivate()
    }
  }

  update(deltaTime: number): void {
    if (this.visible) {
      this.currentAnimation.updateTime(deltaTime)
    }
  }

  destroy(): void {
    this._animations.forEach((anim) => {
      anim.deactivate()
      anim.releaseInstanceSlot()
    })
    this._animations.clear()
    this._isVisibleState = false
  }

  getCurrentAnimationName(): string {
    return this._currentAnimation.name
  }

  getWorldTransform(): THREE.Matrix4 {
    return this._calculateAnimationWorldMatrix(this._currentAnimation.state)
  }

  getWorldPlaneSize(): THREE.Vector2 {
    const animState = this._currentAnimation.state
    const worldHeight = this._transformObject.scale.y
    const frameActualWidthPx = animState.sheetTilesetWidth / animState.sheetNumFrames
    const frameAspectRatio = frameActualWidthPx / animState.sheetTilesetHeight
    const worldWidth = worldHeight * frameAspectRatio
    return new THREE.Vector2(worldWidth, worldHeight)
  }

  get visible(): boolean {
    return this._isVisibleState
  }

  set visible(value: boolean) {
    if (this._isVisibleState === value) {
      return
    }
    this._isVisibleState = value
    if (value) {
      const finalMatrix = this._calculateAnimationWorldMatrix(this._currentAnimation.state)
      this._currentAnimation.activate(finalMatrix)
    } else {
      this._currentAnimation.deactivate()
    }
  }

  public get definition(): SpriteDefinition {
    return this.originalDefinition
  }

  public get currentTransform(): {
    position: THREE.Vector3
    quaternion: THREE.Quaternion
    scale: THREE.Vector3
  } {
    return {
      position: this._transformObject.position.clone(),
      quaternion: this._transformObject.quaternion.clone(),
      scale: this._transformObject.scale.clone(),
    }
  }
}

interface SpriteAnimatorInstanceManager {
  instanceManager: InstanceManager
  frameAttribute: THREE.InstancedBufferAttribute
  flipAttribute: THREE.InstancedBufferAttribute
  uvTileSize: THREE.Vector2
}

export class SpriteAnimator {
  private instances: Map<string, TiledSprite> = new Map()
  private _idCounter = 0
  private instanceManagers: Map<string, SpriteAnimatorInstanceManager> = new Map()

  constructor(private scene: Scene) {}

  private createSpriteAnimationMaterial(
    resource: SpriteResource,
    frameAttribute: THREE.InstancedBufferAttribute,
    flipAttribute: THREE.InstancedBufferAttribute,
    materialFactory: () => NodeMaterial,
  ): NodeMaterial {
    const texture = resource.texture
    const sheetProps = resource.sheetProperties

    const uvTileWidth = 1.0 / sheetProps.sheetNumFrames
    const uvTileHeight = 1.0
    const uvTileSize = new THREE.Vector2(uvTileWidth, uvTileHeight)

    const tileSizeUniform = uniform(uvTileSize)
    const epsilon = float(0.000001)

    const baseUV = uv()
    const oneFloat = float(1.0)

    const a_frameIndex = bufferAttribute(frameAttribute)
    const a_flip = bufferAttribute(flipAttribute)

    const calculatedTileCoordX = a_frameIndex.mul(tileSizeUniform.x)
    const calculatedTileCoord = vec2(calculatedTileCoordX, float(0))

    const flippedX = mix(baseUV.x, oneFloat.sub(baseUV.x), a_flip.x)
    const flippedY = mix(baseUV.y, oneFloat.sub(baseUV.y), a_flip.y)
    const finalLocalUV = vec2(flippedX, flippedY)

    const mapNode = tslTexture(texture)
    const finalUV = finalLocalUV.mul(tileSizeUniform).min(tileSizeUniform.sub(epsilon)).add(calculatedTileCoord)
    const sampledColor = mapNode.sample(finalUV)

    const material = materialFactory()
    material.colorNode = sampledColor

    return material
  }

  private getOrCreateInstanceManager(
    resource: SpriteResource,
    maxInstances: number,
    renderOrder: number,
    depthWrite: boolean,
    materialFactory: () => NodeMaterial,
  ): SpriteAnimatorInstanceManager {
    const key = `${resource.sheetProperties.imagePath}_${maxInstances}_${renderOrder}_${depthWrite}`
    let manager = this.instanceManagers.get(key)

    if (!manager) {
      const geometry = new THREE.PlaneGeometry(1, 1)
      const frameArray = new Float32Array(maxInstances)
      const frameAttribute = new THREE.InstancedBufferAttribute(frameArray, 1)
      frameAttribute.setUsage(THREE.DynamicDrawUsage)

      const flipArray = new Float32Array(maxInstances * 2)
      const flipAttribute = new THREE.InstancedBufferAttribute(flipArray, 2)
      flipAttribute.setUsage(THREE.DynamicDrawUsage)

      const material = this.createSpriteAnimationMaterial(resource, frameAttribute, flipAttribute, materialFactory)

      geometry.setAttribute("a_frameIndexInstanced", frameAttribute)
      geometry.setAttribute("a_flipInstanced", flipAttribute)

      for (let i = 0; i < maxInstances; i++) {
        flipAttribute.setXY(i, 0.0, 0.0)
      }
      flipAttribute.needsUpdate = true

      const instanceManager = resource.createInstanceManager(geometry, material, {
        maxInstances,
        renderOrder,
        depthWrite,
        name: `SpriteAnimator_${key}`,
      })

      const uvTileWidth = 1.0 / resource.sheetProperties.sheetNumFrames
      const uvTileSize = new THREE.Vector2(uvTileWidth, 1.0)

      manager = {
        instanceManager,
        frameAttribute,
        flipAttribute,
        uvTileSize,
      }

      this.instanceManagers.set(key, manager)
    }

    return manager
  }

  async createSprite(
    userSpriteDefinition: SpriteDefinition,
    materialFactory?: () => NodeMaterial,
  ): Promise<TiledSprite> {
    const id = userSpriteDefinition.id ?? `sprite_${this._idCounter++}`
    const animationInstanceParams: Array<{
      name: string
      state: ResolvedAnimationState
      resource: SpriteResource
      index: number
      instanceManager: InstanceManager
      frameAttribute: THREE.InstancedBufferAttribute
      flipAttribute: THREE.InstancedBufferAttribute
    }> = []

    const resolvedMaterialFactory =
      materialFactory ??
      (() =>
        new MeshBasicNodeMaterial({
          transparent: true,
          alphaTest: 0.1,
          depthWrite: true,
        }))

    // Track instance managers as we encounter resources
    const resourceManagers = new Map<SpriteResource, SpriteAnimatorInstanceManager>()

    for (const animName in userSpriteDefinition.animations) {
      const animDef = userSpriteDefinition.animations[animName]
      const resource = animDef.resource

      // Get or create instance manager for this resource
      let managerInfo = resourceManagers.get(resource)
      if (!managerInfo) {
        const maxInstances = userSpriteDefinition.maxInstances ?? 1024
        const renderOrder = userSpriteDefinition.renderOrder ?? 0
        const depthWrite = userSpriteDefinition.depthWrite ?? true
        managerInfo = this.getOrCreateInstanceManager(
          resource,
          maxInstances,
          renderOrder,
          depthWrite,
          resolvedMaterialFactory,
        )
        resourceManagers.set(resource, managerInfo)
      }

      const instanceIndex = managerInfo.instanceManager.acquireInstanceSlot()

      const resolvedState: ResolvedAnimationState = {
        imagePath: resource.sheetProperties.imagePath,
        sheetTilesetWidth: resource.sheetProperties.sheetTilesetWidth,
        sheetTilesetHeight: resource.sheetProperties.sheetTilesetHeight,
        sheetNumFrames: resource.sheetProperties.sheetNumFrames,
        animNumFrames: animDef.animNumFrames ?? resource.sheetProperties.sheetNumFrames,
        animFrameOffset: animDef.animFrameOffset ?? 0,
        frameDuration: animDef.frameDuration ?? DEFAULT_FRAME_DURATION,
        loop: animDef.loop ?? true,
        initialFrame: animDef.initialFrame ?? DEFAULT_INITIAL_FRAME,
        flipX: animDef.flipX ?? DEFAULT_FLIP_X,
        flipY: animDef.flipY ?? DEFAULT_FLIP_Y,
        texture: resource.texture,
      }

      animationInstanceParams.push({
        name: animName,
        state: resolvedState,
        resource,
        index: instanceIndex,
        instanceManager: managerInfo.instanceManager,
        frameAttribute: managerInfo.frameAttribute,
        flipAttribute: managerInfo.flipAttribute,
      })
    }

    if (
      !userSpriteDefinition.initialAnimation ||
      !userSpriteDefinition.animations[userSpriteDefinition.initialAnimation]
    ) {
      let found = false
      for (const p of animationInstanceParams) if (p.name === userSpriteDefinition.initialAnimation) found = true
      if (!found) {
        for (const params of animationInstanceParams) {
          params.instanceManager.releaseInstanceSlot(params.index)
        }
        throw new Error(
          `[SpriteAnimator] initialAnimation "${userSpriteDefinition.initialAnimation}" not found or invalid for sprite "${id}".`,
        )
      }
    }
    const tiledSprite = new TiledSprite(id, userSpriteDefinition, this, animationInstanceParams)
    this.instances.set(id, tiledSprite)
    return tiledSprite
  }

  update(deltaTime: number): void {
    for (const sprite of this.instances.values()) {
      sprite.update(deltaTime)
    }
  }

  removeSprite(id: string): void {
    const sprite = this.instances.get(id)
    if (sprite) {
      sprite.destroy()
      this.instances.delete(id)
    }
  }

  removeAllSprites(): void {
    const ids = Array.from(this.instances.keys())
    for (const id of ids) {
      this.removeSprite(id)
    }
  }
}


================================================
FILE: packages/core/src/3d/animation/SpriteParticleGenerator.ts
================================================
import * as THREE from "three"
import {
  uniform,
  texture as tslTexture,
  uv,
  float,
  vec2,
  vec3,
  vec4,
  bufferAttribute,
  step,
  max,
  sin,
  cos,
  positionLocal,
  mat3,
  mix,
  floor,
  mod,
} from "three/tsl"
import { MeshBasicNodeMaterial, NodeMaterial } from "three/webgpu"
import type { SpriteResource, InstanceManager } from "../SpriteResourceManager.js"

export interface ParticleEffectParameters {
  resource: SpriteResource
  animNumFrames?: number
  animFrameOffset?: number
  frameDuration?: number
  loop?: boolean
  scale?: number
  renderOrder?: number
  depthWrite?: boolean
  maxParticles: number
  lifetimeMsMin: number
  lifetimeMsMax: number
  origins: THREE.Vector3[]
  spawnRadius: number | THREE.Vector3
  initialVelocityMin: THREE.Vector3
  initialVelocityMax: THREE.Vector3
  angularVelocityMin: THREE.Vector3
  angularVelocityMax: THREE.Vector3
  gravity?: THREE.Vector3
  randomGravityFactorMinMax?: THREE.Vector2
  scaleOverLifeMinMax?: THREE.Vector2
  fadeOut?: boolean
  materialFactory?: () => NodeMaterial
}

interface AutoSpawnConfig {
  resolvedParams: ParticleEffectParameters
  originalOverrides?: Partial<ParticleEffectParameters>
  ratePerSecond: number
  accumulator: number
}

interface ParticleSlot {
  isActive: boolean
  spawnTime: number
  lifespan: number
}

export class SpriteParticleGenerator {
  private scene: THREE.Scene
  private baseConfig: ParticleEffectParameters
  private autoSpawnConfig: AutoSpawnConfig | null = null
  private _currentOriginIndex: number = 0

  private instanceManager: InstanceManager | null = null
  private material: NodeMaterial | null = null
  private texture: THREE.DataTexture | null = null

  private particleDataAttribute: THREE.InstancedBufferAttribute | null = null // [originX, originY, originZ, spawnTime]
  private velocityAttribute: THREE.InstancedBufferAttribute | null = null // [velX, velY, velZ, gravityFactor]
  private angularVelAttribute: THREE.InstancedBufferAttribute | null = null // [angVelX, angVelY, angVelZ, lifespan]
  private scaleDataAttribute: THREE.InstancedBufferAttribute | null = null // [initialScale, scaleMin, scaleMax, randomSeed]

  private timeUniform: ReturnType<typeof uniform<number>>
  private gravityUniform: ReturnType<typeof uniform<THREE.Vector3>>
  private animationUniform: ReturnType<typeof uniform<THREE.Vector4>> // [frameDuration, animNumFrames, loop, animFrameOffset]
  private sheetNumFramesUniform: ReturnType<typeof uniform<number>>

  private particleSlots: ParticleSlot[] = []
  private currentTime: number = 0
  private maxParticles: number
  private isInitialized: boolean = false

  constructor(scene: THREE.Scene, initialBaseConfig: ParticleEffectParameters) {
    this.scene = scene
    this.baseConfig = { ...initialBaseConfig }
    this.maxParticles = this.baseConfig.maxParticles

    if (!this.baseConfig.resource) {
      throw new Error("[SpriteParticleGenerator] resource is mandatory in initialBaseConfig.")
    }

    this.timeUniform = uniform(0)
    this.gravityUniform = uniform(this.baseConfig.gravity || new THREE.Vector3(0, -9.8, 0))
    this.animationUniform = uniform(new THREE.Vector4())
    this.sheetNumFramesUniform = uniform(1)
  }

  private async _ensureInitialized(): Promise<void> {
    if (this.isInitialized) return
    await this._initializeGPUParticleSystem()
    this.isInitialized = true
  }

  private async _initializeGPUParticleSystem(): Promise<void> {
    const resource = this.baseConfig.resource

    this.texture = resource.texture

    // Set up animation uniforms from particle config
    const frameDuration = (this.baseConfig.frameDuration ?? 100) / 1000 // Convert to seconds
    const animNumFrames = this.baseConfig.animNumFrames ?? resource.sheetProperties.sheetNumFrames
    const loop = (this.baseConfig.loop ?? true) ? 1.0 : 0.0 // Default to true
    const animFrameOffset = this.baseConfig.animFrameOffset ?? 0

    this.animationUniform.value.set(frameDuration, animNumFrames, loop, animFrameOffset)
    this.sheetNumFramesUniform.value = resource.sheetProperties.sheetNumFrames

    const particleData = new Float32Array(this.maxParticles * 4)
    const velocityData = new Float32Array(this.maxParticles * 4)
    const angularVelData = new Float32Array(this.maxParticles * 4)
    const scaleData = new Float32Array(this.maxParticles * 4)

    this.particleDataAttribute = new THREE.InstancedBufferAttribute(particleData, 4)
    this.velocityAttribute = new THREE.InstancedBufferAttribute(velocityData, 4)
    this.angularVelAttribute = new THREE.InstancedBufferAttribute(angularVelData, 4)
    this.scaleDataAttribute = new THREE.InstancedBufferAttribute(scaleData, 4)

    this.particleDataAttribute.setUsage(THREE.DynamicDrawUsage)
    this.velocityAttribute.setUsage(THREE.DynamicDrawUsage)
    this.angularVelAttribute.setUsage(THREE.DynamicDrawUsage)
    this.scaleDataAttribute.setUsage(THREE.DynamicDrawUsage)

    for (let i = 0; i < this.maxParticles; i++) {
      this.particleSlots.push({ isActive: false, spawnTime: 0, lifespan: 0 })

      particleData[i * 4 + 3] = -1 // Mark as inactive with negative spawn time
    }

    const frameAspectRatio =
      this.texture.image.width / resource.sheetProperties.sheetNumFrames / this.texture.image.height
    const scale = this.baseConfig.scale ?? 1.0
    const geometry = new THREE.PlaneGeometry(scale * frameAspectRatio, scale)

    geometry.setAttribute("a_particleData", this.particleDataAttribute)
    geometry.setAttribute("a_velocity", this.velocityAttribute)
    geometry.setAttribute("a_angularVel", this.angularVelAttribute)
    geometry.setAttribute("a_scaleData", this.scaleDataAttribute)

    const materialFactory =
      this.baseConfig.materialFactory ??
      (() =>
        new MeshBasicNodeMaterial({
          transparent: true,
          alphaTest: 0.01,
          side: THREE.DoubleSide,
          depthWrite: this.baseConfig.depthWrite ?? false,
        }))
    const material = this._createGPUMaterial(materialFactory)
    this.instanceManager = resource.createInstanceManager(geometry, material, {
      maxInstances: this.maxParticles,
      renderOrder: this.baseConfig.renderOrder ?? 0,
      depthWrite: this.baseConfig.depthWrite ?? true,
      name: `SpriteParticleGenerator_${resource.sheetProperties.imagePath.replace(/[^a-zA-Z0-9_]/g, "_")}`,
      matrix: new THREE.Matrix4(),
    })
  }

  private _createGPUMaterial(materialFactory: () => NodeMaterial): NodeMaterial {
    const a_particleData = bufferAttribute(this.particleDataAttribute!)
    const a_velocity = bufferAttribute(this.velocityAttribute!)
    const a_angularVel = bufferAttribute(this.angularVelAttribute!)
    const a_scaleData = bufferAttribute(this.scaleDataAttribute!)

    const origin = vec3(a_particleData.x, a_particleData.y, a_particleData.z)
    const spawnTime = a_particleData.w

    const initialVelocity = vec3(a_velocity.x, a_velocity.y, a_velocity.z)
    const gravityFactor = a_velocity.w

    const angularVelocity = vec3(a_angularVel.x, a_angularVel.y, a_angularVel.z)
    const lifespan = a_angularVel.w

    const initialScale = a_scaleData.x
    const scaleMin = a_scaleData.y
    const scaleMax = a_scaleData.z
    const randomSeed = a_scaleData.w

    const age = this.timeUniform.sub(spawnTime)
    const normalizedAge = age.div(lifespan)
    const isAlive = step(float(0), spawnTime).mul(step(normalizedAge, float(1.0)))

    const gravity = this.gravityUniform.mul(gravityFactor)
    const velocityContribution = initialVelocity.mul(age)
    const gravityContribution = gravity.mul(age).mul(age).mul(float(0.5))
    const currentPosition = origin.add(velocityContribution).add(gravityContribution)

    const rotationAmount = angularVelocity.mul(age)
    const cosX = cos(rotationAmount.x)
    const sinX = sin(rotationAmount.x)
    const cosY = cos(rotationAmount.y)
    const sinY = sin(rotationAmount.y)
    const cosZ = cos(rotationAmount.z)
    const sinZ = sin(rotationAmount.z)

    const rotationMatrix = mat3(
      cosY.mul(cosZ),
      cosY.mul(sinZ).negate(),
      sinY,
      sinX.mul(sinY).mul(cosZ).add(cosX.mul(sinZ)),
      sinX.mul(sinY).mul(sinZ).negate().add(cosX.mul(cosZ)),
      sinX.mul(cosY).negate(),
      cosX.mul(sinY).mul(cosZ).negate().add(sinX.mul(sinZ)),
      cosX.mul(sinY).mul(sinZ).add(sinX.mul(cosZ)),
      cosX.mul(cosY),
    )

    const rotatedVertexPosition = rotationMatrix.mul(positionLocal)

    let currentScale = initialScale
    if (this.baseConfig.scaleOverLifeMinMax) {
      const scaleMultiplier = mix(scaleMin, scaleMax, normalizedAge)
      currentScale = initialScale.mul(scaleMultiplier)
    }

    const scaledPosition = rotatedVertexPosition.mul(currentScale)
    const finalPosition = scaledPosition.add(currentPosition)

    let opacity = float(1.0)
    if (this.baseConfig.fadeOut) {
      const fadeStart = float(0.7)
      const fadeProgress = max(float(0), normalizedAge.sub(fadeStart).div(float(1.0).sub(fadeStart)))
      opacity = float(1.0).sub(fadeProgress)
    }
    opacity = opacity.mul(isAlive)

    // Dynamic frame calculation based on particle age
    const frameDuration = this.animationUniform.x
    const animNumFrames = this.animationUniform.y
    const loopFlag = this.animationUniform.z
    const animFrameOffset = this.animationUniform.w

    const frameFloat = age.div(frameDuration)
    const rawFrameIndex = floor(frameFloat)

    // Handle looping vs clamping
    const maxFrame = animNumFrames.sub(float(1))
    const clampedFrame = max(float(0), rawFrameIndex).min(maxFrame)
    const loopedFrame = rawFrameIndex.mod(animNumFrames)
    const finalLocalFrame = mix(clampedFrame, loopedFrame, loopFlag)

    const frameIndex = animFrameOffset.add(finalLocalFrame)

    const uvTileWidth = float(1.0).div(this.sheetNumFramesUniform)
    const uvOffset = vec2(frameIndex.mul(uvTileWidth), float(0))
    const uvSize = vec2(uvTileWidth, float(1.0))

    const baseUV = uv()
    const finalUV = baseUV.mul(uvSize).add(uvOffset)

    const mapNode = tslTexture(this.texture!)
    const sampledColor = mapNode.sample(finalUV)

    this.material = materialFactory()

    const finalColor = vec4(sampledColor.rgb, sampledColor.a.mul(opacity))
    this.material.colorNode = finalColor
    this.material.positionNode = finalPosition

    return this.material
  }

  private _resolveCurrentOrigin(originsArray: THREE.Vector3[]): THREE.Vector3 {
    const currentOrigin = originsArray[this._currentOriginIndex]
    this._currentOriginIndex = (this._currentOriginIndex + 1) % originsArray.length
    return currentOrigin
  }

  public getActiveParticleCount(): number {
    return this.particleSlots.filter((slot) => slot.isActive).length
  }

  private _resolveSpawnRadius(spawnRadius: number | THREE.Vector3): THREE.Vector3 {
    return typeof spawnRadius === "number" ? new THREE.Vector3(spawnRadius, spawnRadius, spawnRadius) : spawnRadius
  }

  private _spawnParticle(effectiveParams: Readonly<ParticleEffectParameters>, spawnRadiusVec: THREE.Vector3): void {
    if (!this.instanceManager?.hasFreeIndices) return

    const index = this.instanceManager!.acquireInstanceSlot()
    const particleOrigin = this._resolveCurrentOrigin(effectiveParams.origins)

    const spawnOffset = new THREE.Vector3(
      (Math.random() - 0.5) * 2 * spawnRadiusVec.x,
      (Math.random() - 0.5) * 2 * spawnRadiusVec.y,
      (Math.random() - 0.5) * 2 * spawnRadiusVec.z,
    )
    const initialPosition = new THREE.Vector3().copy(particleOrigin).add(spawnOffset)

    const velocity = new THREE.Vector3(
      THREE.MathUtils.randFloat(effectiveParams.initialVelocityMin.x, effectiveParams.initialVelocityMax.x),
      THREE.MathUtils.randFloat(effectiveParams.initialVelocityMin.y, effectiveParams.initialVelocityMax.y),
      THREE.MathUtils.randFloat(effectiveParams.initialVelocityMin.z, effectiveParams.initialVelocityMax.z),
    )

    const angularVelocity = new THREE.Vector3(
      THREE.MathUtils.randFloat(effectiveParams.angularVelocityMin.x, effectiveParams.angularVelocityMax.x),
      THREE.MathUtils.randFloat(effectiveParams.angularVelocityMin.y, effectiveParams.angularVelocityMax.y),
      THREE.MathUtils.randFloat(effectiveParams.angularVelocityMin.z, effectiveParams.angularVelocityMax.z),
    )

    const lifespan = THREE.MathUtils.randFloat(effectiveParams.lifetimeMsMin, effectiveParams.lifetimeMsMax) / 1000

    let gravityFactor = 1.0
    if (effectiveParams.randomGravityFactorMinMax) {
      gravityFactor = THREE.MathUtils.randFloat(
        effectiveParams.randomGravityFactorMinMax.x,
        effectiveParams.randomGravityFactorMinMax.y,
      )
    }

    const initialScale = effectiveParams.scale ?? 1.0
    let scaleMin = initialScale
    let scaleMax = initialScale
    if (effectiveParams.scaleOverLifeMinMax) {
      scaleMin = initialScale * effectiveParams.scaleOverLifeMinMax.x
      scaleMax = initialScale * effectiveParams.scaleOverLifeMinMax.y
    }

    this.particleDataAttribute!.setXYZW(
      index,
      initialPosition.x,
      initialPosition.y,
      initialPosition.z,
      this.currentTime,
    )
    this.velocityAttribute!.setXYZW(index, velocity.x, velocity.y, velocity.z, gravityFactor)
    this.angularVelAttribute!.setXYZW(index, angularVelocity.x, angularVelocity.y, angularVelocity.z, lifespan)
    this.scaleDataAttribute!.setXYZW(index, initialScale, scaleMin, scaleMax, Math.random())

    this.particleSlots[index] = {
      isActive: true,
      spawnTime: this.currentTime,
      lifespan: lifespan,
    }

    this.particleDataAttribute!.needsUpdate = true
    this.velocityAttribute!.needsUpdate = true
    this.angularVelAttribute!.needsUpdate = true
    this.scaleDataAttribute!.needsUpdate = true
  }

  public async spawnParticles(count: number, overrides: Partial<ParticleEffectParameters> = {}): Promise<void> {
    await this._ensureInitialized()
    if (count <= 0) return

    const finalParams: ParticleEffectParameters = {
      ...this.baseConfig,
      ...overrides,
    }

    const spawnRadiusVec = this._resolveSpawnRadius(finalParams.spawnRadius)

    for (let i = 0; i < count; i++) {
      this._spawnParticle(finalParams, spawnRadiusVec)
    }
  }

  public setAutoSpawn(ratePerSecond: number, autoSpawnParamOverrides: Partial<ParticleEffectParameters> = {}): void {
    if (ratePerSecond <= 0) {
      this.stopAutoSpawn()
      return
    }
    const originalOverridesToStore =
      Object.keys(autoSpawnParamOverrides).length > 0 ? { ...autoSpawnParamOverrides } : undefined

    this.autoSpawnConfig = {
      resolvedParams: { ...this.baseConfig, ...autoSpawnParamOverrides },
      originalOverrides: originalOverridesToStore,
      ratePerSecond: ratePerSecond,
      accumulator: 0,
    }
  }

  public hasAutoSpawn(): boolean {
    return this.autoSpawnConfig !== null
  }

  public stopAutoSpawn(): void {
    this.autoSpawnConfig = null
  }

  public async update(deltaTimeMs: number): Promise<void> {
    await this._ensureInitialized()

    this.currentTime += deltaTimeMs / 1000
    this.timeUniform.value = this.currentTime

    if (this.autoSpawnConfig) {
      this.autoSpawnConfig.accumulator += deltaTimeMs
      const particlesToSpawnThisFrame = Math.floor(
        this.autoSpawnConfig.accumulator * (this.autoSpawnConfig.ratePerSecond / 1000),
      )

      if (particlesToSpawnThisFrame > 0) {
        const spawnRadiusVec = this._resolveSpawnRadius(this.autoSpawnConfig.resolvedParams.spawnRadius)
        for (let i = 0; i < particlesToSpawnThisFrame; i++) {
          this._spawnParticle(this.autoSpawnConfig.resolvedParams, spawnRadiusVec)
        }
        this.autoSpawnConfig.accumulator -= (particlesToSpawnThisFrame * 1000) / this.autoSpawnConfig.ratePerSecond
      }
    }

    for (let i = 0; i < this.particleSlots.length; i++) {
      const slot = this.particleSlots[i]
      if (slot.isActive && this.currentTime - slot.spawnTime >= slot.lifespan) {
        slot.isActive = false
        this.particleDataAttribute!.setW(i, -1)
        this.instanceManager!.releaseInstanceSlot(i)
        this.particleDataAttribute!.needsUpdate = true
      }
    }
  }

  public dispose(): void {
    if (this.instanceManager) {
      this.instanceManager.dispose()
      this.material?.dispose()
    }
    this.stopAutoSpawn()
  }
}


================================================
FILE: packages/core/src/3d/canvas.ts
================================================
import { GPUCanvasContextMock } from "bun-webgpu"
import { RGBA } from "../lib/RGBA.js"
import { SuperSampleType } from "./WGPURenderer.js"
import type { OptimizedBuffer } from "../buffer.js"
import { toArrayBuffer } from "bun:ffi"
import { Jimp } from "jimp"

// @ts-ignore
import shaderTemplate from "./shaders/supersampling.wgsl" with { type: "text" }

const WORKGROUP_SIZE = 4
const SUPERSAMPLING_COMPUTE_SHADER = shaderTemplate.replace(/\${WORKGROUP_SIZE}/g, WORKGROUP_SIZE.toString())

export enum SuperSampleAlgorithm {
  STANDARD = 0,
  PRE_SQUEEZED = 1,
}

export class CLICanvas {
  private device: GPUDevice
  private readbackBuffer: GPUBuffer | null = null
  private width: number
  private height: number
  private gpuCanvasContext: GPUCanvasContextMock

  public superSampleDrawTimeMs: number = 0
  public mapAsyncTimeMs: number = 0
  public superSample: SuperSampleType = SuperSampleType.GPU

  // Compute shader super sampling
  private computePipeline: GPUComputePipeline | null = null
  private computeBindGroupLayout: GPUBindGroupLayout | null = null
  private computeOutputBuffer: GPUBuffer | null = null
  private computeParamsBuffer: GPUBuffer | null = null
  private computeReadbackBuffer: GPUBuffer | null = null
  private updateScheduled: boolean = false
  private screenshotGPUBuffer: GPUBuffer | null = null
  private superSampleAlgorithm: SuperSampleAlgorithm = SuperSampleAlgorithm.STANDARD
  private destroyed: boolean = false

  constructor(
    device: GPUDevice,
    width: number,
    height: number,
    superSample: SuperSampleType,
    sampleAlgo: SuperSampleAlgorithm = SuperSampleAlgorithm.STANDARD,
  ) {
    this.device = device
    this.width = width
    this.height = height
    this.superSample = superSample
    this.gpuCanvasContext = new GPUCanvasContextMock(this as unknown as HTMLCanvasElement, width, height)
    this.superSampleAlgorithm = sampleAlgo
  }

  public destroy(): void {
    this.destroyed = true
  }

  public setSuperSampleAlgorithm(superSampleAlgorithm: SuperSampleAlgorithm): void {
    this.superSampleAlgorithm = superSampleAlgorithm
    this.scheduleUpdateComputeBuffers()
  }

  public getSuperSampleAlgorithm(): SuperSampleAlgorithm {
    return this.superSampleAlgorithm
  }

  getContext(type: string, attrs?: WebGLContextAt
Download .txt
gitextract_ou224iei/

├── .editorconfig
├── .github/
│   ├── CODEOWNERS
│   └── workflows/
│       ├── build-core.yml
│       ├── build-examples.yml
│       ├── build-native.yml
│       ├── build-react.yml
│       ├── build-solid.yml
│       ├── deploy.yml
│       ├── npm-latest-release.yml
│       ├── npm-release.yml
│       ├── opencode.yml
│       ├── pkg-pr-new.yml
│       ├── prettier.yml
│       ├── release.yml
│       └── review.yml
├── .gitignore
├── .prettierignore
├── .zig-version
├── AGENTS.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── opentui.pc.in
├── package.json
├── packages/
│   ├── core/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── dev/
│   │   │   ├── keypress-debug-renderer.ts
│   │   │   ├── keypress-debug.ts
│   │   │   ├── print-env-vars.ts
│   │   │   ├── test-tmux-graphics-334.sh
│   │   │   └── thai-debug-test.ts
│   │   ├── docs/
│   │   │   └── development.md
│   │   ├── package.json
│   │   ├── scripts/
│   │   │   ├── build.ts
│   │   │   └── publish.ts
│   │   ├── src/
│   │   │   ├── 3d/
│   │   │   │   ├── SpriteResourceManager.ts
│   │   │   │   ├── SpriteUtils.ts
│   │   │   │   ├── TextureUtils.ts
│   │   │   │   ├── ThreeRenderable.ts
│   │   │   │   ├── WGPURenderer.ts
│   │   │   │   ├── animation/
│   │   │   │   │   ├── ExplodingSpriteEffect.ts
│   │   │   │   │   ├── PhysicsExplodingSpriteEffect.ts
│   │   │   │   │   ├── SpriteAnimator.ts
│   │   │   │   │   └── SpriteParticleGenerator.ts
│   │   │   │   ├── canvas.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── physics/
│   │   │   │   │   ├── PlanckPhysicsAdapter.ts
│   │   │   │   │   ├── RapierPhysicsAdapter.ts
│   │   │   │   │   └── physics-interface.ts
│   │   │   │   └── shaders/
│   │   │   │       └── supersampling.wgsl
│   │   │   ├── 3d.ts
│   │   │   ├── NativeSpanFeed.ts
│   │   │   ├── Renderable.ts
│   │   │   ├── __snapshots__/
│   │   │   │   └── buffer.test.ts.snap
│   │   │   ├── animation/
│   │   │   │   ├── Timeline.test.ts
│   │   │   │   └── Timeline.ts
│   │   │   ├── ansi.ts
│   │   │   ├── benchmark/
│   │   │   │   ├── .gitignore
│   │   │   │   ├── attenuation-benchmark.ts
│   │   │   │   ├── colormatrix-benchmark.ts
│   │   │   │   ├── gain-benchmark.ts
│   │   │   │   ├── latest-all-bench-run.json
│   │   │   │   ├── latest-async-bench-run.json
│   │   │   │   ├── latest-default-bench-run.json
│   │   │   │   ├── latest-large-bench-run.json
│   │   │   │   ├── latest-quick-bench-run.json
│   │   │   │   ├── markdown-benchmark.ts
│   │   │   │   ├── native-span-feed-async-benchmark.ts
│   │   │   │   ├── native-span-feed-benchmark.md
│   │   │   │   ├── native-span-feed-benchmark.ts
│   │   │   │   ├── native-span-feed-compare.ts
│   │   │   │   ├── renderer-benchmark.ts
│   │   │   │   └── text-table-benchmark.ts
│   │   │   ├── buffer.test.ts
│   │   │   ├── buffer.ts
│   │   │   ├── console.test.ts
│   │   │   ├── console.ts
│   │   │   ├── edit-buffer.test.ts
│   │   │   ├── edit-buffer.ts
│   │   │   ├── editor-view.test.ts
│   │   │   ├── editor-view.ts
│   │   │   ├── examples/
│   │   │   │   ├── ascii-font-selection-demo.ts
│   │   │   │   ├── assets/
│   │   │   │   │   └── hast-example.json
│   │   │   │   ├── build.ts
│   │   │   │   ├── code-demo.ts
│   │   │   │   ├── console-demo.ts
│   │   │   │   ├── core-plugin-slots-demo.ts
│   │   │   │   ├── diff-demo.ts
│   │   │   │   ├── draggable-three-demo.ts
│   │   │   │   ├── editor-demo.ts
│   │   │   │   ├── extmarks-demo.ts
│   │   │   │   ├── focus-restore-demo.ts
│   │   │   │   ├── fonts.ts
│   │   │   │   ├── fractal-shader-demo.ts
│   │   │   │   ├── framebuffer-demo.ts
│   │   │   │   ├── full-unicode-demo.ts
│   │   │   │   ├── golden-star-demo.ts
│   │   │   │   ├── grayscale-buffer-demo.ts
│   │   │   │   ├── hast-syntax-highlighting-demo.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── input-demo.ts
│   │   │   │   ├── input-select-layout-demo.ts
│   │   │   │   ├── install.sh
│   │   │   │   ├── keypress-debug-demo.ts
│   │   │   │   ├── lib/
│   │   │   │   │   ├── HexList.ts
│   │   │   │   │   ├── PaletteGrid.ts
│   │   │   │   │   ├── standalone-keys.ts
│   │   │   │   │   └── tab-controller.ts
│   │   │   │   ├── lights-phong-demo.ts
│   │   │   │   ├── link-demo.ts
│   │   │   │   ├── live-state-demo.ts
│   │   │   │   ├── markdown-demo.ts
│   │   │   │   ├── mouse-interaction-demo.ts
│   │   │   │   ├── nested-zindex-demo.ts
│   │   │   │   ├── opacity-example.ts
│   │   │   │   ├── opentui-demo.ts
│   │   │   │   ├── physx-planck-2d-demo.ts
│   │   │   │   ├── physx-rapier-2d-demo.ts
│   │   │   │   ├── relative-positioning-demo.ts
│   │   │   │   ├── scroll-example.ts
│   │   │   │   ├── scrollbox-mouse-test.ts
│   │   │   │   ├── scrollbox-overlay-hit-test.ts
│   │   │   │   ├── select-demo.ts
│   │   │   │   ├── shader-cube-demo.ts
│   │   │   │   ├── simple-layout-example.ts
│   │   │   │   ├── slider-demo.ts
│   │   │   │   ├── split-mode-demo.ts
│   │   │   │   ├── sprite-animation-demo.ts
│   │   │   │   ├── sprite-particle-generator-demo.ts
│   │   │   │   ├── static-sprite-demo.ts
│   │   │   │   ├── sticky-scroll-example.ts
│   │   │   │   ├── styled-text-demo.ts
│   │   │   │   ├── tab-select-demo.ts
│   │   │   │   ├── terminal-title.ts
│   │   │   │   ├── terminal.ts
│   │   │   │   ├── text-node-demo.ts
│   │   │   │   ├── text-selection-demo.ts
│   │   │   │   ├── text-table-demo.ts
│   │   │   │   ├── text-truncation-demo.ts
│   │   │   │   ├── text-wrap.ts
│   │   │   │   ├── texture-loading-demo.ts
│   │   │   │   ├── timeline-example.ts
│   │   │   │   ├── transparency-demo.ts
│   │   │   │   └── vnode-composition-demo.ts
│   │   │   ├── index.ts
│   │   │   ├── lib/
│   │   │   │   ├── KeyHandler.integration.test.ts
│   │   │   │   ├── KeyHandler.stopPropagation.test.ts
│   │   │   │   ├── KeyHandler.test.ts
│   │   │   │   ├── KeyHandler.ts
│   │   │   │   ├── RGBA.test.ts
│   │   │   │   ├── RGBA.ts
│   │   │   │   ├── ascii.font.ts
│   │   │   │   ├── border.test.ts
│   │   │   │   ├── border.ts
│   │   │   │   ├── bunfs.test.ts
│   │   │   │   ├── bunfs.ts
│   │   │   │   ├── clipboard.test.ts
│   │   │   │   ├── clipboard.ts
│   │   │   │   ├── clock.ts
│   │   │   │   ├── data-paths.test.ts
│   │   │   │   ├── data-paths.ts
│   │   │   │   ├── debounce.ts
│   │   │   │   ├── detect-links.test.ts
│   │   │   │   ├── detect-links.ts
│   │   │   │   ├── env.test.ts
│   │   │   │   ├── env.ts
│   │   │   │   ├── extmarks-history.ts
│   │   │   │   ├── extmarks-multiwidth.test.ts
│   │   │   │   ├── extmarks.test.ts
│   │   │   │   ├── extmarks.ts
│   │   │   │   ├── fonts/
│   │   │   │   │   ├── block.json
│   │   │   │   │   ├── grid.json
│   │   │   │   │   ├── huge.json
│   │   │   │   │   ├── pallet.json
│   │   │   │   │   ├── shade.json
│   │   │   │   │   ├── slick.json
│   │   │   │   │   └── tiny.json
│   │   │   │   ├── hast-styled-text.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── keymapping.test.ts
│   │   │   │   ├── keymapping.ts
│   │   │   │   ├── objects-in-viewport.test.ts
│   │   │   │   ├── objects-in-viewport.ts
│   │   │   │   ├── output.capture.ts
│   │   │   │   ├── parse.keypress-kitty.protocol.test.ts
│   │   │   │   ├── parse.keypress-kitty.test.ts
│   │   │   │   ├── parse.keypress-kitty.ts
│   │   │   │   ├── parse.keypress.test.ts
│   │   │   │   ├── parse.keypress.ts
│   │   │   │   ├── parse.mouse.test.ts
│   │   │   │   ├── parse.mouse.ts
│   │   │   │   ├── paste.ts
│   │   │   │   ├── queue.ts
│   │   │   │   ├── renderable.validations.test.ts
│   │   │   │   ├── renderable.validations.ts
│   │   │   │   ├── scroll-acceleration.ts
│   │   │   │   ├── selection.ts
│   │   │   │   ├── singleton.ts
│   │   │   │   ├── stdin-parser.test.ts
│   │   │   │   ├── stdin-parser.ts
│   │   │   │   ├── styled-text.ts
│   │   │   │   ├── terminal-capability-detection.test.ts
│   │   │   │   ├── terminal-capability-detection.ts
│   │   │   │   ├── terminal-palette.test.ts
│   │   │   │   ├── terminal-palette.ts
│   │   │   │   ├── tree-sitter/
│   │   │   │   │   ├── assets/
│   │   │   │   │   │   ├── README.md
│   │   │   │   │   │   ├── javascript/
│   │   │   │   │   │   │   ├── highlights.scm
│   │   │   │   │   │   │   └── tree-sitter-javascript.wasm
│   │   │   │   │   │   ├── markdown/
│   │   │   │   │   │   │   ├── highlights.scm
│   │   │   │   │   │   │   ├── injections.scm
│   │   │   │   │   │   │   └── tree-sitter-markdown.wasm
│   │   │   │   │   │   ├── markdown_inline/
│   │   │   │   │   │   │   ├── highlights.scm
│   │   │   │   │   │   │   └── tree-sitter-markdown_inline.wasm
│   │   │   │   │   │   ├── typescript/
│   │   │   │   │   │   │   ├── highlights.scm
│   │   │   │   │   │   │   └── tree-sitter-typescript.wasm
│   │   │   │   │   │   ├── update.ts
│   │   │   │   │   │   └── zig/
│   │   │   │   │   │       ├── highlights.scm
│   │   │   │   │   │       └── tree-sitter-zig.wasm
│   │   │   │   │   ├── assets.d.ts
│   │   │   │   │   ├── cache.test.ts
│   │   │   │   │   ├── client.test.ts
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── default-parsers.ts
│   │   │   │   │   ├── download-utils.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── parser.worker.ts
│   │   │   │   │   ├── parsers-config.ts
│   │   │   │   │   ├── resolve-ft.test.ts
│   │   │   │   │   ├── resolve-ft.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── tree-sitter-styled-text.test.ts
│   │   │   │   ├── tree-sitter-styled-text.ts
│   │   │   │   ├── validate-dir-name.ts
│   │   │   │   ├── yoga.options.test.ts
│   │   │   │   └── yoga.options.ts
│   │   │   ├── plugins/
│   │   │   │   ├── core-slot.ts
│   │   │   │   ├── registry.ts
│   │   │   │   └── types.ts
│   │   │   ├── post/
│   │   │   │   ├── effects.ts
│   │   │   │   ├── filters.ts
│   │   │   │   └── matrices.ts
│   │   │   ├── renderables/
│   │   │   │   ├── ASCIIFont.ts
│   │   │   │   ├── Box.test.ts
│   │   │   │   ├── Box.ts
│   │   │   │   ├── Code.test.ts
│   │   │   │   ├── Code.ts
│   │   │   │   ├── Diff.regression.test.ts
│   │   │   │   ├── Diff.test.ts
│   │   │   │   ├── Diff.ts
│   │   │   │   ├── EditBufferRenderable.ts
│   │   │   │   ├── FrameBuffer.ts
│   │   │   │   ├── Input.test.ts
│   │   │   │   ├── Input.ts
│   │   │   │   ├── LineNumberRenderable.ts
│   │   │   │   ├── Markdown.ts
│   │   │   │   ├── ScrollBar.ts
│   │   │   │   ├── ScrollBox.ts
│   │   │   │   ├── Select.test.ts
│   │   │   │   ├── Select.ts
│   │   │   │   ├── Slider.test.ts
│   │   │   │   ├── Slider.ts
│   │   │   │   ├── TabSelect.test.ts
│   │   │   │   ├── TabSelect.ts
│   │   │   │   ├── Text.selection-buffer.test.ts
│   │   │   │   ├── Text.test.ts
│   │   │   │   ├── Text.ts
│   │   │   │   ├── TextBufferRenderable.ts
│   │   │   │   ├── TextNode.test.ts
│   │   │   │   ├── TextNode.ts
│   │   │   │   ├── TextTable.test.ts
│   │   │   │   ├── TextTable.ts
│   │   │   │   ├── Textarea.ts
│   │   │   │   ├── TimeToFirstDraw.ts
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   ├── Code.test.ts.snap
│   │   │   │   │   ├── Diff.test.ts.snap
│   │   │   │   │   ├── Text.test.ts.snap
│   │   │   │   │   └── TextTable.test.ts.snap
│   │   │   │   ├── __tests__/
│   │   │   │   │   ├── LineNumberRenderable.scrollbox-simple.test.ts
│   │   │   │   │   ├── LineNumberRenderable.scrollbox.test.ts
│   │   │   │   │   ├── LineNumberRenderable.test.ts
│   │   │   │   │   ├── LineNumberRenderable.wrapping.test.ts
│   │   │   │   │   ├── Markdown.code-colors.test.ts
│   │   │   │   │   ├── Markdown.test.ts
│   │   │   │   │   ├── MultiRenderable.selection.test.ts
│   │   │   │   │   ├── Textarea.buffer.test.ts
│   │   │   │   │   ├── Textarea.destroyed-events.test.ts
│   │   │   │   │   ├── Textarea.editing.test.ts
│   │   │   │   │   ├── Textarea.error-handling.test.ts
│   │   │   │   │   ├── Textarea.events.test.ts
│   │   │   │   │   ├── Textarea.highlights.test.ts
│   │   │   │   │   ├── Textarea.keybinding.test.ts
│   │   │   │   │   ├── Textarea.paste.test.ts
│   │   │   │   │   ├── Textarea.rendering.test.ts
│   │   │   │   │   ├── Textarea.scroll.test.ts
│   │   │   │   │   ├── Textarea.selection.test.ts
│   │   │   │   │   ├── Textarea.stress.test.ts
│   │   │   │   │   ├── Textarea.undo-redo.test.ts
│   │   │   │   │   ├── Textarea.visual-lines.test.ts
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   ├── LineNumberRenderable.code.test.ts.snap
│   │   │   │   │   │   ├── LineNumberRenderable.scrollbox-simple.test.ts.snap
│   │   │   │   │   │   ├── LineNumberRenderable.scrollbox.test.ts.snap
│   │   │   │   │   │   ├── LineNumberRenderable.test.ts.snap
│   │   │   │   │   │   └── Textarea.rendering.test.ts.snap
│   │   │   │   │   ├── markdown-parser.test.ts
│   │   │   │   │   └── renderable-test-utils.ts
│   │   │   │   ├── composition/
│   │   │   │   │   ├── README.md
│   │   │   │   │   ├── VRenderable.ts
│   │   │   │   │   ├── constructs.ts
│   │   │   │   │   └── vnode.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── markdown-parser.ts
│   │   │   ├── renderer.ts
│   │   │   ├── runtime-plugin-support.ts
│   │   │   ├── runtime-plugin.ts
│   │   │   ├── syntax-style.test.ts
│   │   │   ├── syntax-style.ts
│   │   │   ├── testing/
│   │   │   │   ├── README.md
│   │   │   │   ├── capture-spans.test.ts
│   │   │   │   ├── integration.test.ts
│   │   │   │   ├── manual-clock.ts
│   │   │   │   ├── mock-keys.test.ts
│   │   │   │   ├── mock-keys.ts
│   │   │   │   ├── mock-mouse.test.ts
│   │   │   │   ├── mock-mouse.ts
│   │   │   │   ├── mock-tree-sitter-client.ts
│   │   │   │   ├── spy.ts
│   │   │   │   ├── test-recorder.test.ts
│   │   │   │   ├── test-recorder.ts
│   │   │   │   └── test-renderer.ts
│   │   │   ├── testing.ts
│   │   │   ├── tests/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   ├── absolute-positioning.snapshot.test.ts.snap
│   │   │   │   │   ├── renderable.snapshot.test.ts.snap
│   │   │   │   │   └── scrollbox.test.ts.snap
│   │   │   │   ├── absolute-positioning.snapshot.test.ts
│   │   │   │   ├── allocator-stats.test.ts
│   │   │   │   ├── destroy-during-render.test.ts
│   │   │   │   ├── hover-cursor.test.ts
│   │   │   │   ├── native-span-feed-async.test.ts
│   │   │   │   ├── native-span-feed-close.test.ts
│   │   │   │   ├── native-span-feed-coverage.test.ts
│   │   │   │   ├── native-span-feed-edge-cases.test.ts
│   │   │   │   ├── native-span-feed-use-after-free.test.ts
│   │   │   │   ├── opacity.test.ts
│   │   │   │   ├── renderable.snapshot.test.ts
│   │   │   │   ├── renderable.test.ts
│   │   │   │   ├── renderer.clock.test.ts
│   │   │   │   ├── renderer.console-startup.test.ts
│   │   │   │   ├── renderer.control.test.ts
│   │   │   │   ├── renderer.core-slot-binding.test.ts
│   │   │   │   ├── renderer.cursor.test.ts
│   │   │   │   ├── renderer.destroy-during-render.test.ts
│   │   │   │   ├── renderer.focus-restore.test.ts
│   │   │   │   ├── renderer.focus.test.ts
│   │   │   │   ├── renderer.idle.test.ts
│   │   │   │   ├── renderer.input.test.ts
│   │   │   │   ├── renderer.kitty-flags.test.ts
│   │   │   │   ├── renderer.mouse.test.ts
│   │   │   │   ├── renderer.palette.test.ts
│   │   │   │   ├── renderer.selection.test.ts
│   │   │   │   ├── renderer.slot-registry.test.ts
│   │   │   │   ├── renderer.useMouse.test.ts
│   │   │   │   ├── runtime-plugin-resolve-roots.fixture.ts
│   │   │   │   ├── runtime-plugin-support.fixture.ts
│   │   │   │   ├── runtime-plugin-support.test.ts
│   │   │   │   ├── runtime-plugin.fixture.ts
│   │   │   │   ├── runtime-plugin.test.ts
│   │   │   │   ├── scrollbox-culling-bug.test.ts
│   │   │   │   ├── scrollbox-hitgrid-resize.test.ts
│   │   │   │   ├── scrollbox-hitgrid.test.ts
│   │   │   │   ├── scrollbox.test.ts
│   │   │   │   ├── wrap-resize-perf.test.ts
│   │   │   │   └── yoga-setters.test.ts
│   │   │   ├── text-buffer-view.test.ts
│   │   │   ├── text-buffer-view.ts
│   │   │   ├── text-buffer.test.ts
│   │   │   ├── text-buffer.ts
│   │   │   ├── types.ts
│   │   │   ├── utils.ts
│   │   │   ├── zig/
│   │   │   │   ├── ansi.zig
│   │   │   │   ├── bench/
│   │   │   │   │   ├── README.md
│   │   │   │   │   ├── buffer-draw-text-buffer_bench.zig
│   │   │   │   │   ├── edit-buffer_bench.zig
│   │   │   │   │   ├── native-span-feed_bench.zig
│   │   │   │   │   ├── rope-markers_bench.zig
│   │   │   │   │   ├── rope_bench.zig
│   │   │   │   │   ├── styled-text_bench.zig
│   │   │   │   │   ├── text-buffer-coords_bench.zig
│   │   │   │   │   ├── text-buffer-view_bench.zig
│   │   │   │   │   ├── text-chunk-graphemes_bench.zig
│   │   │   │   │   └── utf8_bench.zig
│   │   │   │   ├── bench-utils.zig
│   │   │   │   ├── bench.zig
│   │   │   │   ├── buffer-methods.zig
│   │   │   │   ├── buffer.zig
│   │   │   │   ├── build.zig
│   │   │   │   ├── build.zig.zon
│   │   │   │   ├── edit-buffer.zig
│   │   │   │   ├── editor-view.zig
│   │   │   │   ├── event-bus.zig
│   │   │   │   ├── event-emitter.zig
│   │   │   │   ├── file-logger.zig
│   │   │   │   ├── grapheme.zig
│   │   │   │   ├── lib.zig
│   │   │   │   ├── link.zig
│   │   │   │   ├── logger.zig
│   │   │   │   ├── mem-registry.zig
│   │   │   │   ├── native-span-feed-bench-lib.zig
│   │   │   │   ├── native-span-feed.zig
│   │   │   │   ├── renderer.zig
│   │   │   │   ├── rope.zig
│   │   │   │   ├── syntax-style.zig
│   │   │   │   ├── terminal.zig
│   │   │   │   ├── test.zig
│   │   │   │   ├── tests/
│   │   │   │   │   ├── README.md
│   │   │   │   │   ├── buffer-methods_test.zig
│   │   │   │   │   ├── buffer_test.zig
│   │   │   │   │   ├── edit-buffer-history_test.zig
│   │   │   │   │   ├── edit-buffer_test.zig
│   │   │   │   │   ├── editor-view_test.zig
│   │   │   │   │   ├── event-emitter_test.zig
│   │   │   │   │   ├── grapheme_test.zig
│   │   │   │   │   ├── link_test.zig
│   │   │   │   │   ├── mem-registry_test.zig
│   │   │   │   │   ├── memory_leak_regression_test.zig
│   │   │   │   │   ├── native-span-feed_test.zig
│   │   │   │   │   ├── renderer_test.zig
│   │   │   │   │   ├── rope-nested_test.zig
│   │   │   │   │   ├── rope_fuzz_test.zig
│   │   │   │   │   ├── rope_test.zig
│   │   │   │   │   ├── segment-merge.test.zig
│   │   │   │   │   ├── syntax-style_test.zig
│   │   │   │   │   ├── terminal_test.zig
│   │   │   │   │   ├── text-buffer-drawing_test.zig
│   │   │   │   │   ├── text-buffer-highlights_test.zig
│   │   │   │   │   ├── text-buffer-iterators_test.zig
│   │   │   │   │   ├── text-buffer-segment_test.zig
│   │   │   │   │   ├── text-buffer-selection_test.zig
│   │   │   │   │   ├── text-buffer-selection_viewport_test.zig
│   │   │   │   │   ├── text-buffer-view_test.zig
│   │   │   │   │   ├── text-buffer_test.zig
│   │   │   │   │   ├── unicode-width-map.zon
│   │   │   │   │   ├── utf8_no_zwj_test.zig
│   │   │   │   │   ├── utf8_test.zig
│   │   │   │   │   ├── utf8_wcwidth_cursor_test.zig
│   │   │   │   │   ├── utf8_wcwidth_test.zig
│   │   │   │   │   ├── word-wrap-editing_test.zig
│   │   │   │   │   └── wrap-cache-perf_test.zig
│   │   │   │   ├── text-buffer-iterators.zig
│   │   │   │   ├── text-buffer-segment.zig
│   │   │   │   ├── text-buffer-view.zig
│   │   │   │   ├── text-buffer.zig
│   │   │   │   ├── utf8.zig
│   │   │   │   └── utils.zig
│   │   │   ├── zig-structs.ts
│   │   │   └── zig.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── react/
│   │   ├── README.md
│   │   ├── docs/
│   │   │   └── EXTEND.md
│   │   ├── examples/
│   │   │   ├── .plugin/
│   │   │   │   ├── index.tsx
│   │   │   │   └── slot-components.tsx
│   │   │   ├── animation.tsx
│   │   │   ├── ascii.tsx
│   │   │   ├── basic.tsx
│   │   │   ├── borders.tsx
│   │   │   ├── box.tsx
│   │   │   ├── build.ts
│   │   │   ├── counter.tsx
│   │   │   ├── diff.tsx
│   │   │   ├── extend-example.tsx
│   │   │   ├── external-plugin-slots-demo.tsx
│   │   │   ├── flush-sync.tsx
│   │   │   ├── index.tsx
│   │   │   ├── line-number.tsx
│   │   │   ├── opacity.tsx
│   │   │   ├── plugin-slots-errors.tsx
│   │   │   ├── scroll.tsx
│   │   │   ├── text.tsx
│   │   │   └── tsconfig.json
│   │   ├── jsx-dev-runtime.d.ts
│   │   ├── jsx-dev-runtime.js
│   │   ├── jsx-namespace.d.ts
│   │   ├── jsx-runtime.d.ts
│   │   ├── jsx-runtime.js
│   │   ├── package.json
│   │   ├── scripts/
│   │   │   ├── build.ts
│   │   │   ├── publish.ts
│   │   │   └── runtime-plugin-support.ts
│   │   ├── src/
│   │   │   ├── components/
│   │   │   │   ├── app.tsx
│   │   │   │   ├── error-boundary.tsx
│   │   │   │   ├── index.ts
│   │   │   │   └── text.ts
│   │   │   ├── hooks/
│   │   │   │   ├── index.ts
│   │   │   │   ├── use-event.ts
│   │   │   │   ├── use-keyboard.ts
│   │   │   │   ├── use-renderer.ts
│   │   │   │   ├── use-resize.ts
│   │   │   │   ├── use-terminal-dimensions.ts
│   │   │   │   └── use-timeline.ts
│   │   │   ├── index.ts
│   │   │   ├── plugins/
│   │   │   │   └── slot.tsx
│   │   │   ├── reconciler/
│   │   │   │   ├── devtools-polyfill.ts
│   │   │   │   ├── devtools.ts
│   │   │   │   ├── host-config.ts
│   │   │   │   ├── reconciler.ts
│   │   │   │   └── renderer.ts
│   │   │   ├── test-utils.ts
│   │   │   ├── time-to-first-draw.tsx
│   │   │   ├── types/
│   │   │   │   ├── components.ts
│   │   │   │   └── host.ts
│   │   │   └── utils/
│   │   │       ├── id.ts
│   │   │       └── index.ts
│   │   ├── tests/
│   │   │   ├── __snapshots__/
│   │   │   │   └── layout.test.tsx.snap
│   │   │   ├── destroy-crash.test.tsx
│   │   │   ├── layout.test.tsx
│   │   │   ├── link.test.tsx
│   │   │   ├── runtime-plugin-support.fixture.ts
│   │   │   ├── runtime-plugin-support.test.ts
│   │   │   └── slot.test.tsx
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── solid/
│   │   ├── README.md
│   │   ├── bunfig.toml
│   │   ├── examples/
│   │   │   ├── .plugin/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── package.json
│   │   │   │   └── slot-components.tsx
│   │   │   ├── build.ts
│   │   │   ├── components/
│   │   │   │   ├── ExampleSelector.tsx
│   │   │   │   ├── animation-demo.tsx
│   │   │   │   ├── autocomplete-demo.tsx
│   │   │   │   ├── code-demo.tsx
│   │   │   │   ├── custom-scroll-accel-demo.tsx
│   │   │   │   ├── diff-demo.tsx
│   │   │   │   ├── extend-demo.tsx
│   │   │   │   ├── external-plugin-path.test.ts
│   │   │   │   ├── external-plugin-path.ts
│   │   │   │   ├── external-plugin-runtime.ts
│   │   │   │   ├── external-plugin-slots-demo.tsx
│   │   │   │   ├── input-demo.tsx
│   │   │   │   ├── line-number-demo.tsx
│   │   │   │   ├── mouse-demo.tsx
│   │   │   │   ├── plugin-slots-demo.tsx
│   │   │   │   ├── scroll-demo.tsx
│   │   │   │   ├── tab-select-demo.tsx
│   │   │   │   ├── text-selection-demo.tsx
│   │   │   │   ├── text-style-demo.tsx
│   │   │   │   ├── text-truncation-demo.tsx
│   │   │   │   ├── textarea-demo.tsx
│   │   │   │   ├── textarea-keybindings.ts
│   │   │   │   └── textarea-minimal-demo.tsx
│   │   │   ├── index.tsx
│   │   │   ├── package.json
│   │   │   ├── repro-empty-styled-text.tsx
│   │   │   ├── repro-filter-list.tsx
│   │   │   ├── repro-onSubmit.tsx
│   │   │   ├── session.tsx
│   │   │   └── tsconfig.json
│   │   ├── index.ts
│   │   ├── jsx-runtime.d.ts
│   │   ├── package.json
│   │   ├── scripts/
│   │   │   ├── build.ts
│   │   │   ├── preload.ts
│   │   │   ├── publish.ts
│   │   │   ├── runtime-plugin-support.ts
│   │   │   └── solid-plugin.ts
│   │   ├── src/
│   │   │   ├── elements/
│   │   │   │   ├── extras.ts
│   │   │   │   ├── hooks.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── slot.ts
│   │   │   ├── plugins/
│   │   │   │   └── slot.tsx
│   │   │   ├── reconciler.ts
│   │   │   ├── renderer/
│   │   │   │   ├── index.ts
│   │   │   │   ├── universal.d.ts
│   │   │   │   └── universal.js
│   │   │   ├── time-to-first-draw.tsx
│   │   │   ├── types/
│   │   │   │   └── elements.ts
│   │   │   └── utils/
│   │   │       ├── id-counter.ts
│   │   │       └── log.ts
│   │   ├── tests/
│   │   │   ├── __snapshots__/
│   │   │   │   ├── control-flow.test.tsx.snap
│   │   │   │   ├── dynamic-collections.test.tsx.snap
│   │   │   │   ├── dynamic-portal.test.tsx.snap
│   │   │   │   ├── layout.test.tsx.snap
│   │   │   │   ├── line-number-debug.test.tsx.snap
│   │   │   │   ├── line-number-scrollbox.test.tsx.snap
│   │   │   │   └── textarea.test.tsx.snap
│   │   │   ├── box.test.tsx
│   │   │   ├── control-flow.test.tsx
│   │   │   ├── cursor-behavior.test.tsx
│   │   │   ├── destroy-crash.test.tsx
│   │   │   ├── destroy-race-repro.test.ts
│   │   │   ├── destroy-race.fixture.tsx
│   │   │   ├── diff.test.tsx
│   │   │   ├── dynamic-collections.test.tsx
│   │   │   ├── dynamic-portal.test.tsx
│   │   │   ├── events.test.tsx
│   │   │   ├── layout.test.tsx
│   │   │   ├── line-number-scrollbox.test.tsx
│   │   │   ├── line-number.test.tsx
│   │   │   ├── link.test.tsx
│   │   │   ├── runtime-plugin-support-preload.fixture.ts
│   │   │   ├── runtime-plugin-support-preload.test.ts
│   │   │   ├── runtime-plugin-support.fixture.ts
│   │   │   ├── runtime-plugin-support.test.ts
│   │   │   ├── scrollbox-cleanchildren.test.tsx
│   │   │   ├── scrollbox-content.test.tsx
│   │   │   ├── slot.test.tsx
│   │   │   ├── solid-plugin.fixture.ts
│   │   │   ├── solid-plugin.test.ts
│   │   │   ├── sticky-scroll.test.tsx
│   │   │   └── textarea.test.tsx
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   └── web/
│       ├── .gitignore
│       ├── astro.config.mjs
│       ├── package.json
│       ├── scripts/
│       │   ├── test-doc-examples.ts
│       │   └── verify-doc-examples.ts
│       ├── src/
│       │   ├── components/
│       │   │   └── TuiSurface.astro
│       │   ├── content/
│       │   │   ├── config.ts
│       │   │   └── docs/
│       │   │       ├── bindings/
│       │   │       │   ├── react.mdx
│       │   │       │   └── solid.mdx
│       │   │       ├── components/
│       │   │       │   ├── ascii-font.mdx
│       │   │       │   ├── box.mdx
│       │   │       │   ├── code.mdx
│       │   │       │   ├── diff.mdx
│       │   │       │   ├── frame-buffer.mdx
│       │   │       │   ├── input.mdx
│       │   │       │   ├── line-number.mdx
│       │   │       │   ├── markdown.mdx
│       │   │       │   ├── scrollbar.mdx
│       │   │       │   ├── scrollbox.mdx
│       │   │       │   ├── select.mdx
│       │   │       │   ├── slider.mdx
│       │   │       │   ├── tab-select.mdx
│       │   │       │   ├── text.mdx
│       │   │       │   └── textarea.mdx
│       │   │       ├── core-concepts/
│       │   │       │   ├── colors.mdx
│       │   │       │   ├── console.mdx
│       │   │       │   ├── constructs.mdx
│       │   │       │   ├── keyboard.mdx
│       │   │       │   ├── layout.mdx
│       │   │       │   ├── lifecycle.mdx
│       │   │       │   ├── renderables-vs-constructs.mdx
│       │   │       │   ├── renderables.mdx
│       │   │       │   └── renderer.mdx
│       │   │       ├── getting-started.mdx
│       │   │       ├── plugins/
│       │   │       │   ├── core.mdx
│       │   │       │   ├── react.mdx
│       │   │       │   ├── slots.mdx
│       │   │       │   └── solid.mdx
│       │   │       └── reference/
│       │   │           ├── env-vars.mdx
│       │   │           └── tree-sitter.mdx
│       │   ├── layouts/
│       │   │   ├── Base.astro
│       │   │   └── Docs.astro
│       │   ├── pages/
│       │   │   ├── 404.astro
│       │   │   ├── docs/
│       │   │   │   └── [...slug].astro
│       │   │   └── index.astro
│       │   └── styles/
│       │       └── global.css
│       └── tsconfig.json
└── scripts/
    ├── create-snapshot.sh
    ├── link-opentui-dev.sh
    ├── pre-publish.ts
    └── prepare-release.ts
Download .txt
Showing preview only (381K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (4327 symbols across 333 files)

FILE: packages/core/dev/keypress-debug-renderer.ts
  function addEvent (line 24) | function addEvent(eventType: string, event: object) {
  function main (line 65) | async function main() {

FILE: packages/core/dev/thai-debug-test.ts
  function main (line 4) | async function main() {

FILE: packages/core/scripts/build.ts
  type Variant (line 8) | interface Variant {
  type PackageJson (line 13) | interface PackageJson {

FILE: packages/core/scripts/publish.ts
  type PackageJson (line 7) | interface PackageJson {

FILE: packages/core/src/3d/SpriteResourceManager.ts
  type ResourceConfig (line 5) | interface ResourceConfig {
  type SheetProperties (line 10) | interface SheetProperties {
  type InstanceManagerOptions (line 17) | interface InstanceManagerOptions {
  type MeshPoolOptions (line 26) | interface MeshPoolOptions {
  constant HIDDEN_MATRIX (line 33) | const HIDDEN_MATRIX = new THREE.Matrix4().scale(new THREE.Vector3(0, 0, 0))
  class MeshPool (line 35) | class MeshPool {
    method acquireMesh (line 38) | public acquireMesh(poolId: string, options: MeshPoolOptions): THREE.In...
    method releaseMesh (line 58) | public releaseMesh(poolId: string, mesh: THREE.InstancedMesh): void {
    method fill (line 64) | public fill(poolId: string, options: MeshPoolOptions, count: number): ...
    method clearPool (line 79) | public clearPool(poolId: string): void {
    method clearAllPools (line 94) | public clearAllPools(): void {
  class InstanceManager (line 102) | class InstanceManager {
    method constructor (line 111) | constructor(scene: Scene, geometry: THREE.BufferGeometry, material: TH...
    method acquireInstanceSlot (line 135) | acquireInstanceSlot(): number {
    method releaseInstanceSlot (line 144) | releaseInstanceSlot(instanceIndex: number): void {
    method getInstanceCount (line 159) | getInstanceCount(): number {
    method getMaxInstances (line 163) | getMaxInstances(): number {
    method hasFreeIndices (line 167) | get hasFreeIndices(): boolean {
    method mesh (line 171) | get mesh(): THREE.InstancedMesh {
    method dispose (line 175) | dispose(): void {
  class SpriteResource (line 186) | class SpriteResource {
    method constructor (line 192) | constructor(texture: THREE.DataTexture, sheetProperties: SheetProperti...
    method texture (line 199) | public get texture(): THREE.DataTexture {
    method sheetProperties (line 203) | public get sheetProperties(): SheetProperties {
    method meshPool (line 207) | public get meshPool(): MeshPool {
    method createInstanceManager (line 211) | public createInstanceManager(
    method uvTileSize (line 224) | public get uvTileSize(): THREE.Vector2 {
    method dispose (line 230) | public dispose(): void {
  class SpriteResourceManager (line 235) | class SpriteResourceManager {
    method constructor (line 240) | constructor(scene: Scene) {
    method getResourceKey (line 244) | private getResourceKey(sheetProps: SheetProperties): string {
    method getOrCreateResource (line 248) | public async getOrCreateResource(texture: THREE.DataTexture, sheetProp...
    method createResource (line 260) | public async createResource(config: ResourceConfig): Promise<SpriteRes...
    method clearCache (line 282) | public clearCache(): void {

FILE: packages/core/src/3d/SpriteUtils.ts
  class SheetSprite (line 4) | class SheetSprite extends Sprite {
    method constructor (line 8) | constructor(material: SpriteMaterial, numFrames: number) {
  class SpriteUtils (line 21) | class SpriteUtils {
    method fromFile (line 22) | static async fromFile(
    method sheetFromFile (line 50) | static async sheetFromFile(path: string, numFrames: number): Promise<S...

FILE: packages/core/src/3d/TextureUtils.ts
  type SimpleImageData (line 5) | interface SimpleImageData {
  class TextureUtils (line 12) | class TextureUtils {
    method loadTextureFromFile (line 17) | static async loadTextureFromFile(path: string): Promise<DataTexture | ...
    method fromFile (line 49) | static async fromFile(path: string): Promise<DataTexture | null> {
    method createCheckerboard (line 56) | static createCheckerboard(
    method createGradient (line 94) | static createGradient(
    method createNoise (line 144) | static createNoise(

FILE: packages/core/src/3d/ThreeRenderable.ts
  type ThreeRenderableOptions (line 10) | interface ThreeRenderableOptions extends RenderableOptions<ThreeRenderab...
  class ThreeRenderable (line 17) | class ThreeRenderable extends Renderable {
    method constructor (line 29) | constructor(ctx: RenderContext, options: ThreeRenderableOptions) {
    method aspectRatio (line 59) | public get aspectRatio(): number {
    method renderer (line 63) | public get renderer(): ThreeCliRenderer {
    method getScene (line 67) | public getScene(): Scene | null {
    method setScene (line 71) | public setScene(scene: Scene | null): void {
    method getActiveCamera (line 76) | public getActiveCamera(): PerspectiveCamera | OrthographicCamera {
    method setActiveCamera (line 80) | public setActiveCamera(camera: PerspectiveCamera | OrthographicCamera)...
    method setAutoAspect (line 86) | public setAutoAspect(autoAspect: boolean): void {
    method onResize (line 94) | protected onResize(width: number, height: number): void {
    method renderSelf (line 102) | protected renderSelf(buffer: OptimizedBuffer, deltaTime: number): void {
    method destroySelf (line 109) | protected destroySelf(): void {
    method registerFrameCallback (line 120) | private registerFrameCallback(): void {
    method renderToBuffer (line 133) | private async renderToBuffer(buffer: OptimizedBuffer, deltaTime: numbe...
    method ensureInitialized (line 151) | private async ensureInitialized(): Promise<boolean> {
    method updateCameraAspect (line 166) | private updateCameraAspect(width: number, height: number): void {
    method getAspectRatio (line 176) | private getAspectRatio(width: number, height: number): number {
    method getRenderSize (line 191) | private getRenderSize(): { width: number; height: number } {

FILE: packages/core/src/3d/WGPURenderer.ts
  type SuperSampleType (line 9) | enum SuperSampleType {
  type ThreeCliRendererOptions (line 15) | interface ThreeCliRendererOptions {
  class ThreeCliRenderer (line 26) | class ThreeCliRenderer {
    method aspectRatio (line 58) | public get aspectRatio(): number {
    method constructor (line 69) | constructor(
    method toggleDebugStats (line 122) | public toggleDebugStats(): void {
    method init (line 126) | async init(): Promise<void> {
    method getSuperSampleAlgorithm (line 153) | public getSuperSampleAlgorithm(): SuperSampleAlgorithm {
    method setSuperSampleAlgorithm (line 157) | public setSuperSampleAlgorithm(superSampleAlgorithm: SuperSampleAlgori...
    method saveToFile (line 161) | public saveToFile(filePath: string): Promise<void> {
    method setActiveCamera (line 165) | setActiveCamera(camera: PerspectiveCamera | OrthographicCamera): void {
    method getActiveCamera (line 169) | getActiveCamera(): PerspectiveCamera | OrthographicCamera {
    method setBackgroundColor (line 173) | public setBackgroundColor(color: RGBA): void {
    method setSize (line 180) | setSize(width: number, height: number, forceUpdate: boolean = false): ...
    method drawScene (line 201) | public async drawScene(root: Scene, buffer: OptimizedBuffer, deltaTime...
    method doDrawScene (line 211) | async doDrawScene(
    method toggleSuperSampling (line 242) | public toggleSuperSampling(): void {
    method renderStats (line 254) | public renderStats(buffer: OptimizedBuffer): void {
    method destroy (line 275) | public destroy(): void {

FILE: packages/core/src/3d/animation/ExplodingSpriteEffect.ts
  type ExplosionEffectParameters (line 22) | interface ExplosionEffectParameters {
  constant DEFAULT_EXPLOSION_PARAMETERS (line 38) | const DEFAULT_EXPLOSION_PARAMETERS: ExplosionEffectParameters = {
  type ExplosionCreationData (line 60) | interface ExplosionCreationData {
  type SpriteRecreationData (line 67) | interface SpriteRecreationData {
  type ExplosionHandle (line 76) | interface ExplosionHandle {
  class ExplodingSpriteEffect (line 83) | class ExplodingSpriteEffect {
    method constructor (line 101) | constructor(
    method _createGPUParticles (line 122) | private _createGPUParticles(materialFactory: () => NodeMaterial): void {
    method _createGPUMaterial (line 257) | private _createGPUMaterial(materialFactory: () => NodeMaterial): void {
    method _buildTemplateMaterial (line 270) | public static _buildTemplateMaterial(
    method update (line 359) | update(deltaTimeMs: number): void {
    method dispose (line 369) | dispose(): void {
  class ExplosionManager (line 383) | class ExplosionManager {
    method constructor (line 387) | constructor(scene: THREE.Scene) {
    method fillPool (line 391) | public fillPool(resource: SpriteResource, count: number, params: Parti...
    method _createEffectCreationData (line 435) | private _createEffectCreationData(sprite: TiledSprite): ExplosionCreat...
    method createExplosionForSprite (line 448) | public createExplosionForSprite(
    method update (line 499) | public update(deltaTimeMs: number): void {
    method disposeAll (line 509) | public disposeAll(): void {

FILE: packages/core/src/3d/animation/PhysicsExplodingSpriteEffect.ts
  type PhysicsExplosionEffectParameters (line 14) | interface PhysicsExplosionEffectParameters {
  constant DEFAULT_PHYSICS_EXPLOSION_PARAMETERS (line 31) | const DEFAULT_PHYSICS_EXPLOSION_PARAMETERS: PhysicsExplosionEffectParame...
  type PhysicsExplosionCreationData (line 54) | interface PhysicsExplosionCreationData {
  type PhysicsSpriteRecreationData (line 61) | interface PhysicsSpriteRecreationData {
  type PhysicsExplosionHandle (line 70) | interface PhysicsExplosionHandle {
  type ExplosionParticle (line 77) | interface ExplosionParticle {
  class PhysicsExplodingSpriteEffect (line 87) | class PhysicsExplodingSpriteEffect {
    method constructor (line 109) | constructor(
    method _createPhysicsParticles (line 132) | private _createPhysicsParticles(materialFactory: () => NodeMaterial): ...
    method getSharedMaterial (line 247) | public static getSharedMaterial(texture: THREE.DataTexture, materialFa...
    method update (line 269) | update(deltaTimeMs: number): void {
    method dispose (line 296) | dispose(): void {
  class PhysicsExplosionManager (line 314) | class PhysicsExplosionManager {
    method constructor (line 319) | constructor(scene: THREE.Scene, physicsWorld: PhysicsWorld) {
    method fillPool (line 324) | public fillPool(
    method _createEffectCreationData (line 351) | private _createEffectCreationData(sprite: TiledSprite): PhysicsExplosi...
    method createExplosionForSprite (line 364) | public async createExplosionForSprite(
    method update (line 415) | public update(deltaTimeMs: number): void {
    method disposeAll (line 425) | public disposeAll(): void {

FILE: packages/core/src/3d/animation/SpriteAnimator.ts
  type AnimationStateConfig (line 7) | interface AnimationStateConfig {
  type ResolvedAnimationState (line 21) | type ResolvedAnimationState = Required<AnimationStateConfig> & {
  type AnimationDefinition (line 27) | interface AnimationDefinition {
  type SpriteDefinition (line 38) | interface SpriteDefinition {
  constant HIDDEN_MATRIX (line 48) | const HIDDEN_MATRIX = new THREE.Matrix4().scale(new THREE.Vector3(0, 0, 0))
  constant DEFAULT_FRAME_DURATION (line 50) | const DEFAULT_FRAME_DURATION = 100
  constant DEFAULT_INITIAL_FRAME (line 51) | const DEFAULT_INITIAL_FRAME = 0
  constant DEFAULT_SCALE (line 52) | const DEFAULT_SCALE = 1.0
  constant DEFAULT_FLIP_X (line 53) | const DEFAULT_FLIP_X = false
  constant DEFAULT_FLIP_Y (line 54) | const DEFAULT_FLIP_Y = false
  class Animation (line 56) | class Animation {
    method constructor (line 70) | constructor(
    method activate (line 97) | activate(worldTransform: THREE.Matrix4): void {
    method deactivate (line 111) | deactivate(): void {
    method updateVisuals (line 117) | updateVisuals(worldTransform: THREE.Matrix4): void {
    method updateTime (line 122) | updateTime(deltaTimeMs: number): boolean {
    method play (line 157) | play(): void {
    method stop (line 162) | stop(): void {
    method goToFrame (line 166) | goToFrame(localFrame: number): void {
    method setFrameDuration (line 178) | setFrameDuration(newFrameDuration: number): void {
    method getResource (line 184) | getResource(): SpriteResource {
    method releaseInstanceSlot (line 188) | releaseInstanceSlot(): void {
  class TiledSprite (line 193) | class TiledSprite {
    method constructor (line 205) | constructor(
    method _calculateAnimationWorldMatrix (line 255) | private _calculateAnimationWorldMatrix(animState: ResolvedAnimationSta...
    method currentAnimation (line 266) | public get currentAnimation(): Animation {
    method updateCurrentAnimationVisuals (line 270) | private updateCurrentAnimationVisuals(): void {
    method setPosition (line 280) | setPosition(position: THREE.Vector3): void {
    method setRotation (line 285) | setRotation(rotation: THREE.Quaternion): void {
    method setScale (line 290) | setScale(scale: THREE.Vector3): void {
    method getScale (line 295) | getScale(): THREE.Vector3 {
    method setTransform (line 299) | setTransform(position: THREE.Vector3, rotation: THREE.Quaternion, newS...
    method play (line 306) | play(): void {
    method stop (line 309) | stop(): void {
    method goToFrame (line 312) | goToFrame(frame: number): void {
    method setFrameDuration (line 315) | setFrameDuration(newFrameDuration: number): void {
    method isPlaying (line 319) | isPlaying(): boolean {
    method setAnimation (line 323) | async setAnimation(animationName: string): Promise<void> {
    method update (line 346) | update(deltaTime: number): void {
    method destroy (line 352) | destroy(): void {
    method getCurrentAnimationName (line 361) | getCurrentAnimationName(): string {
    method getWorldTransform (line 365) | getWorldTransform(): THREE.Matrix4 {
    method getWorldPlaneSize (line 369) | getWorldPlaneSize(): THREE.Vector2 {
    method visible (line 378) | get visible(): boolean {
    method visible (line 382) | set visible(value: boolean) {
    method definition (line 395) | public get definition(): SpriteDefinition {
    method currentTransform (line 399) | public get currentTransform(): {
  type SpriteAnimatorInstanceManager (line 412) | interface SpriteAnimatorInstanceManager {
  class SpriteAnimator (line 419) | class SpriteAnimator {
    method constructor (line 424) | constructor(private scene: Scene) {}
    method createSpriteAnimationMaterial (line 426) | private createSpriteAnimationMaterial(
    method getOrCreateInstanceManager (line 465) | private getOrCreateInstanceManager(
    method createSprite (line 518) | async createSprite(
    method update (line 613) | update(deltaTime: number): void {
    method removeSprite (line 619) | removeSprite(id: string): void {
    method removeAllSprites (line 627) | removeAllSprites(): void {

FILE: packages/core/src/3d/animation/SpriteParticleGenerator.ts
  type ParticleEffectParameters (line 24) | interface ParticleEffectParameters {
  type AutoSpawnConfig (line 49) | interface AutoSpawnConfig {
  type ParticleSlot (line 56) | interface ParticleSlot {
  class SpriteParticleGenerator (line 62) | class SpriteParticleGenerator {
    method constructor (line 87) | constructor(scene: THREE.Scene, initialBaseConfig: ParticleEffectParam...
    method _ensureInitialized (line 102) | private async _ensureInitialized(): Promise<void> {
    method _initializeGPUParticleSystem (line 108) | private async _initializeGPUParticleSystem(): Promise<void> {
    method _createGPUMaterial (line 172) | private _createGPUMaterial(materialFactory: () => NodeMaterial): NodeM...
    method _resolveCurrentOrigin (line 276) | private _resolveCurrentOrigin(originsArray: THREE.Vector3[]): THREE.Ve...
    method getActiveParticleCount (line 282) | public getActiveParticleCount(): number {
    method _resolveSpawnRadius (line 286) | private _resolveSpawnRadius(spawnRadius: number | THREE.Vector3): THRE...
    method _spawnParticle (line 290) | private _spawnParticle(effectiveParams: Readonly<ParticleEffectParamet...
    method spawnParticles (line 356) | public async spawnParticles(count: number, overrides: Partial<Particle...
    method setAutoSpawn (line 372) | public setAutoSpawn(ratePerSecond: number, autoSpawnParamOverrides: Pa...
    method hasAutoSpawn (line 388) | public hasAutoSpawn(): boolean {
    method stopAutoSpawn (line 392) | public stopAutoSpawn(): void {
    method update (line 396) | public async update(deltaTimeMs: number): Promise<void> {
    method dispose (line 428) | public dispose(): void {

FILE: packages/core/src/3d/canvas.ts
  constant WORKGROUP_SIZE (line 11) | const WORKGROUP_SIZE = 4
  constant SUPERSAMPLING_COMPUTE_SHADER (line 12) | const SUPERSAMPLING_COMPUTE_SHADER = shaderTemplate.replace(/\${WORKGROU...
  type SuperSampleAlgorithm (line 14) | enum SuperSampleAlgorithm {
  class CLICanvas (line 19) | class CLICanvas {
    method constructor (line 41) | constructor(
    method destroy (line 56) | public destroy(): void {
    method setSuperSampleAlgorithm (line 60) | public setSuperSampleAlgorithm(superSampleAlgorithm: SuperSampleAlgori...
    method getSuperSampleAlgorithm (line 65) | public getSuperSampleAlgorithm(): SuperSampleAlgorithm {
    method getContext (line 69) | getContext(type: string, attrs?: WebGLContextAttributes) {
    method setSize (line 78) | setSize(width: number, height: number) {
    method addEventListener (line 86) | addEventListener(event: string, listener: any, options?: any) {
    method removeEventListener (line 90) | removeEventListener(event: string, listener: any, options?: any) {
    method dispatchEvent (line 94) | dispatchEvent(event: Event) {
    method setSuperSample (line 98) | public setSuperSample(superSample: SuperSampleType): void {
    method saveToFile (line 102) | public async saveToFile(filePath: string): Promise<void> {
    method initComputePipeline (line 168) | private async initComputePipeline(): Promise<void> {
    method updateComputeParams (line 221) | private updateComputeParams(): void {
    method scheduleUpdateComputeBuffers (line 236) | private scheduleUpdateComputeBuffers(): void {
    method updateComputeBuffers (line 240) | private updateComputeBuffers(width: number, height: number): void {
    method runComputeShaderSuperSampling (line 275) | private async runComputeShaderSuperSampling(texture: GPUTexture, buffe...
    method updateReadbackBuffer (line 356) | private updateReadbackBuffer(renderWidth: number, renderHeight: number...
    method readPixelsIntoBuffer (line 371) | async readPixelsIntoBuffer(buffer: OptimizedBuffer): Promise<void> {

FILE: packages/core/src/3d/physics/PlanckPhysicsAdapter.ts
  class PlanckRigidBody (line 10) | class PlanckRigidBody implements PhysicsRigidBody {
    method constructor (line 11) | constructor(private planckBody: planck.Body) {}
    method applyImpulse (line 13) | applyImpulse(force: PhysicsVector2): void {
    method applyTorqueImpulse (line 17) | applyTorqueImpulse(torque: number): void {
    method getTranslation (line 21) | getTranslation(): PhysicsVector2 {
    method getRotation (line 26) | getRotation(): number {
    method nativeBody (line 30) | get nativeBody(): planck.Body {
  class PlanckPhysicsWorld (line 35) | class PlanckPhysicsWorld implements PhysicsWorld {
    method constructor (line 36) | constructor(private planckWorld: planck.World) {}
    method createRigidBody (line 38) | createRigidBody(desc: PhysicsRigidBodyDesc): PhysicsRigidBody {
    method createCollider (line 50) | createCollider(colliderDesc: PhysicsColliderDesc, rigidBody: PhysicsRi...
    method removeRigidBody (line 64) | removeRigidBody(rigidBody: PhysicsRigidBody): void {
    method createFromPlanckWorld (line 69) | static createFromPlanckWorld(planckWorld: planck.World): PlanckPhysics...

FILE: packages/core/src/3d/physics/RapierPhysicsAdapter.ts
  class RapierRigidBody (line 10) | class RapierRigidBody implements PhysicsRigidBody {
    method constructor (line 11) | constructor(private rapierBody: RAPIER.RigidBody) {}
    method applyImpulse (line 13) | applyImpulse(force: PhysicsVector2): void {
    method applyTorqueImpulse (line 17) | applyTorqueImpulse(torque: number): void {
    method getTranslation (line 21) | getTranslation(): PhysicsVector2 {
    method getRotation (line 26) | getRotation(): number {
    method nativeBody (line 30) | get nativeBody(): RAPIER.RigidBody {
  class RapierPhysicsWorld (line 35) | class RapierPhysicsWorld implements PhysicsWorld {
    method constructor (line 36) | constructor(private rapierWorld: RAPIER.World) {}
    method createRigidBody (line 38) | createRigidBody(desc: PhysicsRigidBodyDesc): PhysicsRigidBody {
    method createCollider (line 48) | createCollider(colliderDesc: PhysicsColliderDesc, rigidBody: PhysicsRi...
    method removeRigidBody (line 58) | removeRigidBody(rigidBody: PhysicsRigidBody): void {
    method createFromRapierWorld (line 63) | static createFromRapierWorld(rapierWorld: RAPIER.World): RapierPhysics...

FILE: packages/core/src/3d/physics/physics-interface.ts
  type PhysicsVector2 (line 1) | interface PhysicsVector2 {
  type PhysicsRigidBodyDesc (line 6) | interface PhysicsRigidBodyDesc {
  type PhysicsColliderDesc (line 12) | interface PhysicsColliderDesc {
  type PhysicsRigidBody (line 20) | interface PhysicsRigidBody {
  type PhysicsWorld (line 27) | interface PhysicsWorld {

FILE: packages/core/src/NativeSpanFeed.ts
  type EventId (line 8) | const enum EventId {
  function toPointer (line 16) | function toPointer(value: number | bigint): Pointer {
  function toNumber (line 26) | function toNumber(value: number | bigint): number {
  type StreamEventHandler (line 30) | type StreamEventHandler = (eventId: number, arg0: Pointer, arg1: number ...
  type DataHandler (line 32) | type DataHandler = (data: Uint8Array) => void | Promise<void>
  class NativeSpanFeed (line 37) | class NativeSpanFeed {
    method create (line 38) | static create(options?: NativeSpanFeedOptions): NativeSpanFeed {
    method attach (line 55) | static attach(streamPtr: bigint | number, _options?: NativeSpanFeedOpt...
    method constructor (line 90) | private constructor(streamPtr: Pointer) {
    method ensureDrainBuffer (line 98) | private ensureDrainBuffer(): void {
    method onData (line 104) | onData(handler: DataHandler): () => void {
    method onError (line 113) | onError(handler: (code: number) => void): () => void {
    method close (line 118) | close(): void {
    method processPendingClose (line 134) | private processPendingClose(): void {
    method performClose (line 141) | private performClose(): void {
    method finalizeDestroy (line 155) | private finalizeDestroy(): void {
    method handleEvent (line 169) | private handleEvent(eventId: number, arg0: Pointer, arg1: number | big...
    method decrementRefcount (line 219) | private decrementRefcount(chunkIndex: number): void {
    method drainOnce (line 226) | private drainOnce(): number {
    method drainAll (line 294) | drainAll(): void {

FILE: packages/core/src/Renderable.ts
  type LayoutEvents (line 39) | enum LayoutEvents {
  type RenderableEvents (line 46) | enum RenderableEvents {
  type Position (line 51) | interface Position {
  type BaseRenderableOptions (line 58) | interface BaseRenderableOptions {
  type LayoutOptions (line 62) | interface LayoutOptions extends BaseRenderableOptions {
  type RenderableOptions (line 98) | interface RenderableOptions<T extends BaseRenderable = BaseRenderable> e...
  function isRenderable (line 131) | function isRenderable(obj: any): obj is Renderable {
  method constructor (line 145) | constructor(options: BaseRenderableOptions) {
  method id (line 160) | public get id(): string {
  method id (line 164) | public set id(value: string) {
  method isDirty (line 168) | public get isDirty(): boolean {
  method markClean (line 172) | protected markClean(): void {
  method markDirty (line 176) | protected markDirty(): void {
  method destroy (line 180) | public destroy(): void {
  method destroyRecursively (line 185) | public destroyRecursively(): void {
  method visible (line 190) | public get visible(): boolean {
  method visible (line 194) | public set visible(value: boolean) {
  method constructor (line 257) | constructor(ctx: RenderContext, options: RenderableOptions<any>) {
  method id (line 297) | public override get id() {
  method id (line 301) | public override set id(value: string) {
  method focusable (line 309) | public get focusable(): boolean {
  method focusable (line 313) | public set focusable(value: boolean) {
  method ctx (line 317) | public get ctx(): RenderContext {
  method visible (line 321) | public get visible(): boolean {
  method primaryAxis (line 325) | public get primaryAxis(): "row" | "column" {
  method visible (line 330) | public set visible(value: boolean) {
  method opacity (line 351) | public get opacity(): number {
  method opacity (line 355) | public set opacity(value: number) {
  method hasSelection (line 363) | public hasSelection(): boolean {
  method onSelectionChanged (line 367) | public onSelectionChanged(selection: Selection | null): boolean {
  method getSelectedText (line 373) | public getSelectedText(): string {
  method shouldStartSelection (line 377) | public shouldStartSelection(x: number, y: number): boolean {
  method focus (line 381) | public focus(): void {
  method blur (line 413) | public blur(): void {
  method focused (line 432) | public get focused(): boolean {
  method live (line 436) | public get live(): boolean {
  method liveCount (line 440) | public get liveCount(): number {
  method live (line 444) | public set live(value: boolean) {
  method propagateLiveCount (line 455) | protected propagateLiveCount(delta: number): void {
  method findDescendantById (line 463) | public findDescendantById(id: string): Renderable | undefined {
  method requestRender (line 474) | public requestRender() {
  method translateX (line 479) | public get translateX(): number {
  method translateX (line 483) | public set translateX(value: number) {
  method translateY (line 490) | public get translateY(): number {
  method translateY (line 494) | public set translateY(value: number) {
  method x (line 501) | public get x(): number {
  method x (line 508) | public set x(value: number) {
  method top (line 512) | public get top(): number | "auto" | `${number}%` | undefined {
  method top (line 516) | public set top(value: number | "auto" | `${number}%` | undefined) {
  method right (line 522) | public get right(): number | "auto" | `${number}%` | undefined {
  method right (line 526) | public set right(value: number | "auto" | `${number}%` | undefined) {
  method bottom (line 532) | public get bottom(): number | "auto" | `${number}%` | undefined {
  method bottom (line 536) | public set bottom(value: number | "auto" | `${number}%` | undefined) {
  method left (line 542) | public get left(): number | "auto" | `${number}%` | undefined {
  method left (line 546) | public set left(value: number | "auto" | `${number}%` | undefined) {
  method y (line 552) | public get y(): number {
  method y (line 559) | public set y(value: number) {
  method width (line 563) | public get width(): number {
  method width (line 567) | public set width(value: number | "auto" | `${number}%`) {
  method height (line 581) | public get height(): number {
  method height (line 585) | public set height(value: number | "auto" | `${number}%`) {
  method zIndex (line 599) | public get zIndex(): number {
  method zIndex (line 603) | public set zIndex(value: number) {
  method requestZIndexSort (line 611) | private requestZIndexSort(): void {
  method ensureZIndexSorted (line 615) | private ensureZIndexSorted(): void {
  method getChildrenSortedByPrimaryAxis (line 622) | public getChildrenSortedByPrimaryAxis(): Renderable[] {
  method setupYogaProperties (line 645) | private setupYogaProperties(options: RenderableOptions<Renderable>): void {
  method setupMarginAndPadding (line 728) | private setupMarginAndPadding(options: RenderableOptions<Renderable>): v...
  method position (line 778) | set position(positionType: PositionTypeString | null | undefined) {
  method overflow (line 786) | get overflow(): OverflowString {
  method overflow (line 790) | set overflow(overflow: OverflowString | null | undefined) {
  method setPosition (line 798) | public setPosition(position: Position): void {
  method updateYogaPosition (line 803) | private updateYogaPosition(position: Position): void {
  method flexGrow (line 838) | public set flexGrow(grow: number | null | undefined) {
  method flexShrink (line 847) | public set flexShrink(shrink: number | null | undefined) {
  method flexDirection (line 854) | public set flexDirection(direction: FlexDirectionString | null | undefin...
  method flexWrap (line 859) | public set flexWrap(wrap: WrapString | null | undefined) {
  method alignItems (line 864) | public set alignItems(alignItems: AlignString | null | undefined) {
  method justifyContent (line 869) | public set justifyContent(justifyContent: JustifyString | null | undefin...
  method alignSelf (line 874) | public set alignSelf(alignSelf: AlignString | null | undefined) {
  method flexBasis (line 879) | public set flexBasis(basis: number | "auto" | null | undefined) {
  method minWidth (line 886) | public set minWidth(minWidth: number | `${number}%` | null | undefined) {
  method maxWidth (line 893) | public set maxWidth(maxWidth: number | `${number}%` | null | undefined) {
  method minHeight (line 900) | public set minHeight(minHeight: number | `${number}%` | null | undefined) {
  method maxHeight (line 907) | public set maxHeight(maxHeight: number | `${number}%` | null | undefined) {
  method margin (line 914) | public set margin(margin: number | "auto" | `${number}%` | null | undefi...
  method marginX (line 921) | public set marginX(marginX: number | "auto" | `${number}%` | null | unde...
  method marginY (line 928) | public set marginY(marginY: number | "auto" | `${number}%` | null | unde...
  method marginTop (line 935) | public set marginTop(margin: number | "auto" | `${number}%` | null | und...
  method marginRight (line 942) | public set marginRight(margin: number | "auto" | `${number}%` | null | u...
  method marginBottom (line 949) | public set marginBottom(margin: number | "auto" | `${number}%` | null | ...
  method marginLeft (line 956) | public set marginLeft(margin: number | "auto" | `${number}%` | null | un...
  method padding (line 963) | public set padding(padding: number | `${number}%` | null | undefined) {
  method paddingX (line 970) | public set paddingX(paddingX: number | `${number}%` | null | undefined) {
  method paddingY (line 977) | public set paddingY(paddingY: number | `${number}%` | null | undefined) {
  method paddingTop (line 984) | public set paddingTop(padding: number | `${number}%` | null | undefined) {
  method paddingRight (line 991) | public set paddingRight(padding: number | `${number}%` | null | undefine...
  method paddingBottom (line 998) | public set paddingBottom(padding: number | `${number}%` | null | undefin...
  method paddingLeft (line 1005) | public set paddingLeft(padding: number | `${number}%` | null | undefined) {
  method getLayoutNode (line 1012) | public getLayoutNode(): YogaNode {
  method updateFromLayout (line 1016) | public updateFromLayout(): void {
  method onLayoutResize (line 1044) | protected onLayoutResize(width: number, height: number): void {
  method handleFrameBufferResize (line 1053) | protected handleFrameBufferResize(width: number, height: number): void {
  method createFrameBuffer (line 1067) | protected createFrameBuffer(): void {
  method onResize (line 1089) | protected onResize(width: number, height: number): void {
  method replaceParent (line 1095) | private replaceParent(obj: Renderable) {
  method add (line 1102) | public add(obj: Renderable | VNode<any, any[]> | unknown, index?: number...
  method insertBefore (line 1156) | insertBefore(obj: Renderable | VNode<any, any[]> | unknown, anchor?: Ren...
  method getRenderable (line 1236) | public getRenderable(id: string): Renderable | undefined {
  method remove (line 1240) | public remove(id: string): void {
  method onRemove (line 1276) | protected onRemove(): void {
  method getChildren (line 1281) | public getChildren(): Renderable[] {
  method getChildrenCount (line 1285) | public getChildrenCount(): number {
  method updateLayout (line 1289) | public updateLayout(deltaTime: number, renderList: RenderCommand[] = [])...
  method render (line 1360) | public render(buffer: OptimizedBuffer, deltaTime: number): void {
  method _getVisibleChildren (line 1384) | protected _getVisibleChildren(): number[] {
  method onUpdate (line 1388) | protected onUpdate(deltaTime: number): void {
  method getScissorRect (line 1393) | protected getScissorRect(): { x: number; y: number; width: number; heigh...
  method renderSelf (line 1402) | protected renderSelf(buffer: OptimizedBuffer, deltaTime: number): void {
  method isDestroyed (line 1407) | public get isDestroyed(): boolean {
  method destroy (line 1411) | public destroy(): void {
  method destroyRecursively (line 1447) | public destroyRecursively(): void {
  method destroySelf (line 1457) | protected destroySelf(): void {
  method processMouseEvent (line 1462) | public processMouseEvent(event: MouseEvent): void {
  method onMouseEvent (line 1472) | protected onMouseEvent(event: MouseEvent): void {
  method onMouse (line 1477) | public set onMouse(handler: ((event: MouseEvent) => void) | undefined) {
  method onMouseDown (line 1482) | public set onMouseDown(handler: ((event: MouseEvent) => void) | undefine...
  method onMouseUp (line 1487) | public set onMouseUp(handler: ((event: MouseEvent) => void) | undefined) {
  method onMouseMove (line 1492) | public set onMouseMove(handler: ((event: MouseEvent) => void) | undefine...
  method onMouseDrag (line 1497) | public set onMouseDrag(handler: ((event: MouseEvent) => void) | undefine...
  method onMouseDragEnd (line 1502) | public set onMouseDragEnd(handler: ((event: MouseEvent) => void) | undef...
  method onMouseDrop (line 1507) | public set onMouseDrop(handler: ((event: MouseEvent) => void) | undefine...
  method onMouseOver (line 1512) | public set onMouseOver(handler: ((event: MouseEvent) => void) | undefine...
  method onMouseOut (line 1517) | public set onMouseOut(handler: ((event: MouseEvent) => void) | undefined) {
  method onMouseScroll (line 1522) | public set onMouseScroll(handler: ((event: MouseEvent) => void) | undefi...
  method onPaste (line 1527) | public set onPaste(handler: ((event: PasteEvent) => void) | undefined) {
  method onPaste (line 1530) | public get onPaste(): ((event: PasteEvent) => void) | undefined {
  method onKeyDown (line 1534) | public set onKeyDown(handler: ((key: KeyEvent) => void) | undefined) {
  method onKeyDown (line 1538) | public get onKeyDown(): ((key: KeyEvent) => void) | undefined {
  method onSizeChange (line 1542) | public set onSizeChange(handler: (() => void) | undefined) {
  method onSizeChange (line 1545) | public get onSizeChange(): (() => void) | undefined {
  method applyEventOptions (line 1549) | private applyEventOptions(options: RenderableOptions<Renderable>): void {
  type RenderCommandBase (line 1566) | interface RenderCommandBase {
  type RenderCommandPushScissorRect (line 1570) | interface RenderCommandPushScissorRect extends RenderCommandBase {
  type RenderCommandPopScissorRect (line 1580) | interface RenderCommandPopScissorRect extends RenderCommandBase {
  type RenderCommandRender (line 1584) | interface RenderCommandRender extends RenderCommandBase {
  type RenderCommandPushOpacity (line 1589) | interface RenderCommandPushOpacity extends RenderCommandBase {
  type RenderCommandPopOpacity (line 1594) | interface RenderCommandPopOpacity extends RenderCommandBase {
  type RenderCommand (line 1598) | type RenderCommand =
  class RootRenderable (line 1605) | class RootRenderable extends Renderable {
    method constructor (line 1608) | constructor(ctx: RenderContext) {
    method render (line 1623) | public render(buffer: OptimizedBuffer, deltaTime: number): void {
    method propagateLiveCount (line 1676) | protected propagateLiveCount(delta: number): void {
    method calculateLayout (line 1687) | public calculateLayout(): void {
    method resize (line 1692) | public resize(width: number, height: number): void {

FILE: packages/core/src/animation/Timeline.test.ts
  class TestEffect (line 2029) | class TestEffect {
    method brightness (line 2033) | get brightness(): number {
    method brightness (line 2037) | set brightness(value: number) {
    method contrast (line 2041) | get contrast(): number {
    method contrast (line 2045) | set contrast(value: number) {

FILE: packages/core/src/animation/Timeline.ts
  type TimelineOptions (line 3) | interface TimelineOptions {
  type AnimationOptions (line 11) | interface AnimationOptions {
  type JSAnimation (line 25) | interface JSAnimation {
  type TimelineItem (line 32) | interface TimelineItem {
  type TimelineTimelineItem (line 37) | interface TimelineTimelineItem extends TimelineItem {
  type TimelineCallbackItem (line 43) | interface TimelineCallbackItem extends TimelineItem {
  type TimelineAnimationItem (line 49) | interface TimelineAnimationItem extends TimelineItem {
  type EasingFunctions (line 70) | type EasingFunctions = keyof typeof easingFunctions
  function captureInitialValues (line 113) | function captureInitialValues(item: TimelineAnimationItem): void {
  function applyAnimationAtProgress (line 135) | function applyAnimationAtProgress(
  function evaluateAnimation (line 172) | function evaluateAnimation(item: TimelineAnimationItem, timelineTime: nu...
  function evaluateCallback (line 251) | function evaluateCallback(item: TimelineCallbackItem, timelineTime: numb...
  function evaluateTimelineSync (line 258) | function evaluateTimelineSync(item: TimelineTimelineItem, timelineTime: ...
  function evaluateItem (line 276) | function evaluateItem(item: TimelineItem, timelineTime: number, deltaTim...
  class Timeline (line 284) | class Timeline {
    method constructor (line 298) | constructor(options: TimelineOptions = {}) {
    method addStateChangeListener (line 306) | public addStateChangeListener(listener: (timeline: Timeline) => void):...
    method removeStateChangeListener (line 310) | public removeStateChangeListener(listener: (timeline: Timeline) => voi...
    method notifyStateChange (line 314) | private notifyStateChange(): void {
    method add (line 320) | add(target: any, properties: AnimationOptions, startTime: number | str...
    method once (line 362) | once(target: any, properties: AnimationOptions): this {
    method call (line 375) | call(callback: () => void, startTime: number | string = 0): this {
    method sync (line 388) | sync(timeline: Timeline, startTime: number = 0): this {
    method play (line 402) | play(): this {
    method pause (line 416) | pause(): this {
    method resetItems (line 428) | resetItems() {
    method restart (line 447) | restart(): this {
    method update (line 457) | update(deltaTime: number): void {
  class TimelineEngine (line 500) | class TimelineEngine {
    method attach (line 509) | attach(renderer: CliRenderer): void {
    method detach (line 522) | detach(): void {
    method updateLiveState (line 534) | private updateLiveState(): void {
    method register (line 554) | register(timeline: Timeline): void {
    method unregister (line 562) | unregister(timeline: Timeline): void {
    method clear (line 570) | clear(): void {
    method update (line 578) | update(deltaTime: number): void {
  function createTimeline (line 589) | function createTimeline(options: TimelineOptions = {}): Timeline {

FILE: packages/core/src/ansi.ts
  constant ANSI (line 1) | const ANSI = {

FILE: packages/core/src/benchmark/attenuation-benchmark.ts
  type Scenario (line 7) | type Scenario = { width: number; height: number }
  type ScenarioResult (line 8) | type ScenarioResult = {
  constant ITERATIONS (line 17) | const ITERATIONS = 5000
  constant WARMUP_ITERATIONS (line 18) | const WARMUP_ITERATIONS = 100
  constant STRENGTH (line 19) | const STRENGTH = 0.7
  function calculateStats (line 28) | function calculateStats(samples: number[]): { avgMs: number; medianMs: n...
  function formatMs (line 40) | function formatMs(value: number): number {
  function formatNs (line 44) | function formatNs(value: number): number {
  function runScenario (line 48) | function runScenario({ width, height }: Scenario): ScenarioResult {

FILE: packages/core/src/benchmark/colormatrix-benchmark.ts
  type Scenario (line 6) | type Scenario = { width: number; height: number; mode: "uniform" | "mask...
  type ScenarioResult (line 7) | type ScenarioResult = {
  constant ITERATIONS (line 21) | const ITERATIONS = 1000
  constant WARMUP_ITERATIONS (line 22) | const WARMUP_ITERATIONS = 100
  function generateCellMask (line 34) | function generateCellMask(width: number, height: number, density: number...
  function calculateStats (line 48) | function calculateStats(samples: number[]): { avgMs: number; medianMs: n...
  function formatMs (line 60) | function formatMs(value: number): number {
  function formatNs (line 64) | function formatNs(value: number): number {
  function fillBufferColors (line 68) | function fillBufferColors(buffer: OptimizedBuffer): void {
  function runScenario (line 83) | function runScenario({ width, height, mode }: Scenario): ScenarioResult {

FILE: packages/core/src/benchmark/gain-benchmark.ts
  type Scenario (line 7) | type Scenario = { width: number; height: number }
  type ScenarioResult (line 8) | type ScenarioResult = {
  constant ITERATIONS (line 17) | const ITERATIONS = 5000
  constant WARMUP_ITERATIONS (line 18) | const WARMUP_ITERATIONS = 100
  constant GAIN_FACTOR (line 19) | const GAIN_FACTOR = 1.3
  function calculateStats (line 28) | function calculateStats(samples: number[]): { avgMs: number; medianMs: n...
  function formatMs (line 40) | function formatMs(value: number): number {
  function formatNs (line 44) | function formatNs(value: number): number {
  function runScenario (line 48) | function runScenario({ width, height }: Scenario): ScenarioResult {

FILE: packages/core/src/benchmark/markdown-benchmark.ts
  constant WORDS (line 15) | const WORDS = [
  constant CODE_WORDS (line 56) | const CODE_WORDS = [
  type MemorySample (line 72) | type MemorySample = {
  type MemoryFieldStats (line 80) | type MemoryFieldStats = {
  type MemoryStats (line 87) | type MemoryStats = {
  type NativeMemorySample (line 102) | type NativeMemorySample = {
  type NativeMemoryStats (line 110) | type NativeMemoryStats = {
  type TimingStats (line 125) | type TimingStats = {
  type ScenarioResult (line 135) | type ScenarioResult = {
  type StaticScenarioPlan (line 156) | type StaticScenarioPlan = {
  type StreamingScenarioPlan (line 166) | type StreamingScenarioPlan = {
  type StyleScenarioPlan (line 178) | type StyleScenarioPlan = {
  type ScenarioPlan (line 188) | type ScenarioPlan = StaticScenarioPlan | StreamingScenarioPlan | StyleSc...
  type StreamState (line 190) | type StreamState = {
  type RunContext (line 200) | type RunContext = {
  type SuiteConfig (line 212) | type SuiteConfig = {
  type MemorySampler (line 219) | type MemorySampler = {
  type StaticScenarioConfig (line 226) | type StaticScenarioConfig = {
  type StreamingScenarioConfig (line 240) | type StreamingScenarioConfig = StaticScenarioConfig & {
  type OutputMeta (line 244) | type OutputMeta = {
  function createScenarios (line 467) | function createScenarios(suite: string, config: SuiteConfig, runSeed: nu...
  function runScenario (line 831) | async function runScenario(plan: ScenarioPlan, ctx: RunContext): Promise...
  function runStaticScenario (line 841) | async function runStaticScenario(plan: StaticScenarioPlan, ctx: RunConte...
  function runStreamingScenario (line 901) | async function runStreamingScenario(plan: StreamingScenarioPlan, ctx: Ru...
  function runStyleScenario (line 965) | async function runStyleScenario(plan: StyleScenarioPlan, ctx: RunContext...
  function runStreamingIterations (line 1025) | async function runStreamingIterations(
  function createStreamState (line 1057) | function createStreamState(input: {
  function appendStream (line 1074) | function appendStream(state: StreamState, linesPerTick: number): { updat...
  function buildMarkdownDocument (line 1104) | function buildMarkdownDocument(rng: () => number, config: StaticScenario...
  function buildTableOnlyDocument (line 1156) | function buildTableOnlyDocument(
  function buildCodeOnlyDocument (line 1177) | function buildCodeOnlyDocument(
  function buildHeadingsOnlyDocument (line 1196) | function buildHeadingsOnlyDocument(
  function buildHeadingChunks (line 1217) | function buildHeadingChunks(
  function buildCodeBlockChunks (line 1228) | function buildCodeBlockChunks(rng: () => number, config: { blocks: numbe...
  function buildTableRowChunks (line 1240) | function buildTableRowChunks(rng: () => number, config: { rows: number; ...
  function buildStreamingChunks (line 1248) | function buildStreamingChunks(rng: () => number, config: StreamingScenar...
  function pushLine (line 1287) | function pushLine(chunks: string[], line: string): void {
  function makeParagraph (line 1291) | function makeParagraph(rng: () => number, sentences: number): string {
  function makeSentence (line 1299) | function makeSentence(rng: () => number, minWords: number, maxWords: num...
  function wrapInline (line 1313) | function wrapInline(rng: () => number, word: string): string {
  function makeList (line 1322) | function makeList(rng: () => number, items: number): string {
  function makeListLines (line 1326) | function makeListLines(rng: () => number, items: number): string[] {
  function makeCodeBlock (line 1334) | function makeCodeBlock(rng: () => number, lines: number): string {
  function makeCodeBlockLines (line 1338) | function makeCodeBlockLines(rng: () => number, lines: number): string[] {
  function makeTableLines (line 1359) | function makeTableLines(rng: () => number, columns: number, rows: number...
  function makeTableRowLine (line 1385) | function makeTableRowLine(rng: () => number, row: number, columns: numbe...
  function makeHeadingLine (line 1393) | function makeHeadingLine(rng: () => number, depthMin: number, depthMax: ...
  function makeCellText (line 1402) | function makeCellText(rng: () => number, row: number, col: number): stri...
  function pick (line 1413) | function pick<T>(rng: () => number, list: T[]): T {
  function scaled (line 1417) | function scaled(value: number, scaleValue: number): number {
  function createRng (line 1421) | function createRng(initialSeed: number): () => number {
  function toNumber (line 1429) | function toNumber(value: unknown, fallback: number): number {
  function shouldSampleMemory (line 1438) | function shouldSampleMemory(ctx: RunContext): boolean {
  function readMemorySample (line 1442) | function readMemorySample(): MemorySample {
  function readNativeMemorySample (line 1453) | function readNativeMemorySample(): NativeMemorySample {
  function createMemorySampler (line 1464) | function createMemorySampler(ctx: RunContext): MemorySampler {
  function computeMemoryStats (line 1506) | function computeMemoryStats(samples: MemorySample[], start: MemorySample...
  function computeNativeMemoryStats (line 1529) | function computeNativeMemoryStats(
  function updatePeak (line 1557) | function updatePeak(sample: MemorySample, peak: MemorySample): void {
  function updateNativePeak (line 1565) | function updateNativePeak(sample: NativeMemorySample, peak: NativeMemory...
  function diffMemory (line 1573) | function diffMemory(start: MemorySample, end: MemorySample): MemorySample {
  function diffNativeMemory (line 1583) | function diffNativeMemory(start: NativeMemorySample, end: NativeMemorySa...
  function computeFieldStats (line 1593) | function computeFieldStats(values: number[]): MemoryFieldStats {
  function computeTimingStats (line 1602) | function computeTimingStats(durations: number[]): TimingStats {
  function outputResults (line 1624) | async function outputResults(
  function formatBytes (line 1676) | function formatBytes(value: number): string {
  function formatAllocs (line 1695) | function formatAllocs(value: number): string {
  function formatScenarioResult (line 1701) | function formatScenarioResult(result: ScenarioResult): string {
  function writeLine (line 1728) | function writeLine(line: string): void {
  function runSpawnedScenarios (line 1732) | async function runSpawnedScenarios(plans: ScenarioPlan[]): Promise<void> {
  function buildChildArgs (line 1790) | function buildChildArgs(args: string[], scenarioName: string, jsonPath: ...

FILE: packages/core/src/benchmark/native-span-feed-async-benchmark.ts
  function getArg (line 11) | function getArg(name: string): string | null {
  function hasFlag (line 19) | function hasFlag(name: string): boolean {
  type MemorySample (line 40) | type MemorySample = {
  function readMemory (line 48) | function readMemory(): MemorySample {
  function formatMB (line 59) | function formatMB(bytes: number): string {
  type AsyncScenario (line 63) | type AsyncScenario = {
  type AsyncScenarioResult (line 75) | type AsyncScenarioResult = {
  function runAsyncScenario (line 102) | async function runAsyncScenario(scenario: AsyncScenario): Promise<AsyncS...
  function makeAsyncScenarios (line 213) | function makeAsyncScenarios(): AsyncScenario[] {

FILE: packages/core/src/benchmark/native-span-feed-benchmark.ts
  function getArg (line 11) | function getArg(name: string): string | null {
  function hasFlag (line 19) | function hasFlag(name: string): boolean {
  type PatternSpec (line 64) | type PatternSpec =
  type ProducerAPI (line 74) | type ProducerAPI = "reserve" | "write"
  type Scenario (line 76) | type Scenario = {
  type ScenarioResult (line 89) | type ScenarioResult = {
  type MemorySample (line 119) | type MemorySample = {
  function repeatPattern (line 135) | function repeatPattern(base: Uint8Array, size: number): Uint8Array {
  function buildPattern (line 147) | function buildPattern(spec?: PatternSpec): Uint8Array | null {
  function readMemory (line 178) | function readMemory(): MemorySample {
  function updatePeak (line 189) | function updatePeak(current: MemorySample, peak: MemorySample): void {
  function diffMemory (line 197) | function diffMemory(start: MemorySample, end: MemorySample): MemorySample {
  function formatBytes (line 207) | function formatBytes(value: number): string {
  function createStreamForScenario (line 212) | function createStreamForScenario(
  type BaseScenario (line 235) | type BaseScenario = Omit<Scenario, "producerAPI">
  function withAPIs (line 237) | function withAPIs(bases: BaseScenario[]): Scenario[] {
  function makeScenarios (line 246) | function makeScenarios(baseIters: number, reuse: boolean): Scenario[] {
  function buildPatternSpec (line 418) | function buildPatternSpec(): PatternSpec | undefined {
  function runScenario (line 433) | function runScenario(scenario: Scenario): ScenarioResult {
  function createSingleScenario (line 552) | function createSingleScenario(): Scenario {

FILE: packages/core/src/benchmark/native-span-feed-compare.ts
  type ScenarioResult (line 4) | type ScenarioResult = {
  type MemorySample (line 33) | type MemorySample = {
  type BenchRun (line 41) | type BenchRun = {
  type MetricDelta (line 48) | type MetricDelta = {
  type ScenarioDiff (line 55) | type ScenarioDiff = {
  function getArg (line 77) | function getArg(name: string): string | null {
  function hasFlag (line 85) | function hasFlag(name: string): boolean {
  function readBench (line 100) | function readBench(path: string): BenchRun {
  function toBigInt (line 105) | function toBigInt(value: string | number | undefined): bigint | null {
  function formatBigPair (line 115) | function formatBigPair(baseline?: string | number, current?: string | nu...
  function formatPair (line 123) | function formatPair(base: number, curr: number, digits = 3): string {
  function formatBytes (line 131) | function formatBytes(value: number): string {
  function formatBytesPair (line 136) | function formatBytesPair(base: number, curr: number): string {
  function metricDelta (line 144) | function metricDelta(base?: number, curr?: number): MetricDelta | undefi...
  function diffOptions (line 151) | function diffOptions(base?: ScenarioResult["options"], curr?: ScenarioRe...

FILE: packages/core/src/benchmark/renderer-benchmark.ts
  type MemorySnapshot (line 26) | type MemorySnapshot = { heapUsed: number; heapTotal: number; arrayBuffer...
  constant SCENARIO_DURATION_MS (line 46) | const SCENARIO_DURATION_MS = parseInt(options.duration)
  type BenchmarkScenario (line 67) | enum BenchmarkScenario {
  constant WIDTH (line 81) | const WIDTH = renderer.terminalWidth
  constant HEIGHT (line 82) | const HEIGHT = renderer.terminalHeight
  constant TEST_CUBE_COUNT (line 153) | const TEST_CUBE_COUNT = 300
  type ScenarioResult (line 190) | type ScenarioResult = {
  constant RADIUS (line 209) | const RADIUS = 1
  constant MULTIPLE_CUBES_COUNT (line 210) | const MULTIPLE_CUBES_COUNT = 8
  function clearPreviousCubes (line 239) | function clearPreviousCubes() {
  function updateTextContent (line 246) | function updateTextContent(textId: string, content: string) {
  function setupScenario (line 253) | async function setupScenario(scenario: BenchmarkScenario) {
  function createSingleCubeScenario (line 274) | function createSingleCubeScenario() {
  function createMultipleCubesScenario (line 289) | function createMultipleCubesScenario() {
  function createTexturedCubesScenario (line 316) | async function createTexturedCubesScenario() {
  function addOutOfViewCubes (line 379) | function addOutOfViewCubes() {
  function getScenarioName (line 522) | function getScenarioName(scenario: BenchmarkScenario): string {
  function displayBenchmarkResults (line 535) | function displayBenchmarkResults(): void {

FILE: packages/core/src/benchmark/text-table-benchmark.ts
  constant WORDS (line 19) | const WORDS = [
  type MemorySample (line 60) | type MemorySample = {
  type MemoryStats (line 68) | type MemoryStats = {
  type TimingStats (line 76) | type TimingStats = {
  type ScenarioResult (line 86) | type ScenarioResult = {
  type ReplaceScenarioPlan (line 107) | type ReplaceScenarioPlan = {
  type IncrementalScenarioPlan (line 119) | type IncrementalScenarioPlan = {
  type SelectionScenarioPlan (line 133) | type SelectionScenarioPlan = {
  type ScenarioPlan (line 146) | type ScenarioPlan = ReplaceScenarioPlan | IncrementalScenarioPlan | Sele...
  type BenchmarkTableConfig (line 148) | type BenchmarkTableConfig = {
  type RunContext (line 154) | type RunContext = {
  type SuiteConfig (line 161) | type SuiteConfig = {
  type OutputMeta (line 168) | type OutputMeta = {
  type IncrementalState (line 180) | type IncrementalState = {
  constant PROPORTIONAL_TABLE_CONFIG (line 218) | const PROPORTIONAL_TABLE_CONFIG: BenchmarkTableConfig = {
  constant BALANCED_TABLE_CONFIG (line 224) | const BALANCED_TABLE_CONFIG: BenchmarkTableConfig = {
  function createScenarios (line 331) | function createScenarios(suite: string, config: SuiteConfig, runSeed: nu...
  function runScenario (line 483) | async function runScenario(plan: ScenarioPlan, ctx: RunContext): Promise...
  function applyTableConfig (line 493) | function applyTableConfig(table: TextTableRenderable, config: BenchmarkT...
  function runReplaceScenario (line 499) | async function runReplaceScenario(plan: ReplaceScenarioPlan, ctx: RunCon...
  function runIncrementalScenario (line 558) | async function runIncrementalScenario(plan: IncrementalScenarioPlan, ctx...
  function runSelectionScenario (line 628) | async function runSelectionScenario(plan: SelectionScenarioPlan, ctx: Ru...
  function nextIncrementalContent (line 714) | function nextIncrementalContent(plan: IncrementalScenarioPlan, state: In...
  function makeHeader (line 733) | function makeHeader(cols: number): TextTableCellContent[] {
  function buildTableContent (line 741) | function buildTableContent(rng: () => number, rows: number, cols: number...
  function buildRows (line 745) | function buildRows(rng: () => number, rows: number, cols: number, rowOff...
  function makeDataRow (line 753) | function makeDataRow(rng: () => number, rowIndex: number, cols: number):...
  function chunkCell (line 761) | function chunkCell(text: string): TextTableCellContent {
  function makeCellText (line 770) | function makeCellText(rng: () => number, row: number, col: number): stri...
  function pick (line 790) | function pick<T>(rng: () => number, list: T[]): T {
  function createRng (line 794) | function createRng(initialSeed: number): () => number {
  function scaled (line 802) | function scaled(value: number, scaleValue: number): number {
  function toNumber (line 806) | function toNumber(value: unknown, fallback: number): number {
  function shouldSampleMemory (line 815) | function shouldSampleMemory(memSampleEvery: number): boolean {
  function readMemorySample (line 819) | function readMemorySample(): MemorySample {
  function computeMemoryStats (line 830) | function computeMemoryStats(samples: MemorySample[], start: MemorySample...
  function diffMemory (line 851) | function diffMemory(start: MemorySample, end: MemorySample): MemorySample {
  function computeTimingStats (line 861) | function computeTimingStats(durations: number[]): TimingStats {
  function outputResults (line 883) | async function outputResults(
  function formatBytes (line 926) | function formatBytes(value: number): string {
  function formatScenarioResult (line 930) | function formatScenarioResult(result: ScenarioResult): string {
  function writeLine (line 945) | function writeLine(line: string): void {

FILE: packages/core/src/buffer.ts
  function packDrawOptions (line 11) | function packDrawOptions(
  class OptimizedBuffer (line 42) | class OptimizedBuffer {
    method ptr (line 59) | get ptr(): Pointer {
    method guard (line 66) | private guard(): void {
    method buffers (line 70) | get buffers(): {
    method constructor (line 95) | constructor(
    method create (line 111) | static create(
    method widthMethod (line 124) | public get widthMethod(): WidthMethod {
    method width (line 128) | public get width(): number {
    method height (line 132) | public get height(): number {
    method setRespectAlpha (line 136) | public setRespectAlpha(respectAlpha: boolean): void {
    method getNativeId (line 142) | public getNativeId(): string {
    method getRealCharBytes (line 147) | public getRealCharBytes(addLineBreaks: boolean = false): Uint8Array {
    method getSpanLines (line 155) | public getSpanLines(): CapturedLine[] {
    method clear (line 219) | public clear(bg: RGBA = RGBA.fromValues(0, 0, 0, 1)): void {
    method setCell (line 224) | public setCell(x: number, y: number, char: string, fg: RGBA, bg: RGBA,...
    method setCellWithAlphaBlending (line 229) | public setCellWithAlphaBlending(
    method drawText (line 241) | public drawText(
    method fillRect (line 286) | public fillRect(x: number, y: number, width: number, height: number, b...
    method colorMatrix (line 290) | public colorMatrix(
    method colorMatrixUniform (line 302) | public colorMatrixUniform(
    method drawFrameBuffer (line 314) | public drawFrameBuffer(
    method destroy (line 327) | public destroy(): void {
    method drawTextBuffer (line 333) | public drawTextBuffer(textBufferView: TextBufferView, x: number, y: nu...
    method drawEditorView (line 338) | public drawEditorView(editorView: EditorView, x: number, y: number): v...
    method drawSuperSampleBuffer (line 343) | public drawSuperSampleBuffer(
    method drawPackedBuffer (line 363) | public drawPackedBuffer(
    method drawGrayscaleBuffer (line 383) | public drawGrayscaleBuffer(
    method drawGrayscaleBufferSupersampled (line 396) | public drawGrayscaleBufferSupersampled(
    method resize (line 418) | public resize(width: number, height: number): void {
    method drawBox (line 429) | public drawBox(options: {
    method pushScissorRect (line 463) | public pushScissorRect(x: number, y: number, width: number, height: nu...
    method popScissorRect (line 468) | public popScissorRect(): void {
    method clearScissorRects (line 473) | public clearScissorRects(): void {
    method pushOpacity (line 478) | public pushOpacity(opacity: number): void {
    method popOpacity (line 483) | public popOpacity(): void {
    method getCurrentOpacity (line 488) | public getCurrentOpacity(): number {
    method clearOpacity (line 493) | public clearOpacity(): void {
    method encodeUnicode (line 498) | public encodeUnicode(text: string): { ptr: Pointer; data: Array<{ widt...
    method freeUnicode (line 503) | public freeUnicode(encoded: { ptr: Pointer; data: Array<{ width: numbe...
    method drawGrid (line 508) | public drawGrid(options: {
    method drawChar (line 538) | public drawChar(char: number, x: number, y: number, fg: RGBA, bg: RGBA...

FILE: packages/core/src/console.test.ts
  type MockRenderer (line 6) | interface MockRenderer {
  function createMouseEvent (line 21) | function createMouseEvent(

FILE: packages/core/src/console.ts
  type CallerInfo (line 25) | interface CallerInfo {
  function getCallerInfo (line 33) | function getCallerInfo(): CallerInfo | null {
  type LogLevel (line 55) | enum LogLevel {
  class TerminalConsoleCache (line 79) | class TerminalConsoleCache extends EventEmitter {
    method cachedLogs (line 86) | get cachedLogs(): [Date, LogLevel, any[], CallerInfo | null][] {
    method constructor (line 90) | constructor() {
    method activate (line 97) | public activate(): void {
    method setupConsoleCapture (line 105) | private setupConsoleCapture(): void {
    method overrideConsoleMethods (line 127) | private overrideConsoleMethods(): void {
    method setCollectCallerInfo (line 149) | public setCollectCallerInfo(enabled: boolean): void {
    method clearConsole (line 153) | public clearConsole(): void {
    method setCachingEnabled (line 157) | public setCachingEnabled(enabled: boolean): void {
    method deactivate (line 161) | public deactivate(): void {
    method restoreOriginalConsole (line 165) | private restoreOriginalConsole(): void {
    method addLogEntry (line 173) | public addLogEntry(level: LogLevel, ...args: any[]) {
    method appendToConsole (line 187) | private appendToConsole(level: LogLevel, ...args: any[]): void {
    method destroy (line 195) | public destroy(): void {
  type ConsolePosition (line 208) | enum ConsolePosition {
  type ConsoleSelection (line 215) | interface ConsoleSelection {
  type ConsoleAction (line 222) | type ConsoleAction =
  type ConsoleKeyBinding (line 234) | type ConsoleKeyBinding = BaseKeyBinding<ConsoleAction>
  type ConsoleOptions (line 250) | interface ConsoleOptions {
  constant DEFAULT_CONSOLE_OPTIONS (line 275) | const DEFAULT_CONSOLE_OPTIONS: Required<
  constant INDENT_WIDTH (line 305) | const INDENT_WIDTH = 2
  type DisplayLine (line 307) | interface DisplayLine {
  class TerminalConsole (line 313) | class TerminalConsole extends EventEmitter {
    method markNeedsRerender (line 356) | private markNeedsRerender(): void {
    method getCopyButtonLabel (line 361) | private getCopyButtonLabel(): string {
    method constructor (line 391) | constructor(renderer: CliRenderer, options: ConsoleOptions = {}) {
    method buildActionHandlers (line 432) | private buildActionHandlers(): Map<ConsoleAction, () => boolean> {
    method activate (line 447) | public activate(): void {
    method deactivate (line 451) | public deactivate(): void {
    method _handleNewLog (line 456) | private _handleNewLog(logEntry: [Date, LogLevel, any[], CallerInfo | n...
    method _updateConsoleDimensions (line 480) | private _updateConsoleDimensions(termWidth?: number, termHeight?: numb...
    method handleKeyPress (line 514) | private handleKeyPress(event: KeyEvent): void {
    method scrollUp (line 540) | private scrollUp(): boolean {
    method scrollDown (line 554) | private scrollDown(): boolean {
    method scrollToTop (line 572) | private scrollToTop(): boolean {
    method scrollToBottomAction (line 582) | private scrollToBottomAction(): boolean {
    method positionPrevious (line 592) | private positionPrevious(): boolean {
    method positionNext (line 600) | private positionNext(): boolean {
    method sizeIncrease (line 608) | private sizeIncrease(): boolean {
    method sizeDecrease (line 614) | private sizeDecrease(): boolean {
    method saveLogsAction (line 620) | private saveLogsAction(): boolean {
    method triggerCopyAction (line 625) | private triggerCopyAction(): boolean {
    method attachStdin (line 630) | private attachStdin(): void {
    method detachStdin (line 636) | private detachStdin(): void {
    method formatTimestamp (line 642) | private formatTimestamp(date: Date): string {
    method formatArguments (line 651) | private formatArguments(args: any[]): string {
    method resize (line 674) | public resize(width: number, height: number): void {
    method clear (line 694) | public clear(): void {
    method toggle (line 701) | public toggle(): void {
    method focus (line 716) | public focus(): void {
    method blur (line 722) | public blur(): void {
    method show (line 727) | public show(): void {
    method hide (line 750) | public hide(): void {
    method destroy (line 758) | public destroy(): void {
    method getCachedLogs (line 765) | public getCachedLogs(): string {
    method updateFrameBuffer (line 771) | private updateFrameBuffer(): void {
    method renderToBuffer (line 870) | public renderToBuffer(buffer: OptimizedBuffer): void {
    method setDebugMode (line 881) | public setDebugMode(enabled: boolean): void {
    method toggleDebugMode (line 889) | public toggleDebugMode(): void {
    method keyBindings (line 893) | public set keyBindings(bindings: ConsoleKeyBinding[]) {
    method keyAliasMap (line 900) | public set keyAliasMap(aliases: KeyAliasMap) {
    method onCopySelection (line 907) | public set onCopySelection(callback: ((text: string) => void) | undefi...
    method onCopySelection (line 911) | public get onCopySelection(): ((text: string) => void) | undefined {
    method _scrollToBottom (line 915) | private _scrollToBottom(forceCursorToLastLine: boolean = false): void {
    method _processLogEntry (line 928) | private _processLogEntry(logEntry: [Date, LogLevel, any[], CallerInfo ...
    method _processCachedLogs (line 965) | private _processCachedLogs(): void {
    method hasSelection (line 985) | private hasSelection(): boolean {
    method normalizeSelection (line 991) | private normalizeSelection(): ConsoleSelection | null {
    method getSelectedText (line 1016) | private getSelectedText(): string {
    method clearSelection (line 1043) | private clearSelection(): void {
    method stopAutoScroll (line 1050) | private stopAutoScroll(): void {
    method startAutoScroll (line 1057) | private startAutoScroll(direction: "up" | "down"): void {
    method triggerCopy (line 1096) | private triggerCopy(): void {
    method getLineSelectionRange (line 1108) | private getLineSelectionRange(lineIndex: number): { start: number; end...
    method handleMouse (line 1137) | public handleMouse(event: MouseEvent): boolean {
    method visible (line 1216) | public get visible(): boolean {
    method bounds (line 1220) | public get bounds(): { x: number; y: number; width: number; height: nu...
    method saveLogsToFile (line 1229) | private saveLogsToFile(): void {

FILE: packages/core/src/edit-buffer.ts
  class EditBuffer (line 14) | class EditBuffer extends EventEmitter {
    method constructor (line 28) | constructor(lib: RenderLib, ptr: Pointer) {
    method create (line 39) | static create(widthMethod: WidthMethod): EditBuffer {
    method subscribeToNativeEvents (line 45) | private static subscribeToNativeEvents(lib: RenderLib): void {
    method guard (line 66) | private guard(): void {
    method ptr (line 70) | public get ptr(): Pointer {
    method setText (line 79) | public setText(text: string): void {
    method setTextOwned (line 96) | public setTextOwned(text: string): void {
    method replaceText (line 106) | public replaceText(text: string): void {
    method replaceTextOwned (line 118) | public replaceTextOwned(text: string): void {
    method getLineCount (line 124) | public getLineCount(): number {
    method getText (line 129) | public getText(): string {
    method insertChar (line 141) | public insertChar(char: string): void {
    method insertText (line 146) | public insertText(text: string): void {
    method deleteChar (line 151) | public deleteChar(): void {
    method deleteCharBackward (line 156) | public deleteCharBackward(): void {
    method deleteRange (line 161) | public deleteRange(startLine: number, startCol: number, endLine: numbe...
    method newLine (line 166) | public newLine(): void {
    method deleteLine (line 171) | public deleteLine(): void {
    method moveCursorLeft (line 176) | public moveCursorLeft(): void {
    method moveCursorRight (line 181) | public moveCursorRight(): void {
    method moveCursorUp (line 186) | public moveCursorUp(): void {
    method moveCursorDown (line 191) | public moveCursorDown(): void {
    method gotoLine (line 196) | public gotoLine(line: number): void {
    method setCursor (line 201) | public setCursor(line: number, col: number): void {
    method setCursorToLineCol (line 206) | public setCursorToLineCol(line: number, col: number): void {
    method setCursorByOffset (line 211) | public setCursorByOffset(offset: number): void {
    method getCursorPosition (line 216) | public getCursorPosition(): LogicalCursor {
    method getNextWordBoundary (line 221) | public getNextWordBoundary(): LogicalCursor {
    method getPrevWordBoundary (line 231) | public getPrevWordBoundary(): LogicalCursor {
    method getEOL (line 241) | public getEOL(): LogicalCursor {
    method offsetToPosition (line 251) | public offsetToPosition(offset: number): { row: number; col: number } ...
    method positionToOffset (line 258) | public positionToOffset(row: number, col: number): number {
    method getLineStartOffset (line 263) | public getLineStartOffset(row: number): number {
    method getTextRange (line 268) | public getTextRange(startOffset: number, endOffset: number): string {
    method getTextRangeByCoords (line 284) | public getTextRangeByCoords(startRow: number, startCol: number, endRow...
    method debugLogRope (line 302) | public debugLogRope(): void {
    method undo (line 307) | public undo(): string | null {
    method redo (line 315) | public redo(): string | null {
    method canUndo (line 323) | public canUndo(): boolean {
    method canRedo (line 328) | public canRedo(): boolean {
    method clearHistory (line 333) | public clearHistory(): void {
    method setDefaultFg (line 338) | public setDefaultFg(fg: RGBA | null): void {
    method setDefaultBg (line 343) | public setDefaultBg(bg: RGBA | null): void {
    method setDefaultAttributes (line 348) | public setDefaultAttributes(attributes: number | null): void {
    method resetDefaults (line 353) | public resetDefaults(): void {
    method setSyntaxStyle (line 358) | public setSyntaxStyle(style: SyntaxStyle | null): void {
    method getSyntaxStyle (line 364) | public getSyntaxStyle(): SyntaxStyle | null {
    method addHighlight (line 369) | public addHighlight(lineIdx: number, highlight: Highlight): void {
    method addHighlightByCharRange (line 374) | public addHighlightByCharRange(highlight: Highlight): void {
    method removeHighlightsByRef (line 379) | public removeHighlightsByRef(hlRef: number): void {
    method clearLineHighlights (line 384) | public clearLineHighlights(lineIdx: number): void {
    method clearAllHighlights (line 389) | public clearAllHighlights(): void {
    method getLineHighlights (line 394) | public getLineHighlights(lineIdx: number): Array<Highlight> {
    method clear (line 399) | public clear(): void {
    method destroy (line 404) | public destroy(): void {

FILE: packages/core/src/editor-view.ts
  type Viewport (line 7) | interface Viewport {
  class EditorView (line 16) | class EditorView {
    method constructor (line 24) | constructor(lib: RenderLib, ptr: Pointer, editBuffer: EditBuffer) {
    method create (line 30) | static create(editBuffer: EditBuffer, viewportWidth: number, viewportH...
    method guard (line 36) | private guard(): void {
    method ptr (line 40) | public get ptr(): Pointer {
    method setViewportSize (line 45) | public setViewportSize(width: number, height: number): void {
    method setViewport (line 50) | public setViewport(x: number, y: number, width: number, height: number...
    method getViewport (line 55) | public getViewport(): Viewport {
    method setScrollMargin (line 60) | public setScrollMargin(margin: number): void {
    method setWrapMode (line 65) | public setWrapMode(mode: "none" | "char" | "word"): void {
    method getVirtualLineCount (line 70) | public getVirtualLineCount(): number {
    method getTotalVirtualLineCount (line 75) | public getTotalVirtualLineCount(): number {
    method setSelection (line 80) | public setSelection(start: number, end: number, bgColor?: RGBA, fgColo...
    method updateSelection (line 85) | public updateSelection(end: number, bgColor?: RGBA, fgColor?: RGBA): v...
    method resetSelection (line 90) | public resetSelection(): void {
    method getSelection (line 95) | public getSelection(): { start: number; end: number } | null {
    method hasSelection (line 100) | public hasSelection(): boolean {
    method setLocalSelection (line 105) | public setLocalSelection(
    method updateLocalSelection (line 129) | public updateLocalSelection(
    method resetLocalSelection (line 153) | public resetLocalSelection(): void {
    method getSelectedText (line 158) | public getSelectedText(): string {
    method getCursor (line 169) | public getCursor(): { row: number; col: number } {
    method getText (line 174) | public getText(): string {
    method getVisualCursor (line 182) | public getVisualCursor(): VisualCursor {
    method moveUpVisual (line 187) | public moveUpVisual(): void {
    method moveDownVisual (line 192) | public moveDownVisual(): void {
    method deleteSelectedText (line 197) | public deleteSelectedText(): void {
    method setCursorByOffset (line 202) | public setCursorByOffset(offset: number): void {
    method getNextWordBoundary (line 207) | public getNextWordBoundary(): VisualCursor {
    method getPrevWordBoundary (line 212) | public getPrevWordBoundary(): VisualCursor {
    method getEOL (line 217) | public getEOL(): VisualCursor {
    method getVisualSOL (line 222) | public getVisualSOL(): VisualCursor {
    method getVisualEOL (line 227) | public getVisualEOL(): VisualCursor {
    method getLineInfo (line 232) | public getLineInfo(): LineInfo {
    method getLogicalLineInfo (line 237) | public getLogicalLineInfo(): LineInfo {
    method extmarks (line 242) | public get extmarks(): any {
    method setPlaceholderStyledText (line 249) | public setPlaceholderStyledText(chunks: { text: string; fg?: RGBA; bg?...
    method setTabIndicator (line 254) | public setTabIndicator(indicator: string | number): void {
    method setTabIndicatorColor (line 260) | public setTabIndicatorColor(color: RGBA): void {
    method measureForDimensions (line 265) | public measureForDimensions(width: number, height: number): { lineCoun...
    method destroy (line 273) | public destroy(): void {

FILE: packages/core/src/examples/ascii-font-selection-demo.ts
  function run (line 17) | function run(renderer: CliRenderer): void {
  function destroy (line 218) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/code-demo.ts
  function run (line 257) | async function run(rendererInstance: CliRenderer): Promise<void> {
  function destroy (line 558) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/console-demo.ts
  class ConsoleButton (line 28) | class ConsoleButton extends BoxRenderable {
    method constructor (line 37) | constructor(
    method renderSelf (line 72) | protected renderSelf(buffer: OptimizedBuffer): void {
    method onMouseEvent (line 96) | protected onMouseEvent(event: MouseEvent): void {
    method triggerConsoleLog (line 123) | private triggerConsoleLog(): void {
  function run (line 182) | function run(renderer: CliRenderer): void {
  function destroy (line 317) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/core-plugin-slots-demo.ts
  type DemoSlot (line 17) | type DemoSlot = "statusbar" | "sidebar"
  type DemoContext (line 18) | type DemoContext = { appName: string; version: string }
  type DemoSlotData (line 19) | type DemoSlotData = { label?: string; section?: string }
  constant DEMO_STATUS_LABEL (line 21) | const DEMO_STATUS_LABEL = "host-status"
  constant DEMO_SIDEBAR_SECTION (line 22) | const DEMO_SIDEBAR_SECTION = "plugins"
  type PluginStats (line 24) | interface PluginStats {
  constant MAX_PLUGIN_ERROR_HISTORY (line 63) | const MAX_PLUGIN_ERROR_HISTORY = 6
  function nextStatusbarMode (line 68) | function nextStatusbarMode(mode: CoreSlotMode): CoreSlotMode {
  function formatPluginError (line 80) | function formatPluginError(event: PluginErrorEvent): string {
  function pushPluginError (line 85) | function pushPluginError(event: PluginErrorEvent): void {
  function createPluginFailurePlaceholder (line 89) | function createPluginFailurePlaceholder(
  function remountEnabledPlugins (line 124) | function remountEnabledPlugins(): void {
  function resetPluginFailureState (line 143) | function resetPluginFailureState(): void {
  function updateInfoPanel (line 154) | function updateInfoPanel(): void {
  function createClockPlugin (line 188) | function createClockPlugin(rendererInstance: CliRenderer): CorePlugin<De...
  function createActivityPlugin (line 374) | function createActivityPlugin(rendererInstance: CliRenderer): CorePlugin...
  function setClockPluginEnabled (line 490) | function setClockPluginEnabled(enabled: boolean): void {
  function setActivityPluginEnabled (line 507) | function setActivityPluginEnabled(enabled: boolean): void {
  function handleKeyPress (line 524) | function handleKeyPress(key: KeyEvent): void {
  function createLayout (line 580) | function createLayout(rendererInstance: CliRenderer): void {
  function run (line 624) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 715) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/diff-demo.ts
  type DiffTheme (line 13) | interface DiffTheme {
  type ContentExample (line 227) | interface ContentExample {
  function run (line 506) | async function run(rendererInstance: CliRenderer): Promise<void> {
  function destroy (line 674) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/draggable-three-demo.ts
  constant HEADER_HEIGHT (line 32) | const HEADER_HEIGHT = 4
  class DraggableThreeRenderable (line 34) | class DraggableThreeRenderable extends ThreeRenderable {
    method constructor (line 40) | constructor(ctx: CliRenderer, dragBoundsTop: number, options: Construc...
    method setDragBoundsTop (line 45) | public setDragBoundsTop(top: number): void {
    method onMouseEvent (line 49) | protected onMouseEvent(event: MouseEvent): void {
    method updateDragPosition (line 72) | private updateDragPosition(pointerX: number, pointerY: number): void {
  function getRenderSize (line 83) | function getRenderSize(width: number, height: number): { width: number; ...
  function run (line 90) | function run(renderer: CliRenderer): void {
  function destroy (line 227) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/editor-demo.ts
  function run (line 87) | async function run(rendererInstance: CliRenderer): Promise<void> {
  function destroy (line 305) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/extmarks-demo.ts
  function run (line 42) | async function run(rendererInstance: CliRenderer): Promise<void> {
  function findAndMarkVirtualRanges (line 162) | function findAndMarkVirtualRanges(): void {
  function destroy (line 183) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/focus-restore-demo.ts
  function ts (line 53) | function ts(): string {
  function addLogLine (line 57) | function addLogLine(renderer: CliRenderer, text: string, color: RGBA) {
  function updateDisplay (line 86) | function updateDisplay() {
  function run (line 104) | function run(renderer: CliRenderer): void {
  function destroy (line 265) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/fonts.ts
  function updateScrollPosition (line 19) | function updateScrollPosition(): void {
  function handleKeyPress (line 28) | function handleKeyPress(key: KeyEvent): void {
  function run (line 46) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 221) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/fractal-shader-demo.ts
  function run (line 39) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 231) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/framebuffer-demo.ts
  function run (line 36) | function run(renderer: CliRenderer): void {
  function destroy (line 634) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/full-unicode-demo.ts
  constant GRAPHEME_LINES (line 17) | const GRAPHEME_LINES: string[] = [
  class DraggableGraphemeBox (line 24) | class DraggableGraphemeBox extends FrameBufferRenderable {
    method constructor (line 29) | constructor(
    method onMouseEvent (line 53) | protected onMouseEvent(event: MouseEvent): void {
  class GraphemeBackground (line 78) | class GraphemeBackground extends FrameBufferRenderable {
    method constructor (line 79) | constructor(ctx: RenderContext, id: string, width: number, height: num...
  class DraggableStyledText (line 93) | class DraggableStyledText extends TextRenderable {
    method constructor (line 98) | constructor(ctx: RenderContext, id: string, x: number, y: number) {
    method onMouseEvent (line 117) | protected onMouseEvent(event: MouseEvent): void {
  function run (line 142) | function run(renderer: CliRenderer): void {
  function destroy (line 174) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/golden-star-demo.ts
  type StarParticle (line 30) | interface StarParticle {
  class StarParticleSystem (line 43) | class StarParticleSystem {
    method constructor (line 62) | constructor(scene: ThreeScene, maxParticles: number = 100) {
    method createMiniStarShape (line 150) | private createMiniStarShape(outerRadius: number, innerRadius: number, ...
    method setEmitterPosition (line 170) | setEmitterPosition(x: number, y: number, z: number) {
    method emit (line 174) | emit(count: number = 1) {
    method update (line 227) | update(deltaTime: number) {
    method setHellMode (line 272) | setHellMode(isHellMode: boolean) {
    method dispose (line 284) | dispose() {
  function run (line 296) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 918) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/grayscale-buffer-demo.ts
  constant PATTERN_NAMES (line 20) | const PATTERN_NAMES = ["Plasma", "Ripples", "Waves", "Starburst", "Dots"...
  function generatePlasma (line 22) | function generatePlasma(x: number, y: number, w: number, h: number, t: n...
  function generateRipples (line 32) | function generateRipples(x: number, y: number, w: number, h: number, t: ...
  function generateWaves (line 41) | function generateWaves(x: number, y: number, w: number, h: number, t: nu...
  function generateStarburst (line 49) | function generateStarburst(x: number, y: number, w: number, h: number, t...
  function generateDots (line 61) | function generateDots(x: number, y: number, w: number, h: number, t: num...
  function generateCheckers (line 72) | function generateCheckers(x: number, y: number, w: number, h: number, t:...
  function getIntensity (line 87) | function getIntensity(x: number, y: number, w: number, h: number, t: num...
  function run (line 106) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 222) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/hast-syntax-highlighting-demo.ts
  function run (line 13) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 110) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/index.ts
  type Example (line 76) | interface Example {
  type ExampleTheme (line 83) | interface ExampleTheme {
  constant DEFAULT_THEME_MODE (line 100) | const DEFAULT_THEME_MODE: ThemeMode = "dark"
  constant MENU_THEMES (line 102) | const MENU_THEMES: Record<ThemeMode, ExampleTheme> = {
  class ExampleSelector (line 471) | class ExampleSelector {
    method constructor (line 488) | constructor(renderer: CliRenderer) {
    method createLayout (line 506) | private createLayout(): void {
    method applyTheme (line 635) | private applyTheme(mode: ThemeMode | null): void {
    method filterExamples (line 682) | private filterExamples(): void {
    method handleResize (line 707) | private handleResize(width: number, height: number): void {
    method setupKeyboardHandling (line 717) | private setupKeyboardHandling(): void {
    method runSelected (line 798) | private runSelected(selected: Example): void {
    method hideMenuElements (line 823) | private hideMenuElements(): void {
    method showMenuElements (line 850) | private showMenuElements(): void {
    method returnToMenu (line 878) | private returnToMenu(): void {
    method restart (line 893) | private restart(): void {
    method cleanup (line 901) | private cleanup(): void {

FILE: packages/core/src/examples/input-demo.ts
  function getActiveInput (line 29) | function getActiveInput(): InputRenderable | null {
  function updateDisplays (line 33) | function updateDisplays() {
  function getInputName (line 91) | function getInputName(input: InputRenderable | null): string {
  function validateName (line 99) | function validateName(value: string): boolean {
  function validateEmail (line 103) | function validateEmail(value: string): boolean {
  function validatePassword (line 108) | function validatePassword(value: string): boolean {
  function navigateToInput (line 112) | function navigateToInput(index: number): void {
  function resetInputs (line 125) | function resetInputs(): void {
  function run (line 141) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 343) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/input-select-layout-demo.ts
  function createLayoutElements (line 43) | function createLayoutElements(rendererInstance: CliRenderer): void {
  function setupEventHandlers (line 292) | function setupEventHandlers(): void {
  function updateDisplay (line 320) | function updateDisplay(): void {
  function handleResize (line 341) | function handleResize(width: number, height: number): void {
  function updateFocus (line 345) | function updateFocus(): void {
  function handleKeyPress (line 359) | function handleKeyPress(key: KeyEvent): void {
  function run (line 371) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 377) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/keypress-debug-demo.ts
  function saveToFile (line 40) | function saveToFile(capabilities: CliRenderer["capabilities"]) {
  function formatEventAsText (line 63) | function formatEventAsText(renderer: CliRenderer, eventType: string, eve...
  function addEvent (line 172) | function addEvent(renderer: CliRenderer, eventType: string, event: objec...
  function run (line 202) | function run(renderer: CliRenderer): void {
  function destroy (line 401) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/lib/HexList.ts
  type HexListOptions (line 7) | interface HexListOptions extends Omit<RenderableOptions<HexListRenderabl...
  class HexListRenderable (line 15) | class HexListRenderable extends FrameBufferRenderable {
    method constructor (line 23) | constructor(ctx: RenderContext, options: HexListOptions) {
    method colors (line 52) | get colors(): string[] {
    method colors (line 56) | set colors(value: string[]) {
    method updateDimensions (line 63) | private updateDimensions(): void {
    method onResize (line 73) | protected onResize(width: number, height: number): void {
    method renderHexList (line 78) | private renderHexList(): void {

FILE: packages/core/src/examples/lib/PaletteGrid.ts
  type PaletteGridOptions (line 7) | interface PaletteGridOptions extends Omit<RenderableOptions<PaletteGridR...
  class PaletteGridRenderable (line 15) | class PaletteGridRenderable extends FrameBufferRenderable {
    method constructor (line 22) | constructor(ctx: RenderContext, options: PaletteGridOptions) {
    method colors (line 49) | get colors(): string[] {
    method colors (line 53) | set colors(value: string[]) {
    method updateDimensions (line 60) | private updateDimensions(): void {
    method onResize (line 70) | protected onResize(width: number, height: number): void {
    method renderPalette (line 75) | private renderPalette(): void {

FILE: packages/core/src/examples/lib/standalone-keys.ts
  function setupCommonDemoKeys (line 3) | function setupCommonDemoKeys(renderer: CliRenderer) {

FILE: packages/core/src/examples/lib/tab-controller.ts
  type TabObject (line 8) | interface TabObject {
  type Tab (line 16) | interface Tab {
  type TabControllerOptions (line 23) | interface TabControllerOptions extends RenderableOptions<TabControllerRe...
  type TabControllerEvents (line 36) | enum TabControllerEvents {
  class TabControllerRenderable (line 40) | class TabControllerRenderable extends Renderable {
    method constructor (line 47) | constructor(
    method addTab (line 84) | public addTab(tabObject: TabObject): Tab {
    method updateTabSelectOptions (line 109) | private updateTabSelectOptions(): void {
    method initializeTab (line 129) | private initializeTab(tab: Tab): void {
    method getCurrentTab (line 136) | public getCurrentTab(): Tab {
    method getCurrentTabGroup (line 140) | public getCurrentTabGroup(): Renderable {
    method switchToTab (line 144) | public switchToTab(index: number): void {
    method nextTab (line 169) | public nextTab(): void {
    method previousTab (line 173) | public previousTab(): void {
    method update (line 177) | public update(deltaMs: number): void {
    method getCurrentTabIndex (line 184) | public getCurrentTabIndex(): number {
    method getTabSelectElement (line 188) | public getTabSelectElement(): TabSelectRenderable {
    method focus (line 192) | public focus(): void {
    method blur (line 197) | public blur(): void {
    method focused (line 202) | public get focused(): boolean {
    method onResize (line 206) | public onResize(width: number, height: number): void {
    method renderSelf (line 222) | protected renderSelf(buffer: OptimizedBuffer, deltaTime: number): void {
    method destroySelf (line 227) | protected destroySelf(): void {

FILE: packages/core/src/examples/lights-phong-demo.ts
  type PhongDemoState (line 34) | interface PhongDemoState {
  function run (line 53) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 274) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/link-demo.ts
  class DraggableBox (line 22) | class DraggableBox extends BoxRenderable {
    method constructor (line 27) | constructor(
    method onMouseEvent (line 52) | protected onMouseEvent(event: MouseEvent): void {
  function getHeaderContent (line 86) | function getHeaderContent(): ReturnType<typeof t> {
  function run (line 93) | function run(renderer: CliRenderer): void {
  function createCard (line 177) | function createCard(
  function destroy (line 202) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/live-state-demo.ts
  function LiveButton (line 36) | function LiveButton(options: BoxOptions & { label: string }) {
  function updateStatusText (line 79) | function updateStatusText(message: string): void {
  function updateRendererState (line 86) | function updateRendererState(renderer: CliRenderer): void {
  function updateRenderableState (line 100) | function updateRenderableState(): void {
  function addDemoRenderable (line 112) | function addDemoRenderable(renderer: CliRenderer): void {
  function removeDemoRenderable (line 137) | function removeDemoRenderable(renderer: CliRenderer): void {
  function run (line 148) | function run(renderer: CliRenderer): void {
  function destroy (line 461) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/markdown-demo.ts
  type ThemeKey (line 312) | type ThemeKey = keyof typeof themes
  constant JSON_PARSER_WASM_URL (line 344) | const JSON_PARSER_WASM_URL =
  constant JSON_HIGHLIGHTS_QUERY_URL (line 346) | const JSON_HIGHLIGHTS_QUERY_URL =
  function registerJsonParserForDemo (line 351) | function registerJsonParserForDemo(): void {
  function getCurrentTheme (line 365) | function getCurrentTheme() {
  function getThemeTextColor (line 369) | function getThemeTextColor(theme: (typeof themes)[ThemeKey]) {
  function getThemeMutedTextColor (line 373) | function getThemeMutedTextColor(theme: (typeof themes)[ThemeKey]) {
  function getCurrentSpeed (line 377) | function getCurrentSpeed() {
  function stopStreaming (line 381) | function stopStreaming() {
  function startStreaming (line 390) | function startStreaming() {
  function run (line 457) | async function run(rendererInstance: CliRenderer): Promise<void> {
  function destroy (line 691) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/mouse-interaction-demo.ts
  type TrailCell (line 24) | interface TrailCell {
  function DraggableBox (line 37) | function DraggableBox(
  class MouseInteractionFrameBuffer (line 211) | class MouseInteractionFrameBuffer extends FrameBufferRenderable {
    method constructor (line 222) | constructor(id: string, renderer: CliRenderer) {
    method renderSelf (line 231) | protected renderSelf(buffer: OptimizedBuffer): void {
    method onMouseEvent (line 274) | protected onMouseEvent(event: MouseEvent): void {
    method clearState (line 311) | public clearState(): void {
  function run (line 317) | function run(renderer: CliRenderer): void {
  function destroy (line 417) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/nested-zindex-demo.ts
  function run (line 9) | function run(renderer: CliRenderer): void {
  function destroy (line 337) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/opacity-example.ts
  function createOpacityDemo (line 12) | function createOpacityDemo(rendererInstance: CliRenderer): void {
  function updateOpacityLabels (line 149) | function updateOpacityLabels(): void {
  function handleKeyPress (line 158) | function handleKeyPress(key: KeyEvent): void {
  function toggleAnimation (line 182) | function toggleAnimation(): void {
  function run (line 204) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 209) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/opentui-demo.ts
  function run (line 19) | function run(renderer: CliRenderer): void {
  function destroy (line 1034) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/physx-planck-2d-demo.ts
  type PhysicsBox (line 28) | interface PhysicsBox {
  type PhysicsWorld (line 36) | interface PhysicsWorld {
  type DemoState (line 42) | interface DemoState {
  function run (line 73) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 476) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/physx-rapier-2d-demo.ts
  constant SUBDIVISION (line 29) | const SUBDIVISION = 4
  constant DENSITY (line 30) | const DENSITY = 2.2
  constant EXPLOSION_FORCE (line 31) | const EXPLOSION_FORCE = 2.0
  constant EXPLOSION_FORCE_VARIATION (line 32) | const EXPLOSION_FORCE_VARIATION = 0.2
  constant TORQUE_STRENGTH (line 33) | const TORQUE_STRENGTH = 2.0
  type PhysicsBox (line 35) | interface PhysicsBox {
  type PhysicsWorld (line 43) | interface PhysicsWorld {
  type DemoState (line 49) | interface DemoState {
  function run (line 87) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 495) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/relative-positioning-demo.ts
  function run (line 9) | function run(renderer: CliRenderer): void {
  function destroy (line 303) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/scroll-example.ts
  function addBox (line 23) | function addBox(i: number) {
  function addAsciiRenderable (line 43) | function addAsciiRenderable(i: number) {
  function makeMultilineContent (line 80) | function makeMultilineContent(i: number) {
  function run (line 99) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 196) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/scrollbox-mouse-test.ts
  function run (line 10) | function run(renderer: CliRenderer): void {
  function destroy (line 95) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/scrollbox-overlay-hit-test.ts
  function run (line 46) | function run(renderer: CliRenderer): void {
  function destroy (line 179) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/select-demo.ts
  function updateDisplays (line 47) | function updateDisplays() {
  function run (line 88) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 210) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/shader-cube-demo.ts
  type ShaderCubeDemoState (line 39) | interface ShaderCubeDemoState {
  function run (line 90) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 988) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/simple-layout-example.ts
  type LayoutDemo (line 4) | interface LayoutDemo {
  function resetElementLayout (line 56) | function resetElementLayout(element: BoxRenderable): void {
  function setupHorizontalLayout (line 69) | function setupHorizontalLayout(): void {
  function setupVerticalLayout (line 102) | function setupVerticalLayout(): void {
  function setupCenteredLayout (line 136) | function setupCenteredLayout(): void {
  function setupThreeColumnLayout (line 161) | function setupThreeColumnLayout(): void {
  function createLayoutElements (line 206) | function createLayoutElements(rendererInstance: CliRenderer): void {
  function handleResize (line 414) | function handleResize(width: number, height: number): void {
  function handleKeyPress (line 419) | function handleKeyPress(key: KeyEvent): void {
  function nextDemo (line 449) | function nextDemo(): void {
  function toggleAutoplay (line 454) | function toggleAutoplay(): void {
  function toggleMoveableElement (line 474) | function toggleMoveableElement(): void {
  function moveMoveableElement (line 482) | function moveMoveableElement(deltaX: number, deltaY: number): void {
  function centerMoveableElement (line 497) | function centerMoveableElement(): void {
  function updateFooterText (line 509) | function updateFooterText(): void {
  function applyCurrentDemo (line 517) | function applyCurrentDemo(): void {
  function run (line 536) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 543) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/slider-demo.ts
  function updateDisplays (line 31) | function updateDisplays() {
  function resetSliders (line 56) | function resetSliders() {
  function focusSlider (line 75) | function focusSlider(index: number) {
  function run (line 127) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 572) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/split-mode-demo.ts
  class SplitModeAnimations (line 12) | class SplitModeAnimations {
    method constructor (line 31) | constructor(renderer: CliRenderer) {
    method setupUI (line 49) | private setupUI(): void {
    method setupAnimations (line 181) | private setupAnimations(): void {
    method update (line 297) | public update(deltaTime: number): void {
    method destroy (line 301) | public destroy(): void {
  function run (line 307) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 403) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/sprite-animation-demo.ts
  type SpriteAnimationDemoState (line 33) | interface SpriteAnimationDemoState {
  function run (line 54) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 417) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/sprite-particle-generator-demo.ts
  function run (line 51) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 419) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/static-sprite-demo.ts
  function run (line 31) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 146) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/sticky-scroll-example.ts
  type AnimatedItem (line 13) | interface AnimatedItem {
  function clearAllItems (line 25) | function clearAllItems() {
  function interpolateColor (line 49) | function interpolateColor(color1: string, color2: string, factor: number...
  function updateAnimations (line 69) | function updateAnimations() {
  function addItem (line 125) | function addItem(atTop: boolean = false) {
  function run (line 183) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 284) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/styled-text-demo.ts
  function run (line 29) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 251) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/tab-select-demo.ts
  function updateDisplays (line 39) | function updateDisplays() {
  function run (line 84) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 189) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/terminal-title.ts
  function testTerminalTitle (line 3) | async function testTerminalTitle() {

FILE: packages/core/src/examples/terminal.ts
  function run (line 35) | function run(renderer: CliRenderer): void {
  function fetchAndDisplayPalette (line 155) | async function fetchAndDisplayPalette(renderer: CliRenderer, size: numbe...
  function clearPaletteCache (line 179) | function clearPaletteCache(renderer: CliRenderer): void {
  function drawPalette (line 187) | function drawPalette(renderer: CliRenderer, terminalColors: TerminalColo...
  function destroy (line 275) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/text-node-demo.ts
  function clearUpdateInterval (line 24) | function clearUpdateInterval(): void {
  function run (line 31) | function run(renderer: CliRenderer): void {
  function showExample1 (line 103) | function showExample1(): void {
  function showExample2 (line 158) | function showExample2(): void {
  function showExample3 (line 220) | function showExample3(): void {
  function showExample4 (line 290) | function showExample4(): void {
  function toggleDynamicUpdates (line 362) | function toggleDynamicUpdates(): void {
  function resetDemo (line 373) | function resetDemo(): void {
  function updateInstructions (line 379) | function updateInstructions(title: string, description: string): void {
  function updateStatus (line 392) | function updateStatus(message: string): void {
  function destroy (line 397) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/text-selection-demo.ts
  function run (line 30) | function run(renderer: CliRenderer): void {
  function destroy (line 348) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/text-table-demo.ts
  constant PALETTE (line 40) | const PALETTE = {
  constant WRAP_MODES (line 55) | const WRAP_MODES: Array<"none" | "word" | "char"> = ["none", "word", "ch...
  constant BORDER_STYLES (line 56) | const BORDER_STYLES: BorderStyle[] = ["single", "rounded", "double", "he...
  constant COLUMN_WIDTH_MODES (line 57) | const COLUMN_WIDTH_MODES: TextTableColumnWidthMode[] = ["content", "full"]
  constant COLUMN_FITTERS (line 58) | const COLUMN_FITTERS: TextTableColumnFitter[] = ["proportional", "balanc...
  constant CELL_PADDING_VALUES (line 59) | const CELL_PADDING_VALUES: number[] = [0, 1, 2]
  function cell (line 61) | function cell(text: string): TextChunk[] {
  function currentWrapMode (line 173) | function currentWrapMode(): "none" | "word" | "char" {
  function currentBorderStyle (line 177) | function currentBorderStyle(): BorderStyle {
  function currentColumnWidthMode (line 181) | function currentColumnWidthMode(): TextTableColumnWidthMode {
  function currentColumnFitter (line 185) | function currentColumnFitter(): TextTableColumnFitter {
  function currentCellPadding (line 189) | function currentCellPadding(): number {
  function updateControlsText (line 193) | function updateControlsText(): void {
  function clearSelectionStatus (line 200) | function clearSelectionStatus(message: string): void {
  function applyTableState (line 209) | function applyTableState(): void {
  function run (line 242) | function run(renderer: CliRenderer): void {
  function destroy (line 462) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/text-truncation-demo.ts
  function createLayout (line 44) | function createLayout(rendererInstance: CliRenderer): void {
  function updateFooterText (line 358) | function updateFooterText(): void {
  function toggleTruncation (line 367) | function toggleTruncation(): void {
  function cycleWrapMode (line 377) | function cycleWrapMode(): void {
  function toggleColumnSizes (line 393) | function toggleColumnSizes(): void {
  function handleKeyPress (line 415) | function handleKeyPress(event: any): void {
  function run (line 440) | function run(rendererInstance: CliRenderer): void {
  function destroy (line 445) | function destroy(rendererInstance: CliRenderer): void {

FILE: packages/core/src/examples/text-wrap.ts
  function getResizeDirection (line 44) | function getResizeDirection(
  function showFileInput (line 82) | function showFileInput(): void {
  function hideFileInput (line 91) | function hideFileInput(): void {
  function handleTextBoxMouse (line 100) | function handleTextBoxMouse(event: MouseEvent): void {
  function handleGlobalMouse (line 172) | function handleGlobalMouse(event: MouseEvent): void {
  function createDemoText (line 261) | function createDemoText(): TextNodeRenderable {
  function run (line 457) | function run(renderer: CliRenderer): void {
  function destroy (line 734) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/texture-loading-demo.ts
  function run (line 30) | async function run(renderer: CliRenderer): Promise<void> {
  function destroy (line 226) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/timeline-example.ts
  class TimelineExample (line 5) | class TimelineExample {
    method constructor (line 24) | constructor(renderer: CliRenderer) {
    method update (line 281) | public update(deltaTime: number): void {
    method updateVisuals (line 287) | private updateVisuals(): void {
    method setupAnimations (line 352) | private setupAnimations(): void {
    method start (line 608) | public start(): void {
    method pause (line 613) | public pause(): void {
    method stop (line 617) | public stop(): void {
    method destroy (line 621) | public destroy(): void {
  function run (line 628) | function run(renderer: CliRenderer): void {
  function destroy (line 652) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/transparency-demo.ts
  constant DEFAULT_THEME_MODE (line 24) | const DEFAULT_THEME_MODE: ThemeMode = "dark"
  constant THEMES (line 26) | const THEMES = {
  type ThemeName (line 56) | type ThemeName = keyof typeof THEMES
  constant THEME_ORDER (line 57) | const THEME_ORDER: ThemeName[] = ["dark", "light", "transparent"]
  function getTransparentFallbackBackgroundColor (line 59) | function getTransparentFallbackBackgroundColor(themeMode: ThemeMode): RG...
  function getThemeBackgroundColor (line 63) | function getThemeBackgroundColor(themeName: ThemeName, themeMode: ThemeM...
  function getHeaderText (line 71) | function getHeaderText(themeName: ThemeName) {
  class DraggableTransparentBox (line 78) | class DraggableTransparentBox extends BoxRenderable {
    method constructor (line 85) | constructor(
    method setLabelColor (line 109) | public setLabelColor(color: RGBA): void {
    method renderSelf (line 113) | protected renderSelf(buffer: OptimizedBuffer): void {
    method onMouseEvent (line 123) | protected onMouseEvent(event: MouseEvent): void {
  function run (line 155) | function run(renderer: CliRenderer): void {
  function destroy (line 369) | function destroy(renderer: CliRenderer): void {

FILE: packages/core/src/examples/vnode-composition-demo.ts
  function MyRenderable (line 29) | function MyRenderable(props: any, children: VNode[] = []) {
  function Button (line 48) | function Button(
  function VNodeButton (line 69) | function VNodeButton(
  class MyRoot (line 95) | class MyRoot {
    method constructor (line 98) | constructor(private readonly props: { title: string; borderColor?: RGB...
    method render (line 103) | render(buffer: OptimizedBuffer, deltaTime: number, renderable: Rendera...
  function ButtonWithClassRender (line 108) | function ButtonWithClassRender(
  function MyDelegateToVNodeRenderable (line 126) | function MyDelegateToVNodeRenderable(props: any, children: VNode[] = []) {
  function MyDelegateToRenderableComponent (line 140) | function MyDelegateToRenderableComponent(renderer: RenderContext, props:...
  function MyInstancedRenderable (line 157) | function MyInstancedRenderable(renderer: RenderContext, props: any, chil...
  function LabeledInput (line 161) | function LabeledInput(props: { id: string; label: string; placeholder: s...
  function BaseBox (line 182) | function BaseBox(props: BoxOptions, children: VNode[] = []) {
  function ExtendedBaseBox (line 199) | function ExtendedBaseBox(props: BoxOptions, children: VNode[] = []) {
  function run (line 212) | function run(renderer: CliRenderer) {
  function destroy (line 327) | function destroy(renderer: CliRenderer) {
  function demoRenderFn (line 342) | function demoRenderFn(

FILE: packages/core/src/lib/KeyHandler.integration.test.ts
  function createKeyHandler (line 9) | function createKeyHandler(): InternalKeyHandler {
  function dispatchInput (line 13) | function dispatchInput(handler: InternalKeyHandler, data: string): boole...

FILE: packages/core/src/lib/KeyHandler.stopPropagation.test.ts
  function createKeyHandler (line 6) | function createKeyHandler(): InternalKeyHandler {
  function dispatchInput (line 10) | function dispatchInput(handler: InternalKeyHandler, data: string): boole...

FILE: packages/core/src/lib/KeyHandler.test.ts
  function createKeyHandler (line 10) | function createKeyHandler(): InternalKeyHandler {
  function dispatchInput (line 14) | function dispatchInput(handler: InternalKeyHandler, data: string, option...

FILE: packages/core/src/lib/KeyHandler.ts
  class KeyEvent (line 5) | class KeyEvent implements ParsedKey {
    method constructor (line 27) | constructor(key: ParsedKey) {
    method defaultPrevented (line 47) | get defaultPrevented(): boolean {
    method propagationStopped (line 51) | get propagationStopped(): boolean {
    method preventDefault (line 55) | preventDefault(): void {
    method stopPropagation (line 59) | stopPropagation(): void {
  class PasteEvent (line 64) | class PasteEvent {
    method constructor (line 71) | constructor(bytes: Uint8Array, metadata?: PasteMetadata) {
    method defaultPrevented (line 76) | get defaultPrevented(): boolean {
    method propagationStopped (line 80) | get propagationStopped(): boolean {
    method preventDefault (line 84) | preventDefault(): void {
    method stopPropagation (line 88) | stopPropagation(): void {
  type KeyHandlerEventMap (line 93) | type KeyHandlerEventMap = {
  class KeyHandler (line 99) | class KeyHandler extends EventEmitter<KeyHandlerEventMap> {
    method processParsedKey (line 100) | public processParsedKey(parsedKey: ParsedKey): boolean {
    method processPaste (line 121) | public processPaste(bytes: Uint8Array, metadata?: PasteMetadata): void {
  class InternalKeyHandler (line 134) | class InternalKeyHandler extends KeyHandler {
    method emit (line 137) | public emit<K extends keyof KeyHandlerEventMap>(event: K, ...args: Key...
    method emitWithPriority (line 141) | private emitWithPriority<K extends keyof KeyHandlerEventMap>(event: K,...
    method onInternal (line 203) | public onInternal<K extends keyof KeyHandlerEventMap>(
    method offInternal (line 213) | public offInternal<K extends keyof KeyHandlerEventMap>(

FILE: packages/core/src/lib/RGBA.ts
  class RGBA (line 1) | class RGBA {
    method constructor (line 4) | constructor(buffer: Float32Array) {
    method fromArray (line 8) | static fromArray(array: Float32Array) {
    method fromValues (line 12) | static fromValues(r: number, g: number, b: number, a: number = 1.0) {
    method fromInts (line 16) | static fromInts(r: number, g: number, b: number, a: number = 255) {
    method fromHex (line 20) | static fromHex(hex: string): RGBA {
    method toInts (line 24) | toInts(): [number, number, number, number] {
    method r (line 28) | get r(): number {
    method r (line 32) | set r(value: number) {
    method g (line 36) | get g(): number {
    method g (line 40) | set g(value: number) {
    method b (line 44) | get b(): number {
    method b (line 48) | set b(value: number) {
    method a (line 52) | get a(): number {
    method a (line 56) | set a(value: number) {
    method map (line 60) | map<R>(fn: (value: number) => R) {
    method toString (line 64) | toString() {
    method equals (line 68) | equals(other?: RGBA): boolean {
  type ColorInput (line 74) | type ColorInput = string | RGBA
  function hexToRgb (line 76) | function hexToRgb(hex: string): RGBA {
  function rgbToHex (line 98) | function rgbToHex(rgb: RGBA): string {
  function hsvToRgb (line 111) | function hsvToRgb(h: number, s: number, v: number): RGBA {
  constant CSS_COLOR_NAMES (line 158) | const CSS_COLOR_NAMES: Record<string, string> = {
  function parseColor (line 189) | function parseColor(color: ColorInput): RGBA {

FILE: packages/core/src/lib/ascii.font.ts
  type ASCIIFontName (line 16) | type ASCIIFontName = "tiny" | "block" | "shade" | "slick" | "huge" | "gr...
  type FontSegment (line 28) | type FontSegment = {
  type FontDefinition (line 33) | type FontDefinition = {
  type ParsedFontDefinition (line 42) | type ParsedFontDefinition = {
  function parseColorTags (line 53) | function parseColorTags(text: string): FontSegment[] {
  function getParsedFont (line 86) | function getParsedFont(fontKey: keyof typeof fonts): ParsedFontDefinition {
  function measureText (line 105) | function measureText({ text, font = "tiny" }: { text: string; font?: key...
  function getCharacterPositions (line 155) | function getCharacterPositions(text: string, font: keyof typeof fonts = ...
  function coordinateToCharacterIndex (line 196) | function coordinateToCharacterIndex(x: number, text: string, font: keyof...
  function renderFontToFrameBuffer (line 220) | function renderFontToFrameBuffer(

FILE: packages/core/src/lib/border.ts
  type BorderCharacters (line 3) | interface BorderCharacters {
  type BorderStyle (line 17) | type BorderStyle = "single" | "double" | "rounded" | "heavy"
  type BorderSides (line 18) | type BorderSides = "top" | "right" | "bottom" | "left"
  constant VALID_BORDER_STYLES (line 20) | const VALID_BORDER_STYLES: readonly BorderStyle[] = ["single", "double",...
  function isValidBorderStyle (line 22) | function isValidBorderStyle(value: unknown): value is BorderStyle {
  function parseBorderStyle (line 26) | function parseBorderStyle(value: unknown, fallback: BorderStyle = "singl...
  type BorderConfig (line 94) | interface BorderConfig {
  type BoxDrawOptions (line 101) | interface BoxDrawOptions {
  type BorderSidesConfig (line 116) | interface BorderSidesConfig {
  function getBorderFromSides (line 123) | function getBorderFromSides(sides: BorderSidesConfig): boolean | BorderS...
  function getBorderSides (line 132) | function getBorderSides(border: boolean | BorderSides[]): BorderSidesCon...
  function borderCharsToArray (line 146) | function borderCharsToArray(chars: BorderCharacters): Uint32Array {

FILE: packages/core/src/lib/bunfs.ts
  function isBunfsPath (line 3) | function isBunfsPath(path: string): boolean {
  function getBunfsRootPath (line 8) | function getBunfsRootPath(): string {
  function normalizeBunfsPath (line 16) | function normalizeBunfsPath(fileName: string): string {

FILE: packages/core/src/lib/clipboard.ts
  type ClipboardTarget (line 7) | enum ClipboardTarget {
  function encodeOsc52Payload (line 14) | function encodeOsc52Payload(text: string, encoder: TextEncoder = new Tex...
  class Clipboard (line 19) | class Clipboard {
    method constructor (line 23) | constructor(lib: RenderLib, rendererPtr: Pointer) {
    method copyToClipboardOSC52 (line 28) | public copyToClipboardOSC52(text: string, target: ClipboardTarget = Cl...
    method clearClipboardOSC52 (line 36) | public clearClipboardOSC52(target: ClipboardTarget = ClipboardTarget.C...
    method isOsc52Supported (line 43) | public isOsc52Supported(): boolean {

FILE: packages/core/src/lib/clock.ts
  type TimerHandle (line 1) | type TimerHandle = ReturnType<typeof globalThis.setTimeout> | number
  type Clock (line 3) | interface Clock {
  class SystemClock (line 11) | class SystemClock implements Clock {
    method now (line 12) | public now(): number {
    method setTimeout (line 20) | public setTimeout(fn: () => void, delayMs: number): TimerHandle {
    method clearTimeout (line 24) | public clearTimeout(handle: TimerHandle): void {
    method setInterval (line 28) | public setInterval(fn: () => void, delayMs: number): TimerHandle {
    method clearInterval (line 32) | public clearInterval(handle: TimerHandle): void {

FILE: packages/core/src/lib/data-paths.ts
  type DataPaths (line 23) | interface DataPaths {
  type DataPathsEvents (line 30) | interface DataPathsEvents {
  class DataPathsManager (line 34) | class DataPathsManager extends EventEmitter<DataPathsEvents> {
    method constructor (line 40) | constructor() {
    method appName (line 45) | get appName(): string {
    method appName (line 49) | set appName(value: string) {
    method globalConfigPath (line 63) | get globalConfigPath(): string {
    method globalConfigFile (line 73) | get globalConfigFile(): string {
    method localConfigFile (line 80) | get localConfigFile(): string {
    method globalDataPath (line 87) | get globalDataPath(): string {
    method toObject (line 97) | toObject(): DataPaths {
  function getDataPaths (line 107) | function getDataPaths(): DataPathsManager {

FILE: packages/core/src/lib/debounce.ts
  constant TIMERS_MAP (line 5) | const TIMERS_MAP = new Map<string | number, Map<string | number, ReturnT...
  class DebounceController (line 10) | class DebounceController {
    method constructor (line 11) | constructor(private scopeId: string | number) {
    method debounce (line 25) | debounce<R>(id: string | number, ms: number, fn: () => Promise<R>): Pr...
    method clearDebounce (line 54) | clearDebounce(id: string | number): void {
    method clear (line 65) | clear(): void {
  function createDebounce (line 80) | function createDebounce(scopeId: string | number): DebounceController {
  function clearDebounceScope (line 89) | function clearDebounceScope(scopeId: string | number): void {
  function clearAllDebounces (line 100) | function clearAllDebounces(): void {

FILE: packages/core/src/lib/detect-links.test.ts
  function chunk (line 7) | function chunk(text: string): TextChunk {

FILE: packages/core/src/lib/detect-links.ts
  constant URL_SCOPES (line 4) | const URL_SCOPES = ["markup.link.url", "string.special.url"]
  function detectLinks (line 6) | function detectLinks(

FILE: packages/core/src/lib/env.ts
  type EnvVarConfig (line 34) | interface EnvVarConfig {
  function registerEnvVar (line 43) | function registerEnvVar(config: EnvVarConfig): void {
  function normalizeBoolean (line 61) | function normalizeBoolean(value: string): boolean {
  function parseEnvValue (line 66) | function parseEnvValue(config: EnvVarConfig): string | boolean | number {
  class EnvStore (line 92) | class EnvStore {
    method get (line 95) | get(key: string): any {
    method has (line 113) | has(key: string): boolean {
    method clearCache (line 117) | clearCache(): void {
  function clearEnvCache (line 124) | function clearEnvCache(): void {
  function generateEnvMarkdown (line 128) | function generateEnvMarkdown(): string {
  function generateEnvColored (line 156) | function generateEnvColored(): string {
  method get (line 184) | get(target, prop: string) {
  method has (line 191) | has(target, prop: string) {
  method ownKeys (line 195) | ownKeys() {
  method getOwnPropertyDescriptor (line 199) | getOwnPropertyDescriptor(target, prop: string) {

FILE: packages/core/src/lib/extmarks-history.ts
  type ExtmarksSnapshot (line 3) | interface ExtmarksSnapshot {
  class ExtmarksHistory (line 8) | class ExtmarksHistory {
    method saveSnapshot (line 12) | saveSnapshot(extmarks: Map<number, Extmark>, nextId: number): void {
    method undo (line 21) | undo(): ExtmarksSnapshot | null {
    method redo (line 26) | redo(): ExtmarksSnapshot | null {
    method pushRedo (line 31) | pushRedo(snapshot: ExtmarksSnapshot): void {
    method pushUndo (line 35) | pushUndo(snapshot: ExtmarksSnapshot): void {
    method clear (line 39) | clear(): void {
    method canUndo (line 44) | canUndo(): boolean {
    method canRedo (line 48) | canRedo(): boolean {

FILE: packages/core/src/lib/extmarks-multiwidth.test.ts
  function setup (line 14) | async function setup(initialValue: string = "Hello World") {

FILE: packages/core/src/lib/extmarks.test.ts
  function setup (line 14) | async function setup(initialValue: string = "Hello World") {

FILE: packages/core/src/lib/extmarks.ts
  type Extmark (line 5) | interface Extmark {
  type ExtmarkOptions (line 16) | interface ExtmarkOptions {
  class ExtmarksController (line 32) | class ExtmarksController {
    method constructor (line 64) | constructor(editBuffer: EditBuffer, editorView: EditorView) {
    method wrapCursorMovement (line 95) | private wrapCursorMovement(): void {
    method wrapDeletion (line 253) | private wrapDeletion(): void {
    method wrapInsertion (line 393) | private wrapInsertion(): void {
    method wrapEditorViewDeleteSelectedText (line 467) | private wrapEditorViewDeleteSelectedText(): void {
    method setupContentChangeListener (line 493) | private setupContentChangeListener(): void {
    method deleteExtmarkById (line 500) | private deleteExtmarkById(id: number): void {
    method findVirtualExtmarkContaining (line 509) | private findVirtualExtmarkContaining(offset: number): Extmark | null {
    method adjustExtmarksAfterInsertion (line 518) | private adjustExtmarksAfterInsertion(insertOffset: number, length: num...
    method adjustExtmarksAfterDeletion (line 530) | public adjustExtmarksAfterDeletion(deleteOffset: number, length: numbe...
    method offsetToPosition (line 561) | private offsetToPosition(offset: number): { row: number; col: number } {
    method positionToOffset (line 569) | private positionToOffset(row: number, col: number): number {
    method updateHighlights (line 573) | private updateHighlights(): void {
    method offsetExcludingNewlines (line 595) | private offsetExcludingNewlines(offset: number): number {
    method create (line 638) | public create(options: ExtmarkOptions): number {
    method delete (line 672) | public delete(id: number): boolean {
    method get (line 686) | public get(id: number): Extmark | null {
    method getAll (line 691) | public getAll(): Extmark[] {
    method getVirtual (line 696) | public getVirtual(): Extmark[] {
    method getAtOffset (line 701) | public getAtOffset(offset: number): Extmark[] {
    method getAllForTypeId (line 706) | public getAllForTypeId(typeId: number): Extmark[] {
    method clear (line 715) | public clear(): void {
    method saveSnapshot (line 724) | private saveSnapshot(): void {
    method restoreSnapshot (line 728) | private restoreSnapshot(snapshot: ExtmarksSnapshot): void {
    method wrapUndoRedo (line 734) | private wrapUndoRedo(): void {
    method registerType (line 778) | public registerType(typeName: string): number {
    method getTypeId (line 794) | public getTypeId(typeName: string): number | null {
    method getTypeName (line 799) | public getTypeName(typeId: number): string | null {
    method getMetadataFor (line 804) | public getMetadataFor(extmarkId: number): any {
    method destroy (line 809) | public destroy(): void {
  function createExtmarksController (line 841) | function createExtmarksController(editBuffer: EditBuffer, editorView: Ed...

FILE: packages/core/src/lib/hast-styled-text.ts
  type HASTText (line 5) | interface HASTText {
  type HASTElement (line 10) | interface HASTElement {
  type HASTNode (line 19) | type HASTNode = HASTText | HASTElement
  function hastToTextChunks (line 23) | function hastToTextChunks(node: HASTNode, syntaxStyle: SyntaxStyle, pare...
  function hastToStyledText (line 56) | function hastToStyledText(hast: HASTNode, syntaxStyle: SyntaxStyle): Sty...

FILE: packages/core/src/lib/keymapping.ts
  type KeyBinding (line 1) | interface KeyBinding<Action extends string = string> {
  type KeyAliasMap (line 10) | type KeyAliasMap = Record<string, string>
  function mergeKeyAliases (line 17) | function mergeKeyAliases(defaults: KeyAliasMap, custom: KeyAliasMap): Ke...
  function mergeKeyBindings (line 21) | function mergeKeyBindings<Action extends string>(
  function getKeyBindingKey (line 37) | function getKeyBindingKey<Action extends string>(binding: KeyBinding<Act...
  function buildKeyBindingsMap (line 41) | function buildKeyBindingsMap<Action extends string>(
  function keyBindingToString (line 76) | function keyBindingToString<Action extends string>(binding: KeyBinding<A...

FILE: packages/core/src/lib/objects-in-viewport.test.ts
  type TestObject (line 5) | interface TestObject {
  function createObject (line 14) | function createObject(id: string, x: number, y: number, width: number, h...

FILE: packages/core/src/lib/objects-in-viewport.ts
  type ViewportObject (line 3) | interface ViewportObject {
  function getObjectsInViewport (line 25) | function getObjectsInViewport<T extends ViewportObject>(

FILE: packages/core/src/lib/output.capture.ts
  type CapturedOutput (line 4) | type CapturedOutput = {
  class Capture (line 9) | class Capture extends EventEmitter {
    method constructor (line 13) | constructor() {
    method size (line 17) | get size(): number {
    method write (line 21) | write(stream: "stdout" | "stderr", data: string): void {
    method claimOutput (line 26) | claimOutput() {
    method clear (line 32) | private clear(): void {
  class CapturedWritableStream (line 37) | class CapturedWritableStream extends Writable {
    method constructor (line 42) | constructor(
    method _write (line 49) | _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error ...
    method getColorDepth (line 55) | getColorDepth(): number {

FILE: packages/core/src/lib/parse.keypress-kitty.protocol.test.ts
  type ExpectedKey (line 11) | type ExpectedKey = Partial<ParsedKey> & Pick<ParsedKey, "name">
  type KeyCase (line 13) | interface KeyCase {
  function parse (line 19) | function parse(sequence: string): ParsedKey {
  function expectKey (line 25) | function expectKey(sequence: string, expected: ExpectedKey): void {
  function defineKeyCases (line 29) | function defineKeyCases(cases: readonly KeyCase[]): void {
  function rangeCases (line 37) | function rangeCases(start: number, names: readonly string[]): Array<[num...
  function functionalCase (line 41) | function functionalCase(code: number, name: string): KeyCase {
  function legacyAliasCase (line 54) | function legacyAliasCase(sequence: string, name: string): KeyCase {
  function enhancedAliasCase (line 65) | function enhancedAliasCase(sequence: string, name: string): KeyCase {
  function canonicalAliasCase (line 77) | function canonicalAliasCase(sequence: string, expected: ExpectedKey): Ke...
  function modifierCase (line 88) | function modifierCase(modifier: number, expected: ExpectedKey): KeyCase {

FILE: packages/core/src/lib/parse.keypress-kitty.ts
  function fromKittyMods (line 139) | function fromKittyMods(mod: number): {
  function parseKittySpecialKey (line 207) | function parseKittySpecialKey(sequence: string): ParsedKey | null {
  function parseKittyKeyboard (line 278) | function parseKittyKeyboard(sequence: string): ParsedKey | null {

FILE: packages/core/src/lib/parse.keypress.ts
  type KeyEventType (line 114) | type KeyEventType = "press" | "repeat" | "release"
  type ParsedKey (line 116) | interface ParsedKey {
  type ParseKeypressOptions (line 136) | type ParseKeypressOptions = {

FILE: packages/core/src/lib/parse.mouse.test.ts
  function encodeBasic (line 8) | function encodeBasic(buttonByte: number, x: number, y: number): Buffer {
  function encodeSGR (line 16) | function encodeSGR(buttonCode: number, x: number, y: number, press: bool...

FILE: packages/core/src/lib/parse.mouse.ts
  type MouseEventType (line 1) | type MouseEventType = "down" | "up" | "move" | "drag" | "drag-end" | "dr...
  type ScrollInfo (line 3) | interface ScrollInfo {
  type RawMouseEvent (line 8) | type RawMouseEvent = {
  type ParsedMouseSequence (line 17) | type ParsedMouseSequence = {
  class MouseParser (line 22) | class MouseParser {
    method reset (line 32) | public reset(): void {
    method decodeInput (line 38) | private decodeInput(data: Buffer | Uint8Array): string {
    method parseMouseEvent (line 43) | public parseMouseEvent(data: Buffer | Uint8Array): RawMouseEvent | null {
    method parseAllMouseEvents (line 49) | public parseAllMouseEvents(data: Buffer | Uint8Array): RawMouseEvent[] {
    method parseMouseSequenceAt (line 69) | private parseMouseSequenceAt(str: string, offset: number): ParsedMouse...
    method parseSgrSequence (line 84) | private parseSgrSequence(str: string, offset: number): ParsedMouseSequ...
    method parseBasicSequence (line 126) | private parseBasicSequence(str: string, offset: number): ParsedMouseSe...
    method decodeSgrEvent (line 141) | private decodeSgrEvent(rawButtonCode: number, wireX: number, wireY: nu...
    method decodeBasicEvent (line 192) | private decodeBasicEvent(buttonByte: number, x: number, y: number): Ra...

FILE: packages/core/src/lib/paste.ts
  type PasteKind (line 1) | type PasteKind = "text" | "binary" | "unknown"
  type PasteMetadata (line 3) | interface PasteMetadata {
  constant PASTE_TEXT_DECODER (line 8) | const PASTE_TEXT_DECODER = new TextDecoder()
  function decodePasteBytes (line 10) | function decodePasteBytes(bytes: Uint8Array): string {
  function stripAnsiSequences (line 14) | function stripAnsiSequences(text: string): string {

FILE: packages/core/src/lib/queue.ts
  class ProcessQueue (line 4) | class ProcessQueue<T> {
    method constructor (line 9) | constructor(
    method enqueue (line 16) | enqueue(item: T): void {
    method processQueue (line 24) | private processQueue(): void {
    method clear (line 54) | clear(): void {
    method isProcessing (line 58) | isProcessing(): boolean {
    method size (line 62) | size(): number {

FILE: packages/core/src/lib/renderable.validations.ts
  function validateOptions (line 4) | function validateOptions(id: string, options: RenderableOptions<Renderab...
  function isValidPercentage (line 17) | function isValidPercentage(value: any): value is `${number}%` {
  function isMarginType (line 26) | function isMarginType(value: any): value is number | "auto" | `${number}...
  function isPaddingType (line 36) | function isPaddingType(value: any): value is number | `${number}%` {
  function isPositionType (line 43) | function isPositionType(value: any): value is number | "auto" | `${numbe...
  function isPositionTypeType (line 53) | function isPositionTypeType(value: any): value is PositionTypeString {
  function isOverflowType (line 57) | function isOverflowType(value: any): value is OverflowString {
  function isDimensionType (line 61) | function isDimensionType(value: any): value is number | "auto" | `${numb...
  function isFlexBasisType (line 65) | function isFlexBasisType(value: any): value is number | "auto" | undefin...
  function isSizeType (line 75) | function isSizeType(value: any): value is number | `${number}%` | undefi...

FILE: packages/core/src/lib/scroll-acceleration.ts
  type ScrollAcceleration (line 1) | interface ScrollAcceleration {
  class LinearScrollAccel (line 6) | class LinearScrollAccel implements ScrollAcceleration {
    method tick (line 7) | tick(_now?: number): number {
    method reset (line 11) | reset(): void {}
  class MacOSScrollAccel (line 34) | class MacOSScrollAccel implements ScrollAcceleration {
    method constructor (line 44) | constructor(
    method tick (line 52) | tick(now = Date.now()): number {
    method reset (line 94) | reset(): void {

FILE: packages/core/src/lib/selection.ts
  class SelectionAnchor (line 4) | class SelectionAnchor {
    method constructor (line 8) | constructor(
    method x (line 17) | get x(): number {
    method y (line 21) | get y(): number {
  class Selection (line 26) | class Selection {
    method constructor (line 35) | constructor(anchorRenderable: Renderable, anchor: { x: number; y: numb...
    method isStart (line 40) | get isStart(): boolean {
    method isStart (line 44) | set isStart(value: boolean) {
    method anchor (line 48) | get anchor(): { x: number; y: number } {
    method focus (line 52) | get focus(): { x: number; y: number } {
    method focus (line 56) | set focus(value: { x: number; y: number }) {
    method isActive (line 60) | get isActive(): boolean {
    method isActive (line 64) | set isActive(value: boolean) {
    method isDragging (line 68) | get isDragging(): boolean {
    method isDragging (line 72) | set isDragging(value: boolean) {
    method bounds (line 76) | get bounds(): ViewportBounds {
    method updateSelectedRenderables (line 96) | updateSelectedRenderables(selectedRenderables: Renderable[]): void {
    method selectedRenderables (line 100) | get selectedRenderables(): Renderable[] {
    method updateTouchedRenderables (line 104) | updateTouchedRenderables(touchedRenderables: Renderable[]): void {
    method touchedRenderables (line 108) | get touchedRenderables(): Renderable[] {
    method getSelectedText (line 112) | getSelectedText(): string {
  type LocalSelectionBounds (line 130) | interface LocalSelectionBounds {
  function convertGlobalToLocalSelection (line 138) | function convertGlobalToLocalSelection(
  class ASCIIFontSelectionHelper (line 156) | class ASCIIFontSelectionHelper {
    method constructor (line 159) | constructor(
    method hasSelection (line 164) | hasSelection(): boolean {
    method getSelection (line 168) | getSelection(): { start: number; end: number } | null {
    method shouldStartSelection (line 172) | shouldStartSelection(localX: number, localY: number, width: number, he...
    method onLocalSelectionChanged (line 184) | onLocalSelectionChanged(localSelection: LocalSelectionBounds | null, w...

FILE: packages/core/src/lib/singleton.ts
  function singleton (line 7) | function singleton<T>(key: string, factory: () => T): T {
  function destroySingleton (line 16) | function destroySingleton(key: string): void {
  function hasSingleton (line 24) | function hasSingleton(key: string): boolean {

FILE: packages/core/src/lib/stdin-parser.test.ts
  type KeySnap (line 7) | type KeySnap = {
  type MouseSnap (line 16) | type MouseSnap = { type: "mouse"; raw: string; encoding: "sgr" | "x10"; ...
  type PasteSnap (line 17) | type PasteSnap = { type: "paste"; bytes: Uint8Array }
  type RespSnap (line 18) | type RespSnap = { type: "response"; protocol: string; sequence: string }
  type Snap (line 19) | type Snap = KeySnap | MouseSnap | PasteSnap | RespSnap
  constant K_DEFAULTS (line 21) | const K_DEFAULTS = { ctrl: false, meta: false, shift: false, eventType: ...
  type KOpts (line 22) | type KOpts = { raw?: string; ctrl?: boolean; meta?: boolean; shift?: boo...
  function k (line 24) | function k(name: string, opts: KOpts = {}): KeySnap {
  function resp (line 28) | function resp(protocol: string, sequence: string): RespSnap {
  function paste (line 32) | function paste(text: string): PasteSnap {
  constant NO_MODS (line 36) | const NO_MODS = { shift: false, alt: false, ctrl: false }
  function sgr (line 38) | function sgr(
  function x10m (line 56) | function x10m(
  function createParser (line 74) | function createParser(options: StdinParserOptions = {}): StdinParser {
  function createTimedParser (line 78) | function createTimedParser(options: StdinParserOptions = {}): { parser: ...
  function snapshotEvent (line 83) | function snapshotEvent(event: StdinEvent): Snap {
  function snap (line 107) | function snap(parser: StdinParser): Snap[] {
  type ChunkInput (line 113) | type ChunkInput = string | number[] | Uint8Array
  function buf (line 115) | function buf(input: ChunkInput): Uint8Array {
  function latin1 (line 120) | function latin1(input: number[] | Uint8Array): string {
  function snapChunks (line 124) | function snapChunks(chunks: ChunkInput[], opts?: StdinParserOptions): Sn...
  function concatChunks (line 134) | function concatChunks(chunks: ChunkInput[]): Uint8Array {
  function x10bytes (line 138) | function x10bytes(rawButton: number, x: number, y: number): number[] {
  type Case (line 142) | type Case = [label: string, input: ChunkInput, expected: Snap[]]
  function table (line 144) | function table(cases: Case[], opts?: StdinParserOptions) {
  function assertChunkInvariant (line 159) | function assertChunkInvariant(input: Uint8Array, opts?: StdinParserOptio...

FILE: packages/core/src/lib/stdin-parser.ts
  type StdinResponseProtocol (line 16) | type StdinResponseProtocol = "csi" | "osc" | "dcs" | "apc" | "unknown"
  type StdinEvent (line 20) | type StdinEvent =
  type StdinParserProtocolContext (line 43) | interface StdinParserProtocolContext {
  type StdinParserOptions (line 50) | interface StdinParserOptions {
  type ParserState (line 64) | type ParserState =
  type PasteCollector (line 92) | interface PasteCollector {
  constant DEFAULT_TIMEOUT_MS (line 100) | const DEFAULT_TIMEOUT_MS = 10
  constant DEFAULT_MAX_PENDING_BYTES (line 101) | const DEFAULT_MAX_PENDING_BYTES = 64 * 1024
  constant INITIAL_PENDING_CAPACITY (line 102) | const INITIAL_PENDING_CAPACITY = 256
  constant ESC (line 103) | const ESC = 0x1b
  constant BEL (line 104) | const BEL = 0x07
  constant BRACKETED_PASTE_START (line 105) | const BRACKETED_PASTE_START = Buffer.from("\x1b[200~")
  constant BRACKETED_PASTE_END (line 106) | const BRACKETED_PASTE_END = Buffer.from("\x1b[201~")
  constant EMPTY_BYTES (line 107) | const EMPTY_BYTES = new Uint8Array(0)
  constant KEY_DECODER (line 108) | const KEY_DECODER = new TextDecoder()
  constant DEFAULT_PROTOCOL_CONTEXT (line 109) | const DEFAULT_PROTOCOL_CONTEXT: StdinParserProtocolContext = {
  constant RXVT_DOLLAR_CSI_RE (line 118) | const RXVT_DOLLAR_CSI_RE = /^\x1b\[\d+\$$/
  constant SYSTEM_CLOCK (line 120) | const SYSTEM_CLOCK = new SystemClock()
  class ByteQueue (line 125) | class ByteQueue {
    method constructor (line 130) | constructor(capacity = INITIAL_PENDING_CAPACITY) {
    method length (line 134) | get length(): number {
    method capacity (line 138) | get capacity(): number {
    method view (line 142) | view(): Uint8Array {
    method take (line 148) | take(): Uint8Array {
    method append (line 155) | append(chunk: Uint8Array): void {
    method consume (line 167) | consume(count: number): void {
    method clear (line 186) | clear(): void {
    method reset (line 191) | reset(capacity = INITIAL_PENDING_CAPACITY): void {
    method ensureCapacity (line 199) | private ensureCapacity(requiredLength: number): void {
  function normalizePositiveOption (line 228) | function normalizePositiveOption(value: number | undefined, fallback: nu...
  function utf8SequenceLength (line 240) | function utf8SequenceLength(first: number): number {
  function bytesEqual (line 248) | function bytesEqual(left: Uint8Array, right: Uint8Array): boolean {
  function isMouseSgrSequence (line 264) | function isMouseSgrSequence(sequence: Uint8Array): boolean {
  function isAsciiDigit (line 299) | function isAsciiDigit(byte: number): boolean {
  type ParametricCsiLike (line 303) | interface ParametricCsiLike {
  type PrivateReplyCsiLike (line 310) | interface PrivateReplyCsiLike {
  function parsePositiveDecimalPrefix (line 316) | function parsePositiveDecimalPrefix(sequence: Uint8Array, start: number,...
  function canStillBeKittyU (line 331) | function canStillBeKittyU(state: ParametricCsiLike): boolean {
  function canStillBeKittySpecial (line 335) | function canStillBeKittySpecial(state: ParametricCsiLike): boolean {
  function canStillBeExplicitWidthCpr (line 339) | function canStillBeExplicitWidthCpr(state: ParametricCsiLike): boolean {
  function canStillBePixelResolution (line 343) | function canStillBePixelResolution(state: ParametricCsiLike): boolean {
  function canDeferParametricCsi (line 347) | function canDeferParametricCsi(state: ParametricCsiLike, context: StdinP...
  function canCompleteDeferredParametricCsi (line 355) | function canCompleteDeferredParametricCsi(
  function canDeferPrivateReplyCsi (line 395) | function canDeferPrivateReplyCsi(context: StdinParserProtocolContext): b...
  function canCompleteDeferredPrivateReplyCsi (line 399) | function canCompleteDeferredPrivateReplyCsi(
  function concatBytes (line 410) | function concatBytes(left: Uint8Array, right: Uint8Array): Uint8Array {
  function indexOfBytes (line 425) | function indexOfBytes(haystack: Uint8Array, needle: Uint8Array): number {
  function decodeLatin1 (line 451) | function decodeLatin1(bytes: Uint8Array): string {
  function decodeUtf8 (line 455) | function decodeUtf8(bytes: Uint8Array): string {
  function createPasteCollector (line 459) | function createPasteCollector(): PasteCollector {
  function joinPasteBytes (line 467) | function joinPasteBytes(parts: Uint8Array[], totalLength: number): Uint8...
  class StdinParser (line 494) | class StdinParser {
    method constructor (line 526) | constructor(options: StdinParserOptions = {}) {
    method bufferCapacity (line 542) | public get bufferCapacity(): number {
    method updateProtocolContext (line 546) | public updateProtocolContext(patch: Partial<StdinParserProtocolContext...
    method push (line 559) | public push(data: Uint8Array): void {
    method read (line 607) | public read(): StdinEvent | null {
    method drain (line 620) | public drain(onEvent: (event: StdinEvent) => void): void {
    method flushTimeout (line 641) | public flushTimeout(nowMsValue: number = this.clock.now()): void {
    method reset (line 655) | public reset(): void {
    method resetMouseState (line 664) | public resetMouseState(): void {
    method destroy (line 669) | public destroy(): void {
    method ensureAlive (line 679) | private ensureAlive(): void {
    method scanPending (line 691) | private scanPending(): void {
    method emitKeyOrResponse (line 1531) | private emitKeyOrResponse(protocol: StdinResponseProtocol, raw: string...
    method emitMouse (line 1549) | private emitMouse(rawBytes: Uint8Array, encoding: "sgr" | "x10"): void {
    method emitLegacyHighByte (line 1568) | private emitLegacyHighByte(byte: number): void {
    method emitOpaqueResponse (line 1586) | private emitOpaqueResponse(protocol: StdinResponseProtocol, rawBytes: ...
    method consumePrefix (line 1596) | private consumePrefix(endExclusive: number): void {
    method takePendingBytes (line 1607) | private takePendingBytes(): Uint8Array {
    method flushPendingOverflow (line 1619) | private flushPendingOverflow(): void {
    method markPending (line 1635) | private markPending(): void {
    method consumePasteBytes (line 1646) | private consumePasteBytes(chunk: Uint8Array): Uint8Array {
    method pushPasteBytes (line 1675) | private pushPasteBytes(bytes: Uint8Array): void {
    method reconcileDeferredStateWithProtocolContext (line 1687) | private reconcileDeferredStateWithProtocolContext(): void {
    method reconcileTimeoutState (line 1711) | private reconcileTimeoutState(): void {
    method clearTimeout (line 1737) | private clearTimeout(): void {
    method resetState (line 1749) | private resetState(): void {

FILE: packages/core/src/lib/styled-text.ts
  type Color (line 8) | type Color = ColorInput
  type StyleAttrs (line 10) | interface StyleAttrs {
  function isStyledText (line 22) | function isStyledText(obj: any): obj is StyledText {
  class StyledText (line 26) | class StyledText {
    method constructor (line 31) | constructor(chunks: TextChunk[]) {
  function stringToStyledText (line 36) | function stringToStyledText(content: string): StyledText {
  type StylableInput (line 44) | type StylableInput = string | number | boolean | TextChunk
  function applyStyle (line 46) | function applyStyle(input: StylableInput, style: StyleAttrs): TextChunk {
  function t (line 150) | function t(strings: TemplateStringsArray, ...values: StylableInput[]): S...

FILE: packages/core/src/lib/terminal-capability-detection.ts
  function isCapabilityResponse (line 18) | function isCapabilityResponse(sequence: string): boolean {
  function isPixelResolutionResponse (line 62) | function isPixelResolutionResponse(sequence: string): boolean {
  function parsePixelResolution (line 70) | function parsePixelResolution(sequence: string): { width: number; height...

FILE: packages/core/src/lib/terminal-palette.test.ts
  class MockStream (line 7) | class MockStream extends EventEmitter {
    method isPaused (line 10) | isPaused() {
    method write (line 13) | write(_data: string) {
  function createPaletteHarness (line 18) | function createPaletteHarness(
  function flushAsync (line 34) | async function flushAsync(): Promise<void> {
  function startPaletteDetection (line 39) | async function startPaletteDetection(
  function advanceClock (line 59) | async function advanceClock(clock: ManualClock, ms: number): Promise<voi...
  method subscribeOsc (line 852) | subscribeOsc(handler: (sequence: string) => void) {

FILE: packages/core/src/lib/terminal-palette.ts
  type Hex (line 3) | type Hex = string | null
  constant SYSTEM_CLOCK (line 5) | const SYSTEM_CLOCK = new SystemClock()
  constant OSC4_RESPONSE (line 7) | const OSC4_RESPONSE =
  constant OSC_SPECIAL_RESPONSE (line 10) | const OSC_SPECIAL_RESPONSE =
  type WriteFunction (line 13) | type WriteFunction = (data: string | Buffer) => boolean
  type TerminalColors (line 15) | interface TerminalColors {
  type GetPaletteOptions (line 28) | interface GetPaletteOptions {
  type TerminalPaletteDetector (line 33) | interface TerminalPaletteDetector {
  type OscSubscriptionSource (line 39) | type OscSubscriptionSource = {
  function scaleComponent (line 43) | function scaleComponent(comp: string): string {
  function toHex (line 51) | function toHex(r?: string, g?: string, b?: string, hex6?: string): string {
  function wrapForTmux (line 62) | function wrapForTmux(osc: string): string {
  class TerminalPalette (line 68) | class TerminalPalette implements TerminalPaletteDetector {
    method constructor (line 77) | constructor(
    method writeOsc (line 96) | private writeOsc(osc: string): boolean {
    method cleanup (line 101) | cleanup(): void {
    method subscribeInput (line 108) | private subscribeInput(handler: (chunk: string | Buffer) => void): () ...
    method createQuerySession (line 121) | private createQuerySession() {
    method detectOSCSupport (line 175) | async detectOSCSupport(timeoutMs = 300): Promise<boolean> {
    method queryPalette (line 209) | private async queryPalette(indices: number[], timeoutMs = 1200): Promi...
    method querySpecialColors (line 258) | private async querySpecialColors(timeoutMs = 1200): Promise<Record<num...
    method detect (line 334) | async detect(options?: GetPaletteOptions): Promise<TerminalColors> {
  function createTerminalPalette (line 374) | function createTerminalPalette(

FILE: packages/core/src/lib/tree-sitter-styled-text.ts
  type ConcealOptions (line 11) | interface ConcealOptions {
  type Boundary (line 15) | interface Boundary {
  function getSpecificity (line 21) | function getSpecificity(group: string): number {
  function shouldSuppressInInjection (line 25) | function shouldSuppressInInjection(group: string, meta: any): boolean {
  function treeSitterToTextChunks (line 38) | function treeSitterToTextChunks(
  type TreeSitterToStyledTextOptions (line 278) | interface TreeSitterToStyledTextOptions {
  function treeSitterToStyledText (line 282) | async function treeSitterToStyledText(

FILE: packages/core/src/lib/tree-sitter/assets/update.ts
  type ParsersConfig (line 10) | interface ParsersConfig {
  type GeneratedParser (line 14) | interface GeneratedParser {
  type UpdateOptions (line 23) | interface UpdateOptions {
  function getDefaultOptions (line 32) | function getDefaultOptions(): UpdateOptions {
  function loadConfig (line 40) | async function loadConfig(configPath: string): Promise<ParsersConfig> {
  function downloadLanguage (line 68) | async function downloadLanguage(
  function downloadAndCombineQueries (line 87) | async function downloadAndCombineQueries(
  function generateDefaultParsersFile (line 148) | async function generateDefaultParsersFile(parsers: GeneratedParser[], ou...
  function main (line 218) | async function main(options?: Partial<UpdateOptions>): Promise<void> {
  function parseCLIArgs (line 284) | function parseCLIArgs(): Partial<UpdateOptions> | null {

FILE: packages/core/src/lib/tree-sitter/cache.test.ts
  method fetch (line 19) | fetch(req) {

FILE: packages/core/src/lib/tree-sitter/client.ts
  type EditQueueItem (line 31) | interface EditQueueItem {
  constant DEFAULT_PARSERS (line 38) | let DEFAULT_PARSERS: FiletypeParserOptions[] = getParsers()
  function addDefaultParsers (line 40) | function addDefaultParsers(parsers: FiletypeParserOptions[]): void {
  class TreeSitterClient (line 53) | class TreeSitterClient extends EventEmitter<TreeSitterClientEvents> {
    method constructor (line 67) | constructor(options: TreeSitterClientOptions) {
    method emitError (line 74) | private emitError(error: string, bufferId?: number): void {
    method emitWarning (line 80) | private emitWarning(warning: string, bufferId?: number): void {
    method startWorker (line 86) | private startWorker() {
    method stopWorker (line 126) | private stopWorker() {
    method handleReset (line 136) | private handleReset() {
    method initialize (line 145) | async initialize(): Promise<void> {
    method registerDefaultParsers (line 172) | private async registerDefaultParsers(): Promise<void> {
    method resolvePath (line 178) | private resolvePath(path: string): string {
    method addFiletypeParser (line 191) | public addFiletypeParser(filetypeParser: FiletypeParserOptions): void {
    method getPerformance (line 206) | public async getPerformance(): Promise<PerformanceStats> {
    method highlightOnce (line 214) | public async highlightOnce(
    method handleWorkerMessage (line 238) | private handleWorkerMessage(event: MessageEvent) {
    method preloadParser (line 357) | public async preloadParser(filetype: string): Promise<boolean> {
    method createBuffer (line 370) | public async createBuffer(
    method updateBuffer (line 426) | public async updateBuffer(id: number, edits: Edit[], newContent: strin...
    method processEdit (line 452) | private async processEdit(
    method removeBuffer (line 468) | public async removeBuffer(bufferId: number): Promise<void> {
    method destroy (line 508) | public async destroy(): Promise<void> {
    method resetBuffer (line 539) | public async resetBuffer(bufferId: number, version: number, content: s...
    method getBuffer (line 557) | public getBuffer(bufferId: number): BufferState | undefined {
    method getAllBuffers (line 561) | public getAllBuffers(): BufferState[] {
    method isInitialized (line 565) | public isInitialized(): boolean {
    method setDataPath (line 569) | public async setDataPath(dataPath: string): Promise<void> {
    method clearCache (line 595) | public async clearCache(): Promise<void> {

FILE: packages/core/src/lib/tree-sitter/default-parsers.ts
  function getParsers (line 24) | function getParsers(): FiletypeParserOptions[] {

FILE: packages/core/src/lib/tree-sitter/download-utils.ts
  type DownloadResult (line 4) | interface DownloadResult {
  class DownloadUtils (line 10) | class DownloadUtils {
    method hashUrl (line 11) | private static hashUrl(url: string): string {
    method downloadOrLoad (line 24) | static async downloadOrLoad(
    method downloadToPath (line 90) | static async downloadToPath(source: string, targetPath: string): Promi...
    method fetchHighlightQueries (line 126) | static async fetchHighlightQueries(sources: string[], cacheDir: string...
    method fetchHighlightQuery (line 134) | private static async fetchHighlightQuery(source: string, cacheDir: str...

FILE: packages/core/src/lib/tree-sitter/index.ts
  function getTreeSitterClient (line 13) | function getTreeSitterClient(): TreeSitterClient {

FILE: packages/core/src/lib/tree-sitter/parser.worker.ts
  type ParserState (line 19) | type ParserState = {
  type FiletypeParser (line 31) | interface FiletypeParser {
  type ReusableParserState (line 41) | interface ReusableParserState {
  class ParserWorker (line 50) | class ParserWorker {
    method constructor (line 64) | constructor() {
    method fetchQueries (line 73) | private async fetchQueries(sources: string[], filetype: string): Promi...
    method initialize (line 80) | async initialize({ dataPath }: { dataPath: string }) {
    method addFiletypeParser (line 115) | public addFiletypeParser(filetypeParser: FiletypeParserOptions) {
    method resolveCanonicalFiletype (line 138) | private resolveCanonicalFiletype(filetype: string): string {
    method invalidateParserCaches (line 146) | private invalidateParserCaches(filetype: string): void {
    method createQueries (line 159) | private async createQueries(
    method loadLanguage (line 199) | private async loadLanguage(languageSource: string): Promise<Language |...
    method resolveFiletypeParser (line 227) | private async resolveFiletypeParser(filetype: string): Promise<Filetyp...
    method loadFiletypeParser (line 252) | private async loadFiletypeParser(filetype: string): Promise<FiletypePa...
    method preloadParser (line 274) | public async preloadParser(filetype: string) {
    method getReusableParser (line 278) | private async getReusableParser(filetype: string): Promise<ReusablePar...
    method createReusableParser (line 303) | private async createReusableParser(filetype: string): Promise<Reusable...
    method handleInitializeParser (line 321) | async handleInitializeParser(
    method initialQuery (line 380) | private async initialQuery(parserState: ParserState) {
    method getNodeText (line 394) | private getNodeText(node: any, content: string): string {
    method processInjections (line 398) | private async processInjections(
    method editToRange (line 528) | private editToRange(edit: Edit): Range {
    method handleEdits (line 543) | async handleEdits(
    method nodeContainsRange (line 648) | private nodeContainsRange(node: any, range: any): boolean {
    method getHighlights (line 657) | private getHighlights(
    method getSimpleHighlights (line 709) | private getSimpleHighlights(
    method handleResetBuffer (line 772) | async handleResetBuffer(
    method disposeBuffer (line 803) | disposeBuffer(bufferId: number): void {
    method handleOneShotHighlight (line 815) | async handleOneShotHighlight(content: string, filetype: string, messag...
    method updateDataPath (line 876) | async updateDataPath(dataPath: string): Promise<void> {
    method clearCache (line 888) | async clearCache(): Promise<void> {
  function logMessage (line 915) | function logMessage(type: "log" | "error" | "warn", ...args: any[]) {

FILE: packages/core/src/lib/tree-sitter/resolve-ft.ts
  function normalizeFiletypeToken (line 133) | function normalizeFiletypeToken(value: string): string | undefined {
  function getBasename (line 138) | function getBasename(value: string): string | undefined {
  function extToFiletype (line 146) | function extToFiletype(extension: string): string | undefined {
  function pathToFiletype (line 153) | function pathToFiletype(path: string): string | undefined {
  function infoStringToFiletype (line 173) | function infoStringToFiletype(infoString: string): string | undefined {

FILE: packages/core/src/lib/tree-sitter/types.ts
  type HighlightRange (line 1) | interface HighlightRange {
  type HighlightResponse (line 7) | interface HighlightResponse {
  type HighlightMeta (line 13) | interface HighlightMeta {
  type SimpleHighlight (line 21) | type SimpleHighlight = [number, number, string, HighlightMeta?]
  type InjectionMapping (line 23) | interface InjectionMapping {
  type FiletypeParserOptions (line 30) | interface FiletypeParserOptions {
  type BufferState (line 41) | interface BufferState {
  type ParsedBuffer (line 49) | interface ParsedBuffer extends BufferState {
  type TreeSitterClientEvents (line 53) | interface TreeSitterClientEvents {
  type TreeSitterClientOptions (line 62) | interface TreeSitterClientOptions {
  type Edit (line 68) | interface Edit {
  type PerformanceStats (line 77) | interface PerformanceStats {

FILE: packages/core/src/lib/validate-dir-name.ts
  function isValidDirectoryName (line 1) | function isValidDirectoryName(name: string): boolean {

FILE: packages/core/src/lib/yoga.options.ts
  type AlignString (line 19) | type AlignString =
  type BoxSizingString (line 29) | type BoxSizingString = "border-box" | "content-box"
  type DimensionString (line 30) | type DimensionString = "width" | "height"
  type DirectionString (line 31) | type DirectionString = "inherit" | "ltr" | "rtl"
  type DisplayString (line 32) | type DisplayString = "flex" | "none" | "contents"
  type EdgeString (line 33) | type EdgeString = "left" | "top" | "right" | "bottom" | "start" | "end" ...
  type FlexDirectionString (line 34) | type FlexDirectionString = "column" | "column-reverse" | "row" | "row-re...
  type GutterString (line 35) | type GutterString = "column" | "row" | "all"
  type JustifyString (line 36) | type JustifyString = "flex-start" | "center" | "flex-end" | "space-betwe...
  type LogLevelString (line 37) | type LogLevelString = "error" | "warn" | "info" | "debug" | "verbose" | ...
  type MeasureModeString (line 38) | type MeasureModeString = "undefined" | "exactly" | "at-most"
  type OverflowString (line 39) | type OverflowString = "visible" | "hidden" | "scroll"
  type PositionTypeString (line 40) | type PositionTypeString = "static" | "relative" | "absolute"
  type UnitString (line 41) | type UnitString = "undefined" | "point" | "percent" | "auto"
  type WrapString (line 42) | type WrapString = "no-wrap" | "wrap" | "wrap-reverse"
  function parseAlign (line 44) | function parseAlign(value: string | null | undefined): Align {
  function parseAlignItems (line 72) | function parseAlignItems(value: string | null | undefined): Align {
  function parseBoxSizing (line 100) | function parseBoxSizing(value: string): BoxSizing {
  function parseDimension (line 114) | function parseDimension(value: string): Dimension {
  function parseDirection (line 128) | function parseDirection(value: string): Direction {
  function parseDisplay (line 144) | function parseDisplay(value: string): Display {
  function parseEdge (line 160) | function parseEdge(value: string): Edge {
  function parseFlexDirection (line 188) | function parseFlexDirection(value: string | null | undefined): FlexDirec...
  function parseGutter (line 206) | function parseGutter(value: string): Gutter {
  function parseJustify (line 222) | function parseJustify(value: string | null | undefined): Justify {
  function parseLogLevel (line 244) | function parseLogLevel(value: string): LogLevel {
  function parseMeasureMode (line 266) | function parseMeasureMode(value: string): MeasureMode {
  function parseOverflow (line 282) | function parseOverflow(value: string | null | undefined): Overflow {
  function parsePositionType (line 298) | function parsePositionType(value: string | null | undefined): PositionTy...
  function parseUnit (line 314) | function parseUnit(value: string): Unit {
  function parseWrap (line 332) | function parseWrap(value: string | null | undefined): Wrap {

FILE: packages/core/src/plugins/core-slot.ts
  type CoreSlotMode (line 7) | type CoreSlotMode = SlotMode
  type CoreSlotProps (line 9) | type CoreSlotProps<TSlotName extends string, TData extends object> = {
  type CoreSlotRegistry (line 13) | type CoreSlotRegistry<
  type CoreSlotRenderer (line 19) | type CoreSlotRenderer<
  type CoreManagedSlot (line 24) | interface CoreManagedSlot<
  type CoreSlotContribution (line 34) | type CoreSlotContribution<
  type CorePlugin (line 39) | interface CorePlugin<
  type CoreResolvedSlotRenderer (line 51) | interface CoreResolvedSlotRenderer<
  type FallbackNodes (line 59) | type FallbackNodes = BaseRenderable | BaseRenderable[] | undefined
  type CoreSlotFailurePlaceholder (line 61) | type CoreSlotFailurePlaceholder<TContext extends PluginContext = PluginC...
  type CoreSlotOwnership (line 66) | type CoreSlotOwnership = "host" | "plugin"
  type WrappedCoreSlotRenderer (line 68) | type WrappedCoreSlotRenderer<
  type ResolvedCoreSlotEntry (line 76) | interface ResolvedCoreSlotEntry<
  type SlotNodeState (line 84) | interface SlotNodeState<
  function isCoreManagedSlot (line 94) | function isCoreManagedSlot<
  function toCorePlugin (line 101) | function toCorePlugin<
  function asArray (line 138) | function asArray(value: FallbackNodes): BaseRenderable[] {
  function ensureValidNode (line 146) | function ensureValidNode(node: unknown, pluginId: string, mount: BaseRen...
  function createCoreSlotRegistry (line 168) | function createCoreSlotRegistry<
  function registerCorePlugin (line 185) | function registerCorePlugin<
  function resolveCoreSlot (line 193) | function resolveCoreSlot<
  function resolveCoreSlotEntries (line 207) | function resolveCoreSlotEntries<
  type SlotRenderableOptions (line 227) | interface SlotRenderableOptions<
  class SlotRenderable (line 241) | class SlotRenderable<
    method constructor (line 259) | constructor(ctx: RenderContext, options: SlotRenderableOptions<TSlotNa...
    method mode (line 279) | public get mode(): CoreSlotMode {
    method mode (line 283) | public set mode(value: CoreSlotMode) {
    method data (line 288) | public get data(): TData {
    method data (line 292) | public set data(value: TData) {
    method refresh (line 297) | public refresh(): void {
    method destroySelf (line 379) | protected override destroySelf(): void {
    method _cleanupAll (line 383) | private _cleanupAll(): void {
    method _ensureFallbackNodes (line 423) | private _ensureFallbackNodes(): BaseRenderable[] {
    method _callManagedHook (line 438) | private _callManagedHook(
    method _detachNodeFromMount (line 462) | private _detachNodeFromMount(node: BaseRenderable): void {
    method _cleanupInactivePluginNodes (line 468) | private _cleanupInactivePluginNodes(nextActivePluginIds: Set<string>, ...
    method _cleanupReplacedPluginNodes (line 507) | private _cleanupReplacedPluginNodes(
    method _resolvePluginFailurePlaceholder (line 526) | private _resolvePluginFailurePlaceholder(failure: PluginErrorEvent): B...
    method _reconcileMountedNodes (line 552) | private _reconcileMountedNodes(desiredNodes: BaseRenderable[]): void {

FILE: packages/core/src/plugins/registry.ts
  constant DEFAULT_DEBUG_PLUGIN_ERRORS (line 12) | const DEFAULT_DEBUG_PLUGIN_ERRORS = false
  constant DEFAULT_MAX_PLUGIN_ERRORS (line 13) | const DEFAULT_MAX_PLUGIN_ERRORS = 100
  function normalizeError (line 15) | function normalizeError(error: unknown): Error {
  type SlotRegistryOptions (line 27) | interface SlotRegistryOptions {
  type RegisteredPlugin (line 33) | interface RegisteredPlugin<TNode, TSlots extends object, TContext extend...
  class SlotRegistry (line 40) | class SlotRegistry<TNode, TSlots extends object, TContext extends Plugin...
    method constructor (line 52) | constructor(renderer: CliRenderer, context: TContext, options: SlotReg...
    method renderer (line 62) | public get renderer(): CliRenderer {
    method context (line 66) | public get context(): Readonly<TContext> {
    method configure (line 70) | public configure(options: SlotRegistryOptions): void {
    method register (line 84) | public register(plugin: Plugin<TNode, TSlots, TContext>): () => void {
    method unregister (line 117) | public unregister(id: string): boolean {
    method updateOrder (line 143) | public updateOrder(id: string, order: number): boolean {
    method clear (line 160) | public clear(): void {
    method subscribe (line 185) | public subscribe(listener: () => void): () => void {
    method onPluginError (line 192) | public onPluginError(listener: (event: PluginErrorEvent) => void): () ...
    method getPluginErrors (line 199) | public getPluginErrors(): readonly PluginErrorEvent[] {
    method clearPluginErrors (line 203) | public clearPluginErrors(): void {
    method reportPluginError (line 207) | public reportPluginError(report: PluginErrorReport): PluginErrorEvent {
    method resolve (line 247) | public resolve<K extends keyof TSlots>(slot: K): Array<SlotRenderer<TN...
    method resolveEntries (line 251) | public resolveEntries<K extends keyof TSlots>(slot: K): Array<Resolved...
    method getSortedPlugins (line 267) | private getSortedPlugins(): RegisteredPlugin<TNode, TSlots, TContext>[] {
    method syncPluginSortMetadata (line 292) | private syncPluginSortMetadata(): void {
    method invalidateSortedPluginsCache (line 311) | private invalidateSortedPluginsCache(): void {
    method notifyListeners (line 315) | private notifyListeners(): void {
  function getSlotRegistryStore (line 328) | function getSlotRegistryStore(renderer: CliRenderer): Map<string, SlotRe...
  function createSlotRegistry (line 353) | function createSlotRegistry<TNode, TSlots extends object, TContext exten...

FILE: packages/core/src/plugins/types.ts
  type PluginContext (line 3) | type PluginContext = object
  type SlotMode (line 5) | type SlotMode = "append" | "replace" | "single_winner"
  type PluginErrorPhase (line 7) | type PluginErrorPhase = "setup" | "render" | "dispose" | "error_placehol...
  type PluginErrorSource (line 9) | type PluginErrorSource = "registry" | "core" | (string & {})
  type PluginErrorEvent (line 11) | interface PluginErrorEvent {
  type PluginErrorReport (line 20) | interface PluginErrorReport {
  type SlotRenderer (line 28) | type SlotRenderer<TNode, TProps, TContext extends PluginContext = Plugin...
  type Plugin (line 33) | interface Plugin<TNode, TSlots extends object, TContext extends PluginCo...
  type ResolvedSlotRenderer (line 43) | interface ResolvedSlotRenderer<TNode, TProps, TContext extends PluginCon...

FILE: packages/core/src/post/effects.ts
  type ActiveGlitch (line 3) | interface ActiveGlitch {
  class DistortionEffect (line 9) | class DistortionEffect {
    method constructor (line 24) | constructor(options?: Partial<DistortionEffect>) {
    method apply (line 33) | public apply(buffer: OptimizedBuffer, deltaTime: number): void {
  class VignetteEffect (line 255) | class VignetteEffect {
    method constructor (line 264) | constructor(strength: number = 0.5) {
    method strength (line 268) | public set strength(newStrength: number) {
    method strength (line 276) | public get strength(): number {
    method _computeFactors (line 280) | private _computeFactors(width: number, height: number): void {
    method apply (line 313) | public apply(buffer: OptimizedBuffer): void {
  class PerlinNoise (line 335) | class PerlinNoise {
    method constructor (line 352) | constructor() {
    method dot (line 370) | private dot(g: number[], x: number, y: number, z: number): number {
    method mix (line 374) | private mix(a: number, b: number, t: number): number {
    method fade (line 378) | private fade(t: number): number {
    method noise3d (line 386) | noise3d(x: number, y: number, z: number): number {
  class CloudsEffect (line 449) | class CloudsEffect {
    method constructor (line 457) | constructor(scale: number = 0.02, speed: number = 0.5, density: number...
    method scale (line 465) | public set scale(newScale: number) {
    method scale (line 468) | public get scale(): number {
    method speed (line 472) | public set speed(newSpeed: number) {
    method speed (line 475) | public get speed(): number {
    method density (line 479) | public set density(newDensity: number) {
    method density (line 482) | public get density(): number {
    method darkness (line 486) | public set darkness(newDarkness: number) {
    method darkness (line 489) | public get darkness(): number {
    method apply (line 497) | public apply(buffer: OptimizedBuffer, deltaTime: number): void {
  class FlamesEffect (line 560) | class FlamesEffect {
    method constructor (line 567) | constructor(scale: number = 0.03, speed: number = 0.02, intensity: num...
    method scale (line 574) | public set scale(newScale: number) {
    method scale (line 577) | public get scale(): number {
    method speed (line 581) | public set speed(newSpeed: number) {
    method speed (line 584) | public get speed(): number {
    method intensity (line 588) | public set intensity(newIntensity: number) {
    method intensity (line 591) | public get intensity(): number {
    method apply (line 599) | public apply(buffer: OptimizedBuffer, deltaTime: number): void {
  class CRTRollingBarEffect (line 678) | class CRTRollingBarEffect {
    method constructor (line 685) | constructor(speed: number = 0.5, height: number = 0.15, intensity: num...
    method speed (line 692) | public set speed(newSpeed: number) {
    method speed (line 695) | public get speed(): number {
    method height (line 699) | public set height(newHeight: number) {
    method height (line 702) | public get height(): number {
    method intensity (line 706) | public set intensity(newIntensity: number) {
    method intensity (line 709) | public get intensity(): number {
    method fadeDistance (line 713) | public set fadeDistance(newFadeDistance: number) {
    method fadeDistance (line 716) | public get fadeDistance(): number {
    method apply (line 725) | public apply(buffer: OptimizedBuffer, deltaTime: number): void {
  class RainbowTextEffect (line 783) | class RainbowTextEffect {
    method constructor (line 790) | constructor(speed: number = 0.01, saturation: number = 1.0, value: num...
    method speed (line 797) | public set speed(newSpeed: number) {
    method speed (line 800) | public get speed(): number {
    method saturation (line 804) | public set saturation(newSaturation: number) {
    method saturation (line 807) | public get saturation(): number {
    method value (line 811) | public set value(newValue: number) {
    method value (line 814) | public get value(): number {
    method repeats (line 818) | public set repeats(newRepeats: number) {
    method repeats (line 821) | public get repeats(): number {
    method hsvToRgb (line 832) | private hsvToRgb(h: number, s: number, v: number): [number, number, nu...
    method apply (line 883) | public apply(buffer: OptimizedBuffer, deltaTime: number): void {

FILE: packages/core/src/post/filters.ts
  function applyScanlines (line 7) | function applyScanlines(buffer: OptimizedBuffer, strength: number = 0.8,...
  function applyInvert (line 56) | function applyInvert(buffer: OptimizedBuffer, strength: number = 1.0): v...
  function applyNoise (line 87) | function applyNoise(buffer: OptimizedBuffer, strength: number = 0.1): vo...
  function applyChromaticAberration (line 139) | function applyChromaticAberration(buffer: OptimizedBuffer, strength: num...
  function applyAsciiArt (line 173) | function applyAsciiArt(
  function applyBrightness (line 250) | function applyBrightness(buffer: OptimizedBuffer, brightness: number = 0...
  function applyGain (line 287) | function applyGain(buffer: OptimizedBuffer, gain: number = 1.0, cellMask...
  function createSaturationMatrix (line 321) | function createSaturationMatrix(saturation: number): Float32Array {
  function applySaturation (line 366) | function applySaturation(buffer: OptimizedBuffer, cellMask?: Float32Arra...
  class BloomEffect (line 385) | class BloomEffect {
    method constructor (line 390) | constructor(threshold: number = 0.8, strength: number = 0.2, radius: n...
    method threshold (line 396) | public set threshold(newThreshold: number) {
    method threshold (line 399) | public get threshold(): number {
    method strength (line 403) | public set strength(newStrength: number) {
    method strength (line 406) | public get strength(): number {
    method radius (line 410) | public set radius(newRadius: number) {
    method radius (line 413) | public get radius(): number {
    method apply (line 417) | public apply(buffer: OptimizedBuffer): void {

FILE: packages/core/src/post/matrices.ts
  constant SEPIA_MATRIX (line 2) | const SEPIA_MATRIX = new Float32Array([
  constant PROTANOPIA_SIM_MATRIX (line 26) | const PROTANOPIA_SIM_MATRIX = new Float32Array([
  constant DEUTERANOPIA_SIM_MATRIX (line 46) | const DEUTERANOPIA_SIM_MATRIX = new Float32Array([
  constant TRITANOPIA_SIM_MATRIX (line 66) | const TRITANOPIA_SIM_MATRIX = new Float32Array([
  constant ACHROMATOPSIA_MATRIX (line 86) | const ACHROMATOPSIA_MATRIX = new Float32Array([
  constant PROTANOPIA_COMP_MATRIX (line 106) | const PROTANOPIA_COMP_MATRIX = new Float32Array([
  constant DEUTERANOPIA_COMP_MATRIX (line 126) | const DEUTERANOPIA_COMP_MATRIX = new Float32Array([
  constant TRITANOPIA_COMP_MATRIX (line 146) | const TRITANOPIA_COMP_MATRIX = new Float32Array([
  constant TECHNICOLOR_MATRIX (line 170) | const TECHNICOLOR_MATRIX = new Float32Array([
  constant SOLARIZATION_MATRIX (line 191) | const SOLARIZATION_MATRIX = new Float32Array([
  constant SYNTHWAVE_MATRIX (line 211) | const SYNTHWAVE_MATRIX = new Float32Array([
  constant GREENSCALE_MATRIX (line 231) | const GREENSCALE_MATRIX = new Float32Array([
  constant GRAYSCALE_MATRIX (line 251) | const GRAYSCALE_MATRIX = new Float32Array([
  constant INVERT_MATRIX (line 271) | const INVERT_MATRIX = new Float32Array([

FILE: packages/core/src/renderables/ASCIIFont.ts
  type ASCIIFontOptions (line 19) | interface ASCIIFontOptions extends Omit<RenderableOptions<ASCIIFontRende...
  class ASCIIFontRenderable (line 29) | class ASCIIFontRenderable extends FrameBufferRenderable {
    method constructor (line 52) | constructor(ctx: RenderContext, options: ASCIIFontOptions) {
    method text (line 82) | get text(): string {
    method text (line 86) | set text(value: string) {
    method font (line 98) | get font(): keyof typeof fonts {
    method font (line 102) | set font(value: keyof typeof fonts) {
    method color (line 114) | get color(): ColorInput | ColorInput[] {
    method color (line 118) | set color(value: ColorInput | ColorInput[]) {
    method backgroundColor (line 124) | get backgroundColor(): ColorInput {
    method backgroundColor (line 128) | set backgroundColor(value: ColorInput) {
    method updateDimensions (line 134) | private updateDimensions(): void {
    method shouldStartSelection (line 140) | shouldStartSelection(x: number, y: number): boolean {
    method onSelectionChanged (line 146) | onSelectionChanged(selection: Selection | null): boolean {
    method getSelectedText (line 157) | getSelectedText(): string {
    method hasSelection (line 163) | hasSelection(): boolean {
    method onResize (line 167) | protected onResize(width: number, height: number): void {
    method renderFontToBuffer (line 172) | private renderFontToBuffer(): void {
    method renderSelectionHighlight (line 191) | private renderSelectionHighlight(selection: { start: number; end: numb...

FILE: packages/core/src/renderables/Box.ts
  type BoxOptions (line 17) | interface BoxOptions<TRenderable extends Renderable = BoxRenderable> ext...
  function isGapType (line 33) | function isGapType(value: any): value is number | undefined {
  class BoxRenderable (line 43) | class BoxRenderable extends Renderable {
    method constructor (line 66) | constructor(ctx: RenderContext, options: BoxOptions) {
    method initializeBorder (line 100) | private initializeBorder(): void {
    method customBorderChars (line 112) | public get customBorderChars(): BorderCharacters | undefined {
    method customBorderChars (line 116) | public set customBorderChars(value: BorderCharacters | undefined) {
    method backgroundColor (line 122) | public get backgroundColor(): RGBA {
    method backgroundColor (line 126) | public set backgroundColor(value: RGBA | string | undefined) {
    method border (line 134) | public get border(): boolean | BorderSides[] {
    method border (line 138) | public set border(value: boolean | BorderSides[]) {
    method borderStyle (line 147) | public get borderStyle(): BorderStyle {
    method borderStyle (line 151) | public set borderStyle(value: BorderStyle) {
    method borderColor (line 161) | public get borderColor(): RGBA {
    method borderColor (line 165) | public set borderColor(value: RGBA | string) {
    method focusedBorderColor (line 174) | public get focusedBorderColor(): RGBA {
    method focusedBorderColor (line 178) | public set focusedBorderColor(value: RGBA | string) {
    method title (line 189) | public get title(): string | undefined {
    method title (line 193) | public set title(value: string | undefined) {
    method titleAlignment (line 200) | public get titleAlignment(): "left" | "center" | "right" {
    method titleAlignment (line 204) | public set titleAlignment(value: "left" | "center" | "right") {
    method renderSelf (line 211) | protected renderSelf(buffer: OptimizedBuffer): void {
    method getScissorRect (line 230) | protected getScissorRect(): { x: number; y: number; width: number; hei...
    method applyYogaBorders (line 250) | private applyYogaBorders(): void {
    method applyYogaGap (line 259) | private applyYogaGap(options: BoxOptions): void {
    method gap (line 275) | public set gap(gap: number | `${number}%` | undefined) {
    method rowGap (line 282) | public set rowGap(rowGap: number | `${number}%` | undefined) {
    method columnGap (line 289) | public set columnGap(columnGap: number | `${number}%` | undefined) {

FILE: packages/core/src/renderables/Code.test.ts
  class HangingMockClient (line 465) | class HangingMockClient extends TreeSitterClient {
    method constructor (line 466) | constructor() {
    method highlightOnce (line 470) | async highlightOnce(

FILE: packages/core/src/renderables/Code.ts
  type HighlightContext (line 11) | interface HighlightContext {
  type OnHighlightCallback (line 17) | type OnHighlightCallback = (
  type ChunkRenderContext (line 22) | interface ChunkRenderContext extends HighlightContext {
  type OnChunksCallback (line 26) | type OnChunksCallback = (
  type CodeOptions (line 31) | interface CodeOptions extends TextBufferOptions {
  class CodeRenderable (line 43) | class CodeRenderable extends TextBufferRenderable {
    method constructor (line 68) | constructor(ctx: RenderContext, options: CodeOptions) {
    method content (line 90) | get content(): string {
    method content (line 94) | set content(value: string) {
    method filetype (line 109) | get filetype(): string | undefined {
    method filetype (line 113) | set filetype(value: string | undefined) {
    method syntaxStyle (line 120) | get syntaxStyle(): SyntaxStyle {
    method syntaxStyle (line 124) | set syntaxStyle(value: SyntaxStyle) {
    method conceal (line 131) | get conceal(): boolean {
    method conceal (line 135) | set conceal(value: boolean) {
    method drawUnstyledText (line 142) | get drawUnstyledText(): boolean {
    method drawUnstyledText (line 146) | set drawUnstyledText(value: boolean) {
    method streaming (line 153) | get streaming(): boolean {
    method streaming (line 157) | set streaming(value: boolean) {
    method treeSitterClient (line 166) | get treeSitterClient(): TreeSitterClient {
    method treeSitterClient (line 170) | set treeSitterClient(value: TreeSitterClient) {
    method onHighlight (line 177) | get onHighlight(): OnHighlightCallback | undefined {
    method onHighlight (line 181) | set onHighlight(value: OnHighlightCallback | undefined) {
    method onChunks (line 188) | get onChunks(): OnChunksCallback | undefined {
    method onChunks (line 192) | set onChunks(value: OnChunksCallback | undefined) {
    method isHighlighting (line 199) | get isHighlighting(): boolean {
    method highlightingDone (line 203) | get highlightingDone(): Promise<void> {
    method transformChunks (line 207) | protected async transformChunks(chunks: TextChunk[], context: ChunkRen...
    method ensureVisibleTextBeforeHighlight (line 214) | private ensureVisibleTextBeforeHighlight(): void {
    method startHighlight (line 237) | private async startHighlight(): Promise<void> {
    method getLineHighlights (line 333) | public getLineHighlights(lineIdx: number) {
    method renderSelf (line 337) | protected renderSelf(buffer: OptimizedBuffer): void {

FILE: packages/core/src/renderables/Diff.ts
  type LogicalLine (line 12) | interface LogicalLine {
  type DiffRenderableOptions (line 21) | interface DiffRenderableOptions extends RenderableOptions<DiffRenderable> {
  class DiffRenderable (line 54) | class DiffRenderable extends Renderable {
    method constructor (line 106) | constructor(ctx: RenderContext, options: DiffRenderableOptions) {
    method parseDiff (line 149) | private parseDiff(): void {
    method buildView (line 173) | private buildView(): void {
    method onMouseEvent (line 190) | protected override onMouseEvent(event: MouseEvent): void {
    method isInsideSide (line 204) | private isInsideSide(target: Renderable | null, side: "left" | "right"...
    method onResize (line 214) | protected override onResize(width: number, height: number): void {
    method requestRebuild (line 225) | private requestRebuild(): void {
    method rebuildView (line 240) | private rebuildView(): void {
    method attachLineInfoListeners (line 261) | private attachLineInfoListeners(): void {
    method detachLineInfoListeners (line 270) | private detachLineInfoListeners(): void {
    method destroyRecursively (line 282) | public override destroyRecursively(): void {
    method buildErrorView (line 290) | private buildErrorView(): void {
    method createOrUpdateCodeRenderable (line 347) | private createOrUpdateCodeRenderable(
    method createOrUpdateSide (line 407) | private createOrUpdateSide(
    method buildUnifiedView (line 461) | private buildUnifiedView(): void {
    method buildSplitView (line 561) | private buildSplitView(): void {
    method diff (line 882) | public get diff(): string {
    method diff (line 886) | public set diff(value: string) {
    method syncScroll (line 895) | public get syncScroll(): boolean {
    method syncScroll (line 899) | public set syncScroll(value: boolean) {
    method view (line 908) | public get view(): "unified" | "split" {
    method view (line 912) | public set view(value: "unified" | "split") {
    method filetype (line 920) | public get filetype(): string | undefined {
    method filetype (line 924) | public set filetype(value: string | undefined) {
    method syntaxStyle (line 931) | public get syntaxStyle(): SyntaxStyle | undefined {
    method syntaxStyle (line 935) | public set syntaxStyle(value: SyntaxStyle | undefined) {
    method wrapMode (line 942) | public get wrapMode(): "word" | "char" | "none" | undefined {
    method wrapMode (line 946) | public set wrapMode(value: "word" | "char" | "none" | undefined) {
    method showLineNumbers (line 958) | public get showLineNumbers(): boolean {
    method showLineNumbers (line 962) | public set showLineNumbers(value: boolean) {
    method addedBg (line 974) | public get addedBg(): RGBA {
    method addedBg (line 978) | public set addedBg(value: string | RGBA) {
    method removedBg (line 986) | public get removedBg(): RGBA {
    method removedBg (line 990) | public set removedBg(value: string | RGBA) {
    method contextBg (line 998) | public get contextBg(): RGBA {
    method contextBg (line 1002) | public set contextBg(value: string | RGBA) {
    method addedSignColor (line 1010) | public get addedSignColor(): RGBA {
    method addedSignColor (line 1014) | public set addedSignColor(value: string | RGBA) {
    method removedSignColor (line 1022) | public get removedSignColor(): RGBA {
    method removedSignColor (line 1026) | public set removedSignColor(value: string | RGBA) {
    method addedLineNumberBg (line 1034) | public get addedLineNumberBg(): RGBA {
    method addedLineNumberBg (line 1038) | public set addedLineNumberBg(value: string | RGBA) {
    method removedLineNumberBg (line 1046) | public get removedLineNumberBg(): RGBA {
    method removedLineNumberBg (line 1050) | public set removedLineNumberBg(value: string | RGBA) {
    method lineNumberFg (line 1058) | public get lineNumberFg(): RGBA {
    method lineNumberFg (line 1062) | public set lineNumberFg(value: string | RGBA) {
    method lineNumberBg (line 1070) | public get lineNumberBg(): RGBA {
    method lineNumberBg (line 1074) | public set lineNumberBg(value: string | RGBA) {
    method addedContentBg (line 1082) | public get addedContentBg(): RGBA | null {
    method addedContentBg (line 1086) | public set addedContentBg(value: string | RGBA | null) {
    method removedContentBg (line 1094) | public get removedContentBg(): RGBA | null {
    method removedContentBg (line 1098) | public set removedContentBg(value: string | RGBA | null) {
    method contextContentBg (line 1106) | public get contextContentBg(): RGBA | null {
    method contextContentBg (line 1110) | public set contextContentBg(value: string | RGBA | null) {
    method selectionBg (line 1118) | public get selectionBg(): RGBA | undefined {
    method selectionBg (line 1122) | public set selectionBg(value: string | RGBA | undefined) {
    method selectionFg (line 1135) | public get selectionFg(): RGBA | undefined {
    method selectionFg (line 1139) | public set selectionFg(value: string | RGBA | undefined) {
    method conceal (line 1152) | public get conceal(): boolean {
    method conceal (line 1156) | public set conceal(value: boolean) {
    method fg (line 1163) | public get fg(): RGBA | undefined {
    method fg (line 1167) | public set fg(value: string | RGBA | undefined) {
    method setLineColor (line 1180) | public setLineColor(line: number, color: string | RGBA | LineColorConf...
    method clearLineColor (line 1185) | public clearLineColor(line: number): void {
    method setLineColors (line 1190) | public setLineColors(lineColors: Map<number, string | RGBA | LineColor...
    method clearAllLineColors (line 1195) | public clearAllLineColors(): void {
    method highlightLines (line 1200) | public highlightLines(startLine: number, endLine: number, color: strin...
    method clearHighlightLines (line 1205) | public clearHighlightLines(startLine: number, endLine: number): void {

FILE: packages/core/src/renderables/EditBufferRenderable.ts
  type CursorChangeEvent (line 11) | interface CursorChangeEvent {
  type ContentChangeEvent (line 16) | interface ContentChangeEvent {
  type EditBufferOptions (line 20) | interface EditBufferOptions extends RenderableOptions<EditBufferRenderab...
  method constructor (line 89) | constructor(ctx: RenderContext, options: EditBufferOptions) {
  method lineInfo (line 134) | public get lineInfo(): LineInfo {
  method setupEventListeners (line 138) | private setupEventListeners(options: EditBufferOptions): void {
  method lineCount (line 162) | public get lineCount(): number {
  method virtualLineCount (line 166) | public get virtualLineCount(): number {
  method scrollY (line 170) | public get scrollY(): number {
  method plainText (line 174) | get plainText(): string {
  method logicalCursor (line 178) | get logicalCursor(): LogicalCursor {
  method visualCursor (line 182) | get visualCursor(): VisualCursor {
  method cursorOffset (line 186) | get cursorOffset(): number {
  method cursorOffset (line 190) | set cursorOffset(offset: number) {
  method textColor (line 195) | get textColor(): RGBA {
  method textColor (line 199) | set textColor(value: RGBA | string | undefined) {
  method selectionBg (line 208) | get selectionBg(): RGBA | undefined {
  method selectionBg (line 212) | set selectionBg(value: RGBA | string | undefined) {
  method selectionFg (line 223) | get selectionFg(): RGBA | undefined {
  method selectionFg (line 227) | set selectionFg(value: RGBA | string | undefined) {
  method backgroundColor (line 238) | get backgroundColor(): RGBA {
  method backgroundColor (line 242) | set backgroundColor(value: RGBA | string | undefined) {
  method attributes (line 251) | get attributes(): number {
  method attributes (line 255) | set attributes(value: number) {
  method wrapMode (line 263) | get wrapMode(): "none" | "char" | "word" {
  method wrapMode (line 267) | set wrapMode(value: "none" | "char" | "word") {
  method showCursor (line 276) | get showCursor(): boolean {
  method showCursor (line 280) | set showCursor(value: boolean) {
  method cursorColor (line 290) | get cursorColor(): RGBA {
  method cursorColor (line 294) | set cursorColor(value: RGBA | string) {
  method cursorStyle (line 304) | get cursorStyle(): CursorStyleOptions {
  method cursorStyle (line 308) | set cursorStyle(style: CursorStyleOptions) {
  method tabIndicator (line 318) | get tabIndicator(): string | number | undefined {
  method tabIndicator (line 322) | set tabIndicator(value: string | number | undefined) {
  method tabIndicatorColor (line 332) | get tabIndicatorColor(): RGBA | undefined {
  method tabIndicatorColor (line 336) | set tabIndicatorColor(value: RGBA | string | undefined) {
  method scrollSpeed (line 347) | get scrollSpeed(): number {
  method scrollSpeed (line 351) | set scrollSpeed(value: number) {
  method onMouseEvent (line 355) | protected override onMouseEvent(event: any): void {
  method handleScroll (line 361) | protected handleScroll(event: any): void {
  method onResize (line 392) | protected onResize(width: number, height: number): void {
  method refreshLocalSelection (line 396) | protected refreshLocalSelection(): boolean {
  method updateLocalSelection (line 403) | private updateLocalSelection(localSelection: LocalSelectionBounds | null...
  method shouldStartSelection (line 419) | shouldStartSelection(x: number, y: number): boolean {
  method onSelectionChanged (line 428) | onSelectionChanged(selection: Selection | null): boolean {
  method onUpdate (line 489) | protected override onUpdate(deltaTime: number): void {
  method getSelectedText (line 515) | getSelectedText(): string {
  method hasSelection (line 519) | hasSelection(): boolean {
  method getSelection (line 523) | getSelection(): { start: number; end: number } | null {
  method setupMeasureFunc (line 530) | private setupMeasureFunc(): void {
  method render (line 574) | render(buffer: OptimizedBuffer, deltaTime: number): void {
  method renderSelf (line 585) | protected renderSelf(buffer: OptimizedBuffer): void {
  method renderCursor (line 589) | protected renderCursor(buffer: OptimizedBuffer): void {
  method focus (line 601) | public focus(): void {
  method blur (line 607) | public blur(): void {
  method onRemove (line 613) | protected onRemove(): void {
  method destroy (line 619) | override destroy(): void {
  method onCursorChange (line 639) | public set onCursorChange(handler: ((event: CursorChangeEvent) => void) ...
  method onCursorChange (line 643) | public get onCursorChange(): ((event: CursorChangeEvent) => void) | unde...
  method onContentChange (line 647) | public set onContentChange(handler: ((event: ContentChangeEvent) => void...
  method onContentChange (line 651) | public get onContentChange(): ((event: ContentChangeEvent) => void) | un...
  method syntaxStyle (line 655) | get syntaxStyle(): SyntaxStyle | null {
  method syntaxStyle (line 659) | set syntaxStyle(style: SyntaxStyle | null) {
  method addHighlight (line 664) | public addHighlight(lineIdx: number, highlight: Highlight): void {
  method addHighlightByCharRange (line 669) | public addHighlightByCharRange(highlight: Highlight): void {
  method removeHighlightsByRef (line 674) | public removeHighlightsByRef(hlRef: number): void {
  method clearLineHighlights (line 679) | public clearLineHighlights(lineIdx: number): void {
  method clearAllHighlights (line 684) | public clearAllHighlights(): void {
  method getLineHighlights (line 689) | public getLineHighlights(lineIdx: number): Array<Highlight> {
  method setText (line 697) | public setText(text: string): void {
  method replaceText (line 707) | public replaceText(text: string): void {
  method clear (line 713) | public clear(): void {
  method deleteRange (line 720) | public deleteRange(startLine: number, startCol: number, endLine: number,...
  method insertText (line 726) | public insertText(text: string): void {
  method getTextRange (line 732) | public getTextRange(startOffset: number, endOffset: number): string {
  method getTextRangeByCoords (line 736) | public getTextRangeByCoords(startRow: number, startCol: number, endRow: ...
  method updateSelectionForMovement (line 740) | protected updateSelectionForMovement(shiftPressed: boolean, isBeforeMove...

FILE: packages/core/src/renderables/FrameBuffer.ts
  type FrameBufferOptions (line 5) | interface FrameBufferOptions extends RenderableOptions<FrameBufferRender...
  class FrameBufferRenderable (line 11) | class FrameBufferRenderable extends Renderable {
    method constructor (line 15) | constructor(ctx: RenderContext, options: FrameBufferOptions) {
    method onResize (line 24) | protected onResize(width: number, height: number): void {
    method renderSelf (line 34) | protected renderSelf(buffer: OptimizedBuffer): void {
    method destroySelf (line 39) | protected destroySelf(): void {

FILE: packages/core/src/renderables/Input.test.ts
  function createInputRenderable (line 9) | function createInputRenderable(options: InputRenderableOptions): { input...
  function createInputRenderableForMod (line 877) | function createInputRenderableForMod(options: Partial<InputRenderableOpt...

FILE: packages/core/src/renderables/Input.ts
  type InputAction (line 11) | type InputAction = TextareaAction
  type InputKeyBinding (line 12) | type InputKeyBinding = TextareaKeyBinding
  type InputRenderableOptions (line 14) | interface InputRenderableOptions
  type InputRenderableEvents (line 25) | enum InputRenderableEvents {
  class InputRenderable (line 42) | class InputRenderable extends TextareaRenderable {
    method constructor (line 55) | constructor(ctx: RenderContext, options: InputRenderableOptions) {
    method newLine (line 89) | public override newLine(): boolean {
    method handlePaste (line 96) | public override handlePaste(event: PasteEvent): void {
    method insertText (line 106) | public override insertText(text: string): void {
    method value (line 119) | public get value(): string {
    method value (line 123) | public set value(value: string) {
    method focus (line 133) | public override focus(): void {
    method blur (line 138) | public override blur(): void {
    method submit (line 149) | public override submit(): boolean {
    method deleteCharBackward (line 159) | public override deleteCharBackward(): boolean {
    method deleteChar (line 165) | public override deleteChar(): boolean {
    method deleteLine (line 171) | public override deleteLine(): boolean {
    method deleteWordBackward (line 177) | public override deleteWordBackward(): boolean {
    method deleteWordForward (line 183) | public override deleteWordForward(): boolean {
    method deleteToLineStart (line 189) | public override deleteToLineStart(): boolean {
    method deleteToLineEnd (line 195) | public override deleteToLineEnd(): boolean {
    method undo (line 201) | public override undo(): boolean {
    method redo (line 207) | public override redo(): boolean {
    method deleteCharacter (line 213) | public deleteCharacter(direction: "backward" | "forward"): void {
    method maxLength (line 221) | public set maxLength(maxLength: number) {
    method maxLength (line 229) | public get maxLength(): number {
    method placeholder (line 233) | public override set placeholder(placeholder: string) {
    method placeholder (line 237) | public override get placeholder(): string {
    method initialValue (line 242) | public override set initialValue(value: string) {

FILE: packages/core/src/renderables/LineNumberRenderable.ts
  type LineSign (line 7) | interface LineSign {
  type LineColorConfig (line 14) | interface 
Condensed preview — 663 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (8,782K chars).
[
  {
    "path": ".editorconfig",
    "chars": 136,
    "preview": "root = true\n\n[*]\ncharset = utf-8\ninsert_final_newline = true\nend_of_line = lf\nindent_style = space\nindent_size = 2\nmax_l"
  },
  {
    "path": ".github/CODEOWNERS",
    "chars": 203,
    "preview": "*                   @kommander @msmps @Hona @simonklee\n/packages/react/    @msmps @Adictya @fezproof @kommander @Hona @s"
  },
  {
    "path": ".github/workflows/build-core.yml",
    "chars": 2935,
    "preview": "name: Build Core\n\non:\n  push:\n  pull_request:\n    branches: [main]\n\nenv:\n  ZIG_VERSION: 0.15.2\n  # Workaround for bug in"
  },
  {
    "path": ".github/workflows/build-examples.yml",
    "chars": 9366,
    "preview": "name: Build Examples\n\non:\n  workflow_call:\n    inputs:\n      version:\n        description: \"Version being released\"\n    "
  },
  {
    "path": ".github/workflows/build-native.yml",
    "chars": 9620,
    "preview": "name: Build Native\n\non:\n  workflow_call:\n    inputs:\n      version:\n        description: \"Version being released\"\n      "
  },
  {
    "path": ".github/workflows/build-react.yml",
    "chars": 1434,
    "preview": "name: Build React\n\non:\n  push:\n  pull_request:\n    branches: [main]\n\nenv:\n  # Workaround for bug in Zig 0.15.2 (fixed in"
  },
  {
    "path": ".github/workflows/build-solid.yml",
    "chars": 1434,
    "preview": "name: Build Solid\n\non:\n  push:\n  pull_request:\n    branches: [main]\n\nenv:\n  # Workaround for bug in Zig 0.15.2 (fixed in"
  },
  {
    "path": ".github/workflows/deploy.yml",
    "chars": 711,
    "preview": "name: Deploy to GitHub Pages\n\non:\n  push:\n    branches: [main]\n  workflow_dispatch:\n\npermissions:\n  contents: read\n  pag"
  },
  {
    "path": ".github/workflows/npm-latest-release.yml",
    "chars": 3765,
    "preview": "name: NPM Publish\n\non:\n  workflow_call:\n    inputs:\n      version:\n        description: \"Version being published\"\n      "
  },
  {
    "path": ".github/workflows/npm-release.yml",
    "chars": 1645,
    "preview": "name: NPM Snapshot Release\n\non:\n  push:\n    tags:\n      - \"*snapshot*\"\n\npermissions:\n  contents: write\n  pull-requests: "
  },
  {
    "path": ".github/workflows/opencode.yml",
    "chars": 686,
    "preview": "name: opencode\n\non:\n  issue_comment:\n    types: [created]\n\njobs:\n  opencode:\n    if: |\n      contains(github.event.comme"
  },
  {
    "path": ".github/workflows/pkg-pr-new.yml",
    "chars": 1922,
    "preview": "name: Publish Preview Packages\n\non:\n  issue_comment:\n    types: [created]\n\npermissions: {}\n\njobs:\n  publish:\n    name: P"
  },
  {
    "path": ".github/workflows/prettier.yml",
    "chars": 865,
    "preview": "name: Format\n\non:\n  pull_request:\n    branches: [main]\n\njobs:\n  prettier-core:\n    name: Prettier Check\n    runs-on: ubu"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 8657,
    "preview": "name: Release\n\non:\n  push:\n    tags:\n      - \"v*\"\n\npermissions:\n  contents: write\n  pull-requests: write\n\njobs:\n  # Extr"
  },
  {
    "path": ".github/workflows/review.yml",
    "chars": 3559,
    "preview": "name: Guidelines Check\n\non:\n  issue_comment:\n    types: [created]\n\njobs:\n  check-guidelines:\n    if: |\n      github.even"
  },
  {
    "path": ".gitignore",
    "chars": 438,
    "preview": "# dependencies (bun install)\nnode_modules\n\nSession.vim\n\n# output\nout\ndist\npacked\n*.tgz\n*.log\n*.txt\n\n# code coverage\ncove"
  },
  {
    "path": ".prettierignore",
    "chars": 70,
    "preview": "**/.zig-cache/**\npackages/core/src/lib/tree-sitter/default-parsers.ts\n"
  },
  {
    "path": ".zig-version",
    "chars": 7,
    "preview": "0.15.2\n"
  },
  {
    "path": "AGENTS.md",
    "chars": 2493,
    "preview": "# Agent Guidelines for opentui\n\nDefault to using Bun instead of Node.js.\n\n- Use `bun <file>` instead of `node <file>` or"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 674,
    "preview": "# Contributing to Opentui\n\nBug fixes and feature suggestions are always welcome. For bug fixes, open a PR\nfor reviews. F"
  },
  {
    "path": "LICENSE",
    "chars": 1063,
    "preview": "MIT License\n\nCopyright (c) 2025 opentui\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
  },
  {
    "path": "README.md",
    "chars": 3343,
    "preview": "# OpenTUI\n\n<div align=\"center\">\n    <a href=\"https://www.npmjs.com/package/@opentui/core\"><img alt=\"npm\" src=\"https://im"
  },
  {
    "path": "opentui.pc.in",
    "chars": 234,
    "preview": "prefix=@PREFIX@\nlibdir=${prefix}/lib\nincludedir=${prefix}/include\n\nName: OpenTUI\nDescription: High-performance terminal "
  },
  {
    "path": "package.json",
    "chars": 923,
    "preview": "{\n  \"name\": \"@opentui\",\n  \"private\": true,\n  \"workspaces\": [\n    \"packages/*\",\n    \"packages/solid/examples\"\n  ],\n  \"scr"
  },
  {
    "path": "packages/core/.gitignore",
    "chars": 49,
    "preview": "# Zig build cache\n.zig-cache\nzig-out\nsrc/zig/lib\n"
  },
  {
    "path": "packages/core/README.md",
    "chars": 1812,
    "preview": "# OpenTUI Core\n\nOpenTUI is a native terminal UI core written in Zig with TypeScript bindings. The native core exposes a "
  },
  {
    "path": "packages/core/dev/keypress-debug-renderer.ts",
    "chars": 3684,
    "preview": "#!/usr/bin/env bun\nimport { BoxRenderable, type CliRenderer, createCliRenderer, CodeRenderable, addDefaultParsers } from"
  },
  {
    "path": "packages/core/dev/keypress-debug.ts",
    "chars": 1158,
    "preview": "#!/usr/bin/env bun\nimport { parseKeypress } from \"../src/lib/parse.keypress.ts\"\n\nconsole.log(\"Keypress Debug Tool\")\ncons"
  },
  {
    "path": "packages/core/dev/print-env-vars.ts",
    "chars": 1079,
    "preview": "#!/usr/bin/env bun\n\n/**\n * Development script to print all registered environment variables\n *\n * Usage:\n *   bun dev/pr"
  },
  {
    "path": "packages/core/dev/test-tmux-graphics-334.sh",
    "chars": 2046,
    "preview": "#!/bin/bash\n# Test script for issue #334: Kitty Graphics Protocol query leaks into tmux pane title\n#\n# This script verif"
  },
  {
    "path": "packages/core/dev/thai-debug-test.ts",
    "chars": 2864,
    "preview": "#!/usr/bin/env bun\nimport { TextRenderable, createCliRenderer } from \"../src/index.js\"\nimport { ScrollBoxRenderable } fr"
  },
  {
    "path": "packages/core/docs/development.md",
    "chars": 3429,
    "preview": "# Development Guide\n\n## Prerequisites\n\n- [Bun](https://bun.sh) - JavaScript runtime and package manager\n- [Zig](https://"
  },
  {
    "path": "packages/core/package.json",
    "chars": 3243,
    "preview": "{\n  \"name\": \"@opentui/core\",\n  \"description\": \"OpenTUI is a TypeScript library on a native Zig core for building termina"
  },
  {
    "path": "packages/core/scripts/build.ts",
    "chars": 12359,
    "preview": "import { spawnSync, type SpawnSyncReturns } from \"node:child_process\"\nimport { copyFileSync, existsSync, mkdirSync, read"
  },
  {
    "path": "packages/core/scripts/publish.ts",
    "chars": 2040,
    "preview": "import { spawnSync, type SpawnSyncReturns } from \"node:child_process\"\nimport { existsSync, readFileSync } from \"node:fs\""
  },
  {
    "path": "packages/core/src/3d/SpriteResourceManager.ts",
    "chars": 7979,
    "preview": "import * as THREE from \"three\"\nimport { TextureUtils } from \"./TextureUtils.js\"\nimport type { Scene } from \"three\"\n\nexpo"
  },
  {
    "path": "packages/core/src/3d/SpriteUtils.ts",
    "chars": 2186,
    "preview": "import { TextureUtils } from \"./TextureUtils.js\"\nimport { Sprite, SpriteMaterial, DataTexture, type SpriteMaterialParame"
  },
  {
    "path": "packages/core/src/3d/TextureUtils.ts",
    "chars": 6274,
    "preview": "import { readFile } from \"node:fs/promises\"\nimport { Color, Texture, DataTexture, NearestFilter, ClampToEdgeWrapping, RG"
  },
  {
    "path": "packages/core/src/3d/ThreeRenderable.ts",
    "chars": 6222,
    "preview": "import { OrthographicCamera, PerspectiveCamera, Scene } from \"three\"\n\nimport { OptimizedBuffer } from \"../buffer.js\"\nimp"
  },
  {
    "path": "packages/core/src/3d/WGPURenderer.ts",
    "chars": 9490,
    "preview": "import { PerspectiveCamera, OrthographicCamera, Color, NoToneMapping, LinearSRGBColorSpace, Scene } from \"three\"\nimport "
  },
  {
    "path": "packages/core/src/3d/animation/ExplodingSpriteEffect.ts",
    "chars": 18309,
    "preview": "import * as THREE from \"three\"\nimport {\n  uniform,\n  attribute,\n  texture as tslTexture,\n  uv,\n  float,\n  vec2,\n  vec3,\n"
  },
  {
    "path": "packages/core/src/3d/animation/PhysicsExplodingSpriteEffect.ts",
    "chars": 14420,
    "preview": "import * as THREE from \"three\"\nimport { texture as tslTexture, uv, vec2, attribute } from \"three/tsl\"\nimport { MeshBasic"
  },
  {
    "path": "packages/core/src/3d/animation/SpriteAnimator.ts",
    "chars": 20379,
    "preview": "import * as THREE from \"three\"\nimport { uniform, texture as tslTexture, uv, float, vec2, bufferAttribute, mix } from \"th"
  },
  {
    "path": "packages/core/src/3d/animation/SpriteParticleGenerator.ts",
    "chars": 16329,
    "preview": "import * as THREE from \"three\"\nimport {\n  uniform,\n  texture as tslTexture,\n  uv,\n  float,\n  vec2,\n  vec3,\n  vec4,\n  buf"
  },
  {
    "path": "packages/core/src/3d/canvas.ts",
    "chars": 15824,
    "preview": "import { GPUCanvasContextMock } from \"bun-webgpu\"\nimport { RGBA } from \"../lib/RGBA.js\"\nimport { SuperSampleType } from "
  },
  {
    "path": "packages/core/src/3d/index.ts",
    "chars": 523,
    "preview": "export * from \"./WGPURenderer.js\"\nexport * from \"./ThreeRenderable.js\"\nexport * from \"./TextureUtils.js\"\nexport * from \""
  },
  {
    "path": "packages/core/src/3d/physics/PlanckPhysicsAdapter.ts",
    "chars": 2107,
    "preview": "import * as planck from \"planck\"\nimport type {\n  PhysicsVector2,\n  PhysicsRigidBodyDesc,\n  PhysicsColliderDesc,\n  Physic"
  },
  {
    "path": "packages/core/src/3d/physics/RapierPhysicsAdapter.ts",
    "chars": 2081,
    "preview": "import RAPIER from \"@dimforge/rapier2d-simd-compat\"\nimport type {\n  PhysicsVector2,\n  PhysicsRigidBodyDesc,\n  PhysicsCol"
  },
  {
    "path": "packages/core/src/3d/physics/physics-interface.ts",
    "chars": 740,
    "preview": "export interface PhysicsVector2 {\n  x: number\n  y: number\n}\n\nexport interface PhysicsRigidBodyDesc {\n  translation: Phys"
  },
  {
    "path": "packages/core/src/3d/shaders/supersampling.wgsl",
    "chars": 6626,
    "preview": "struct CellResult {\n    bg: vec4<f32>,      // Background RGBA (16 bytes)\n    fg: vec4<f32>,      // Foreground RGBA (16"
  },
  {
    "path": "packages/core/src/3d.ts",
    "chars": 115,
    "preview": "// 3D module exports - requires optional dependencies\nexport * from \"./3d/index.js\"\nexport * as THREE from \"three\"\n"
  },
  {
    "path": "packages/core/src/NativeSpanFeed.ts",
    "chars": 8865,
    "preview": "import { toArrayBuffer, type Pointer } from \"bun:ffi\"\nimport { resolveRenderLib } from \"./zig\"\nimport { SpanInfoStruct }"
  },
  {
    "path": "packages/core/src/Renderable.ts",
    "chars": 49163,
    "preview": "import { EventEmitter } from \"events\"\nimport Yoga, { Direction, Display, Edge, FlexDirection, type Config, type Node as "
  },
  {
    "path": "packages/core/src/__snapshots__/buffer.test.ts.snap",
    "chars": 781,
    "preview": "// Bun Snapshot v1, https://bun.sh/docs/test/snapshots\n\nexports[`OptimizedBuffer snapshot tests with unicode encoding sh"
  },
  {
    "path": "packages/core/src/animation/Timeline.test.ts",
    "chars": 71490,
    "preview": "import { expect, describe, it, beforeEach, afterEach } from \"bun:test\"\nimport { createTimeline, Timeline, type JSAnimati"
  },
  {
    "path": "packages/core/src/animation/Timeline.ts",
    "chars": 16464,
    "preview": "import type { CliRenderer } from \"../renderer.js\"\n\nexport interface TimelineOptions {\n  duration?: number\n  loop?: boole"
  },
  {
    "path": "packages/core/src/ansi.ts",
    "chars": 592,
    "preview": "export const ANSI = {\n  switchToAlternateScreen: \"\\x1b[?1049h\",\n  switchToMainScreen: \"\\x1b[?1049l\",\n  reset: \"\\x1b[0m\","
  },
  {
    "path": "packages/core/src/benchmark/.gitignore",
    "chars": 153,
    "preview": "*.json\n!latest-quick-bench-run.json\n!latest-default-bench-run.json\n!latest-large-bench-run.json\n!latest-all-bench-run.js"
  },
  {
    "path": "packages/core/src/benchmark/attenuation-benchmark.ts",
    "chars": 2383,
    "preview": "#!/usr/bin/env bun\n\nimport { performance } from \"node:perf_hooks\"\nimport { OptimizedBuffer } from \"../buffer\"\nimport { V"
  },
  {
    "path": "packages/core/src/benchmark/colormatrix-benchmark.ts",
    "chars": 3737,
    "preview": "#!/usr/bin/env bun\n\nimport { performance } from \"node:perf_hooks\"\nimport { OptimizedBuffer } from \"../buffer\"\n\ntype Scen"
  },
  {
    "path": "packages/core/src/benchmark/gain-benchmark.ts",
    "chars": 2316,
    "preview": "#!/usr/bin/env bun\n\nimport { performance } from \"node:perf_hooks\"\nimport { OptimizedBuffer } from \"../buffer\"\nimport { a"
  },
  {
    "path": "packages/core/src/benchmark/latest-all-bench-run.json",
    "chars": 17308,
    "preview": "{\n  \"runId\": \"2026-02-11T12:21:31.262Z\",\n  \"suite\": \"all\",\n  \"args\": [\"--suite=all\", \"--json=src/benchmark/latest-all-be"
  },
  {
    "path": "packages/core/src/benchmark/latest-async-bench-run.json",
    "chars": 8814,
    "preview": "{\n  \"runId\": \"2026-02-11T12:21:35.239Z\",\n  \"suite\": \"async\",\n  \"args\": [\"--json=src/benchmark/latest-async-bench-run.jso"
  },
  {
    "path": "packages/core/src/benchmark/latest-default-bench-run.json",
    "chars": 16087,
    "preview": "{\n  \"runId\": \"2026-02-11T12:21:27.641Z\",\n  \"suite\": \"default\",\n  \"args\": [\"--suite=default\", \"--json=src/benchmark/lates"
  },
  {
    "path": "packages/core/src/benchmark/latest-large-bench-run.json",
    "chars": 17332,
    "preview": "{\n  \"runId\": \"2026-02-11T12:21:29.304Z\",\n  \"suite\": \"large\",\n  \"args\": [\"--suite=large\", \"--json=src/benchmark/latest-la"
  },
  {
    "path": "packages/core/src/benchmark/latest-quick-bench-run.json",
    "chars": 5030,
    "preview": "{\n  \"runId\": \"2026-02-11T12:21:26.541Z\",\n  \"suite\": \"quick\",\n  \"args\": [\"--suite=quick\", \"--json=src/benchmark/latest-qu"
  },
  {
    "path": "packages/core/src/benchmark/markdown-benchmark.ts",
    "chars": 54599,
    "preview": "#!/usr/bin/env bun\n\nimport { MarkdownRenderable, SyntaxStyle, createCliRenderer, parseColor } from \"../index\"\nimport { r"
  },
  {
    "path": "packages/core/src/benchmark/native-span-feed-async-benchmark.ts",
    "chars": 9743,
    "preview": "import { dlopen, FFIType, suffix } from \"bun:ffi\"\nimport { setRenderLibPath } from \"../zig\"\n\nif (!process.env.NATIVE_SPA"
  },
  {
    "path": "packages/core/src/benchmark/native-span-feed-benchmark.md",
    "chars": 1915,
    "preview": "# NativeSpanFeed Benchmarks\n\n## Benchmark\n\n### Build\n\nThe benchmark library (`libnative_span_feed_bench`) is built by th"
  },
  {
    "path": "packages/core/src/benchmark/native-span-feed-benchmark.ts",
    "chars": 17385,
    "preview": "import { dlopen, FFIType, suffix } from \"bun:ffi\"\nimport { setRenderLibPath } from \"../zig\"\n\nif (!process.env.NATIVE_SPA"
  },
  {
    "path": "packages/core/src/benchmark/native-span-feed-compare.ts",
    "chars": 8578,
    "preview": "import { readFileSync, writeFileSync } from \"node:fs\"\nimport { basename } from \"node:path\"\n\ntype ScenarioResult = {\n  na"
  },
  {
    "path": "packages/core/src/benchmark/renderer-benchmark.ts",
    "chars": 24716,
    "preview": "#!/usr/bin/env bun\n\nimport { createCliRenderer, RGBA, TextRenderable, BoxRenderable, FrameBufferRenderable } from \"../in"
  },
  {
    "path": "packages/core/src/benchmark/text-table-benchmark.ts",
    "chars": 26978,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  TextTableRenderable,\n  type TextTableCellContent,\n  type TextTableColumnFitter,\n  type Te"
  },
  {
    "path": "packages/core/src/buffer.test.ts",
    "chars": 9549,
    "preview": "import { describe, expect, it, beforeEach, afterEach } from \"bun:test\"\nimport { OptimizedBuffer } from \"./buffer.js\"\nimp"
  },
  {
    "path": "packages/core/src/buffer.ts",
    "chars": 15197,
    "preview": "import { RGBA } from \"./lib\"\nimport { resolveRenderLib, type RenderLib } from \"./zig\"\nimport { type Pointer, toArrayBuff"
  },
  {
    "path": "packages/core/src/console.test.ts",
    "chars": 21970,
    "preview": "import { test, expect, describe, mock, beforeEach } from \"bun:test\"\nimport { TerminalConsole, ConsolePosition } from \"./"
  },
  {
    "path": "packages/core/src/console.ts",
    "chars": 39763,
    "preview": "import { EventEmitter } from \"events\"\nimport { Console } from \"node:console\"\nimport fs from \"node:fs\"\nimport path from \""
  },
  {
    "path": "packages/core/src/edit-buffer.test.ts",
    "chars": 49579,
    "preview": "import { describe, expect, it, beforeEach, afterEach } from \"bun:test\"\nimport { EditBuffer } from \"./edit-buffer.js\"\n\nde"
  },
  {
    "path": "packages/core/src/edit-buffer.ts",
    "chars": 11783,
    "preview": "import { resolveRenderLib, type LogicalCursor, type RenderLib } from \"./zig.js\"\nimport { type Pointer } from \"bun:ffi\"\ni"
  },
  {
    "path": "packages/core/src/editor-view.test.ts",
    "chars": 31913,
    "preview": "import { describe, expect, it, beforeEach, afterEach } from \"bun:test\"\nimport { EditBuffer } from \"./edit-buffer.js\"\nimp"
  },
  {
    "path": "packages/core/src/editor-view.ts",
    "chars": 7716,
    "preview": "import { RGBA } from \"./lib/RGBA.js\"\nimport { resolveRenderLib, type RenderLib, type VisualCursor, type LineInfo } from "
  },
  {
    "path": "packages/core/src/examples/ascii-font-selection-demo.ts",
    "chars": 7147,
    "preview": "#!/usr/bin/env bun\n\nimport { CliRenderer, createCliRenderer, BoxRenderable, TextRenderable, RGBA } from \"../index.js\"\nim"
  },
  {
    "path": "packages/core/src/examples/assets/hast-example.json",
    "chars": 33584,
    "preview": "{\n  \"type\": \"element\",\n  \"tagName\": \"pre\",\n  \"children\": [\n    {\n      \"type\": \"element\",\n      \"tagName\": \"code\",\n     "
  },
  {
    "path": "packages/core/src/examples/build.ts",
    "chars": 3678,
    "preview": "#!/usr/bin/env bun\n\nimport { mkdirSync } from \"node:fs\"\nimport { readFile } from \"node:fs/promises\"\nimport { join, dirna"
  },
  {
    "path": "packages/core/src/examples/code-demo.ts",
    "chars": 17399,
    "preview": "import {\n  CliRenderer,\n  createCliRenderer,\n  CodeRenderable,\n  BoxRenderable,\n  TextRenderable,\n  type ParsedKey,\n  Sc"
  },
  {
    "path": "packages/core/src/examples/console-demo.ts",
    "chars": 9420,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  RGBA,\n  TextAttributes,\n  TextRenderable,\n  BoxRender"
  },
  {
    "path": "packages/core/src/examples/core-plugin-slots-demo.ts",
    "chars": 20189,
    "preview": "import {\n  BoxRenderable,\n  type CliRenderer,\n  createCliRenderer,\n  createCoreSlotRegistry,\n  registerCorePlugin,\n  Slo"
  },
  {
    "path": "packages/core/src/examples/diff-demo.ts",
    "chars": 21756,
    "preview": "import {\n  CliRenderer,\n  createCliRenderer,\n  DiffRenderable,\n  BoxRenderable,\n  TextRenderable,\n  type ParsedKey,\n} fr"
  },
  {
    "path": "packages/core/src/examples/draggable-three-demo.ts",
    "chars": 7035,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  RGBA,\n  BoxRenderable,\n  TextRenderable,\n  type KeyEv"
  },
  {
    "path": "packages/core/src/examples/editor-demo.ts",
    "chars": 11720,
    "preview": "import {\n  CliRenderer,\n  createCliRenderer,\n  TextareaRenderable,\n  BoxRenderable,\n  TextRenderable,\n  LineNumberRender"
  },
  {
    "path": "packages/core/src/examples/extmarks-demo.ts",
    "chars": 5721,
    "preview": "import {\n  CliRenderer,\n  createCliRenderer,\n  TextareaRenderable,\n  BoxRenderable,\n  TextRenderable,\n  KeyEvent,\n  type"
  },
  {
    "path": "packages/core/src/examples/focus-restore-demo.ts",
    "chars": 8171,
    "preview": "#!/usr/bin/env bun\n\n// Interactive demo to test the focus restore fix on Windows Terminal.\n//\n// How to test:\n//   1. Ru"
  },
  {
    "path": "packages/core/src/examples/fonts.ts",
    "chars": 5983,
    "preview": "import {\n  BoxRenderable,\n  CliRenderer,\n  createCliRenderer,\n  FrameBufferRenderable,\n  RGBA,\n  TextRenderable,\n  type "
  },
  {
    "path": "packages/core/src/examples/fractal-shader-demo.ts",
    "chars": 7073,
    "preview": "#!/usr/bin/env bun\n\nimport { BoxRenderable, CliRenderer, createCliRenderer, RGBA, TextRenderable, type KeyEvent } from \""
  },
  {
    "path": "packages/core/src/examples/framebuffer-demo.ts",
    "chars": 19921,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  RGBA,\n  TextAttributes,\n  TextRenderable,\n  FrameBuff"
  },
  {
    "path": "packages/core/src/examples/full-unicode-demo.ts",
    "chars": 4940,
    "preview": "import {\n  createCliRenderer,\n  RGBA,\n  FrameBufferRenderable,\n  TextRenderable,\n  t,\n  blue,\n  bold,\n  underline,\n  fg,"
  },
  {
    "path": "packages/core/src/examples/golden-star-demo.ts",
    "chars": 31002,
    "preview": "#!/usr/bin/env bun\n\nimport { createCliRenderer, CliRenderer, FrameBufferRenderable, BoxRenderable, OptimizedBuffer } fro"
  },
  {
    "path": "packages/core/src/examples/grayscale-buffer-demo.ts",
    "chars": 7600,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  OptimizedBuffer,\n  RGBA,\n  FrameBufferRenderable,\n  t"
  },
  {
    "path": "packages/core/src/examples/hast-syntax-highlighting-demo.ts",
    "chars": 4177,
    "preview": "import { CliRenderer, createCliRenderer, TextRenderable, BoxRenderable, type KeyEvent } from \"../index.js\"\nimport { setu"
  },
  {
    "path": "packages/core/src/examples/index.ts",
    "chars": 29357,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  ASCIIFontRenderable,\n  BoxRenderable,\n  CliRenderer,\n  createCliRenderer,\n  FrameBufferRe"
  },
  {
    "path": "packages/core/src/examples/input-demo.ts",
    "chars": 10405,
    "preview": "import {\n  createCliRenderer,\n  InputRenderable,\n  InputRenderableEvents,\n  RenderableEvents,\n  type CliRenderer,\n  t,\n "
  },
  {
    "path": "packages/core/src/examples/input-select-layout-demo.ts",
    "chars": 11348,
    "preview": "import { CliRenderer, BoxRenderable, TextRenderable, createCliRenderer, type KeyEvent } from \"../index.js\"\nimport { Inpu"
  },
  {
    "path": "packages/core/src/examples/install.sh",
    "chars": 3744,
    "preview": "#!/bin/sh\nset -e\n\n# OpenTUI Examples Installation Script\n# Downloads and runs the latest opentui-examples binary\n\nREPO=\""
  },
  {
    "path": "packages/core/src/examples/keypress-debug-demo.ts",
    "chars": 11880,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  type CliRenderer,\n  createCliRenderer,\n  BoxRenderable,\n  TextRenderable,\n  type KeyEvent"
  },
  {
    "path": "packages/core/src/examples/lib/HexList.ts",
    "chars": 3890,
    "preview": "import type { RenderableOptions } from \"../../Renderable.js\"\nimport { RGBA } from \"../../lib/RGBA.js\"\nimport { FrameBuff"
  },
  {
    "path": "packages/core/src/examples/lib/PaletteGrid.ts",
    "chars": 4029,
    "preview": "import type { RenderableOptions } from \"../../Renderable.js\"\nimport { RGBA } from \"../../lib/RGBA.js\"\nimport { FrameBuff"
  },
  {
    "path": "packages/core/src/examples/lib/standalone-keys.ts",
    "chars": 959,
    "preview": "import { resolveRenderLib, type CliRenderer, type KeyEvent } from \"../../index.js\"\n\nexport function setupCommonDemoKeys("
  },
  {
    "path": "packages/core/src/examples/lib/tab-controller.ts",
    "chars": 6694,
    "preview": "import { Renderable, type RenderableOptions, RenderableEvents } from \"../../Renderable.js\"\nimport { OptimizedBuffer } fr"
  },
  {
    "path": "packages/core/src/examples/lights-phong-demo.ts",
    "chars": 8318,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  RGBA,\n  BoxRenderable,\n  TextRenderable,\n  FrameBuffe"
  },
  {
    "path": "packages/core/src/examples/link-demo.ts",
    "chars": 5330,
    "preview": "import {\n  CliRenderer,\n  createCliRenderer,\n  t,\n  fg,\n  underline,\n  link,\n  bold,\n  italic,\n  BoxRenderable,\n  RGBA,\n"
  },
  {
    "path": "packages/core/src/examples/live-state-demo.ts",
    "chars": 13537,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  RGBA,\n  TextAttributes,\n  TextRenderable,\n  BoxRender"
  },
  {
    "path": "packages/core/src/examples/markdown-demo.ts",
    "chars": 23503,
    "preview": "import {\n  CliRenderer,\n  CliRenderEvents,\n  createCliRenderer,\n  BoxRenderable,\n  TextRenderable,\n  type ParsedKey,\n  S"
  },
  {
    "path": "packages/core/src/examples/mouse-interaction-demo.ts",
    "chars": 11759,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  RGBA,\n  TextAttributes,\n  FrameBufferRenderable,\n  Te"
  },
  {
    "path": "packages/core/src/examples/nested-zindex-demo.ts",
    "chars": 9090,
    "preview": "import { TextAttributes, createCliRenderer, TextRenderable, BoxRenderable, type KeyEvent } from \"../index.js\"\nimport { s"
  },
  {
    "path": "packages/core/src/examples/opacity-example.ts",
    "chars": 6026,
    "preview": "import { CliRenderer, BoxRenderable, TextRenderable, createCliRenderer, type KeyEvent } from \"../index.js\"\nimport { setu"
  },
  {
    "path": "packages/core/src/examples/opentui-demo.ts",
    "chars": 29062,
    "preview": "import {\n  TextAttributes,\n  rgbToHex,\n  hsvToRgb,\n  createCliRenderer,\n  TextRenderable,\n  BoxRenderable,\n  parseColor,"
  },
  {
    "path": "packages/core/src/examples/physx-planck-2d-demo.ts",
    "chars": 14022,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  TextRenderable,\n  FrameBufferRenderable,\n  BoxRenderable,\n  createCliRende"
  },
  {
    "path": "packages/core/src/examples/physx-rapier-2d-demo.ts",
    "chars": 14928,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  TextRenderable,\n  FrameBufferRenderable,\n  BoxRenderable,\n  createCliRende"
  },
  {
    "path": "packages/core/src/examples/relative-positioning-demo.ts",
    "chars": 8209,
    "preview": "import { TextAttributes, createCliRenderer, TextRenderable, BoxRenderable, type KeyEvent } from \"../index.js\"\nimport { s"
  },
  {
    "path": "packages/core/src/examples/scroll-example.ts",
    "chars": 7733,
    "preview": "import {\n  ASCIIFontRenderable,\n  BoxRenderable,\n  type CliRenderer,\n  createCliRenderer,\n  TextRenderable,\n  RGBA,\n  t,"
  },
  {
    "path": "packages/core/src/examples/scrollbox-mouse-test.ts",
    "chars": 2913,
    "preview": "#!/usr/bin/env bun\nimport { BoxRenderable, type CliRenderer, createCliRenderer, TextRenderable, RGBA, t, fg, bold } from"
  },
  {
    "path": "packages/core/src/examples/scrollbox-overlay-hit-test.ts",
    "chars": 4923,
    "preview": "#!/usr/bin/env bun\nimport {\n  BoxRenderable,\n  type CliRenderer,\n  createCliRenderer,\n  TextRenderable,\n  t,\n  fg,\n  bol"
  },
  {
    "path": "packages/core/src/examples/select-demo.ts",
    "chars": 7834,
    "preview": "import {\n  createCliRenderer,\n  SelectRenderable,\n  SelectRenderableEvents,\n  RenderableEvents,\n  type SelectOption,\n  t"
  },
  {
    "path": "packages/core/src/examples/shader-cube-demo.ts",
    "chars": 35344,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  createCliRenderer,\n  CliRenderer,\n  TextRenderable,\n  BoxRenderable,\n  FrameBufferRendera"
  },
  {
    "path": "packages/core/src/examples/simple-layout-example.ts",
    "chars": 15240,
    "preview": "import { CliRenderer, BoxRenderable, TextRenderable, createCliRenderer, type KeyEvent } from \"../index.js\"\nimport { setu"
  },
  {
    "path": "packages/core/src/examples/slider-demo.ts",
    "chars": 17158,
    "preview": "import { type CliRenderer, createCliRenderer, t, fg, bold, BoxRenderable, TextRenderable } from \"../index.js\"\nimport { S"
  },
  {
    "path": "packages/core/src/examples/split-mode-demo.ts",
    "chars": 13527,
    "preview": "import { createCliRenderer, TextRenderable, t, type CliRenderer, BoxRenderable, bold, fg } from \"../index.js\"\nimport { s"
  },
  {
    "path": "packages/core/src/examples/sprite-animation-demo.ts",
    "chars": 13292,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  RGBA,\n  TextRenderable,\n  FrameBufferRenderable,\n  Bo"
  },
  {
    "path": "packages/core/src/examples/sprite-particle-generator-demo.ts",
    "chars": 15033,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  OptimizedBuffer,\n  RGBA,\n  BoxRenderable,\n  TextRende"
  },
  {
    "path": "packages/core/src/examples/static-sprite-demo.ts",
    "chars": 4735,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  RGBA,\n  TextRenderable,\n  FrameBufferRenderable,\n  Bo"
  },
  {
    "path": "packages/core/src/examples/sticky-scroll-example.ts",
    "chars": 9714,
    "preview": "import { BoxRenderable, type CliRenderer, createCliRenderer, TextRenderable, t, fg, bold } from \"../index.js\"\nimport { S"
  },
  {
    "path": "packages/core/src/examples/styled-text-demo.ts",
    "chars": 9817,
    "preview": "import {\n  CliRenderer,\n  createCliRenderer,\n  t,\n  blue,\n  bold,\n  underline,\n  red,\n  green,\n  bgYellow,\n  fg,\n  link,"
  },
  {
    "path": "packages/core/src/examples/tab-select-demo.ts",
    "chars": 6437,
    "preview": "import {\n  createCliRenderer,\n  TabSelectRenderable,\n  TabSelectRenderableEvents,\n  RenderableEvents,\n  BoxRenderable,\n "
  },
  {
    "path": "packages/core/src/examples/terminal-title.ts",
    "chars": 850,
    "preview": "import { TextRenderable, createCliRenderer } from \"../index.js\"\n\nasync function testTerminalTitle() {\n  const renderer ="
  },
  {
    "path": "packages/core/src/examples/terminal.ts",
    "chars": 9671,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  RGBA,\n  TextAttributes,\n  TextRenderable,\n  FrameBuff"
  },
  {
    "path": "packages/core/src/examples/text-node-demo.ts",
    "chars": 11099,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  TextRenderable,\n  BoxRenderable,\n  t,\n  bold,\n  under"
  },
  {
    "path": "packages/core/src/examples/text-selection-demo.ts",
    "chars": 9784,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  TextRenderable,\n  BoxRenderable,\n  t,\n  green,\n  bold"
  },
  {
    "path": "packages/core/src/examples/text-table-demo.ts",
    "chars": 15472,
    "preview": "import {\n  BoxRenderable,\n  CliRenderer,\n  ScrollBoxRenderable,\n  TextTableRenderable,\n  TextRenderable,\n  bold,\n  creat"
  },
  {
    "path": "packages/core/src/examples/text-truncation-demo.ts",
    "chars": 13093,
    "preview": "#!/usr/bin/env bun\n\nimport {\n  CliRenderer,\n  createCliRenderer,\n  TextRenderable,\n  BoxRenderable,\n  t,\n  green,\n  bold"
  },
  {
    "path": "packages/core/src/examples/text-wrap.ts",
    "chars": 24890,
    "preview": "#!/usr/bin/env bun\n/**\n * Text wrapping example\n * Demonstrates automatic text wrapping when the wrap option is enabled\n"
  },
  {
    "path": "packages/core/src/examples/texture-loading-demo.ts",
    "chars": 7069,
    "preview": "#!/usr/bin/env bun\n\nimport { CliRenderer, createCliRenderer, RGBA, BoxRenderable, TextRenderable, type KeyEvent } from \""
  },
  {
    "path": "packages/core/src/examples/timeline-example.ts",
    "chars": 18478,
    "preview": "import { createTimeline, type JSAnimation, Timeline } from \"../animation/Timeline.js\"\nimport { CliRenderer, createCliRen"
  },
  {
    "path": "packages/core/src/examples/transparency-demo.ts",
    "chars": 10155,
    "preview": "import {\n  TextAttributes,\n  createCliRenderer,\n  RGBA,\n  TextRenderable,\n  BoxRenderable,\n  OptimizedBuffer,\n  type Key"
  },
  {
    "path": "packages/core/src/examples/vnode-composition-demo.ts",
    "chars": 11757,
    "preview": "import { createCliRenderer, MouseEvent, type CliRenderer } from \"../renderer.js\"\nimport {\n  Box,\n  Text,\n  Generic,\n  ty"
  },
  {
    "path": "packages/core/src/index.ts",
    "chars": 806,
    "preview": "// Core exports without 3D dependencies\nexport * from \"./Renderable.js\"\nexport * from \"./types.js\"\nexport * from \"./util"
  },
  {
    "path": "packages/core/src/lib/KeyHandler.integration.test.ts",
    "chars": 8266,
    "preview": "import { test, expect } from \"bun:test\"\nimport { InternalKeyHandler, KeyEvent } from \"./KeyHandler.js\"\nimport { parseKey"
  },
  {
    "path": "packages/core/src/lib/KeyHandler.stopPropagation.test.ts",
    "chars": 7298,
    "preview": "import { test, expect } from \"bun:test\"\nimport { InternalKeyHandler, KeyEvent } from \"./KeyHandler.js\"\nimport { parseKey"
  },
  {
    "path": "packages/core/src/lib/KeyHandler.test.ts",
    "chars": 17176,
    "preview": "import { test, expect } from \"bun:test\"\nimport { InternalKeyHandler, KeyEvent } from \"./KeyHandler.js\"\nimport { type Par"
  },
  {
    "path": "packages/core/src/lib/KeyHandler.ts",
    "chars": 6344,
    "preview": "import { EventEmitter } from \"events\"\nimport { type KeyEventType, type ParsedKey } from \"./parse.keypress.js\"\nimport typ"
  },
  {
    "path": "packages/core/src/lib/RGBA.test.ts",
    "chars": 29181,
    "preview": "import { test, expect, describe } from \"bun:test\"\nimport { RGBA, hexToRgb, rgbToHex, hsvToRgb, parseColor } from \"./RGBA"
  },
  {
    "path": "packages/core/src/lib/RGBA.ts",
    "chars": 4367,
    "preview": "export class RGBA {\n  buffer: Float32Array\n\n  constructor(buffer: Float32Array) {\n    this.buffer = buffer\n  }\n\n  static"
  },
  {
    "path": "packages/core/src/lib/ascii.font.ts",
    "chars": 7802,
    "preview": "import { OptimizedBuffer } from \"../buffer.js\"\nimport { parseColor, RGBA, type ColorInput } from \"./RGBA.js\"\nimport bloc"
  },
  {
    "path": "packages/core/src/lib/border.test.ts",
    "chars": 3202,
    "preview": "import { test, expect, describe, spyOn, afterEach } from \"bun:test\"\nimport { isValidBorderStyle, parseBorderStyle, type "
  },
  {
    "path": "packages/core/src/lib/border.ts",
    "chars": 4389,
    "preview": "import type { ColorInput } from \"./RGBA.js\"\n\nexport interface BorderCharacters {\n  topLeft: string\n  topRight: string\n  "
  },
  {
    "path": "packages/core/src/lib/bunfs.test.ts",
    "chars": 835,
    "preview": "import { describe, expect, test } from \"bun:test\"\nimport { isBunfsPath, getBunfsRootPath } from \"./bunfs.js\"\n\ndescribe(\""
  },
  {
    "path": "packages/core/src/lib/bunfs.ts",
    "chars": 552,
    "preview": "import { basename, join } from \"node:path\"\n\nexport function isBunfsPath(path: string): boolean {\n  // Removed ambiguous "
  },
  {
    "path": "packages/core/src/lib/clipboard.test.ts",
    "chars": 1593,
    "preview": "import { describe, expect, it, afterEach } from \"bun:test\"\nimport { createTestRenderer, type TestRenderer } from \"../tes"
  },
  {
    "path": "packages/core/src/lib/clipboard.ts",
    "chars": 1378,
    "preview": "// OSC 52 clipboard support for terminal applications.\n// Delegates to native Zig implementation for ANSI sequence gener"
  },
  {
    "path": "packages/core/src/lib/clock.ts",
    "chars": 1123,
    "preview": "export type TimerHandle = ReturnType<typeof globalThis.setTimeout> | number\n\nexport interface Clock {\n  now(): number\n  "
  },
  {
    "path": "packages/core/src/lib/data-paths.test.ts",
    "chars": 3105,
    "preview": "import { test, expect } from \"bun:test\"\nimport { DataPathsManager } from \"./data-paths.js\"\n\ntest(\"DataPathsManager valid"
  },
  {
    "path": "packages/core/src/lib/data-paths.ts",
    "chars": 3071,
    "preview": "import os from \"os\"\nimport path from \"path\"\nimport { EventEmitter } from \"events\"\nimport { singleton } from \"./singleton"
  },
  {
    "path": "packages/core/src/lib/debounce.ts",
    "chars": 2786,
    "preview": "/**\n * A module-level map to store timeout IDs for all debounced functions\n * Structure: Map<scopeId, Map<debounceId, ti"
  },
  {
    "path": "packages/core/src/lib/detect-links.test.ts",
    "chars": 3812,
    "preview": "import { test, expect, describe } from \"bun:test\"\nimport { detectLinks } from \"./detect-links\"\nimport type { TextChunk }"
  },
  {
    "path": "packages/core/src/lib/detect-links.ts",
    "chars": 1734,
    "preview": "import type { TextChunk } from \"../text-buffer\"\nimport type { SimpleHighlight } from \"./tree-sitter/types\"\n\nconst URL_SC"
  },
  {
    "path": "packages/core/src/lib/env.test.ts",
    "chars": 5972,
    "preview": "import { describe, test, expect, beforeEach, afterEach } from \"bun:test\"\nimport { envRegistry, registerEnvVar, env, clea"
  },
  {
    "path": "packages/core/src/lib/env.ts",
    "chars": 5315,
    "preview": "import { singleton } from \"./singleton.ts\"\n\n/**\n * Environment variable registry\n *\n * Usage:\n * ```ts\n * import { regis"
  },
  {
    "path": "packages/core/src/lib/extmarks-history.ts",
    "chars": 1174,
    "preview": "import type { Extmark } from \"./extmarks.js\"\n\nexport interface ExtmarksSnapshot {\n  extmarks: Map<number, Extmark>\n  nex"
  },
  {
    "path": "packages/core/src/lib/extmarks-multiwidth.test.ts",
    "chars": 9539,
    "preview": "import { describe, expect, it, afterEach } from \"bun:test\"\nimport { TextareaRenderable } from \"../renderables/Textarea.j"
  },
  {
    "path": "packages/core/src/lib/extmarks.test.ts",
    "chars": 92058,
    "preview": "import { describe, expect, it, afterEach } from \"bun:test\"\nimport { TextareaRenderable } from \"../renderables/Textarea.j"
  },
  {
    "path": "packages/core/src/lib/extmarks.ts",
    "chars": 26198,
    "preview": "import type { EditBuffer } from \"../edit-buffer.js\"\nimport type { EditorView } from \"../editor-view.js\"\nimport { Extmark"
  },
  {
    "path": "packages/core/src/lib/fonts/block.json",
    "chars": 13633,
    "preview": "{\n  \"name\": \"block\",\n  \"version\": \"0.2.0\",\n  \"homepage\": \"https://github.com/dominikwilkowski/cfonts\",\n  \"colors\": 2,\n  "
  },
  {
    "path": "packages/core/src/lib/fonts/grid.json",
    "chars": 8971,
    "preview": "{\n  \"name\": \"grid\",\n  \"version\": \"0.1.0\",\n  \"homepage\": \"https://github.com/dominikwilkowski/cfonts\",\n  \"colors\": 2,\n  \""
  },
  {
    "path": "packages/core/src/lib/fonts/huge.json",
    "chars": 30813,
    "preview": "{\n  \"name\": \"huge\",\n  \"version\": \"0.2.0\",\n  \"homepage\": \"https://github.com/dominikwilkowski/cfonts\",\n  \"colors\": 2,\n  \""
  },
  {
    "path": "packages/core/src/lib/fonts/pallet.json",
    "chars": 10050,
    "preview": "{\n  \"name\": \"pallet\",\n  \"version\": \"0.1.0\",\n  \"homepage\": \"https://github.com/dominikwilkowski/cfonts\",\n  \"colors\": 2,\n "
  },
  {
    "path": "packages/core/src/lib/fonts/shade.json",
    "chars": 14060,
    "preview": "{\n  \"name\": \"shade\",\n  \"version\": \"0.2.0\",\n  \"homepage\": \"https://github.com/dominikwilkowski/cfonts\",\n  \"colors\": 2,\n  "
  },
  {
    "path": "packages/core/src/lib/fonts/slick.json",
    "chars": 10103,
    "preview": "{\n  \"name\": \"slick\",\n  \"version\": \"0.1.0\",\n  \"homepage\": \"https://github.com/dominikwilkowski/cfonts\",\n  \"colors\": 2,\n  "
  },
  {
    "path": "packages/core/src/lib/fonts/tiny.json",
    "chars": 1615,
    "preview": "{\n  \"name\": \"tiny\",\n  \"version\": \"0.2.0\",\n  \"homepage\": \"https://github.com/dominikwilkowski/cfonts\",\n  \"colors\": 1,\n  \""
  },
  {
    "path": "packages/core/src/lib/hast-styled-text.ts",
    "chars": 1524,
    "preview": "import type { TextChunk } from \"../text-buffer.js\"\nimport { StyledText } from \"./styled-text.js\"\nimport { SyntaxStyle } "
  },
  {
    "path": "packages/core/src/lib/index.ts",
    "chars": 709,
    "preview": "export * from \"./border.js\"\nexport * from \"./KeyHandler.js\"\nexport * from \"./ascii.font.js\"\nexport * from \"./hast-styled"
  },
  {
    "path": "packages/core/src/lib/keymapping.test.ts",
    "chars": 10341,
    "preview": "import { describe, expect, it } from \"bun:test\"\nimport {\n  mergeKeyBindings,\n  getKeyBindingKey,\n  buildKeyBindingsMap,\n"
  },
  {
    "path": "packages/core/src/lib/keymapping.ts",
    "chars": 2622,
    "preview": "export interface KeyBinding<Action extends string = string> {\n  name: string\n  ctrl?: boolean\n  shift?: boolean\n  meta?:"
  },
  {
    "path": "packages/core/src/lib/objects-in-viewport.test.ts",
    "chars": 32556,
    "preview": "import { test, expect, describe } from \"bun:test\"\nimport { getObjectsInViewport } from \"./objects-in-viewport.js\"\nimport"
  },
  {
    "path": "packages/core/src/lib/objects-in-viewport.ts",
    "chars": 4561,
    "preview": "import type { ViewportBounds } from \"../types.js\"\n\ninterface ViewportObject {\n  x: number\n  y: number\n  width: number\n  "
  },
  {
    "path": "packages/core/src/lib/output.capture.ts",
    "chars": 1290,
    "preview": "import { Writable } from \"stream\"\nimport { EventEmitter } from \"events\"\n\nexport type CapturedOutput = {\n  stream: \"stdou"
  },
  {
    "path": "packages/core/src/lib/parse.keypress-kitty.protocol.test.ts",
    "chars": 8951,
    "preview": "import { describe, expect, test } from \"bun:test\"\nimport { parseKeypress, type ParseKeypressOptions, type ParsedKey } fr"
  },
  {
    "path": "packages/core/src/lib/parse.keypress-kitty.test.ts",
    "chars": 23444,
    "preview": "import { test, expect } from \"bun:test\"\nimport { parseKeypress, type ParseKeypressOptions } from \"./parse.keypress.js\"\n\n"
  },
  {
    "path": "packages/core/src/lib/parse.keypress-kitty.ts",
    "chars": 10230,
    "preview": "// Kitty Keyboard Protocol parser\n// Based on https://sw.kovidgoyal.net/kitty/keyboard-protocol/\n\nimport type { ParsedKe"
  },
  {
    "path": "packages/core/src/lib/parse.keypress.test.ts",
    "chars": 56527,
    "preview": "import { test, expect } from \"bun:test\"\nimport { parseKeypress, nonAlphanumericKeys, type ParsedKey, type KeyEventType }"
  },
  {
    "path": "packages/core/src/lib/parse.keypress.ts",
    "chars": 10759,
    "preview": "// Copied from https://github.com/enquirer/enquirer/blob/36785f3399a41cd61e9d28d1eb9c2fcd73d69b4c/lib/keypress.js\nimport"
  },
  {
    "path": "packages/core/src/lib/parse.mouse.test.ts",
    "chars": 20645,
    "preview": "import { describe, test, expect, beforeEach } from \"bun:test\"\nimport { MouseParser, type RawMouseEvent } from \"./parse.m"
  },
  {
    "path": "packages/core/src/lib/parse.mouse.ts",
    "chars": 6065,
    "preview": "export type MouseEventType = \"down\" | \"up\" | \"move\" | \"drag\" | \"drag-end\" | \"drop\" | \"over\" | \"out\" | \"scroll\"\n\nexport i"
  },
  {
    "path": "packages/core/src/lib/paste.ts",
    "chars": 373,
    "preview": "export type PasteKind = \"text\" | \"binary\" | \"unknown\"\n\nexport interface PasteMetadata {\n  mimeType?: string\n  kind?: Pas"
  },
  {
    "path": "packages/core/src/lib/queue.ts",
    "chars": 1257,
    "preview": "/**\n * Generic processing queue that handles asynchronous job processing\n */\nexport class ProcessQueue<T> {\n  private qu"
  },
  {
    "path": "packages/core/src/lib/renderable.validations.test.ts",
    "chars": 2771,
    "preview": "import { describe, test, expect } from \"bun:test\"\nimport {\n  validateOptions,\n  isPositionType,\n  isDimensionType,\n  isF"
  },
  {
    "path": "packages/core/src/lib/renderable.validations.ts",
    "chars": 2417,
    "preview": "import type { RenderableOptions, Renderable } from \"../Renderable.js\"\nimport type { PositionTypeString, OverflowString }"
  },
  {
    "path": "packages/core/src/lib/scroll-acceleration.ts",
    "chars": 3380,
    "preview": "export interface ScrollAcceleration {\n  tick(now?: number): number\n  reset(): void\n}\n\nexport class LinearScrollAccel imp"
  },
  {
    "path": "packages/core/src/lib/selection.ts",
    "chars": 6537,
    "preview": "import { Renderable, type ViewportBounds } from \"../index.js\"\nimport { coordinateToCharacterIndex, fonts } from \"./ascii"
  },
  {
    "path": "packages/core/src/lib/singleton.ts",
    "chars": 947,
    "preview": "const singletonCacheSymbol = Symbol.for(\"@opentui/core/singleton\")\n\n/**\n * Ensures a value is initialized once per proce"
  },
  {
    "path": "packages/core/src/lib/stdin-parser.test.ts",
    "chars": 72370,
    "preview": "import { describe, expect, test } from \"bun:test\"\nimport { Buffer } from \"node:buffer\"\nimport { ManualClock } from \"../t"
  },
  {
    "path": "packages/core/src/lib/stdin-parser.ts",
    "chars": 55988,
    "preview": "// Byte-level stdin parser that turns raw terminal input into typed StdinEvents.\n//\n// This replaces a two-phase token -"
  }
]

// ... and 463 more files (download for full content)

About this extraction

This page contains the full source code of the anomalyco/opentui GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 663 files (8.0 MB), approximately 2.1M tokens, and a symbol index with 4327 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!