Build1 publisherNot yet confirmed elsewhere3 min readPublished
Chess's one-game-a-day cap is a two-core bill, and WebAssembly moves it onto your laptop
A 40-move review costs 160 core-seconds that nobody can cache. Compiling Stockfish to WebAssembly takes that off the server ledger and puts it on hardware you cannot measure.
The Engineer · Build desk

What happened
- Free chess game review is capped at one game a day on Chess.com and on almost every smaller site that offers the feature.
- A 40-move review is about 80 engine evaluations, and at two seconds each that is close to three minutes of CPU per game.
- The author puts a thousand users reviewing one game a day at roughly 50 CPU hours daily, and calls the quota the number that keeps the free tier survivable.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- cost The 160 core-seconds do not disappear when the engine moves client-side; they are re-billed to the visitor as wall clock on hardware the operator did not choose.
- constraint One Worker is one engine with one UCI pipe, so those seconds cannot be spread across positions in parallel; the review loop must run strictly serially.
- exposure Removing metering removes the server logs too, and the documented client-side mistakes return plausible evaluations rather than errors, so bad numbers reach users unobserved.
- capability Two response headers are the whole gate between single-threaded and multi-threaded search, which makes browser-side strength a deployment decision rather than an engine one.
The arithmetic in the post is rounded generously. Eighty positions at two seconds each is 160 seconds, not quite the three minutes claimed [12], and a thousand daily reviewers therefore cost about 44 core-hours a day rather than 50 [14]. The quibble is worth making because of where it lands: the entire free tier for a thousand people fits inside two cores running flat out around the clock [17]. That is one small instance. Nobody writes a quota policy to protect one small instance.
The cap is priced for the day the free tier works. The same 160 seconds across a hundred thousand daily reviewers is roughly 4,440 core-hours a day, about 185 cores that exist purely to give something away [13]. And because each position belongs to one player's game, none of that work is reusable across users [4], so the bill scales with headcount in a straight line with no cache to bend it.
Putting Stockfish in a Web Worker does delete the line item. The server ships static files and never sees a chess position [5], and with no per-user cost there is nothing to meter and therefore nothing to cap [16]. What it does not delete is the 160 seconds. Those are still spent, now in one browser tab, by a person watching a progress bar on a machine whose speed you did not choose. On chessdream.app that spend is also the worst version of itself: the author checked while writing the post and found the site does not send the cross-origin isolation headers, so every analysis runs single threaded and the depth 15 default is doing more work than the strength it returns [11]. Threads are the obvious lever, and they need SharedArrayBuffer, which since Spectre browsers only hand to a cross-origin isolated page carrying `Cross-Origin-Opener-Policy: same-origin` and `Cross-Origin-Embedder-Policy: require-corp` [3].
The quieter trade is observability. Server-side metering is also server-side logging, and the browser gives you neither. Every failure mode described in the post returns a plausible number instead of an error. Read the wrong `info` line and a depth 4 evaluation is presented as depth 15 [6]. Pass `score mate 3` through the same divide-by-100 as a centipawn score and a forced win renders as 0.03, dead level on the graph [7]. Forget `removeEventListener` and every position after the first carries listeners from all its predecessors, resolving promises that already resolved, silently, without throwing [9]. Forget to terminate the Worker and you leak one per analysis on the visitor's machine rather than yours [10].
None of that argues for keeping the quota. It argues that the two costs are not the same shape. A CPU budget is a number you can see going up. A client-side engine converts it into wrong evaluations on other people's hardware and a wait time you learn about from complaints. The trade is still good at a hundred thousand users, where the alternative is 185 cores [13]. At a thousand, where the alternative is two [17], the honest reason to move the engine into the browser is that you no longer have to defend a quota, not that you saved the money.
What to watch
- Whether chessdream.app ships COOP and COEP, and whether its depth 15 default changes once threads are available.
- Whether any site with a paid review tier moves the engine into the browser and retires its daily quota outright.
- What the serial 160 seconds actually costs in wall clock on low-end mobile silicon, a number the post does not give.