- Published on
We Ran a Massive Flash Game on Mobile Browsers with Ruffle — Here’s What It Took
- Authors

- Name
- Flash Game for Mobile
Caution: This is for testing purpose only, we doesn't own or affiliated or advertise from AQW. This only for showcase of Ruffle capable of.
The Dream
We just want to bring a full-fledged, graphics-heavy Flash MMORPG to the modern web — no plugins, no installs, just a browser. We picked AdventureQuest Worlds (AQW), a game many of us grew up with. We picked Ruffle, the open-source Flash emulator that runs in the browser. Seemed straightforward. But we also weren’t ready for just how powerful Ruffle actually is.
The First Wall: CORS, WebSockets, and a Dead End
We started simple. Load the AQW client, feed it to Ruffle, let the magic happen. Nope. The web version of AQW enforces strict CORS headers and uses a WebSocket connection that expects a specific origin. Ruffle running on our domain or localhost was instantly blocked. We couldn’t fetch assets, couldn’t establish the game socket.
Holy mowly. As farmers (we make a small farming tool, unrelated to AQW), we don’t know many hard stucks until we really touch it. We reached out to Artix Entertainment politely, hoping for an allowlisting or a development endpoint. The response was kind but clear: they can’t officially endorse third-party projects, and they’re busy building the fantastic AQ Infinity. Not a direct rejection, but no permission either. We were on our own.
We decided to push forward anyway. This project (Flash Game for Mobile) was already in its final stretch — but this was worth every penny of our efforts (it may be our application’s last mission before the app switches to unmaintained because of income issues).
The Proxy: Ugly but Necessary
Without the ability to modify AQW’s server configuration or get a dedicated proxy URL from Artix, we routed everything through a small proxy server. Web traffic, game socket, asset requests — all re-routed. It was the only way to bypass CORS and let Ruffle talk to the game world without the browser screaming “blocked by policy.”
Yeah, we don’t want to make the network re-route to our small server. But we cannot directly ask AQW for allowing game resources for our unknown domain. So this is the only choice. (There is a better solution by creating a local server and doing it directly for Android, but 4 days earlier we didn’t know that. We will keep the proxy way for now to make it easier to test both on PC web and mobile, and will change later.)
And then it happened. The login screen. The character select. Battleon loaded.
I almost cried.
The FPS Disaster: 2 Frames Per Second
The celebration was short. The frame rate was a slideshow — literally 2 FPS on a high-end phone. We’d chosen Ruffle’s cutting-edge WGPU render backend because it’s the future. But AQW’s animations are complex: blend modes, filters, constant redraws. WGPU choked.
We switched to the WebGL backend. The game ran at full speed. But it looked… offensive. Blend modes missing, filters broken, assets displaying as raw geometry without their magic. So I tried to add the missing blend mode and filter support to Ruffle’s WebGL backend myself, basing it on how WGPU does it. Sorry, we were dumb, and it ended… poorly. Back to 2 FPS on mobile. We reverted and called ourselves dumb. We’ll add those features properly, piece by piece, but not today.
For now, on desktop WebGL, the game is actually playable and decent-looking. On mobile, we’re still tweaking.
The Crashing Point: WebAssembly Memory Limits
Next horror: the game would crash every time memory usage grew past around 300–500MB. Turns out, WebAssembly has this fun little design issue (see GitHub issue #1397). Growing the Wasm memory dynamically would just… kill the app.
We realized how dumb we were when we picked the web-based emulator for a game that gobbles memory. It should be native based… Yeah. So we don’t care. We just fix it by setting the initial memory to the maximum allowed upfront. No growing, no crash. Quite stupid, but yeah. Stupidity is acceptable when it works.
The Leak Labyrinth: Orphans Everywhere
Even with stable memory, something was still wrong. Every time we changed maps, GPU memory and RAM just grew. Textures from the old map sat around like orphans, never cleaned up. AQW does call unload() on old assets — but the resources were never truly freed. They piled up in an “orphan list.”
We dug into how Adobe Flash Player handles this (see unload()). In AS3, Loader.unload() removes the child from the display list, but the loaded content may still linger. Later versions have unloadAndStop(), but it’s not immediate. Ruffle’s unload was too cautious.
We tested and compared with real Flash Player. The truth? AQW’s code creates new children and never re-parents the old ones. The orphans genuinely have no home again (Batman things). Flash’s GC would eventually handle it, but in Ruffle we needed something better.
So we built a deferred orphan collector: put unloaded assets on a “release later” list and call a GC pass a few frames afterwards. Release immediately doesn’t work — some references still alive in that frame, causing crashes. It’s tricky — we had to test carefully to avoid regressions.
The result? Memory leaks are tiny now. You can actually play AQW on a mobile browser, switch maps multiple times, and survive. We’ll continue to tighten the leaks. When our code is less messy and stupid, we plan to contribute the improvements back to the Ruffle project.
Why This Matters
Despite every self-inflicted wound of our stupidity, Ruffle held up. AQW is not a simple Flash game. It’s massive: hundreds of maps, complex skeletal animations, real-time multiplayer, heavy asset loading. The fact that we got it running — with full speed on desktop, and playable on mobile — in a web browser, using an emulator that didn’t exist a few years ago, is extraordinary.
Ruffle truly can replace Adobe Flash. It can handle a beast like AQW and deliver it to the mobile web, where native Flash never really existed. Performance on desktop WebGL is near-native for this game. On mobile, we’re still pushing the boundaries, but the foundation is solid.
If we, a bunch of stubborn farmers, can make AQW work on a phone through sheer will and a handful of terrible decisions — imagine what Ruffle will be capable of next year.
PS: We’re well aware that a local proxy on Android would be more elegant, and that setting max Wasm memory isn’t a real solution. Sometimes the best engineering is just making it work today and fixing it right tomorrow. The game runs. We’re happy. You can be too. Go test something insane with Ruffle — it’s ready for more than you think.
We just want to share what Ruffle is capable of. Very decent, right? A very large Flash game like AQW running on mobile with a web-based emulator. Hope that Ruffle will get even more powerful!
