Skip to content

feat(rust): ratatui renderer for SceneFrame, alt-screen TUI binary#959

Merged
esengine merged 1 commit into
mainfrom
rust-stage1-ratatui
May 15, 2026
Merged

feat(rust): ratatui renderer for SceneFrame, alt-screen TUI binary#959
esengine merged 1 commit into
mainfrom
rust-stage1-ratatui

Conversation

@esengine
Copy link
Copy Markdown
Owner

First visible Rust output. `reasonix-render` now reads JSONL frames
from stdin, sets up an alt-screen TUI, and renders each frame through
a recursive walker that paints into ratatui's `Buffer`. The trace
files written by `REASONIX_SCENE_TRACE` (#952, #958) are now
viewable end-to-end.

How to try

```
REASONIX_SCENE_TRACE=/tmp/frames.jsonl reasonix # run a session, hit a few keys
cargo run -q --bin reasonix-render < /tmp/frames.jsonl
```

`n` / Right advances, `p` / Left goes back, `q` / Esc exits. Frames
also auto-advance after an 800ms dwell.

Layout model

  • Text runs paint left-to-right into a single row. Overflow
    truncates at the right edge. No wrap yet — the `Wrap` enum is
    in the contract but the renderer ignores it; that lands when we
    hit a real wrapped Text node.
  • Box applies symmetric padding, then splits the inner rect by
    `direction`. Column stacks vertically with children's intrinsic
    heights (1 for Text, recursive for nested Box + gap + padding).
    Row lays out horizontally with intrinsic widths.
  • Gap is between siblings, not after the last.
  • Colors: hex → `Color::Rgb` (truecolor); named → 1:1; `"default"`
    → `Color::Reset`.

Tests

7 new cell-level assertions in `tests/render.rs`:

  • plain text renders at row 0
  • color + bold modifier land on the right cell
  • column stacks with gap leaves the gap row blank
  • row layout places siblings horizontally
  • padding shifts the child two cells right + one cell down
  • overflow truncates at column width
  • hex colors arrive as `Color::Rgb(0xaa, 0xbb, 0xcc)`

Existing 6 round-trip tests still pass.

What's deferred

  • Wrap modes — the `Wrap` enum is in the contract; renderer
    treats every text run as single-line and truncating. First real
    wrapped frame from the producer forces a renderer extension.
  • Width / height constraints — `Dim::Fill` and explicit `Dim::Cells`
    on Box don't influence layout yet. Today the layout uses intrinsic
    sizes. Comes when a producer needs to pin a region.
  • Border rendering — `borderStyle` / `borderColor` deserialize
    fine; renderer ignores them. Same rule.

Each deferred field is in the contract and decodes cleanly — the
renderer just chooses not to use them yet. No silent drops; future
extensions are additive.

Refs #868 #947

First visible Rust output. reasonix-render now reads JSONL frames
from stdin, sets up an alt-screen TUI, and renders each frame
through a recursive walker that paints into ratatui's Buffer.

Layout model:

- Text nodes paint runs left-to-right; styles map to ratatui's
  fg/bg + Modifier bits. Overflow truncates at the right edge of
  the area (single-line for now; wrap modes come when we hit a
  real wrapped Text node).
- Box nodes apply paddingX/paddingY symmetrically, then split the
  inner rect by direction. Column direction stacks children
  vertically using each child's intrinsic height (1 for Text, sum
  of children + gap + 2·paddingY for Box). Row direction lays out
  horizontally with intrinsic width.
- Gap is added between siblings, not after the last one.
- Hex colors round-trip to ratatui::Color::Rgb (truecolor); named
  colors map 1:1; "default" → Reset.

Binary controls:

- Frames advance on 'n' / Right-arrow or after the 800ms dwell.
- 'p' / Left-arrow goes back.
- 'q' / Esc exits cleanly (raw mode disabled, alt screen left,
  cursor shown) even on panic-free error paths.

Tests:

- 7 render tests in tests/render.rs covering plain text, styled
  runs, column stacking with gap, row layout, padding offset,
  text overflow truncation, and hex truecolor.
- Existing 6 round-trip tests still pass.
- Buffer assertions use buf[(x,y)].symbol() / .style() so the
  tests fail at the cell level if styling regresses, not just on
  visual diffs.

Deps added: ratatui 0.29, crossterm 0.28, anyhow 1. These are
the canonical TUI dependency triple and we will live with them
through Stage 3.

Refs #868 #947
@esengine esengine merged commit ff3f7d4 into main May 15, 2026
5 checks passed
@esengine esengine deleted the rust-stage1-ratatui branch May 15, 2026 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant