# Visual review ## Contrast choices and local collapse The fifteen native palettes now give comments vivid color and keep line numbers subdued. The current number uses muted ink and bold weight instead of a tag-colored background block, in SDL and TTY. Active pane and column tags use a small tonal shift without reversing their light/dark polarity. Column tag text starts at the column edge without the former two-cell inset. Forge has neutral coal and silver-blue chrome. `forge_black` and `orchard_black` use pure black; `forge_soft` joins `dusk`, `lagoon` and `solarium` as deliberately softer alternatives. Light and Acme-inspired choices remain available. `Themes` opens with the native collection, followed by a separate legacy and imported section. Keyboard navigation skips both section headings. `Collapse` now transfers all released rows to one expanded pane, preferring the nearest one above and falling back below. Unrelated pane heights stay unchanged. Expansion borrows from one neighbor too, limited by its available body space. Tests cover exact unchanged sibling rectangles, repeated inverse toggles, already-folded neighbors, tiny resizes, drag expansion and Dump/Restore. The refreshed builds pass 791 TTY and 822 SDL unit tests, with one skipped in each suite, plus all 98 interaction snapshots. Snapshot review found only the intended style changes, the expanded grouped theme picker, and flush-left column text/carets (including newly visible text in one- and two-cell columns). The isolated 9P harness `test/collapse_layout.py` passes seven collapse/expand pairs on each host, checking rendered tag boundaries and unchanged contents. The live OS gallery checks all fifteen native themes for bold current-line numbers, unchanged gutter backgrounds and no active-tag polarity inversion. Both hosts pass all twelve column input checks, including first-cell execution, editing and caret reveal. Agave source bytes stay unchanged and no input is sent to the user's session. - [Six contrast studies, OS screenshot crops](screenshots/theme-preferences.png) - [Neutral Forge, full workspace](screenshots/theme-preferences-forge.png) - [Native-first Themes, full workspace](screenshots/theme-selector.png) ## Compact rails, classic palettes and workspace pets `New` now belongs to column tags only. Pane tags keep their local save, terminal and close actions: `Tty` opens a terminal, and `Mode` cycles raw input, normal editing and insert mode. Historical default pane tails upgrade during Restore; explicitly customized text remains owned by the user. SDL paints adjacent tag backgrounds to their full row height, leaving only the thin separator. Square scroll markers share the column's left edge, and a one-pixel continuous line joins its column tag, pane tags and bodies. Pointer targets and the TTY grid are unchanged. `Font MartianMono-NrRg:18` now applies both face and size. The isolated `test/font_size.py` checks startup sizing, fractional sizing, retaining the size when omitted, and rejecting invalid requests without partial changes. Six [classic-inspired themes](themes.md) add `forge`, `lagoon`, `solarium`, `spectrum`, `harvest` and `clay`. ANSI colors retain their terminal meanings instead of borrowing a similarly positioned syntax color. Optional SDL `Pet cat` and `Pet frog` companions walk, idle and reverse in the unused workspace tag; `Pet off` is the default. Editing that tag hides the pet. The original pixel sprites use no external assets or input handlers. `test/appearance_gallery.py` recreates a two-column Agave review with stacked right-hand panes, an embedded terminal, Font 18 and TaglineSize 80. It checks all six new themes, font and pet reports, changing pet frames, and unchanged Agave source bytes. Its `--live-window` mode captures the owned SDL window through the OS, identified by its child PID. It never resizes or sends input to the user's existing Pardes window. - [Compact columns, native OS capture](screenshots/compact-columns.png) - [Six classic adaptations, screenshot contact sheet](screenshots/classic-themes.png) - [Cat and frog, enlarged nearest-neighbor screenshot crops](screenshots/pets.png) - [Gallery checks](screenshots/classic-gallery.json) The full suites passed 807 SDL and 776 TTY tests, with one skipped in each; all 97 interaction snapshots passed. A private mount namespace redirected test-only `/tmp` writes after the host's temporary-file quota was exhausted, without deleting files or changing the user's `/tmp`. These counts include the pet/geometry/font/command changes; palette corrections additionally pass the native contrast tests. ## PDF and terminal tag cleanup PDFs now use `filename.pdf [page/total] Tty Del PdfSections PdfTint Collapse`, keeping sections and tint commands visible without the long generated control/status prefix. Terminal tags include `Mode`, which cycles the body mode even when invoked from an edited tag. Ctrl-B keeps its two-way toggle. `test/tag_cleanup.py` verifies the compact PDF tag, middle-click `Mode`, Ctrl-B, and tag-edit/Tab execution through real host input and 9P observations on both SDL and TTY. The PDF source stays unchanged. The full unit suites pass 773 TTY tests and 797 SDL tests; SDL image/PDF and Kitty PDF rendering harnesses pass. [Native PDF and terminal screenshot](screenshots/pdf-and-tty-tags.png). ## Column and editable-tag follow-up The follow-up adds editable workspace and column command rows, compact pane tags, staged buffer-name edits, and caret reveal for long tags. See [editable tags](tags.md) for the exact interaction and save-target rules. `test/column_tags.py` exercises isolated SDL and TTY sessions against the same Agave source. It sends actual host input bytes while observing through 9P: header typing and selection replacement, UTF-8 deletion, inactive-column `New`/`Tty`, pane-tail edits, filename cancellation, terminal input, and custom-tag Dump/Restore. Source bytes remain unchanged. Input goes through the host PTY parser; compact SDL pixel coordinates are covered separately by round-trip mapping tests, not claimed as physical SDL mouse automation. All 11 live checks passed on each frontend. All 7,200 foreground/background cells and 48 text rows matched for the three final frames after normalizing only the isolated `ct-sdl`/`ct-tty` directory names. The screenshots below are native GPU captures, after removing test-only Unicode markers through normal tag editing. The tested CJK text has correct grid/editing behavior, but the selected font lacks its glyph; this is not claimed as complete font-fallback coverage. - [Two-column Orchard workspace](screenshots/columns-orchard.png) - [Two-column Atelier workspace](screenshots/columns-atelier.png) - [Long tag revealing its actions and caret](screenshots/columns-tag-reveal.png) - [Final SDL/TTY parity evidence](screenshots/columns-parity.json) The final unit suites passed 771 TTY tests and 795 SDL tests. Native image and PDF harnesses passed, including continuous PDF layout and reload. The PDF fixture gains one screen row to preserve its original document area; its pixel assertions are unchanged. Existing terminal snapshots were migrated by adding one screen row and moving pane mouse coordinates down one row, preserving their original body area. Raw SGR mouse sequences were migrated too. The tag-padding/name/navigation fixtures were explicitly rewritten for the new behavior. Review found 86 fixtures with identical text tokens after removing the new column row and normalizing spacing; the remaining differences were reviewed for tag edits, nested editor chrome, resize handles, and debug overlays. All 97 scripts passed both when regenerating the reviewed goldens and in a subsequent independent run with retries disabled. ## Initial palette pass The UI pass was exercised against Agave's real `gossip/src/crds_value.rs`, using isolated named Pardes sessions and the existing Python 9P client. The workflow opened Find and Grep results, ran harmless commands in an embedded terminal, requested Rust document symbols and hover, and sent `gd` through the host's actual terminal input parser. Agave source bytes were checked unchanged after the session. Native SDL screenshots use the GPU capture path. TTY captures contain the real core grid and its styles; they are not screenshots of an independent terminal emulator. Resolving cells to their grapheme, foreground and background yielded **7,200 of 7,200 matching cells** at 150 × 48 for each of `orchard`, `dusk`, `ink`, `paper`, `daybreak`, and `atelier`. Rust-analyzer returned 52 document-symbol rows and one definition result. The initial baseline hover timed out; the updated run returned no hover text for the declaration. No hover popup is claimed as verified. Agave's gossip crate is feature-gated, and workspace loading was still substantial; the exact cause of that empty result was not established. ## Reproduce Run from the Pardes checkout, using an existing SDL binary and an Agave checkout. The output directory is private and also holds isolated startup configuration. ImageMagick and an X11 display are required for PNG captures; the LSP pass additionally needs rust-analyzer (located through rustup unless `--rust-analyzer` is supplied). ```sh python3 -B test/ui_review.py zig-out/ui-review/bin/pardes-gui \ /tmp/pardes-ui-review --project /path/to/agave \ --theme orchard --themes orchard dusk ink paper daybreak atelier ``` For subsequent palette captures, add `--skip-lsp`. To repeat LSP work without rebuilding dependencies, use `--cargo-target /path/to/previous/cargo-target`. Cargo runs offline and stores build output in that isolated directory. For the TTY pass, use the TTY binary and add `--tty`. The script requires Find/Grep results and observed terminal output, fails missing or malformed SDL captures, and writes `report.json` with the actual outcomes. LSP absence or failure is recorded separately rather than passing as a successful popup. Review artifacts from this pass: - [Baseline workspace](screenshots/before.png) - [Orchard: mild dark](screenshots/orchard.png) - [Dusk: warm dark](screenshots/dusk.png) - [Ink: high contrast dark](screenshots/ink.png) - [Paper: mild light](screenshots/paper.png) - [Daybreak: high contrast light](screenshots/daybreak.png) - [Atelier: Acme homage](screenshots/atelier.png) - [Cell parity evidence](screenshots/parity.json) - [Actual Rust LSP responses](screenshots/agave-lsp.txt) ![Orchard with Agave source, terminal and search](screenshots/orchard.png) ## Regression checks Both native binaries built in ReleaseFast. The full TTY and SDL unit suites passed with the inherited nesting variables `PARDES_PID`, `PARDES_9P` and `PARDES_PANE` removed from the test process. Those variables exposed an existing environment-ownership issue in native subprocess tests: libc's environment was changed while the Zig test I/O retained the old slice. This pass does not change that environment code or skip the affected tests. The appearance checks cover native palette contrast, old ThemeFile documents, wrapped search matches, selection precedence, immediate body colors during theme fades, light-theme carets and both quiet and bold syntax preferences. The 9P walkthrough also verifies `FocusTint` and `SyntaxBold` through `Config`. All 97 terminal snapshot scripts passed without retries after reviewing and refreshing 32 appearance goldens. Of those, 27 preserve identical visible text, cursor positions and grid geometry; the remaining five contain the new default theme name or the expanded theme list. SDL image and PDF harnesses also passed, including continuous PDF layout and idle document reload. The PDF color fixture explicitly selects legacy `helix` to preserve its fixed pixel expectations. ## Possible interaction follow-ups These were not needed for the appearance pass: - A way to reveal an abbreviated pane path on demand could recover title space in deep workspaces. The full path should remain selectable and available to Look; replacing it outright would weaken an existing workflow. - Show a query's busy state until its response arrives, and distinguish an empty answer from a timeout. The first full-workspace Rust hover provided little visible feedback while indexing; explicit status would tell users whether to wait or change their selection. This needs clear cancellation and stale-response behavior before changing the interaction.