SMERESKI
  1. PROJECTS
  2. SKILLS
  3. RESUME
  4. BLOG
  5. GAMES
  6. CONTACT

POST · 2026-07-13

2026-07-13 · 5 MIN READ

The threads you cannot have

Godot's web export wants SharedArrayBuffer. SharedArrayBuffer wants headers your static host will not give you. There is a way out, and it costs you threads.

gamesfrontenddistributiongodot

Both of my games are now playable in a browser, on this site, with no install and no store. Getting there took one afternoon and one decision, and the decision is the part worth writing down — because the default path leads directly into a wall that a lot of people hit and then quietly give up at.

Here is the wall. Godot's web export, by default, uses threads. Threads in WebAssembly mean SharedArrayBuffer. And SharedArrayBuffer has been gated behind cross-origin isolation ever since Spectre — the browser will not hand it to you unless the page is served with two specific response headers, Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy. Which means your game does not depend on a build flag. It depends on your ability to set HTTP headers on the host serving it, and on every third-party asset that page loads agreeing to be embedded under those rules.

On a platform where you control the server, fine, set the headers. On a static host, a CDN, an itch.io page, a GitHub Pages deploy — you often simply cannot, or you can but it breaks embeds, fonts, or analytics that were never built for an isolated context. The failure is also miserable to diagnose, because it does not look like a header problem. It looks like your game loading to a black screen.

The way out is the export preset that most people never read: build without threads. Godot ships a nothreads variant of the web target that compiles the whole engine to run on the main thread. No SharedArrayBuffer, no cross-origin isolation, no headers, nothing to configure on the host. You drop the build in a directory, serve it as plain static files, and it runs. My Next.js config has no COOP or COEP entries anywhere in it, and that is not an oversight — it is the entire point.

You do pay for it. Everything runs on one thread, so anything the engine would have parallelized — asset decoding, physics stepping on heavier scenes, audio work — now competes with rendering for the same thread. For a match-three puzzle and a turn-based tower defense, that cost is invisible. For a physics-heavy action game it might not be, and then you have a real decision: fight for the headers, or trim the game. Know which one you are choosing before you are staring at a black screen wondering what you broke.

The broader point is about distribution, not rendering. A game behind a store listing has an install between it and a curious person, and most curious people do not cross an install. A game that is a link is a game people actually try. Trading some threads for the ability to just hand someone a URL was, for these two, not a close call.

REFERENCES4 LINKS