feat(ui): double the blocks arena's resolution with quadrant glyphs - #27
Merged
Conversation
The half-block fallback (1×2 sub-pixels/cell) looked rough on terminals without kitty graphics, especially macOS Terminal. Replace blit_bevy_arena with quadrant_blit: each cell is a 2×2 grid of sub-pixels fitted to a 2-colour Unicode quadrant glyph (quad_cell splits the four sub-pixels on the widest-spread channel, chafa/notcurses-style) — double the resolution, on block-element glyphs every monospace font carries (no sextant tofu risk). Bumps the supersample to QUAD_SS=4 for a square-ish 2×4 render block per sub-pixel; the cols×2·rows aspect is unchanged, so no camera-math change. The headless snapshot (PNG + text dump) re-expands each glyph via quad_pattern. Numbers still composite on top. New tests pin the glyph-table round-trip and the 2-colour fit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The quadrant glyphs render pixel-perfect on modern terminals but macOS Terminal.app draws them through its font, leaving visible seams between cells (the '\''misaligned lines'\'' — its half-block ▀ tiles fine, the 2×2 glyphs don'\''t). So GraphicsMode::Blocks now carries a half_block flag: quadrant_blit fits each cell with quad_cell normally, or half_cell (a seam-free ▀, top-row avg fg / bottom-row avg bg) when set. resolve() sets it from quadrants_tile_cleanly (TERM_PROGRAM != Apple_Terminal), so Terminal.app gets the seamless-but-coarser half-blocks and every capable terminal keeps the crisp quadrants. The debug overlay shows quad vs half. New tests pin the detection and half_cell. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
quadrant_blit was a single-threaded per-pixel pass — box-averaging the supersampled render and fitting each cell to a 2-colour quadrant glyph — that scales with the arena area, so at a full-screen size it dominated the blocks path's per-frame CPU. Split the fit across cores by row band with thread::scope (rows independent, output chunks disjoint → byte-identical to serial, no synchronization), then write the fitted cells into the ratatui buffer serially. Reuses the cached graphics::core_count() (now pub(crate)), so both readback passes — pack_rgb and this — share the one-time available_parallelism lookup. Full-screen blocks compose drops ~6x (debug 24ms→3.9ms at 320x90, ~0.4ms release), erasing the extra CPU the quadrant switch added over the old half-block fallback. The dominant full-screen cost — the per-frame truecolor cell grid written to the pty — is inherent to text rendering and unchanged; kitty stays the fast path where available. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
puradox
force-pushed
the
quadrant-glyph-arena
branch
from
July 19, 2026 12:19
c299061 to
a90f40e
Compare
…where macOS Terminal.app draws the 2×2 quadrant glyphs with faint seams, so the fallback rendered the arena there in coarser `▀` half-blocks. In practice the seams don't warrant a second code path, so render quadrant glyphs on every terminal. This reverts the `half_block` flag, `quadrants_tile_cleanly`, `half_cell`, the resolve/call-site plumbing, and their tests, keeping the parallel `quadrant_blit`. Also points the graphics.rs/scene doc comments at the quadrant blit (they still named the old half-block blit and the renamed `blit_bevy_arena`). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The half-block fallback (1×2 sub-pixels per cell) looked rough on terminals without kitty graphics — macOS Terminal especially. This sharpens that fallback path and makes it cheap at full screen; kitty mode is untouched.
Quadrant glyphs — 2× the resolution.
blit_bevy_arenabecomesquadrant_blit: each cell is a 2×2 grid of sub-pixels fitted to a Unicode quadrant glyph (quad_cellsplits the four on the widest-spread colour channel, chafa/notcurses-style), doubling the arena's resolution on block-element glyphs every monospace font carries (no sextant tofu risk). Supersample isQUAD_SS=4; thecols×2·rowsimage aspect is unchanged, so no camera math moves. The headless snapshot re-expands each glyph viaquad_pattern, and the die numbers still composite on top.Half-blocks where the quadrants seam. macOS Terminal.app draws the 2×2 quadrants through its font, leaving visible seams.
resolvesniffsTERM_PROGRAM(quadrants_tile_cleanly) and there falls back to seam-free▀half-blocks —GraphicsMode::Blocks { half_block }carries the choice. Every other terminal keeps the sharp quadrants.Parallel blit. The per-cell box-average + 2-colour fit is the blocks path's per-frame CPU, and it scales with arena area, so at full screen it was single-thread-bound.
quadrant_blitnow fits the cells across cores by row band withthread::scope(rows independent, output chunks disjoint → byte-identical to serial, no synchronization), reusing the cachedgraphics::core_count()thatpack_rgbalready relies on. Full-screen compose drops ~6× (measured 24ms → 3.9ms in a debug build at a 320×90 terminal; a release build is roughly ⅒ that).Blocks vs kitty at full screen, evaluated before merge. Blocks stays heavier than kitty at large sizes, but that's the terminal write, not our compute: the block path repaints a full truecolor cell grid every animated frame (~0.5–0.8 MB/frame at full screen — one glyph + fg + bg per cell), which is inherent to text rendering and the same volume the old half-blocks wrote. Kitty ships the arena as one image via a ~50-byte
t=fpath reference and is unaffected. So this PR adds no lasting per-frame CPU over the old fallback, and kitty remains the fast default wherever it's available.Validation.
cargo fmt,clippy -D warnings, and the full suite (61 binary + 64 core) are green. New GPU-free tests pin the glyph-table round-trip, the two-colour fit, andblocks == render_bevybyte-for-byte (so the parallel blit matches the serial one exactly). Renderer eyeballed via the headlessTINHORN_BEVY_SNAPSHOTpath.🤖 Generated with Claude Code