Screen Test Pro

How the ScreenTest.Pro Score Works

by Screen Test Propublished last reviewed

This is the methodology page. Nothing here is simplified for marketing; if the code and this page ever disagree, that’s a bug and we’d like to hear about it. (Benchmark version at the time of writing: 2.2.0.)

The question the benchmark asks

Most graphics benchmarks fix the workload and measure your frame rate. Ours inverts that: it fixes the frame-time target and searches for the heaviest workload your device can hold at it. The output is “max stable load” per scene — 840,000 nebula particles, say — which is what the score is built from.

Why inverted? Because frame rates saturate. On a fast machine, a fixed workload pegs at the display’s refresh rate and tells you nothing; the interesting question is how much more it could have handled. Searching for the ceiling keeps the measurement meaningful from a five-year-old phone to a desktop GPU, with the same scenes.

What runs

The Standard profile is five Signature scenes plus one control, each stressing a different axis:

Scene Load unit Axis
Nebula Drift GPU particles shader particle update + fill rate
Neon Metropolis instances instanced geometry throughput
Liquid Chrome internal resolution raymarching / fragment cost
Starfall Cascade CPU particles JavaScript physics + buffer upload
Hypernova burst particles mixed finale
Canvas 2D Basic Circles 2D circles CPU-bound control, no WebGL

Rendering runs at a capped pixel ratio (1.5×) with an internal size cap, so a 5K monitor and a 1080p laptop face comparable pixel counts. Randomness is seeded and simulation steps are fixed, so every run of a given version does the same work.

How stability is judged

The engine never reads an FPS counter. It collects frame times from the browser’s animation clock into windows of roughly 0.7–1.6 seconds, then asks two things of each window:

  • at most 5% of frames may miss the pass threshold — 17.5 ms on adaptive-sync displays; on fixed-rate displays, the first vsync slot that in-budget work could never land on (25.0 ms at 60 Hz, 20.8 ms at 120 Hz);
  • the trimmed mean — worst 2% of frames dropped — must stay within 16.67 ms × 1.15.

Counting misses instead of averaging them lets one garbage-collection pause be one bad frame rather than a failed window; the trimmed mean is the backstop that keeps rare-but-enormous misses from passing on count alone.

Why the threshold cares about your display: a fixed 60 Hz monitor can present a frame after 16.7 ms or 33.3 ms and nothing in between, while an adaptive-sync laptop panel hands an 18 ms frame back as an 18 ms frame. Under 2.1.0’s mean/P95 tolerances that difference let adaptive panels cruise at 55 fps and pass, while 60 Hz monitors had to hold a true 60 — the same GPU scored lower at a desk than in a laptop lid. So before the first scene, a ~600 ms pacing probe watches how your display returns frames, and the criterion adjusts so that “sustains 60 fps” is the same claim on every display class. If the probe finds the display capped below ~50 Hz — Low Power Mode, a 30 Hz cable — the run refuses to start rather than grade a GPU through a 30 Hz straw.

The 16.67 ms budget itself never changes with refresh rate. A 120 Hz screen delivers frames on an 8.3 ms cadence when things are easy, but passing only requires staying inside the 60-per-second budget — high-refresh hardware is measured on equal footing, not punished for showing its extra frames.

Each scene walks a state machine: preflight → baseline → warmup → ramp → bracket → confirm → anchor.

  1. Baseline measures a known light load — this becomes the thermal reference.
  2. Ramp multiplies the load ~1.5× per passing window until a window fails.
  3. Bracket binary-searches between the last pass and the first fail until the range narrows to ~6%.
  4. Confirm demands three consecutive passing windows at the candidate load, within a budget of four. One bad window early on can still be recovered from; two consecutive failures, or spending the budget without three in a row, reject the level and the candidate steps down.
  5. Anchor re-runs the baseline load. If it now runs >15% slower than at the start, the device changed under us — almost always thermal throttling — and the scene is flagged drift instead of pretending nothing happened. The size of the slowdown is recorded too, not just the fact of it.

A few frames after every load change are discarded before statistics resume: changing the load reallocates GPU buffers and render targets, and the browser bills that as one long frame. That hiccup belongs to the transition, not the workload — 2.1.0 counted it, and on the scene that resizes its render target every rung it stopped the search far below what the hardware actually holds.

Every phase has a hard time limit (30 s per scene, 200 s per run). Backgrounding the tab pauses measurement and voids the current window; resizing rebuilds the scene and re-warms. There is no path through the state machine that hangs.

From loads to a score

Scoring is a pure function over the recorded results — you could recompute it by hand:

  1. Each scene’s max stable load is divided by that scene’s reference load (a frozen calibration constant per version; roughly, a solid desktop from 2025 lands near 1.0).
  2. Ratios are floored at 0.05, and capped at the scene’s own ladder ceiling — the heaviest load that scene can physically stage, set roughly 10× beyond the fastest hardware we’ve measured — so the score can only stop rising where the measurement itself ends. (2.1.0 clamped every scene at a flat 20×; an M4 Max pinned two scenes against it and a third against the measurement ceiling, which is why unrelated Apple flagships kept reporting near-identical totals.)
  3. The clamped ratios combine in a weighted geometric mean — the five Signature scenes carry most of the weight, the Canvas 2D control 10%. Geometric, because it rewards balance: a machine great at everything beats a machine legendary at one thing and terrible at another.
  4. Multiply by 1000, apply the stability deduction — 3% per flagged scene, whether the flag is drift or an unconfirmed level, capped at 10% total — and round.

Tiers are fixed thresholds per version, and because a score is 1000× the reference machine each one is really a multiple of it: Entry below 1000, Balanced to 2999, Fast to 8999, Extreme above — that is, under 1×, up to 3×, up to 9×, then beyond. They exist so a number has a handle; the subscores are the real information.

What invalidates comparisons

  • Different benchmark versions never compare. Changing one shader changes the workload; the version string on your results sheet is part of the score.
  • Compatibility runs (no WebGL2) use Classic scenes only and score in their own space, clearly labeled.
  • Throttled runs — every scene measured and confirmed, but the device warmed up and slowed — are real measurements of sustained performance, so they score normally and rank on the top-scores board with the flag shown on the row. Most phone runs land here; that is physics, not a fault.
  • Degraded runs — a scene that produced nothing usable, or a level the search could never confirm — are a floor rather than a peak, so they stay off the board. They are still kept, still counted in the aggregate medians, and the results sheet says which scene and why.
  • Both flags travel with the run into our anonymous dataset, so any published figure can separate them.

Run-to-run variance, quantified expectations

On a plugged-in, idle machine, consecutive runs typically land within a few percent — the confirm phase’s consecutive-window requirement is what buys that. On battery, in power-saver mode, or with a warm chassis, expect more spread and a likely throttled flag; that’s not the benchmark being moody, that’s your device genuinely offering less. Cooling off and plugging in before a run is the single most effective thing you can do for a representative number. The browser-benchmark honesty piece covers what to do with the number once you have it.

Share this page
DiscussionOne thread per language, shared across the whole site. Sign in with Google to post.
Discussion