OpenRA is a fantastic open-source re-implementation of the classic Westwood RTS games like Command & Conquer: Red Alert, Tiberian Dawn, and Dune 2000. The real OpenRA engine is now officially doing exactly that via WebAssembly. We are talking about the exact same C#/.NET codebase that has been evolving for two decades, now compiled to Wasm and booting straight from a URL. No installer, no launcher — just static files.
Getting there took a bit longer than expected. When you take a desktop engine that's been actively developed for 20 years and shove it into a browser tab, things get weird. Over the years, the code accumulated some deep assumptions: that the filesystem is native, that networking means raw TCP, that scripting implies a native Lua binary, and that the renderer speaks OpenGL. On a desktop, these are just indisputable facts. In the browser, they simply don't exist.
This is a story about finding those assumptions, one by one, and what happens when you find one you can't cleanly replace.
Before diving into the code, we had to admit that manually reloading a tab, clicking around, and hoping for the best has a rather low ceiling.
To make real progress, we built proper browser-specific test harnesses. We automated the testing of static boot processes, shellmap startup, skirmish launches, and mission discovery. We even automated audio runtime checks, move-order synchronization, disconnect handling, and timed fog regression.
By the time the really nasty bugs showed up, we weren't just guessing anymore; we had structured diagnostics and automated checks to lean on. This transition is what made the later phases tractable.
Before anything else, the game needed to boot deterministically from static files. It sounds trivial, but our early browser builds suffered from massive race conditions.
OpenRA uses a virtual filesystem layer to abstract its content files, mods, and shaders. Initially, this staging was happening at the exact same time the engine was trying to initialize against it. Sometimes it worked; sometimes the engine reached for a file that wasn't staged yet and hung silently, leaving the user staring at a dead tab.
The fix? Enforce strict order. Browser-side staging (version files, shaders, settings, content, and mods) had to complete and validate fully before a single line of the engine's startup code was allowed to execute. The build stopped behaving like a partially staged runtime and finally started behaving like a real static bundle.
With the engine booting, we hit the rendering issues. And they were not subtle.
Menu text looked like a ransom note, with letters drifting vertically and baselines completely inconsistent in a pattern resembling alternating caps. It turns out the browser's canvas text API returns glyph metrics very differently than a native desktop font rasterizer. The engine was misreading bearings, cropping glyph bitmaps to the wrong bounds, and stacking the ugly results on screen.
Additionally, mouse clicks were landing way off target, sometimes nowhere near the cursor. Why? Because the browser's input event coordinate system doesn't automatically map to the canvas coordinate system if there's any scaling or fit-to-container behavior involved. OpenRA was blindly reading raw event coordinates as if the canvas was always running full-window.
Scripting: Campaign missions rely heavily on Lua scripts. On the desktop, OpenRA uses a native lua51-style binding, but you obviously don't have a native runtime in the browser. We swapped it out for MoonSharp (a managed Lua implementation written in C#) and hid it behind an Eluant-compatible API shim. From the engine's perspective, the interface looked identical, but our scripts were now running in 100% managed code that compiles neatly to Wasm without native dependencies.
Networking: We wanted actual browser-to-browser multiplayer using OpenRA's existing game logic, without relying on a dedicated gameplay server. We kept the game layer, lobby, tick synchronization, and protocol intact, but completely replaced the transport layer. Instead of raw TCP sockets, the browser build uses WebRTC data channels for gameplay, utilizing a signaling server just for room discovery. The engine doesn't see the difference; it just sees a connection.
Every bug I mentioned above followed a pattern: find the desktop assumption, understand why the browser broke it, and write a fix to replace it with browser-appropriate behavior. But we have one open problem that defies this pattern: the Fog of War.
During active multiplayer, the shroud (the fog hiding un-scouted terrain) occasionally visually corrupts. A player might suddenly see terrain they shouldn't. The weird part? It's not a clean map reveal. Tooltip text still reads "Unrevealed Terrain" and enemy bases don't appear. The underlying game state is perfectly correct while the visual output is a liar.
We ruled out the obvious culprits: no accidentally enabled map-reveals, no host/guest state mismatches, no player drift. What investigation confirmed is a browser render-layer invalidation problem. The WebGL compositing pipeline was staling or leaking visual content that the game logic had correctly marked as hidden.
On the desktop, game state and render state are tightly coupled: if the engine marks something hidden, the renderer shows it hidden, with no rebellious layer in between. In the browser, the WebGL pipeline has its own compositing and invalidation behavior sitting between the engine and the screen. The game can be right while the browser stubbornly shows something else. That gap doesn't exist on desktop, which is why 20 years of development never produced a defense against it. Closing it means understanding the browser's rendering behavior under interaction at a microscopic level.
There's a reason a second game, OpenHV, runs in parallel with the Red Alert build.
OpenRA's engine is open source, but Red Alert's original content and assets are not. Hosting EA-derived assets on a commercial product domain is a legal minefield.
OpenHV is an entirely open-content standalone project built on the same engine. The browser port works for it too: boot, shellmap, skirmish, and static export. For any path toward a publicly hosted product, it's the much safer foundation.
The Red Alert build is the main technical achievement, but OpenHV is why it actually has somewhere to go.