feat(compare): replace index card walls with GPU pair selection matrices#600
Draft
Oseltamivir wants to merge 6 commits into
Draft
feat(compare): replace index card walls with GPU pair selection matrices#600Oseltamivir wants to merge 6 commits into
Oseltamivir wants to merge 6 commits into
Conversation
The /compare and /compare-per-dollar indexes rendered ~258 pair cards
across 9+ model sections, which no longer scales as a navigation
surface. Each model section now renders one upper-triangle GPU×GPU
matrix instead: pairs with benchmark data are server-rendered links
(brand tint for cross-vendor, neutral fill for same-vendor), pairs
without data render as dashed ghost cells so coverage gaps are visible
at a glance.
- Axis order derives from HW_REGISTRY: contiguous vendor blocks
(NVIDIA then AMD), oldest-to-newest within a vendor, so the
cross-vendor region forms a rectangle replacing the old three
vendor card groups
- Hover/focus highlights the row and column headers and shows the
pair label in a readout line; cells carry full accessible names,
native tooltips, and sr-only pair-name anchor text for crawlers
- compare_index_pair_clicked fires with the same {slug, label}
payload as the old cards
- Mobile: horizontal scroll with a sticky GPU-label column
- /zh index pages are intentionally unchanged in this PR
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Bring the /zh/compare and /zh/compare-per-dollar index pages to parity
with their English siblings: they now render the ComparePairMatrix
instead of the old vendor-group card walls. The matrix component gains
an { en, zh } STRINGS dict resolved via useLocale(); English strings are
byte-identical. Drops the now-unused per-page VendorGroup helpers and the
bucketComparePairsByVendor helper (plus its interfaces and orphaned
imports) from compare-ssr.ts.
Also fixes a hover/focus bug in ComparePairMatrix: hover and keyboard
focus shared one state, so a pointer entering and leaving a focused cell
cleared the focus highlight. Split into hoveredCell/focusedCell with
active = hoveredCell ?? focusedCell so hover takes precedence while
present and a focused cell's highlight persists after the pointer leaves.
Adds zh coverage to the compare-index-matrix e2e spec.
buildCompareMatrix built cell.label via compareDisplayLabel in display (row vs column) order, so the H100×B200 cell read "H100 vs B200" while its destination page /compare/<model>-b200-vs-h100 titles the pair "B200 vs H100" — and the pre-matrix index cards sent that same alphabetical label in the compare_index_pair_clicked analytics payload. Tooltip, sr-only anchor text, readout, and analytics disagreed with the destination for every pair whose display order differed from A-Z. Label from the already-sorted [first, second] instead so it matches the canonical slug, the destination title, and the analytics payload. Update the CompareMatrixCell.label doc and the unit test accordingly.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5b24bd5. Configure here.
compareMatrixGpuOrder ranked vendor blocks by each vendor's lowest registry sort value. That yields NVIDIA-first today, but the registry interleaves vendors by generation, so a future AMD flagship whose sort dips below GB300's would silently flip the whole axis to AMD-first and move the cross-vendor region — contradicting the docblock's stated NVIDIA-first design. Pin the order with a VENDOR_BLOCK_ORDER constant (NVIDIA, then AMD): listed vendors sort by their pinned index, a listed vendor always precedes an unlisted one, and two unlisted vendors fall back to the existing best-registry-sort comparison so a future third vendor still orders deterministically. Within-vendor ordering is unchanged. Docblock and the contiguity test comment updated to reflect the pinned invariant.
The matrix table previously sized to its content (fixed 32/36px square cells), leaving roughly half of the card empty on desktop viewports. Switch to a fixed-layout full-width table: the row-header column keeps a set width and the nine GPU columns share the remaining space, so cells grow into wide rectangles that fill the card at any width. Column headers become horizontal (they no longer need to fit narrow squares), and the 600px table min-width preserves the horizontal-scroll + sticky row-label behavior on mobile.
…cells Flip the GPU-pair selection matrices from upper to lower triangle: rows now run H200 -> MI355X and columns H100 -> MI325X, with cells below the diagonal (cells[rowKey][colKey], column display-index < row display-index) so the storage matches the rendered grid. Slugs, labels, and cross-vendor flags are unchanged (still canonical alphabetical order). Also add a persistent clickability affordance: every linked cell centers a visible north-east arrow glyph (brand-tinted on cross-vendor cells, muted on same-vendor, brightening on hover) while ghost cells stay empty, so linked vs no-data cells are distinguishable without hovering.
Oseltamivir
marked this pull request as draft
July 20, 2026 13:33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
The
/compareand/compare-per-dollarindex pages rendered one card per comparable GPU pair — ~258 cards across 9+ model sections, split into three vendor groups each. Finding a specific pair meant linearly scanning a card wall, and pairs without data were invisible.Each model section now renders a single upper-triangle GPU×GPU selection matrix:
HW_REGISTRY, not hardcoded: contiguous vendor blocks (NVIDIA, then AMD), oldest→newest within a vendor (H100 → H200 → B200 → B300 → GB200 → GB300 / MI300X → MI325X → MI355X).titletooltips.SEO / behavior preserved
<a>(no client-side model switching), with the pair name as sr-only anchor text and a full accessible label ("DeepSeek R1: H100 vs H200 benchmark comparison").compare_index_pair_clickedanalytics event fires with the same{slug, label}payload as the old cards.idanchors, and JSON-LD are untouched.ComparePairCardLinkstays — the/compare-precisionand/compare-spec-decodeindexes still use it.Notes for review
/zhindex pages are intentionally unchanged in this PR — they keep the existing card UI (which is whybucketComparePairsByVendorremains incompare-ssr.ts). The matrix can be ported to the zh siblings in a follow-up.Testing
compare-matrix.test.ts(10 tests): axis ordering invariants, upper-triangle completeness, availability marking, canonical slug construction, cross-vendor flags.compare-index-matrix.cy.ts: matrix renders per model section, cell hrefs are canonical for both routes, click navigates to the pair page, ghost cells render for missing pairs, focus updates the readout.pnpm typecheck,lint,fmt, production build, and thecompare-precision/compare-redirecte2e specs all pass against the fixtures server.Note
Medium Risk
Large navigation/UI change on SEO-heavy compare index routes; mitigated by preserving server-rendered link URLs, analytics payloads, and new unit/e2e coverage.
Overview
Replaces the vendor-grouped card grids on
/compare,/compare-per-dollar, and their/zhindex pages with one GPU×GPU lower-triangle matrix per model section, built server-side viabuildCompareMatrixand rendered by the new clientComparePairMatrixcomponent.Navigation UX: Every registry GPU appears on a shared axis (NVIDIA then AMD, oldest→newest within vendor). Cells with benchmark data stay real
<a>links (sr-only pair text, samecompare_index_pair_clickedanalytics); missing pairs show as ghost cells so coverage gaps are visible. Cross-vendor cells get brand styling; hover/focus drives a readout and row/column highlights.Cleanup: Per-page
groupPairsByVendorForModelandbucketComparePairsByVendorincompare-ssr.tsare removed.ComparePairCardLinkis unchanged for precision/spec-decode indexes.Tests: New
compare-matrix.test.ts(ordering, slugs, availability) and Cypresscompare-index-matrix.cy.ts(matrices, hrefs, ghosts, focus readout, en/zh routes).Reviewed by Cursor Bugbot for commit 2c49d6b. Bugbot is set up for automated code reviews on this repo. Configure here.