Devlog
Building Awaken
Notes from building a browser-native WebGPU game engine - imports, architecture, rendering, and the occasional rabbit hole.
- #1Why build a browser-native game engine - and why WebGPU, not WebGLThe goal, the technical reason for WebGPU over WebGL, and the plan to ship the same games to browser, desktop and mobile.
- #2Awaken architecture: the core documentThe package graph, the ECS data model, the editor/player boundary, and the frame loop.
- #3Reading Unity, Unreal and Godot files by handA format-level teardown of four asset pipelines - magic bytes, where the geometry hides, and the one trick every non-glTF format forced on us.
- #4Exporting a whole 3D game as one HTML fileHow Awaken bundles a game into a single self-contained file, the geometry-shrinking pipeline (with real numbers), and the plan to export the same game to desktop and mobile.
- #5TypeScript that compiles in the browser (with real autocomplete)The libraries behind Awaken's in-tab scripting, how we wire IntelliSense for our own API, how compilation works with no toolchain, and how a script hooks the engine.
- #6Physics: I wrote my own, then chose Rapier over JoltWhy I deleted my hand-rolled physics, how I picked Rapier over Jolt, the abstraction that keeps it swappable, and two Rapier footguns that make a player fall through the world.
- #7Making WebGPU run on every GPU (including ones you can't test)WebGPU means every GPU on earth - feature detection, a fallback that never rots, and a GPU picker built on the one knob the API gives you.
- #8Editor scripting: the size-cull that made my buildings dissolveModular buildings pop because size-aware distance culling judges every part on its own - small tiles cull close, big walls stay far, and the house comes apart as you move. The fix is an editor tool that merges each building into one object. (Plus a memory rabbit hole I climbed out of empty-handed.)
- #9Precomputed occlusion: how it works, and why it's an option not a defaultThe full PVS pipeline - voxelisation, ray-cast visibility, sparse storage - why it's hard to tune on imported open worlds, and what Awaken does for now instead.
- #10The ids Unity computes and never writes downA .unitypackage says 'deactivate sub-object -3329563214062771084' and ships no map from that number to a name. Re-deriving Unity's hash from first principles, and the three bugs that surfaced on the way.
- #11A shader graph that compiles to the same thing you'd type by handMaterials as four hooks into the standard PBR shader, a 91-node graph that compiles to exactly the same Material as hand-written WGSL, subgraphs inlined like function calls, and the 36% of a shader that was node library nobody called.
- #12Plugins that cannot phone homeDeleting fetch from a worker does not stop it exfiltrating data, because `import` is a keyword you cannot delete. The fix has to come from the browser's network layer, plus a signing chain and the four failures my tests could not see.
- #13Retargeting animation between rigs that disagree about rollTwo exports of the same character do not agree on bone roll - one arm flips 180 degrees, the spine differs 57 to 106 degrees per bone. Building a retarget out of positions instead, and the bug I spent days disproving.
- #14Translating Unreal's material graphs, and knowing when to refuseFlattening a .uasset material graph, transcribing 28 of the 39 engine functions a pack actually used, and why a rotation node measured in turns rather than radians is the most dangerous kind of bug.
- #15Compiling AssemblyScript in the tab, and a library that cannot reach anythingHeavy work needs to leave the main thread. A module that declares zero imports cannot touch the DOM, the network or the scene - not because a sandbox stops it, but because there is nothing to call.
- #16How do you unit-test a picture?Every shader compiling proves nothing about the frame. Rendering a fixed scene headlessly, hashing the pixels against a per-adapter baseline, and cutting a 3,362-line renderer apart behind it.
- #17Particles: a CPU simulator, a four-vertex draw, and three places that disagreedA structure-of-arrays pool on the CPU, one instanced draw with no vertex buffer, and why the preview looked different from the game for weeks.
- #18The HUD is DOM, and that was the right callA WebGPU engine drawing its interface with div elements: why text rendering decided it, what it costs, and importing Unity's uGUI into a flat set of anchored nodes.
- #19Six reasons an imported scene looked wrong, and none of them were the importerBlack surfaces, dead grey metal, a town lighting four of its seventy lamps. Every fix was in the renderer, every cause was an assumption the source engine did not share, and every one was found by measuring rather than by tuning.