GTA III Browser›Blog›WebAssembly
Technology

How GTA III Runs in a Browser with re3 and WebAssembly

Updated Sep 22, 202612 min readGTA III Browser Editorial
Browser engine illustration representing GTA III compiled to WebAssembly

re3 is compiled with Emscripten so the browser can execute the game engine as WebAssembly.

The interesting part of a GTA III browser port is not the HTML button around the game. The hard part is translating a native C/C++ engine environment into a browser sandbox without assuming a desktop filesystem, native windowing, unrestricted memory or operating-system APIs. re3 plus Emscripten provides the engine foundation; the web launcher fills in browser-specific responsibilities around it.

re3 is the engine layer

re3 is an open-source reimplementation of the GTA III engine code. In a native build it behaves like a desktop application: initialize subsystems, open a rendering window, access game files and enter the game loop. For the browser build, Emscripten compiles the C/C++ code into WebAssembly and supplies browser-compatible shims for parts of the standard runtime.

The project deliberately keeps the engine and game-data concerns separate. WebAssembly contains executable logic, while GTA III data files are mounted at runtime into the filesystem the engine expects.

Why WebAssembly is used

JavaScript is excellent for web application orchestration, but rewriting a large C/C++ game engine in JavaScript would be a separate project. WebAssembly provides a compact binary format designed for fast execution in the browser and interoperates with JavaScript for lifecycle, UI and browser APIs.

That means the launcher can stay ordinary web code while the performance-sensitive engine remains close to its C/C++ structure. JavaScript creates the module, feeds it a canvas, connects logging hooks and eventually calls the compiled main entry point.

Rendering through WebGL2

The browser cannot expose desktop OpenGL directly, so rendering is translated onto browser graphics APIs. This build targets WebGL2. The canvas acts as the visible drawing surface, while the runtime resizes its backing buffer to match the display and fullscreen state.

A WebGL context failure can therefore stop the game even when WebAssembly itself loaded correctly. That distinction matters when debugging a black screen: “WASM loaded” proves the engine binary instantiated, not that graphics initialization succeeded.

MEMFS versus OPFS

Emscripten's in-memory filesystem is convenient because native-style file operations can work against paths the engine understands. The downside is that memory-backed files disappear with the page session and large game data consumes RAM. OPFS solves a different problem: it gives the website persistent, origin-scoped browser file storage.

The current architecture keeps the compressed game ZIP in OPFS, then extracts relevant files into the runtime filesystem when a session starts. This avoids a repeated large network download, but not local decompression and memory allocation.

Illustration of a persistent browser cache feeding game data into a runtime

Persistent OPFS storage and the in-memory Emscripten filesystem solve different parts of the loading problem.

Background workers and large downloads

Large downloads should not block the page's main UI thread. The OPFS cache worker streams data in the background, reports byte progress, and can use range requests when the upstream/proxy supports them. This architecture lets the loading interface remain responsive while a large archive is written to local browser storage.

The asset proxy exists because a link that downloads successfully when opened directly in a tab can still reject cross-origin JavaScript requests. A server-side proxy can fetch the authorized upstream file and return CORS and range-friendly headers to the browser worker.

The browser main loop and FPS limit

Native games often depend on platform timing assumptions that do not map neatly to browser scheduling. The re3 browser build registers its main loop with Emscripten and also has an explicit browser-side frame budget. The homepage FPS control calls a WebAssembly export that changes that budget at runtime.

This matters for stability as much as speed. Running far above the game's intended timing can increase CPU load and expose physics or timing problems. A controlled cap gives users a practical way to balance responsiveness and device temperature.

Input, focus and tab visibility

Keyboard and mouse events originate in the browser, while the engine expects continuous game input. The launcher prevents unwanted browser shortcuts in the game context, coordinates pointer lock for mouse look, and clears or suspends state when browser focus changes. Tab visibility also matters because background tabs can throttle animation callbacks.

These are examples of work a native game normally gets from its platform layer. In a browser port, they must be handled explicitly so losing focus does not leave keys stuck or produce a huge elapsed-time jump when the tab becomes visible again.

What WebAssembly does not solve automatically

WebAssembly does not provide commercial game assets, unlimited memory, native filesystem access or perfect compatibility across every device. It also does not remove browser security rules. CORS, storage quotas, autoplay restrictions, GPU drivers and background throttling still exist.

That is why a reliable GTA III browser build is a combination of engine porting and web engineering rather than a single .wasm file dropped into a page.

SEO and version note: This article targets the GTA III browser/re3 WebAssembly experience on this site. Browser behavior changes over time, and original GTA III behavior can differ from later ports or remastered editions.

Play GTA III in your browser

Open the GTA III Browser launcher, choose your settings, and start the full-screen WebAssembly runtime.

▶ Play GTA III