Skip to content

feat(expose): inset opaque panel over a dimmed, correctly-sized backdrop#169

Merged
TraderSamwise merged 4 commits into
masterfrom
chore/tui-next-24
Jun 18, 2026
Merged

feat(expose): inset opaque panel over a dimmed, correctly-sized backdrop#169
TraderSamwise merged 4 commits into
masterfrom
chore/tui-next-24

Conversation

@TraderSamwise

@TraderSamwise TraderSamwise commented Jun 18, 2026

Copy link
Copy Markdown
Owner

What

Iterates the exposé "dimmed real backdrop" into a proper inset modal and fixes its rough edges.

  1. Inset opaque panel. Exposé floats a centered ~90% bordered panel (its own opaque body) over the full-screen dimmed backdrop, instead of being edge-to-edge with a see-through body. The dimmed host shows in the margin around it — matching the dialog model.
  2. Flicker-free. Each frame is wrapped in synchronized output and the full-screen clear only fires on resize, so the timer-driven repaint lands atomically (no blank flash in the panel body).
  3. Instant entry. The backdrop + panel + tile chrome paint immediately; tile previews fill in on the next tick instead of blocking the first frame on N captures.
  4. Correctly-sized backdrop (top-line centering fix). Opening the fullscreen popup transiently reflows the host pane, so capturing the backdrop from inside exposé caught a mis-sized, off-centre frame (the dashboard's centered title appeared shifted left). The backdrop is now snapshotted by the launcher before display-popup, passed via --backdrop-file, and read+deleted by exposé — so it mirrors the host at its real width.

How

  • src/tmux/expose.ts — new panelGeometry/buildPanelFrame (inset opaque frame); render insets title/tiles/help into the panel over a full-screen buildBackdrop; synchronized-output + resize-only clear; render-before-capture; read the launcher's --backdrop-file snapshot (in-popup capture kept as fallback).
  • scripts/tmux-control.sh — exposé popup is borderless fullscreen (-w 100% -h 100% -B); capture the host (capture-pane -e -S 0) to a temp file before opening the popup and pass --backdrop-file.
  • src/main.ts--backdrop-file option plumbed to runTmuxExpose.

Tests

  • New unit tests: panelGeometry (centered inset, clamps), buildPanelFrame (opaque bordered box).
  • Updated control-script.test.ts for the fullscreen -B popup.
  • Full suite green; yarn build clean. Verified the centering fix by rendering a real pre-popup dashboard capture (title lands centered at col 77 of 195).

Notes

  • Multi-pane host windows show the launching pane's content as the backdrop (single-pane — the common case — is exact).
  • Follow-up still queued: a warm/persistent helper to remove the aimux expose Node cold-start blank.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Exposé now captures a snapshot of the host pane before opening, improving visual context in the overlay.
    • Exposé UI now uses an inset framed panel on top of the dimmed backdrop for clearer hierarchy.
    • Added a --backdrop-file <path> option to allow using a pre-supplied backdrop snapshot.
  • Bug Fixes
    • Exposé rendering now appears immediately with improved overlay positioning and refresh behavior.
  • Tests
    • Updated and expanded coverage for exposé panel layout and popup command behavior.

test and others added 3 commits June 18, 2026 20:31
Make exposé a proper inset modal over the dimmed backdrop: the popup goes
borderless-fullscreen so exposé paints an edge-to-edge dimmed host backdrop,
then floats a centered ~90% opaque bordered panel holding the title, tiles,
and help — so the body is solid (no see-through) and inset like before.

Wrap each frame in synchronized output and only clear on resize so the
timer-driven repaint lands atomically without flashing the panel body.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Render the backdrop, panel, and tile chrome before capturing tile previews
so entry shows the framed exposé at once instead of a blank wait; previews
fill in on the next tick.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Opening the fullscreen popup transiently reflows the host pane, so capturing
the backdrop from inside exposé caught a mis-sized, off-centre frame. Capture
the host in the launcher before display-popup, pass it via --backdrop-file,
and have exposé read then delete that snapshot (in-popup capture kept as a
fallback). The dimmed backdrop now mirrors the host at its real width.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment Jun 18, 2026 1:43pm

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 067f9df9-13c1-4fa0-854a-0c0086993486

📥 Commits

Reviewing files that changed from the base of the PR and between 1a0e579 and a94f507.

📒 Files selected for processing (3)
  • scripts/tmux-control.sh
  • src/tmux/expose-tile.test.ts
  • src/tmux/expose.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/tmux/expose-tile.test.ts
  • src/tmux/expose.ts

📝 Walkthrough

Walkthrough

Adds a pre-popup host pane snapshot mechanism to the exposé feature. The shell launcher captures the current pane to a temp file and passes it via --backdrop-file to the CLI, which forwards it to runTmuxExpose. The expose module gains PanelGeometry, panelGeometry, and buildPanelFrame to render an inset framed panel overlay on the dimmed host backdrop, with updated render-loop ordering and title/help positioning.

Changes

Exposé backdrop snapshot and panel overlay

Layer / File(s) Summary
Panel geometry types and frame rendering
src/tmux/expose.ts, src/tmux/expose-tile.test.ts
Extends TmuxExposeOptions with optional backdropFile, adds readFileSync/unlinkSync imports for snapshot handling, and exports PanelGeometry type, panelGeometry() for centered inset bounds computation, and buildPanelFrame() for ANSI-positioned bordered box rendering. Tests verify inset sizing, centering, viewport clamping, and border glyph rendering with cursor positioning.
Backdrop snapshot flow from shell through CLI
scripts/tmux-control.sh, src/main.ts, src/tmux/control-script.test.ts
show_local_expose creates a temp file, runs tmux capture-pane to it, and conditionally appends --backdrop-file <tempfile> to the expose command; on capture or popup failure, the temp file is cleaned up. src/main.ts adds the --backdrop-file <path> CLI option and passes backdropFile into runTmuxExpose. The control-script test is updated to expect the -B flag in the display-popup invocation.
runTmuxExpose backdrop and panel integration
src/tmux/expose.ts
runTmuxExpose reads and deletes backdropFile (falling back to live tmux capture if unavailable), uses panelGeometry/buildPanelFrame for the inset overlay, repositions title/help inside the panel bounds, clears only on terminal size change, calls render() immediately before refreshCaptures() to show the framed UI without waiting for preview updates, and appends helpAt cursor position with alternate-screen mode exit.

Sequence Diagram(s)

sequenceDiagram
  participant Shell as show_local_expose
  participant tmux_cmd as tmux capture-pane
  participant CLI as aimux expose
  participant Core as runTmuxExpose
  
  Shell->>tmux_cmd: capture-pane -p to tempfile
  tmux_cmd-->>Shell: exit 0 (success) or error
  alt capture succeeded
    Shell->>CLI: --backdrop-file <tempfile>
    CLI->>Core: backdropFile: opts.backdropFile
  else capture failed
    Shell->>Shell: rm tempfile
    Shell->>CLI: (no --backdrop-file)
  end
  
  Core->>Core: readFileSync(backdropFile)
  Core->>Core: unlinkSync(backdropFile)
  Core->>Core: panelGeometry(cols, rows) → geo
  Core->>Core: buildPanelFrame(geo) → frame with borders
  Core->>Core: render() immediately with panel overlay
  Core->>Core: refreshCaptures() updates previews in panel
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • TraderSamwise/aimux#122: Established the original exposé TUI wiring across scripts/tmux-control.sh, src/main.ts, and src/tmux/expose.ts that this PR extends with backdrop snapshot support.
  • TraderSamwise/aimux#168: Also modifies src/tmux/expose.ts and scripts/tmux-control.sh to incorporate a dimmed host backdrop, using an alternative buildBackdrop snapshot-and-dim approach.

Poem

🐇 A snapshot in time, captured with care,
A backdrop of pixels hung softly in air,
The panel aligns with its corners precise,
Each glyph drawn in sequence, once—not twice.
The frame glows as tiles peek through with delight,
A rabbit built UI that feels just right! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding an inset opaque panel over a dimmed backdrop in the exposé modal, which is the core refactoring objective of this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/tui-next-24

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/tmux/control-script.test.ts (1)

1359-1359: ⚡ Quick win

Also assert --backdrop-file is present in the generated expose command.

This test now checks -B, but the new cross-layer contract in this PR is the backdrop-file plumbing. Adding that assertion would catch regressions earlier.

✅ Suggested assertion extension
-        entry.includes("display-popup -c /dev/live -T aimux exposé -x C -y C -w 100% -h 100% -B -E exec"),
+        entry.includes("display-popup -c /dev/live -T aimux exposé -x C -y C -w 100% -h 100% -B -E exec") &&
+          entry.includes(" --backdrop-file "),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tmux/control-script.test.ts` at line 1359, The test assertion at line
1359 in the control-script.test.ts file currently verifies that the
display-popup command includes the `-B` flag, but it does not assert that the
`--backdrop-file` argument is present in the generated expose command. Add an
additional assertion (or extend the existing entry.includes check) to verify
that `--backdrop-file` is included in the command string to ensure the
backdrop-file plumbing is working correctly and catch any regressions in this
cross-layer contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/tmux-control.sh`:
- Around line 412-425: The temporary backdrop file stored in expose_backdrop
variable is not being cleaned up if the tmux display-popup command fails. Add
cleanup logic to remove the expose_backdrop file before each return 1 statement
that follows a failed tmux display-popup call. Since there are two tmux
display-popup invocations (one with the -c option and one without), ensure the
cleanup happens for both failure paths. Use rm -f on the expose_backdrop
variable to safely remove the file if it exists before the function returns.

In `@src/tmux/expose.ts`:
- Around line 110-113: The panelGeometry function's width and height
calculations can exceed the actual viewport dimensions on very small terminals
because the Math.max operations with MIN_TILE_WIDTH and MIN_TILE_HEIGHT are
applied after clamping to cols and rows, allowing the minimums to override the
bounds. Add an additional Math.min operation to clamp the final width value to
cols and the final height value to rows after all other calculations in the
panelGeometry function, ensuring the panel dimensions never exceed the actual
viewport bounds.

---

Nitpick comments:
In `@src/tmux/control-script.test.ts`:
- Line 1359: The test assertion at line 1359 in the control-script.test.ts file
currently verifies that the display-popup command includes the `-B` flag, but it
does not assert that the `--backdrop-file` argument is present in the generated
expose command. Add an additional assertion (or extend the existing
entry.includes check) to verify that `--backdrop-file` is included in the
command string to ensure the backdrop-file plumbing is working correctly and
catch any regressions in this cross-layer contract.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4f784250-708c-4162-bc63-cbc48d1dcbc3

📥 Commits

Reviewing files that changed from the base of the PR and between aed8a56 and 1a0e579.

📒 Files selected for processing (5)
  • scripts/tmux-control.sh
  • src/main.ts
  • src/tmux/control-script.test.ts
  • src/tmux/expose-tile.test.ts
  • src/tmux/expose.ts

Comment thread scripts/tmux-control.sh Outdated
Comment thread src/tmux/expose.ts
…lure

- panelGeometry: clamp width/height to the viewport last so the minimum-size
  floor can't make the panel larger than a tiny screen.
- tmux-control.sh: remove the captured backdrop temp file if display-popup
  fails (exposé otherwise reads then deletes it).
- prefer the exact host window id over the session in the capture fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@TraderSamwise

Copy link
Copy Markdown
Owner Author

Concurrent sub-agent review (orphan findings):

  • [Fixed in a94f507] In the in-popup capture fallback, prefer the exact host window id over the client session (currentWindowId || currentClientSession) — more precise and avoids a window-switch race.
  • [Won't fix — cosmetic, fallback-only] The launcher capture uses capture-pane without -J (preserves visual rows) while the in-popup fallback's shared captureTarget uses -J (also used by tile previews, which want it). The fallback path is only hit when no pre-popup snapshot was passed; the primary path is correct.

Geometry, BSU (\x1b[?2026h/l) pairing across both render branches, the resize-only clear, and the changed signatures were verified clean.

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