Launch · 6 min

Command & Conquer: Generals, in the browser

This is the story of how I moved a 1.7-million-line C++ game engine into the browser by writing just 13,700 lines, without touching the game itself.

Published Command & Conquer
Generals Web Port

Hi! I'm Ralph. Today I'm sharing a game port I've been working on for the past three months. This is the story of how I moved a 1.7-million-line C++ game engine into the browser by writing just 13,700 lines, without touching the game itself. But why would I even take on such an adventure?

Finding the narrative in the code

I've built many tools in the past decade, but this year is different. I've been trying to find a narrative in the code me and my agents write, and what better narrative than building things for the people I love? This one is dedicated to my brothers, Mario and Carl, the most hardcore C&C Generals players I know.

I vividly remember rushing through lunch to claim the family PC to play Zero Hour, burning whole afternoons in internet cafés playing it with them. (One of them still mains China. I was the USA Superweapon player whose Auroras slipped past his air defenses every single time. He remembers. I regret nothing.) Today the three of us live on different continents, so I wanted our game to live somewhere we all are: the browser.

Months of porting later, it finally works. The engine boots in a tab: menus render, the 3D battlefield draws, units answer the mouse, and save games persist across tab closes. Today I'm excited to release my web port of Command & Conquer: Generals Zero Hour, and to ask for your help to take it a step further.

Game running in skirmuch mode on web
Game running in skirmuch mode on web

Standing on shoulders

This port exists because EA open-sourced the Generals/Zero Hour code under GPL-3.0 in 2025 (restored by community veteran Luke "CCHyper" Feenan), and because TheSuperHackers/GeneralsGameCode modernized it to C++20, with the wider porting ecosystem (Fighter19, feliwir, fbraz3's GeneralsX) proving the engine could leave Windows at all. We forked their work and built the web layer on top. Credit where it's due: they carried this further than anyone. Thank you for making this possible!

How we ported it

The engine is 1.7 million lines of C++, and all of it matters. Every unit stat, every pathfinding quirk, every physics oddity that makes Zero Hour feel like Zero Hour lives somewhere in that code, and I knew from day one that rewriting any of it would be a mistake — I didn't want something that resembles the game, I wanted the game. So the rule we set for ourselves was simple: the engine stays untouched, and we build a fake Windows around it.

Everything we ended up writing, about 13,700 lines, is exactly that: platform code. Around 0.8% of the codebase, whose only job is convincing the other 99.2% that it's still running on a Windows machine in 2003.

The biggest piece of the illusion is graphics. The engine makes thousands of Direct3D 8 calls every frame and trusts whatever comes back, so we built a drop-in, COM-compatible Direct3D 8 device that accepts all of those calls and quietly translates them to WebGL 2.0 behind the scenes, with one universal shader pair doing the work of the entire old fixed-function pipeline. Input got the same treatment: browser mouse and keyboard events are repackaged into the DirectInput ring buffer format the engine has been reading since 2003. Files too — your 2 GB of .big archives stream over HTTP Range requests, with 16,000+ files indexed from nothing more than 16-byte header probes.

Old tools, unashamedly used

Some of the solutions here are embarrassingly old, and I've made my peace with that. Emscripten's official answer to blocking file I/O is Asyncify. We tried it, watched what it did to our build, and threw it out in favor of synchronous XHR — a browser API that's been deprecated for about fifteen years. It turns out that a 2003 engine which expects the whole world to stop while it reads a file pairs beautifully with a 2003-era way of reading files.

My favorite war story from this project is the black canvas. At some point the render pipeline just went dark: the engine alive, the simulation ticking, the canvas pitch black, and it stayed that way for weeks. No debugger could reach into the problem. What finally cracked it was twenty-five counters printed to the console once a second, which we stared at until the pattern gave itself away. The fix was one line.

About that "we"

When I say "we", I mean one human (me) directing, with Claude Code and Gemini 3.5 Flash doing the engineering shifts on my side, session by session against a shared porting log. Along the way that setup grew its own infrastructure: documented sessions so every agent picked up exactly where the last one stopped, draw-path telemetry, WebGL call instrumentation, fail-fast targeted compiles, and a headless-browser harness that clicks through the game like a player would.

For the first weeks, all of this happened blind — until the first frame renders, there's no way to know a port like this is even possible. Every fix had to prove itself live in a browser before it counted.

Game running for the very first time on my browser after two months of work
Game running for the very first time on my browser after two months of work

Where it stands today

You can play Generals in your browser right now. It boots, renders, and simulates, but I won't pretend it's finished. Performance is the big one: the frame rate dips as your base grows and battles get busy, and draw-call batching, smarter asset caching, and stripping out our own diagnostic logging are the current frontier. The audio bridge is written but still needs its final wiring. And the gameplay last mile could genuinely use more eyes than mine.

The Zero Hour main menu, in a browser tab
The Zero Hour main menu, in a browser tab
A USA Command Center, in game
A USA Command Center, in game

One thing that will never change: no game assets are included or distributed, ever. The code is GPL-3.0; the game data stays yours. You load the .big files from your own copy of Zero Hour (C&C The Ultimate Collection on Steam), and they never leave your machine. EA has not endorsed and does not support this project.

This is where you come in

If you like building things and feel like contributing, here's what's on our list:

This engine crossed twenty-three years and four API generations to end up in a browser tab. If you love Zero Hour, load your game files, play, and tell us what breaks. And stay tuned: the hosted one-click version (you still bring your own game files) lands once performance and multiplayer make us proud. We all know that moment when a game starts chugging right as your army peaks — we want your empire to fall to a GLA sneak attack, not to the frame rate.

⭐️ If you like this, please star the repo. Open an issue. Come port a classic with us.

This is the first of many projects driven by the people I very much love and AI agents I'm proud to call my teammates. Here's to my dear brothers and best friends, Mario and Carl and to whoever you'd send a link to.

Sincerely, Ralph Theodori

GitHub: https://github.com/TheodoryLabs/Generals-Web

Derived from EA's GPL-3.0 source release via TheSuperHackers/GeneralsGameCode. "Command & Conquer" is a trademark of Electronic Arts Inc. EA has not endorsed and does not support this product. No game assets are included.