Overview
X Compute measures how fast a machine moves data through GPU memory and how fast it multiplies matrices, from inside a browser. A run takes about 45 seconds, produces one number, the X-Score, and places the machine among identical hardware.
Every figure on this site is one of three kinds and is labelled as such: measured by a run, published by a vendor, or estimated from the two.
Workload
Two storage buffers of 256 MiB each are filled with hashed data before anything is timed, so no page is untouched. Each memory kernel walks a whole buffer once per dispatch, 64 bytes per invocation, and consecutive dispatches alternate between the two buffers. A byte is touched again only after 512 MiB of other traffic, far more than any cache holds.
| Phase | What runs | Reported |
|---|---|---|
| Read | Four 16-byte loads per invocation, XOR-folded | GB/s |
| Write | Four 16-byte stores, data varies per element | GB/s |
| Copy | Load from one buffer, store to the other; both directions count | GB/s |
| Random | 1M invocations, 16 gathers each, at xorshift addresses | GB/s |
| Compute | 512 × 512 single-precision matrix product | GFLOP/s |
| Sustain | The copy kernel, continuously | GB/s, retention |
Loads stay observable: each fold decides a store that the shader compiler cannot predict, so the reads cannot be optimized away. Browsers without WebGPU run the same phases on one CPU thread over system memory. That is a different path, so those runs are scored but never ranked.
Timing
A sample is one compute pass holding about 40 ms of GPU work. With the timestamp-query feature the pass is timed by the GPU itself; without it, samples grow to about 80 ms and are timed from submit to completion, minus the measured cost of an empty submit. The result records which clock was used.
- Calibrate. Grow the dispatch count until a pass reaches a quarter of the target, then scale to the target.
- Warm up. Unrecorded passes for up to 500 ms.
- Sample. Record passes until the phase budget is spent, at least eight.
- Reject. Drop samples whose modified z-score is above 3.5.
- Report. The median of what remains.
The engine runs in a dedicated worker. While a phase measures, the page's own render loop is stopped: after each sample it draws exactly one frame and acknowledges, and only then does the next pass start. Visuals never overlap a measurement.
| Budget | Read | Write | Copy | Random | Compute | Sustain |
|---|---|---|---|---|---|---|
| full | 5.0 s | 5.0 s | 5.0 s | 4.0 s | 5.0 s | 14.0 s |
| quick | 1.4 s | 1.4 s | 1.4 s | 1.1 s | 1.4 s | 3.5 s |
X-Score
One number on a linear scale. The reference machine scores 1,000; a machine twice as fast on every phase scores 2,000. Each metric is divided by its reference, weighted, and combined as a weighted geometric mean.
score = 1000 · Π (xᵢ ÷ refᵢ) ^ wᵢ
| Metric | Reference | Weight |
|---|---|---|
| Read | 100 GB/s | 0.22 |
| Write | 100 GB/s | 0.13 |
| Copy | 100 GB/s | 0.15 |
| Random | 20 GB/s | 0.10 |
| Compute | 50 GFLOP/s | 0.22 |
| Sustain | 100 GB/s | 0.18 |
The server recomputes the score from the submitted metrics; the browser's own number is never stored. Score version v1, engine xc-1.
Decode ceiling
Generating one token reads every active weight once, so tokens per second cannot exceed read throughput divided by the bytes of active weights. At 100 GB/s, an 8B model at 4-bit is 4 GB of weights and at most 25 tokens per second. Real runtimes land below the ceiling. The model planner applies this to any hardware.
Device classes
A class is one GPU model: RTX 4070, Apple M4 Pro, Iris Xe. The model comes from the renderer string the browser reports, and the server parses it again itself. A class with a fixed memory configuration carries a published peak: bus width × data rate ÷ 8 for discrete cards, the vendor's figure for Apple silicon and datacenter parts. Laptop and integrated GPUs ship in many configurations, so they have no fixed peak and are ranked against their own runs only.
Validation
Browser numbers cannot be proven honest. They can be made hard to fake by accident and awkward to fake on purpose. Every submission gets exactly one status: verified, unranked or rejected. Only verified runs rank or earn points.
- A run opens with a ticket signed by the server. It must be at least 25 seconds old when the result arrives, and at most 30 minutes.
- The ticket's nonce is the run id, and the insert refuses to overwrite. A replayed ticket is refused.
- The claimed duration cannot exceed the ticket's age.
| Flag | Outcome | Meaning |
|---|---|---|
| engine-mismatch | rejected | Sent by an engine version this network does not know. |
| bad-shape | rejected | The result was incomplete. |
| too-few-samples | rejected | A phase kept fewer than five samples. |
| non-finite | rejected | A phase reported zero or a value that is not a number. |
| too-short | rejected | The run finished faster than the phases allow. |
| ticket-young | rejected | The result arrived sooner than a run can finish. |
| ticket-expired | rejected | The run ticket expired. Tickets last 30 minutes. |
| duration-mismatch | rejected | The claimed duration is longer than the ticket has existed. |
| random-over-stream | rejected | Random access came out faster than streaming allows. |
| copy-over-stream | rejected | Copy came out faster than read and write allow. |
| sustain-over-copy | rejected | Sustained throughput came out above the copy phase. |
| over-published-peak | rejected | Throughput is above what this hardware's memory bus can carry. |
| near-published-peak | unranked | Throughput is slightly above the published peak for this class. |
| quick-mode | unranked | Quick run. Shorter phases give a preview, not a ranked result. |
| cpu-engine | unranked | Measured on the CPU because this browser has no WebGPU. |
| model-hidden | unranked | This browser hides the GPU model, so the run cannot join a class. |
| model-unlisted | unranked | The GPU model is not in the spec table yet. |
| software-renderer | unranked | A software renderer did the work, not a GPU. |
| small-working-set | unranked | The GPU allowed less than 128 MiB of working memory. |
| unstable | unranked | Samples varied by more than 30%. Close other GPU work and run again. |
| tab-hidden | note | The tab was hidden for part of the run. |
| wall-clock | note | Timed with the wall clock; this browser offers no GPU timestamps. |
| daily-cap | note | Ranked, but past today's rewarded runs for this operator. No points. |
| network-cap | note | Ranked, but past today's rewarded runs for this network. No points. |
| form-factor-declared | note | Laptop or desktop was declared, not detected. |
The Wafer and proof
Every full run becomes one die on the wafer, filled from the centre outward. 256 dies complete a wafer. Brightness follows the score on a log scale.
Each UTC day, verified runs are hashed into one Merkle root. A leaf commits to the run id, timestamp, class, score and operator, all public, so anyone can rebuild a day's tree and check a run against its root. Roots are published on the wafer page today. Writing them on-chain is planned with the first reward season.
Identity and privacy
- No account and no cookies. Your identity is a random key generated and kept in this browser.
- A run publishes its scores, the GPU model, and the browser and OS family. Nothing else.
- IP addresses are not stored. A keyed hash that changes every day counts runs per network, for the daily cap only.
- No hardware fingerprint is taken or kept.
- Linking a wallet stores its public address against your operator. You can unlink it at any time.
Architecture
- Engine. WGSL kernels and robust statistics in a dedicated worker, with a main-thread fallback where workers have no GPU.
- Visuals. three.js, one shader for the wafer, drawn once per sample during a run and paused off-screen.
- Server. Next.js route handlers on Vercel. They validate, store and rank; they never measure.
- Storage. One immutable document per run, plus an index updated with optimistic concurrency.
- Chain. Robinhood Chain, chain id 4663. Holder tiers are a read of
balanceOfon the linked wallet. Nothing is custodied.
API
Public, read-only, JSON. Cached for a few seconds at the edge.
| GET | /api/stats | Network totals, the latest runs and the dies of the current wafer |
| GET | /api/leaderboard?window=all|week|day | Every class with its medians, and the top runs |
| GET | /api/runs/{id} | One run in full, with its class percentile |
| GET | /api/proof | Daily Merkle roots of verified runs |
| GET | /api/proof?run={id} | One run's leaf, sibling path and day root |
| GET | /api/token | Live market data, once the token exists |
| POST | /api/ticket | Opens a run: returns a signed, single-use ticket |
| POST | /api/submit | Submits a result for validation |
Reading is one thing. Measuring takes 45 seconds.