Gallery: show GT "answer-key" edit-diff for editing fixtures
Michael Rabinovich+1: Cursor
49e27be
The ground-truth row now renders the blue edit-diff turntable (the
correct change vs the input) for editing fixtures instead of a plain GT
turntable, so the reference reads the same way as the candidate
red/amber diff in the same column. Adds a gt_diff_resolver pointing at
the one-time GT-dataset webp (<fixture>/renders/edit_diff_gt.webp, via
the existing /gt proxy) and updates the compare modal caption/legend.
tools/generate_gt_edit_diff.py renders/uploads those webps for the 32
editing fixtures (one-time, per data revision).
Co-authored-by: Cursor <cursoragent@cursor.com>
Rename fixture-named result keys to sample-named keys
Michael Rabinovich+1: Cursor
be6fa3d
Read/write per_sample_scores, per_sample_breakdown, n_samples,
per_sample_results across submit/gallery/admin and tools. Also link the
canonical submission docs from the Submit tab.
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: tighten mobile gallery box to a single scroll
Michael Rabinovich+1: Cursor
4090e8a
Increase the mobile chrome reserve so the capped box fits the phone
viewport (kills the residual outer page scroll on top of the box's own
scroll). GT row stays pinned; shows the GT + a couple of models with the
rest reachable by scrolling the box.
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: mobile uses the same aligned table as desktop
Michael Rabinovich+1: Cursor
0c0ddd8
Revert the mobile card layout (it broke the GT-vs-output comparison by
putting GT in its own card). On phones now show the same table: sticky
sample-column headers + pinned ground-truth row, with each model's four
renders aligned in the same columns directly under the GT. To fit phone
width the per-model name+score becomes a slim bar above that model's
render row (no room for a left identity column plus four renders). The
box still caps + scrolls internally so the GT row stays pinned.
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: dedicated mobile card layout for the gallery
Michael Rabinovich+1: Cursor
a636039
A horizontal-scroll table is unusable on phones (one render at a time).
On narrow screens hide the table and render one card per model instead
(plus a ground-truth card), each showing the four renders in a labelled
2x2 grid, so the whole comparison reads top-to-bottom with a single
vertical scroll.
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: fix mobile gallery (GT row wrap + double scroll)
Michael Rabinovich+1: Cursor
00f76c2
- The GT row wrapped on mobile because a base rule (.grow.gt-row .rank)
re-showed the rank cell only on that row (7 items in a 6-col grid);
force-hide rank on mobile so the row lays out correctly.
- On phones, drop the vertical cap so the page scrolls once vertically
and fixtures are reached by horizontal swipe (frozen Submission
column), instead of a tiny capped box plus a confusing outer scroll.
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: reclaim Gradio chrome + responsive mobile gallery
Michael Rabinovich+1: Cursor
2ec97dd
- Hide the Gradio footer and tighten outer padding (the unused space
between Refresh and the footer) and grow the gallery box to use it, so
more rows fit in one viewport.
- Mobile: the 4-sample matrix no longer clips. On narrow screens the
table scrolls horizontally (swipe), the rank column is dropped, the
Submission column is frozen to the left, and the score breakdown is
hidden -- so the renders are actually visible and you can tell which
model each belongs to, with the header + GT row still pinned.
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: squeeze header/caption, grow gallery to show more rows
Michael Rabinovich+1: Cursor
882faa0
- Drop the gallery caption and collapse the Gradio title to a single
compact line, and cut the gallery body padding (removes the dead gap
between the last row and the Refresh button).
- With that freed vertical space, lower the box chrome reserve and raise
the cap so the gallery shows as many rows as fit in one viewport while
staying a single scroll (harness-verified across screen sizes).
Co-authored-by: Cursor <cursoragent@cursor.com>
- Raise the box height cap (760->900) so larger screens use their
vertical space and show more rows, keeping the chrome reserve so it
still fits in one viewport (single scroll).
- Add a clear scroll affordance: a persistent (styled) scrollbar plus a
'scroll for more models' fade cue at the bottom that hides once the
list is scrolled to the end, and a caption note that the GT row stays
pinned.
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: widen gallery chrome reserve to kill residual outer scroll
Michael Rabinovich+1: Cursor
5fb80c6
Live verification showed a constant ~56px outer-page overflow on smaller
screens (real HF chrome is a bit taller than the harness estimate). Bump
CHROME_RESERVE 560->620 and lower the box floor so the whole gallery fits
the viewport across screen sizes (single scroll).
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: gallery scroll box sized off screen.availHeight
Michael Rabinovich+1: Cursor
a435f45
Verified the real cause with a headless harness reproducing HF's nested
iframes: HF auto-resizes the Space iframe to full content height, so
inside the gallery window.innerHeight / parent.innerHeight / vh are all
inflated to the content height (live: 1642 vs a 900 viewport) and only
the cross-origin top window scrolls -- which is why no inner cap or
sticky-against-the-iframe ever worked and the GT row scrolled away.
screen.availHeight is the one viewport-ish measure that survives the
nesting, so size the gallery's own scroll box from it (availHeight minus
a chrome reserve, clamped). The column header + GT row are sticky inside
that box, so they stay locked while the submission rows scroll, and the
box is the single scroller (harness confirms no outer-page overflow
across laptop/desktop/large screens).
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: make the gallery the single scroller
Michael Rabinovich+1: Cursor
5eaf6b8
Sizing the iframe to a fixed 80vh left two scrollbars (the iframe body
and the outer Gradio page), which was confusing. Now fitIframe measures
the available height from the iframe's own top down to the bottom of the
viewport (via the same-origin parent) and sizes the iframe to
min(content, available), reserving room for the Refresh button. Short
content shrinks the iframe (nothing scrolls); tall content fills the
viewport so only the iframe body scrolls and the sticky header + GT row
stay locked. The outer page no longer needs its own scrollbar.
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: lock GT row via in-iframe scroll capped by max-height
Michael Rabinovich+1: Cursor
a0462d9
The previous attempt capped the gallery scroll box from JS using
window.parent.innerHeight, but inside HF's nested iframes that is not the
browser viewport, so the cap came out huge: the box never scrolled, the
iframe grew to full height, and the page scrolled the GT row away.
Instead, scroll inside the iframe itself (the column header + GT row are
sticky against the iframe viewport, which reliably works) and cap the
iframe with `max-height: 80vh` in app.py, where vh is the Gradio doc
viewport. fitIframe still shrinks the iframe to content for a compact
page when there are few rows; once content exceeds the cap the iframe
body scrolls and the GT row stays pinned. Drops the unreliable JS cap
and the parent-aware modal positioning (back to plain fixed centering).
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: lock GT row + header in a capped gallery scroll box
Michael Rabinovich+1: Cursor
5dd0c03
Make the gallery a scroll container capped at ~78% of the visible
viewport so the column header and ground-truth row stay pinned (sticky)
at the top while submissions scroll inside it. The cap is set from the
parent viewport in JS and the iframe is sized to the (bounded) content,
so the page stays compact and shows no scrollbar when the rows are
shorter than the cap.
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: fixed 4-sample gallery, auto-size iframe, center modal
Michael Rabinovich+1: Cursor
08eae45
Replace the gallery's interactive fixture picker with a fixed
comparison sheet: two generation + two editing samples, one Medium and
one Hard per task. Difficulty is chosen once from the Claude Opus 4.8
baseline's per-sample CAD scores (median = Medium, 20th percentile =
Hard) and frozen into FIXED_FIXTURES; the GUI no longer recomputes it
as the leaderboard evolves, trading a moving ground truth for a simple,
stable interface. Adds tools/pick_gallery_fixtures.py to regenerate the
constant.
Size the gallery iframe to its content (no more 90vh fixed box / nested
scrollbar) and pin the compare modal to the visible part of the iframe
so it opens centered in view instead of far below the fold.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Rename the visual "Gallery" tab to "Leaderboard" and the table tab to
"Detailed View" (order unchanged); update the smoke test accordingly.
- Replace user-facing "fixture" wording with "sample" across the gallery,
task browser, submit instructions, and submitter status/error messages.
Internal data keys, routes, CSS, and identifiers are unchanged.
- Drop the gallery's "more numbers" expander: surface Generation/Editing
inline under the aggregate score and move Download ZIP under the name.
- Link each gallery submission title to its hosted report (same
/reports/<id>.html the Detailed View table uses); drop the date line.
Co-authored-by: Cursor <cursoragent@cursor.com>
leaderboard: show edit-diff turntable in gallery grid for editing fixtures
Michael Rabinovich+1: Cursor
e611f15
The gallery grid tile for an editing fixture now serves the ghost edit-diff
WebP (renders/<id>/<fixture>/edit_diff.webp) instead of the plain candidate
turntable, so a small edit is legible at a glance. Generation tiles, the GT
column, and the cell-click modal are unchanged (the modal keeps the plain
aligned output via img; the grid uses a new gridImg).
- gallery: per-cell gridImg + gridRenderFor hook; build/render take a
diff_resolver.
- app: _fetch_render_diff + /render-diff proxy route + resolver. A miss 404s
to the dashed cell (no fallback to rotating.webp).
Co-authored-by: Cursor <cursoragent@cursor.com>
Serve rotating WebP turntables + GT generator
Michael Rabinovich+1: Cursor
c1cb5e4
Point the gallery and proxy routes at rotating.webp (submissions and
GT), publish the full per-fixture renders folder, and add a reusable
one-time GT turntable generator that renders from the cached GT mesh.
Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the always-open fixture chip grid with the compact reference UI:
current picks as removable pills + an "Add fixture" button opening a
searchable, grouped (Generation/Editing) dropdown, capped at 3 with a
"remove one to add another" note. Persist the 3 picks in ?fixtures= so
shared links reproduce the view; URL read/replaceState are try/catch
guarded for sandboxed iframes. Drop the external Google Fonts @import for
system font stacks so the page never errors in a sandboxed frame.
Serve thumbnails as lazy-loaded, hard-cached /render and /gt-render proxy
URLs (loading="lazy" + decoding="async" + CSS-constrained width) instead
of base64-inlining every tile, so only the ~33 visible thumbnails load and
fixture swaps / repeat visits hit cache. Requires the Space to be public.
Fix a stale test expecting the old 6-tuple _admin_delete signature.
Co-authored-by: Cursor <cursoragent@cursor.com>
Visual-first leaderboard as a new default tab. Self-contained HTML
(gallery.py) inlined into an iframe srcdoc with base64 thumbnails, so
it works on the private Space where HF's edge 404s in-browser
custom-route fetches (same constraint the report viewer's srcdoc path
already handles). Top-10 verified only, teal sticky ground-truth row,
3-fixture picker (drop-oldest, global re-render), dashed cell for
invalid/missing fixtures, per-row generation/editing/validity expander,
and a GT-vs-output compare modal per thumbnail. Existing Leaderboard /
Submit / About / Admin tabs unchanged.
Co-authored-by: Cursor <cursoragent@cursor.com>