HivePaaS
Docker Swarm 기반 오픈소스 자체 호스팅 PaaS, SSL·백업·자동 확장 지원
720p~4K 해상도에서 비와 네온 도시를 비행, 평균 FPS·1% Low 측정 후 Open GPU Benchmarks에 제출
Fly through a rain-soaked neon megacity at 720p, 1080p, 1440p or 4K. Uncapped and GPU-timed, with Average FPS and 1% Low results you can submit to Open GPU Benchmarks.
개발 도구TypeScript · CSSGitHub @MattyStacks온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗An open-source GPU benchmark that runs in the browser with nothing to install (opengpubenchmarker.com). It runs one benchmark, Neon Flythrough: a fixed 96 s flight through a dense, rain-soaked cyberpunk megacity. The camera dives between stacked towers to just above the street traffic, flies under sky bridges, weaves through the streets, rides between stacked sky-lanes of flying cars, and climbs over the rooftops for a skyline that runs out to the horizon. It reports Average FPS and 1% Low FPS, a 3DMark-style score on the two fixed score runs, a stability % on the two ~10-minute stress tests, and a diagnosis of what limited the run (GPU, CPU, driver/browser). You can keep results in your browser or submit them to Open GPU Benchmarks.
0.186.1 on WebGL2 (WebGLRenderer, no WebGPU).npm install
npm run dev # local dev server
npm test # Vitest unit tests
npm run test:coverage # unit tests + coverage report (coverage/)
npm run test:e2e # Playwright browser tests in e2e/ (starts its own dev server)
npm run build # type-check + production build into dist/
npm run preview # serve dist/ locally
npm run deploy # build + wrangler deploy (production)
npm run preview:deploy -- <name> # build + upload a preview at <name>.opengpubenchmarker.com
npm run check:share # after a build: every Share button must pass the link (Playwright)
npx vite --host # dev server on the LAN, e.g. http://192.168.1.20:5173
npx vite preview --host # same for the production build in dist/
The Web Share API and navigator.clipboard need a secure context (HTTPS or
localhost). Over plain LAN HTTP they are unavailable, so on a phone use LAN
only for layout, run flow and results rendering; test share/clipboard paths on
localhost or on a preview deploy:
npm run preview:deploy -- stress-tests # after `npm test` and `npm run build` pass locally
That runs wrangler preview --name stress-tests (Worker Previews; previews = {}
and previews_enabled = true on the route in wrangler.toml). Name each preview after
its feature branch. The Preview is served at https://stress-tests.opengpubenchmarker.com
(the custom domain is set to "Production and Preview") and at
https://stress-tests-openbenchmarker.mattys.workers.dev. A Preview never
touches production: opengpubenchmarker.com changes only on npm run deploy.
Previews are public, like the site itself; public/_headers marks preview
subdomains noindex. A Preview is a different origin, so it has its own
localStorage and does not see results saved on production. Remove it with
npx wrangler preview delete --name stress-tests. See docs/privacy-audit.md
for what the site does and does not store or send.
Sharing. A valid result can be shared as a link (#/r/<payload>) plus a share
card PNG with a QR code. The whole result is encoded in the URL fragment, which
browsers never send to the server; it is encoded, not encrypted, and sharing runs on
the honor system (nothing is signed or verified). Format and test steps:
docs/share-links.md.
Phones can run out of memory at 1440p and 4K on heavier presets, and the OS then closes the page. The site detects this on the next load, offers a lower resolution, and asks for a one-tap confirmation before memory-heavy runs on phones and tablets. See docs/high-res-memory.md for the estimates and docs/device-test-matrix.md for the device checklist.
To deploy, run npx wrangler login once, then npm run deploy. wrangler.toml
serves ./dist with an SPA fallback. Attach the custom domain
opengpubenchmarker.com in the Cloudflare dashboard (Workers → openbenchmarker →
Settings → Domains).
There are two fixed tests, like 3DMark's. Their settings are locked, so every score measures the same workload:
| Score run | Preset | Resolution | Duration |
|---|---|---|---|
| Score: Entry | Low | 720p (1280×720) | 60 s |
| Score: Extreme | Extreme | 4K (3840×2160) | 60 s |
Score = round(Average FPS × 100). The score is linear in FPS, so any gain, from a faster GPU or an overclock, raises it. FPS, the 1%/5% lows and the diagnosis are shown next to it.
requestAnimationFrame wait, and Avg FPS is frames ÷ wall-clock time.Two long locked runs for sustained performance (thermal throttling, power limits), like 3DMark's stress tests. They use the score runs' settings and repeat the whole 96 s flight as laps:
| Stress test | Preset | Resolution | Laps | Timed |
|---|---|---|---|---|
| Stress: Entry | Low | 720p (1280×720) | 6 | 576 s ≈ 10 min |
| Stress: Extreme | Extreme | 4K (3840×2160) | 6 | 576 s ≈ 10 min |
t mod 96), so
traffic, drones and rain repeat exactly and lap 6 renders the same frames as lap 1. Other runs
end before 96 s of scene time, so the wrap never applies to them.?laps=N runs a stress test with N laps for testing; the result doesn't
match the locked test, so it has no stability and can't be shared.During the run, the HUD shows a live LIMIT chip (GPU / CPU / GPU + CPU, with GPU busy %),
plus the GPU and JavaScript time per frame. The results page explains the limit in plain words
and lists fixes. All of it comes from signals the browser exposes (src/benchmark/diagnose.ts):
| Signal | How it's measured |
|---|---|
| GPU busy % / GPU ms per frame | EXT_disjoint_timer_query_webgl2 time per frame ÷ wall-clock |
| JS ms per frame (scene update vs draw submission) | performance.now() around each frame, and around the scene update |
| GPU wait per frame | Time spent waiting with the GPU queue full (three batches queued) |
| Browser overhead | Share of wall-clock outside render batches (1 − loop busy) |
| Main-thread stalls | Yields delayed > 20 ms by other work (tabs, extensions, GC) |
| Hitches, frame-time spread | Frames > 2.5× the median and at least 4 ms over it; standard deviation |
| JS heap growth | performance.memory (Chromium only) |
| Renderer, ANGLE backend, max texture size | WEBGL_debug_renderer_info and gl.getParameter |
| Battery | Battery Status API (Chromium), at the start and when timing begins |
The verdicts:
The diagnosis also flags:
setPixelRatio(1), and CSS only scales it to fit on screen. You also choose a
preset (Low to Extreme) and a duration (30/60/90 s). These settings
can't change during the run.MessageChannel. Batches don't wait for vsync, so the score can go well
above the monitor's refresh rate. The browser only shows the canvas between tasks (a
batch's last frame), so batches are kept short for smooth motion on screen; 2.1.0's
28 ms batches showed only ~35 updates a second however high the FPS.
readPixels at the warm-up→timed
switch and at the end, so timing starts and stops on an idle GPU. Chrome's gl.finish()
doesn't actually wait, so it isn't used. Warm-up/timed membership is fixed when a frame is
submitted.p1_low)
= mean FPS of the slowest 1% of frames, using per-frame times. When
is available, each frame's time is its GPU time
from a timer query, or its batch's average frame time if that is larger (CPU-bound);
results flagged disjoint are dropped. Without the extension, every frame gets its
batch's average frame time. The method is recorded as ( or
) in JSON/CSV. The tool also records 5% low, worst frame, and frame count.
Scores from 1.1.0 aren't comparable with 1.0.0, which synced after every frame.
keeps the GPU queue full (see step 4), so GPU-limited results can be a few
percent higher than on 2.0.0 with the same hardware. Scores from aren't comparable with 1.x either: 2.0.0 is a new scene and new
presets (a much heavier workload). The measurement itself is unchanged. My Results
shows each result's version.The HUD sits inside the stage, below the top banner. The banner stays in normal page flow (never fixed or sticky), so the HUD can't end up hidden under it.
| Preset | Towers | Detail | Rain | Signs | Cars | Lane levels | Drones | Far drones | Holos | Skyline | Clouds | Shafts | Bloom | Shadow map | MSAA | Reflections | Haze steps |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Low | 260 | 0 | 3 000 | 120 | 90 | 2 | 8 | 120 | 2 | 1 | 1 | 2 | 0.4 | – | – | – | – |
| Medium | 520 | 1 | 5 000 | 260 | 200 | 3 | 16 | 300 | 4 | 2 | 1 | 4 | 0.55 | 1024 | 8 | – | – |
| High | 900 | 2 | 8 000 | 500 | 400 | 4 | 28 | 700 | 6 | 3 | 2 | 8 | 0.6 | 2048 | 8 | – | 6 |
| Ultra | 1 600 | 3 |
src/engine/volumetric.ts), a
per-pixel ray march through drifting 3D noise that picks up light from the nearest neon
signs. It is GPU-only work that scales with pixels × steps.MAX_TEXTURE_SIZE (Extreme asks for 8192); a capped
run says so and isn't comparable./?lab on npm run dev).The streets are drawn procedurally on the ground plane on every preset, at no extra draw
calls (src/engine/ground.ts). They have wet asphalt with puddles, neon lane markings that
line up with the traffic lanes, pulsing holographic crosswalks, a guide grid over each
junction, glowing curb strips with light spilling onto the road, paved sidewalks with
floor lights, and drain grates.
Presets with bloom also add a grade pass (chromatic aberration, scanlines, grain,
vignette). On Ultra and Extreme, a Reflector re-renders the whole scene mirrored every
frame to make the wet-street reflections.
Load per preset at 1280×720 (t = 20 s, renderer.info summed over every pass of one
frame, including shadow, reflection and post passes), v1.1.0 → v2.0.0:
| Preset | Draw calls v1 → v2 | Triangles v1 → v2 |
|---|---|---|
| Low | 25 → 23 | 15 k → 92 k |
| Medium | 52 → 52 | 24 k → 416 k |
| High | 53 → 56 | 34 k → 1.16 M |
| Ultra | 103 → 96 | 136 k → 4.14 M |
| Extreme | 165 → 115 | 339 k → 7.47 M |
Camera clearance. Nothing solid comes within 14 units (CLEAR_SOLID) of the camera
path in 3D: every tower part, sky bridge, sign, lantern and filler box is an
axis-aligned box checked against a grid index of the densely sampled path. A failing
upper tier truncates its tower, a failing base shrinks the lot (or leaves a plaza), and
failing details are dropped. Moving things keep 10 units (CLEAR_MOVING): each whole
traffic lane and level-change column, every drone orbit, and every far-swarm ring.
tests/scene.test.ts checks all of these for every preset.
This tool feeds a public dataset, so:
memory_channels is 4 on phone and tablet runs,
because browsers can't detect it. It's listed in the result's suggested field, shown as
"4 (assumed)" in My Results, exported in CSV (suggested_fields) and JSON, and commented
# assumed, not confirmed in submission YAML. Editing the field removes the mark. Rules live
in the field registry, src/benchmark/fields.ts.carry: true in the registry: GPU, OS, OS version, CPU, memory, memory type
and channels, GPU driver, distro, overclocked and the overclock details; not kernel, Mesa or
Proton, which change with updates). They're your own values, so they aren't marked as
suggestions; the form says which result they came from until you edit a field. If the browser
reports a different GPU than on that result, the GPU's own fields (GPU, driver, overclock) start
fresh. The graphics API is never carried: each run records its own.overclock: block right after
overclocked: true (proposed upstream in
docs/upstream-submission-changes.md), and are kept but
ignored (not validated or exported) when overclocked isn't yes.detected: block, for the
diagnosis only. They never fill in the GPU or any system: field. A software-rendered run
(SwiftShader, llvmpipe, Microsoft Basic Render) can't be submitted.Submitting is optional, and it's up to you. Results stay in the browser unless you share, export or submit them. The site keeps nothing and sends nothing itself, so submitting isn't automatic: you submit to Open GPU Benchmarks yourself through GitHub, see exactly what's published, and decide what goes in it. Your GitHub username is public on the pull request. On desktop and laptop results the page shows a short, dismissible invitation to submit ("Not now" hides it; nothing is stored), and links to opengpubenchmarks.com to explore the charts. Nothing opens on its own and there are no pop-ups.
The results page builds result_YYYYMMDD_openbenchmarker_neon_flythrough.yaml for
data/community/<gpu_id>/, and it can open GitHub's new-file form already filled in.
Besides the upstream fields, each result item carries run details. These are the score and
score_test (score runs), rendered_with (the bloom/MSAA/shadows/reflections actually used) and
diagnostics (the limit verdict and the signals behind it). A top-level detected: block holds
the browser-read values, and there is an optional top-level overclocked. Upstream accepts these
today without validating them. docs/upstream-submission-changes.md spells out the
checks.py/template changes that make them first-class.
The first PR that uses this benchmark must also add it to upstream data/games.yaml:
- id: openbenchmarker_neon_flythrough
name: OpenBenchmarker Neon Flythrough
type: synthetic
year: 2026
url: https://opengpubenchmarker.com/
Submitted results join a public dataset under CC BY 4.0 (dataset license), a common license for open data. We believe benchmark results should be open to everyone, so anyone can use, share and build on the data, for any purpose, as long as they credit the source. Submitted results stay public, so leave any optional field blank if you'd rather not share it.
src/benchmark/gpu-catalog.json is a dated snapshot of upstream
data/gpus/<form_factor>/<vendor>/*.yaml (excluding reference/). The catalog is new and
growing: on 2026-10-23 it holds one product, rtx_5080_16gb_fe (upstream also has 309
reference/ base models, which results can't use). Every card added makes the dataset more
useful. To get one added, request it with an issue or open a pull request (see Honest-data rules);
docs/upstream-todos.md lists how requests are handled upstream. After
upstream merges new cards, refresh the snapshot and release:
npm run refresh-catalog # optionally GITHUB_TOKEN=... to avoid rate limits
The script refuses to overwrite the snapshot with an empty list.
System information fields (what the user provides, under system: in the YAML) are defined once,
in src/benchmark/fields.ts. The results form, validate.ts, the YAML and CSV exporters, JSON
export and the storage migration all read that registry. To add one:
templates/community_submission.yaml and scripts/checks.py, and copy its YAML name, type,
allowed values and position. If upstream doesn't have it yet, keep it out of the submission
YAML until it does (and note it in docs/upstream-todos.md).SystemInfo in src/benchmark/types.ts.SYSTEM_FIELDS, at its upstream YAML position: yaml name,
kind (text is quoted, digits is a bare number, signed a bare number that may be
negative, choice a bare word), section (top, system, or overclock for the block
that only applies with overclocked yes), label, placeholder,
optional help, linux: true for Linux-only fields, and a validate rule that mirrors
checks.py. If browsers can't detect it and a best guess helps, add a suggest rule; the
value is then marked in the result's suggested list and the YAML comments it as assumed.
Set carry: true if it rarely changes between runs on the same machine, and gpuSpecific: true
if it describes the GPU itself.tests/fields.test.ts (validation, YAML output and order, CSV column, and
that older saved results load with it blank or suggested).Old saved results need no migration code: missing fields load as blank (or suggested), unknown fields from newer versions are kept, and a field the user cleared stays cleared.
Everything runs in the browser. The site stores nothing on a server: no database, no accounts; the
site sets no cookies and adds no analytics. It's hosted on Cloudflare, which may add its own beacons or other
technology to keep the site running; nothing in the site's code collects user data. See the About
page. Results live in this browser's localStorage. They leave it only when you
share a link, export a file, or submit through GitHub. Share links carry the result in the URL
fragment, which browsers never send to the server, and sharing is on the honor system (nothing is
signed or verified). Links are encoded, not encrypted: anyone with a link can read it, like a
screenshot. Of the system details you typed in, they carry only the catalog GPU you picked and the overclock
details (so others can set up the same test); never CPU, memory (including memory_channels), OS
version or driver. They never carry the diagnostics or the result id. The full list of storage keys and checks is in
docs/privacy-audit.md, and the link format in
docs/share-links.md.
The About & FAQ page (#/about, src/app/about-view.ts) explains all of this in plain words:
principles, every storage key, what the host sees, how sharing works (with a field table decoded
from a real link), submitting, phones, and the FAQ. Sections and FAQ entries can be linked
directly, e.g. #/about/sharing or #/about/faq-memory-channels. tests/about.test.ts keeps the
page honest: its storage list must match the keys in src/, its example link must decode to the
values shown, and every #/about/<id> link elsewhere must have a target.
Phones and tablets can run the benchmark, and share or compare results. They can't submit to Open GPU Benchmarks yet, because the dataset lists desktop and laptop GPUs (an upstream schema change is planned; see docs/upstream-todos.md). Phones can run out of memory at 1440p and 4K, so the site asks for a one-tap confirmation before those runs and offers a lower resolution after a crash (docs/high-res-memory.md). The layout is designed for 360–430 px first.
Browsers can't detect memory channels, so phone and tablet results store memory_channels: 4 as a
marked suggestion (flagship phones run four 16-bit LPDDR channels; many others use two). It isn't
shown on the phone results page yet, but it's in JSON/CSV exports, and "4 (assumed)" shows in My
Results. That way the saved result is already complete when phone submission opens. Phone and
desktop channel counts aren't comparable: four phone channels add up to the width of one 64-bit
desktop channel.
Everything Google Search and link previews need ships from index.html and public/:
<title>, meta description, robots, and a canonical link to https://opengpubenchmarker.com/.
The app uses hash routes (#/history, #/result/…, #/about), which search engines treat as the
same page, so there is one indexable URL. The About & FAQ page is deliberately part of it rather
than in the sitemap; if it ever needs its own search listing, it would move to a static
/about.html.public/og-image.png (1200×630, a real frame of the
Neon Flythrough on Ultra).WebApplication JSON-LD structured data (free, MIT, requires WebGL2).robots.txt (points at the sitemap) and sitemap.xml.favicon.ico (48×48), favicon.svg, apple-touch-icon.png, plus
site.webmanifest with 192 and 512 px icons._headers: basic security headers, and long-lived caching for Vite's hashed /assets/*.<noscript> notice and a footer with site, project and license links.After the first deploy:
https://opengpubenchmarker.com/sitemap.xml under Sitemaps.When the home page changes meaningfully, update <lastmod> in public/sitemap.xml.
See TODO.md: a Safari check, a separate score leaderboard site (submitted to separately from Open GPU Benchmarks), and diagnostics that need more than a browser.
src/benchmark/metrics.ts computeStats / run stats (GPU busy, CPU time, stalls, hitches) / scoreFor (pure)
src/benchmark/diagnose.ts "what limited this run": verdict + findings (pure)
src/benchmark/presets.ts RESOLUTIONS, PRESETS, durations, SCORE_TESTS
src/benchmark/catalog.ts catalog snapshot, NOT_LISTED, BENCHMARKS (exactly one), version
src/benchmark/types.ts SystemInfo, BenchResult
src/benchmark/fields.ts system field registry: form, validation, YAML/CSV, migration, suggestions
src/benchmark/validate.ts validateSubmission (fail-closed)
src/benchmark/exporter.ts toYaml / toCsv / toJson / file names
src/main.ts entry: routing, config form (dev-only ?capture hook)
src/app/run.ts run controller (warm-up, timed batches, GPU timers, validity)
src/app/results-view.ts results page, system form, export & submit
src/app/history-view.ts My Results (#/history): card list, filters, sort
src/app/result-display.ts how a result is shown, by the device that ran it (pure, tested)
src/app/home.ts, shell.ts, router.ts, store.ts, hud.ts, env.ts, dom.ts
src/app/share-env.ts device detection for display/sharing only (pure, tested)
src/app/run-guard.ts crash detection (run-in-progress record), "didn't finish" hints, phone high-res confirmation
src/app/share.ts share link, share text, share card (canvas + QR) and the share flow
src/app/shared-view.ts shared-link view (#/r/<payload>), read-only
src/app/about-view.ts About & FAQ (#/about, #/about/<section>)
src/benchmark/share-codec.ts share-link binary format (versioned, CRC-8, plausibility checks)
src/app/capture.ts dev-only: fixed-t renders and renderer.info for scripts/capture.mjs
src/engine/world.ts grid, clearances, the 96 s flight keys, landmark bridges
src/engine/path.ts FlightPath (pose as a function of t) + 3D clearance index
src/engine/towergen.ts lots, tower archetypes, detail kits, bridges, filler (pure)
src/engine/layout.ts solids index, drones, far swarm, traffic lanes (pure)
src/engine/signlayout.ts sign and lantern-string placement (pure)
src/engine/signatlas.ts generated sign atlas (words, stroke glyphs, billboards)
src/engine/windows.ts procedural window facade material
src/engine/glow.ts instanced glow sprites (nav lights, swarm, lamps)
src/engine/fog.ts height fog (shader chunks + GLSL for additive effects)
src/engine/systems/*.ts sky, atmosphere, towers, signs, rain, traffic, drones, fx
src/engine/city.ts assembles the systems for a preset
src/engine/scenes.ts makeFlythrough: camera, composer, sanitize, bloom fallback, reflector
scripts/refresh-catalog.mjs
scripts/capture.mjs headless screenshots / load reports (Playwright, dev only)
tests/ Vitest unit tests
e2e/ Playwright browser tests (playwright.config.ts)
scripts/capture.mjs starts the Vite dev server and drives headless Chromium
(Playwright, a devDependency; run npx playwright install chromium once). It opens the
dev-only ?capture page, which renders the scene at a fixed scene time. That page isn't
in production builds.
node scripts/capture.mjs --out shots --presets Low,Ultra --times 5,20,40 # screenshots
node scripts/capture.mjs --info # draw calls / triangles per preset
node scripts/capture.mjs --timing [--breakdown] # relative ms/frame (+ per system)
node scripts/capture.mjs --og public/og-image.png --t 8
Headless Chromium renders WebGL in software (SwiftShader), so images are exact but timings only compare relative load. Sign lettering uses the system's bold sans-serif (as v1 did); the katakana-style glyphs are drawn as strokes in code, so they need no CJK font.
npm run test:e2e runs e2e/*.spec.ts with Playwright against a dev server on port 5179. Run
npx playwright install chromium once per machine. Unit tests that need a DOM start with
// @vitest-environment happy-dom; everything else runs in Node.
By default the tests use Playwright's bundled Chromium: SwiftShader WebGL, no WebGPU, no timer queries. That checks that pages work, not how fast they run. To test on a real GPU, choose the browser with environment variables, so nothing machine-specific is committed:
PW_CHANNEL=msedge PW_ARGS="--force-high-performance-gpu" npm run test:e2e # installed Edge (or chrome)
PW_ARGS="--enable-unsafe-webgpu --enable-features=Vulkan" npm run test:e2e # Linux: WebGPU over Vulkan
PW_CDP_URL=http://127.0.0.1:9333 npm run test:e2e # a browser you started with --remote-debugging-port
PW_CDP_URL covers browsers Playwright can't launch well itself, such as Windows Edge driven from
WSL (start it with --remote-debugging-port=9333 --force-high-performance-gpu; WSL needs mirrored
networking to reach the dev server). The "reports graphics capabilities" test prints which
renderer, WebGPU adapter and timer queries the browser under test has.
?inflight=N changes how many batches are queued (1 drains the GPU
between batches, like 2.0.0). Production builds ignore it.EXT_disjoint_timer_query_webgl2timinggpu-timerbatch-avg| 24 000 |
| 1 100 |
| 900 |
| 5 |
| 70 |
| 2 000 |
| 14 |
| 4 |
| 3 |
| 14 |
| 0.7 |
| 2048 |
| 8 |
| 1.0× |
| 12 |
| Extreme | 2 700 | 3 | 330 000 | 2 600 | 2 200 | 5 | 260 | 6 000 | 40 | 4 | 3 | 24 | 0.7 | 8192 | 8 | 1.0× | 24 |
device field
(src/app/share-env.ts: browser + major version, OS, phone/tablet/desktop, WebKit-engine flag,
and the GPU name as reported by the browser, normalized and labelled "reported by browser").
This is a deliberate exception to the browser-hints rule, for display and sharing only: it
never fills a system: field, is never copied into submission YAML, and older saved results
are migrated with only safe inferences (user-filled OS, recorded browser/renderer; an
old "Chrome N" stays unknown because other Chromium browsers recorded the same) or
"unknown". Limit: iPadOS Safari sends a Mac UA, so an iPad is recognised only by a Mac UA
plus more than one touch point; a touch-screen Mac would be misread as an iPad. See docs/privacy-audit.md.gpu_id from the upstream catalog. If your GPU isn't listed yet,
choose My GPU isn't listed: the form then asks for Your GPU (its name) and the
Requested gpu_id (the catalog ID you're asking for). An ID helper builds both: it shows the
GPU lookup command (Windows by default, Linux on a switch), the user pastes what it printed, and
src/benchmark/gpu-id.ts reads the computer type, each GPU's name, VRAM and board maker (PCI
subsystem vendor), matches the chip to an upstream reference id (references in the catalog
snapshot) and builds the id:
laptop <reference>_reference (rtx_5090_laptop_24gb_reference, no laptop maker or model);
desktop <reference>_fe / _reference / _le for the GPU vendor's own card,
<reference>_<brand>_<product_line> when the line is typed, <reference>_<brand>_reference
when only the brand is known, or <reference>_reference. reference stands in for an unknown
variant (proposed upstream, see
docs/upstream-submission-changes.md). The panel also gives
the GPU's catalog file (data/gpus/<form_factor>/<vendor>/<id>.yaml, with base: set to the
reference) to download, copy or open in GitHub's new-file form. Name, requested id and desktop
or laptop are saved with the result and carried to later runs, so you can keep running and
saving until the GPU is added. The paste itself isn't saved, and the page never runs the command. The same panel offers Request your GPU (a prefilled GitHub issue, no coding
needed) and Add it yourself (a pull request using upstream's
templates). The YAML
can still be downloaded, using the requested id as gpu_id, with a warning
(submissionWarnings in validate.ts) and a YAML comment that the submission fails upstream
checks unless the GPU is added to the catalog first or in the same pull request. Or, once it's
listed, reopen the result from My Results, pick it and submit. Share links carry the requested
id (not the name).gpuRequestUrl in
src/benchmark/catalog.ts). The browser's name only seeds a catalog request: it never goes into
a result or a system: field, and it reaches GitHub only when the user clicks the link and
submits the issue.src/benchmark/validate.ts) fails closed and mirrors upstream
templates/community_submission.yaml and scripts/checks.py. Required:
catalog gpu_id (or, for an unlisted GPU, its name and a well-formed requested id), game_id, date, resolution, preset, avg_fps, p1_low,
system.os (windows|linux), and proof.method. The resolution must be
720p, 1080p, 1440p or 4K, and match the rendered pixel size: older results
from the removed Native option at any other size stay local only. A score must match its
score run's locked settings and round(avg_fps × 100). overclocked is optional (yes/no); new runs start at no. memory_channels is optional, a whole number from 1 to 32. Linux-only fields on a
Windows run fail. Blank optional fields are left out of the YAML. YAML
download and copy stay disabled until validation passes.