Skip to content

feat(ui): lay out large matrices as compact grids with baselines and averages - #41

Merged
nekomeowww merged 1 commit into
mainfrom
nekomeowww/feat/matrix-compact
Nov 2, 2026
Merged

nekomeowww merged 1 commit into
mainfrom
nekomeowww/feat/matrix-compact

Conversation

@nekomeowww

@nekomeowww nekomeowww commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Problem

The Matrix tab put one card per cell, with the row axis that has the most values down the side and every other axis across the top. A 3 model × 2 method × 2 view × 3 window sweep became 3 rows × 12 columns, about 3,200 px wide: three screens of horizontal scrolling, and the row labels scrolled away. Every card repeated the same date, case count, and "completed 100.0%". Column labels repeated method decide · view lookahead3 · across every column.

It also hid a misleading cell: one cell's newest run re-ran a single case, so it showed 100.0% beside cells of 60 cases.

Result

Comparison: 43922ab (main) → 2f37778 (head of nekomeowww/feat/matrix-compact). One commit.

  • Layout: the axes fill one screen width, and rows may run long. Each column axis gets its own header level, and outer values span their inner ones. The header and row labels stay frozen. The 3 × 2 × 2 × 3 sweep is now 6 × 6, and it fits without scrolling.

  • Two cell views, picked automatically:

    • Cards while they fit the width and about 1.5 screens of height.
    • Compact filled cells past that.

    The reader can pin either one; the pick is remembered. Hovering a compact cell opens a detail card with:

    • the cell's configuration
    • the full card
    • every score with its n
    • a 95 % interval
    • the comparison to the baseline
    • each repeat of an averaged cell
  • Average: repeat axes (seed, repeat, trial, …) are pooled into one cell by default. The reader can average any other axis too. The menu shows a dot per value on a shared scale, and the gap between the highest and lowest value. So the reader sees what averaging would hide before picking it.

  • Baseline: the reader can pick a value for any number of axes (method = text, optionally view = online, …). Each cell then shows its difference from the cell that has those values and its own values on the other axes. Differences are colored around 0 (score hue up, teal down), and faded when they are within noise. The menu shows each value's mean.

  • Margins and sorting: row and column means appear as margin bars, square at the baseline end. "Best first" sorts outer groups, then rows, by their mean.

  • Completion ring:

    • On cards, it replaces "completed x%". It uses the CountsBar state colors and shows how many cases have a result out of the entry's usual case count. So the one-case rerun reads as 1 of 60, not 100 %.
    • On compact cells, it appears only when the cell is incomplete.
    • Incomplete cells stay out of the best mark, the means, and the color scale.
  • Aligned bars: the bars of the project and compare cards line up across a grid row. A new subgrid option on ScoreCard makes each card span two rows of its parent grid, panel and tray. Matrix cards fill their table row.

  • No hairlines: groups are set apart by space and tinted header bands, not 1px borders.

How it works

Part What it does
client/src/matrixGrid.ts Pure grid logic, tested:
• varying vs shared axes (matrixAxes)
• the layout choice (chooseLayout): among the splits that fit, the one nearest 1.2 rows per column, narrower on ties
• building the grid with averaged pools (buildGrid)
• cell progress against the typical case count
• standard errors from the case scores
• per-axis baselines (compareToBaseline)
• row sorting
• per-value means (axisMeans)
MatrixView.vue The query, the toolbar (view, Average, Baseline, Best first, superseded toggle), the automatic view choice, and one MatrixTable per entry.
MatrixTable.vue Multi-level headers, frozen row header (not frozen when it would take over half a phone screen), margins, gaps for combinations that never ran.
MatrixHeatCell.vue / MatrixCellDetail.vue The compact cell and its hover details (reka-ui HoverCard + AnimatedContent + floating).
MatrixCellCard.vue The cell card shared by the card view and the hover. Its meta line and sparkline are the same as before; averaged cells list each repeat.
CompletionRing.vue / MarginBar.vue The progress ring and the margin bars.
ScoreCard.vue / HeadlineScore.vue New props: corner slot, hideCompletion, and subgrid.

The significance test treats two cells as independent samples (z test on standard errors). Cells of one entry usually ran the same cases, where a paired test would be much tighter. That needs case identities, which GET /api/matrix does not send. This is marked with a NOTICE in differs.

CLI changes

No CLI changes.

Report file and viewer API changes

No report file or viewer API changes. Only packages/ui/client changed. The server, @vieval/ui/contract, and the report files are untouched. No new dependencies.

Validation

At 2f37778:

  • pnpm typecheck passes. pnpm lint shows only the two warnings already on main.
  • Client tests pass: 120 (vitest.client.config.ts, browser mode), including 14 new matrixGrid tests. The one-case-rerun regression test carries a ROOT CAUSE note.
  • Server tests pass: 140 (vitest.server.config.ts).
  • Checked in a browser with agent-browser against a real 36-cell project (reply-parent-llm):
    • compact, cards, and auto views
    • hover details
    • single-axis and two-axis baselines
    • averaging window
    • Best first
    • both menus' mean indicators
    • light and dark themes
    • 1440×900 and 390×844
    • the home page at 2000 px for bar alignment

Follow-up

  • Server: send each cell's case-score histogram instead of every case score (100k-case runs make GET /api/matrix tens of MB), and send paired statistics keyed by case id.
  • Server: look into why a one-case rerun becomes the cell's full run (caseCount: 1).
  • Phones: compact hover cards do not open on touch; tapping a cell opens the task.
  • Card footers: long values in matrix tag footers are still clipped without an ellipsis.

🤖 Generated with Claude Code

…averages

The matrix tab put one card per cell in a single wide row of columns, so a
3 x 2 x 2 x 3 sweep needed three screens of horizontal scrolling and every card
repeated the same metadata.

- Lay the axes out to fill one screen width (rows may run long), with one
  header level per column axis and frozen headers and row labels.
- Switch between cards and compact cells automatically by grid size and
  screen; the reader can pin either. Compact cells open a detail card on
  hover: configuration, full card, every score, 95% interval, baseline
  comparison, and repeats.
- Average repeat axes (seed, repeat, ...) by default, or any axis on demand.
- Compare every cell to a baseline chosen per axis; differences are colored
  around 0 and faded when within noise.
- Show row and column means as margin bars, and sort rows best first.
- Mark completion with a ring measured against the entry's usual case count,
  so a one-case rerun reads as 1 of 60 instead of 100%.
- Show each value's mean beside the baseline and average menus.
- Align card bars across a grid row with CSS subgrid on the home and compare
  pages, and full-height cells in the matrix card view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

Approval required for deploying to Cloudflare Workers (Preview) for docs.

Name Link
Waiting for approval For maintainers, approve here

@nekomeowww
nekomeowww merged commit 984f121 into main Nov 2, 2026
5 checks passed
@nekomeowww
nekomeowww deleted the nekomeowww/feat/matrix-compact branch November 2, 2026 19:35
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