fix(compare-per-dollar): clearer axis labels and curve-extension distinction in PNG#395
Merged
Merged
Conversation
…inction in PNG The indexed performance-per-dollar PNG had two readability problems: 1. Y-axis labels were inconsistent ($0.000 / $9.01 / $18.0 / $27.0) because the per-tick formatter picked precision from each tick's magnitude. Switched to a 1/2/5-step nice-axis with one precision chosen from the step size, applied uniformly to every tick. 2. The curve continued past the rightmost labeled dot with no visual distinction, leaving readers unsure whether the trailing values were real data or extrapolation. The curve is now split at the matched- interactivity bounds: the segment between the labeled dots stays solid, and the portion extending toward each SKU's operating envelope edge renders as dashed, semi-translucent. Faint italic endpoint labels mark the actual x-range, and a one-line caption under the axis explains the convention. `computeCompareImageRows` now accepts an optional `includeTargets` array so the dot targets are guaranteed to be exact samples in the curve — the partition into solid / dashed segments connects cleanly at the boundary without per-segment boundary interpolation in the renderer.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…lyphs The wrapper used `transform: scale(2)` to upsample a 1200x675 layout into the 2400x1350 ImageResponse. Satori rasterizes text glyphs at the source size before applying CSS transforms, so the bitmap got upscaled and the chart came out blurry. Multiplying every pixel constant by R=2 and rendering the wrapper at full size keeps strokes and text as native high-res vectors.
Google's Product rich-result validation requires offers/review/aggregateRating, none of which apply to benchmark subject GPUs. Switch the per-GPU item type to schema.org Thing — vendor/category move into additionalProperty so no crawl info is lost — and the validator warning goes away.
Schema.org Dataset.hasPart expects a CreativeWork (or subclass). Observation isn't a CreativeWork, so Google's structured-data validator rejected each row. Dataset accepts variableMeasured exactly like Observation, so the inner shape is unchanged — only the @type label moves.
Google's Rich Results validator flags Dataset entries without a license URL and a creator. The repo (github.com/SemiAnalysisAI/InferenceX) is Apache-2.0 and the author is SemiAnalysis — use the canonical Apache license URL and the existing AUTHOR_NAME / AUTHOR_URL seo constants so the dataset card is eligible for rich-result rendering.
…crumbs Three SEO-only additions to the compare slug pages: 1. Dataset metadata polish — datePublished / dateModified derived from the benchmark row dates for this pair, plus keywords, isAccessibleForFree, and measurementTechnique. These are the fields Google Dataset Search actually surfaces. 2. distribution: DataDownload — points at /api/v1/benchmarks?model=… so the Dataset isn't just described, it's downloadable in machine-readable form. 3. BreadcrumbList JSON-LD on every /compare/[slug] and /compare-per-dollar/ [slug] page (Home → GPU Comparisons / GPU Performance per Dollar → A vs B (Model)). Drives the Google SERP breadcrumb trail. No behavioral changes to the UI — only the SSR JSON-LD payload grows.
… name H100 vs H200 was producing 'NVIDIA, NVIDIA' in the Dataset keywords list, and MI300X vs MI325X was producing 'AMD, AMD'. Wrap the keyword list in a Set so each value appears at most once. Cross-vendor pairs still get both 'NVIDIA, AMD'.
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
Two readability problems in the indexed
performance-per-dollar.pngshipped in #392:Y-axis labels were inconsistent (
$0.000/$9.01/$18.0/$27.0) because the formatter picked precision from each tick's magnitude. Now uses a 1/2/5-step "nice axis" with a single precision picked from the step size and applied uniformly.Curve continued past the rightmost labeled dot with no visual cue, so it wasn't clear whether the trailing values were real or extrapolation. The curve is now split at the matched-interactivity bounds:
The asymptote story (cost rises sharply approaching each SKU's pareto edge) is preserved, but now the reader can tell at a glance which portion of the curve is the matched comparison and which is the envelope-edge extension.
Implementation
computeCompareImageRowsgains an optionalincludeTargets: number[]argument. The route passes the three plotted-dot targets so they land as exact samples in the curve — the renderer can then partitiontarget >= matchedMin && target <= matchedMaxcleanly without per-segment boundary interpolation.includeTargetsoutside the interactivity range are dropped, and duplicates of the even grid are deduped.Validation
pnpm typecheck,pnpm lint,pnpm fmtall pass (pre-commit hook ran them too)compare-ssr.test.tscovers theincludeTargetscontract: even-grid count preserved, includes are inserted, out-of-range dropped, dedupe works, degenerate range returns emptyE2E_FIXTURES=1 pnpm devfor three representative pairs (DeepSeek V4 Pro B200 vs MI355X, DeepSeek R1 B200 vs H200, DeepSeek V4 Pro GB200 vs MI355X) — y-axis ticks are clean round numbers, dashed extensions are unambiguous, caption renders within the panelBefore / after on the reported case
Before (#392, DeepSeek V4 Pro B200 vs MI355X):
$0.000/$9.01/$18.0/$27.0, curve continues past42with no x-tick or styling change.After: round
$0/$5/$10/$15/$20/$25ticks, solid curve between the dots, dashed continuation past the last dot, italic endpoint labels at the curve's actual x-range.Note
Low Risk
Changes are limited to static OG image rendering, structured data, and sampling helpers—no auth, payments, or core API behavior.
Overview
Improves the performance-per-dollar OG PNG and tightens compare SEO in the same pass.
The PNG route now renders at native 2× resolution (no CSS
scaleblur), uses d3-style “nice” Y-axis ticks with uniform dollar formatting, and draws cost curves as solid in the matched-interactivity band and dashed toward each SKU’s envelope edges, with faint endpoint labels and a short caption.computeCompareImageRowsaccepts optionalincludeTargetsso table dot targets are exact samples for clean segment boundaries; vitest covers merge, clamp, and dedupe behavior.Both
/compareand/compare-per-dollarslug pages emit extra BreadcrumbList JSON-LD, pass benchmark datePublished/dateModified into the main graph, and enrich the sharedbuildJsonLdoutput (license, keywords, JSON DataDownload link,Thinglist items, per-rowDatasetparts).Reviewed by Cursor Bugbot for commit f501dbb. Bugbot is set up for automated code reviews on this repo. Configure here.