DEV Community

Cover image for 🚀 The 30-Hour Odyssey: Building a Rust/WASM Game Engine via Augmented "Vibe Coding"
Jonathan Moutier
Jonathan Moutier

Posted on

🚀 The 30-Hour Odyssey: Building a Rust/WASM Game Engine via Augmented "Vibe Coding"

By Jonathan Moutier / Djodjonx Estimated reading time: 15 minutes


The Hook

Modern web development is a productivity paradise. With frameworks like Nuxt or SvelteKit, everything feels fluid, intuitive, and serene. But the moment you cross the border into high-performance web gaming, that comfort vanishes. You are abruptly forced to choose: either settle for ease of use at the cost of performance, or dive headfirst into the brutal complexity of shared buffers, memory management, and heap stacks.

My challenge? To build a third way: a powerful Rust/WASM engine that handles like a modern web framework. This is the chronological, unfiltered account of a 30-hour technical marathon where every line of code was a direct collaboration with my AIs to give birth to Gwen.


🌩️ Hours 0 to 2: The Negotiation and the AssemblyScript Mirage

It all began with a simple chat window and Gemini. I wasn't looking for a script; I was looking for an architectural partner. My vision was clear: a WASM-based web game engine, ultra-lightweight, plugin-extensible, and above all, boasting a Developer Experience (DX) that wouldn't make me want to quit after ten minutes.

For two hours, we debated. I refused to reinvent the wheel, searching for the perfect compromise. We scanned the tech landscape; nothing quite matched my vision. The initial plan settled on AssemblyScript. "It’s the choice of reason," Gemini whispered. It’s close to TypeScript, it feels safe. We drew the interfaces and data schemas. At that moment, I thought the hardest part was over. I was serene. I was wrong.


⚡ Hours 2 to 5: The Technical Debate and the Rust Pivot

I switched to the IDE. Copilot entered the fray to generate the first AssemblyScript blocks. But as the code materialized, a doubt took root. I began challenging the AI on the actual maturity of the ecosystem for such an ambitious project, specifically on fine-tuned heap management.

A full-blown engineering debate erupted between my two AIs. We analyzed benchmarks, interoperability, and long-term viability. The verdict hit like a gavel: to achieve the target performance, we had to go Rust. It was a major strategic pivot mid-flight. I hadn't touched Rust since a tiny Snake WASM project years ago. I understood the concepts—buffers, pointers—but the syntax is a jungle. I decided to delegate the syntax, but I kept the compass. The "Full Vibe" experience truly started here.


🚀 Hours 5 to 12: Nuxt Inspiration and the "Steel Rails"

The Rust core started to breathe. Within hours, I had a Space Shooter running at a constant 60 FPS. The Rust core orchestrated the frame loop and positions, while a simplified physics engine ran in TypeScript. It worked, but the code was an unreadable "soup" of WASM boilerplate.

Inspired by the philosophy of Nuxt, I dedicated the next seven hours to building an abstraction layer. I wanted this engine to feel "natural" for a web dev. I ordered the AI to forge a custom CLI (Gwen) with prepare and dev commands. I wanted Vite hidden under the hood. Then, I enforced a rigid folder structure and typed helpers: defineComponent, defineSystem, defineScene. By dictating these patterns, I turned the "vibe" into steel rails. The AI knew exactly where to write, and I knew exactly where to look.


⚖️ Hours 12 to 22: The AI Tribunal and the Memory Wall

Next came the heavy lifting: integrating Rapier (2D Physics) into the Rust Core. This is where everything almost collapsed. JS/WASM communication became a minefield. I established what I called the AI Tribunal: I took Copilot’s code and threw it at Gemini for a roast.

Challenging different models yielded terrifying efficiency. Gemini spotted potential memory corruptions in Copilot's code, while Copilot countered with more modern implementations. My past experience with buffers allowed me to act as the ultimate arbiter. To stabilize the mess, we invented a "Sentinel" (canary bytes) injected at the end of buffers to detect overflows, along with a Segmented Address Space. Pure engineering, born from dialogue.


🛠️ Hours 22 to 28: Extreme Pedagogy and Ghost Hunting

Fatigue set in. A vicious bug appeared: collisions were erratic after scene changes. The AI panicked, looping through fragile "quick fixes" that broke our clean architecture.

This is where the gain/cost ratio flipped. I had to become an extreme pedagogue. I literally had to "point my finger" at what the AI had right under its nose in its own console via grep commands. "Look at your logs, you forgot the buffer reset on line 42!" The AI would hallucinate, apologize, and then fail again elsewhere. The urge to grab the keyboard and type those three lines of Rust myself was almost physical. But I held on; the experiment had to be completed. Eventually, we found the culprit: the Rust world was holding onto "ghosts" of un-reset scenes. We forged a proper Reset system inspired by Unity and Godot.


đź§ą Hours 28 to 30: The Great Cleanup

The final two hours were dedicated to pruning. The code had suffered from the previous battles. Together with the AI, we broke down monoliths, removed dead code, and harmonized types. We transformed the battlefield into an elegant framework.


🎯 Epilogue: From "Full Vibe" to Hybrid Control

H+30. The Gwen framework is born. It’s powerful, extensible, and feels like a modern web tool. But the lesson is bittersweet.

Vibe Coding is a weapon of mass destruction for initial velocity (months of R&D collapsed into a weekend). But at scale, it’s a hazard. The mental load of verifying every hallucination is exhausting.

This concludes the first phase of the experiment. For the core foundations and the tricky memory management, I’ve taken back the keyboard. I am no longer just a spectator of a temperamental machine; I’ve stepped back in as the pilot to ensure the quality and stability of Gwen's engine.

But the "Vibe" isn't dead yet. While I’m now getting my hands dirty on the core, I’m far from done with AI-driven development. There are still many layers to build, and I plan to push the boundaries of Vibe Coding even further for the next stages of this project.

Stay tuned for Part 2, where we’ll see if the "Vibe" can handle the next level of complexity... or if the machine finally wins.


🛠️ Explore Gwen on GitHub

The project is now in active development. You can check out the code, the WASM structure, and the CLI on the official repo:

👉 GitHub: https://github.com/djodjonx/gwen


What about you?

Do you use AI strictly for scaffolding, or do you trust it with your architecture? Let’s discuss in the comments.

Top comments (1)

Collapse
 
nyrok profile image
Hamza KONTE

The Rust/WASM context shift you describe is exactly where "vibe coding" breaks down — the mental model for borrow checker + lifetime semantics is fundamentally different, and LLMs have enough Rust in their training data to generate plausible code that still has subtle ownership bugs.

The workflow you landed on (clear objective + constraint per session, tight feedback loops) is essentially structured prompting discipline. The AI works better when it knows: this specific function, these constraints (no unsafe, no clones for performance), this output format (compiles with wasm-pack, passes this test).

That's the core insight behind flompt (flompt.dev) — instead of writing the context ad hoc each session, you build 12 typed blocks (role, context, constraints, output format, etc.) and compile them into a structured prompt that the AI actually follows consistently. For a domain as precise as Rust/WASM, "be careful with lifetimes" as a vague instruction vs a specific Constraints block produces very different output.

Free, open-source, and there's an MCP server for Claude Code integration: github.com/Nyrok/flompt. Impressive 30-hour build!