Document the opt-in shared Zig local cache workflow for repeated native
builds across worktrees.
---------
Co-authored-by: Simon Klee <hello@simonklee.dk>
## Summary
- keep at most one terminal pixel-resolution query in flight and
coalesce resize or suspended refreshes into one follow-up query
- preserve complete and partial pixel-resolution replies across
suspend/resume without leaking suspended protocol prefixes into later
input
- preserve post-resume input across chunk boundaries and discard
retained prefixes when the query is cancelled
- reject unsafe or signed-32-bit-overflowing pixel dimensions before
they reach renderer geometry
- keep the implementation and causal regression coverage independent
from native image support
Extracted from the final implementation in #1283, with additional
regressions proven and fixed during standalone review.
## Verification
- focused parser and renderer tests: 605 passed
- core Bun tests: 5,221 passed, 23 skipped
- Node 26.4 source tests: 4,527 passed, 6 skipped
- library build, formatting, and lint pass
- preserve fixed call shapes for short pointer-bearing Node FFI
functions, enabling V8 fast calls while retaining validation behavior
- reuse one owned Yoga layout output buffer per `FFIRenderLib` instead
of allocating and resolving a pointer per node
- add reproducible Bun/Node render benchmarks and comparison tooling
under `packages/core/src/benchmark`
- Add URL, byte-source, and custom-connector streaming APIs.
- Support MP3/FLAC decoding, buffering, playback controls, stats, and
backpressure.
- Add reconnect policies, lifecycle events, typed errors, and robust
cleanup.
- Support ICY headers, metadata demuxing, and custom demuxers.
- Add a live radio demo with presets, telemetry, meters, and FFT
visualization.
## Breaking
- `remove(id: string)` → `remove(child: BaseRenderable)` across all
renderables;
strings throw at runtime. Look up via `getRenderable(id)` /
`findDescendantById(id)` when needed (docs updated).
## Core
- All internal child bookkeeping uses object identity;
`renderableMapById` removed,
ids remain as a pure query API (first match wins on duplicates)
- `remove` warns in dev when the object is not a child; ScrollBox routes
internal
parts (wrapper, scrollbars) by parentage so `destroy()` fully detaches
them
- TextNode reparenting hygiene in
`add`/`replace`/`insertBefore`/`children`
- `destroy()` no longer skips children (live-array iteration bug) and
clears
z-index/pending-update state
## Renderer (zig)
- Frame output buffers grow on demand instead of dropping ANSI mid-frame
while
still committing cells (the source of "stale cells never repainted")
- Failed growth reports `.failed` → forced full repaint; partial frames
are not
flushed; buffers shrink back after 64 small frames; `deinit` frees with
the
owning allocator
## Frameworks
- react/solid reconcilers pass child references; react host config
tolerates
teardown overlap (unmount during `renderer.destroy()`)
- Route JS Yoga measure/dirtied callbacks through shared native
callbacks.
- Move `TextRenderable` and `TextareaRenderable` measurement to
native-backed renderables.
- Preserve existing JS `setMeasureFunc` support for other renderables.
- Add parity/stress tests for native-backed measurement and callback
routing.
Native calls previously accepted raw pointers, allowing stale references to
dereference freed memory after object destruction. Use generation-tagged
handles so stale, wrong-kind, and borrowed child references fail safely
instead of causing use-after-free.
Co-authored-by: Simon Klee <hello@simonklee.dk>
- Centralizes ScrollBox manual-scroll tracking with
`syncManualScrollState()`.
- Re-enables sticky bottom when users scroll back to the sticky edge via
mouse wheel or keys.
- Prevents programmatic sticky/layout recalculations from accidentally
changing manual-scroll state.
- Documents `renderBefore`/`renderAfter` as draw-only hooks that run
after layout and culling.
- Notes that culled ScrollBox children do not run render hooks, so
layout/state must not depend on them.
Additionally:
- Incorporates PR #1141’s sticky-bottom regression test.
- Extends the centralized manual-scroll sync to also clear manual mode
when sticky sync is active but the viewport is already back at the
sticky edge.
- Confirms this branch covers the #1141 follow-up case without
reintroducing programmatic resize/recalculation regressions.
---------
Co-authored-by: malventano <malventano@users.noreply.github.com>
- Link native audio dependencies into the native_span_feed_bench dylib
- Centralize miniaudio/platform library setup for native build artifacts
- Add a PR smoke workflow for bun run bench:native --mem
- Replace OpenTUI’s process-global native event callback with
per-runtime event sinks.
- Pass each sink into native objects that emit events, avoiding stale
Bun JSCallback pointers across workers/test runtimes.
- Keep native callback support via explicit createEventSink /
destroyEventSink.
- Fixesanomalyco/opencode#27590
- Blends replacement glyph foreground alpha against the cell’s final
background instead of the previous destination background
- Prevents transparent border glyphs from rendering as black over opaque
box backgrounds
- Adds native, core, and Solid regression coverage for transparent box
borders
- Updates foreground-alpha test expectation to match final-background
compositing behavior
- Made audio playback startup strict: start() now only succeeds with an
active output device.
- Added explicit mixer-only mode via startMixer() and isMixerStarted().
- Changed audio autoStart default to false.
- Updated audio tests, native Zig tests, and audio benchmark for
playback vs mixer semantics.
- Updated native audio demo to fall back to mixer-only mode when
playback is unavailable.
- Added Bun standalone executable audio embedding docs and Node.js
“coming soon” note.
- Added typed TerminalCapabilities for renderer.capabilities and
capability events.
- Added testing helpers for terminal capabilities and updated
capability-related tests.
- Updated renderer docs to document TerminalCapabilities.
- Added _screenX/_screenY layout-time absolute coordinate caching and
used it in hot render paths (Renderable, Box, TextBufferRenderable,
EditBufferRenderable).
- Skipped drawBox entirely for boxes with no visible border and no
visible fill.
- Optimized native transparent fill paths in buffer.zig:
- fillRect uses cheaper paths when no grapheme/link tracking is involved
- fully transparent fills preserve existing visible text while
normalizing empty cells
- Optimized native transparent border drawing in drawBox for width-1
opaque border glyphs over transparent backgrounds.
- Optimized native text-buffer rendering for opaque width-1 text over
transparent backgrounds, bypassing generic alpha blending when the
result is equivalent.
- Avoided visible-child filtering work for renderables that do not
actually filter children by adding _hasVisibleChildFilter(); only
viewport-culling ScrollBox content now pays for _getVisibleChildren()
and membership checks.
- Switched primary-axis child sorting and ScrollBox viewport culling to
absolute screenX/screenY, including updating objects-in-viewport to
operate on screen-space coordinates instead of recursive x/y walks.
- Added/expanded correctness tests
- Added new headless benchmarks
- box-draw-benchmark.ts
- render-traversal-benchmark.ts
- text-buffer-render-benchmark.ts
---------
Co-authored-by: Simon Klee <hello@simonklee.dk>