Handmade Web Games

Handmade Web Games

A practical guide to building games for browsers in 2026.

There are many ways to build web games. You have engines like Godot, Unity, GameMaker, or Flash. There are also libraries like Phaser or ThreeJS that wrap lower-level browser APIs. And then there's a third way: building them from scratch. If you're curious about that last one, then this is your guide.

But first...

Why build for the web?

There are many reasons not to use the web as your game's platform. It struggles with large assets. There are performance limitations. Audio can be a pain. Controller support is limited and browser-dependent. Many GPU graphics APIs are missing. Ultimately you're rendering your game to a canvas powered by JavaScript, which is inherently slower than native equivalents. The list goes on.

But all of those constraints pale in comparison to one good reason you should publish your game on the web. And that is because you want people to play your game.

The web is by far the best way to distribute your game to get it in front of as many people as possible. There is a night and day difference between clicking Play and clicking Install--even for a free game.

When you build for the web, it's trivial to put your game in front of players. You can share your game with a link. People with that link can play your game instantly and share it with their friends, who can also play it no matter what devices or consoles they own. By publishing your game on the web, you gain access to vastly more potential players than on any other platform.

The good news is that despite all its shortcomings, the web platform is a lot less bad for games compared to just a few years ago. Tools like WebAssembly, WebGPU, and service workers narrow the gap between what is possible with fast native code and in-browser JavaScript. The Gamepad API introduces controller support with haptics. You also get easy access to fullscreen and pointer-lock capabilities. Offline PWAs can be installed to run just like a desktop app. Implemented correctly, modern web games can look and feel indiscernible from their native equivalents.

To be clear: if you are building a massive 3D world with lots of assets or need high speed UDP networking or other very specific needs, the web isn't ready for you yet. But I think many of us are building smaller games with simpler needs. If you're in that group, and if your goal is to get as many people playing your game as possible, there's no better platform for your game than the web.

So the web is a strong platform choice, but why not just use an engine?

Why handmade web games?

  1. It's more fun and less frustrating Complex game engines are full of bugs. Your handmade code will be, too, but at least those you can fix. It's so much better to be faced with a bug you can actually do something about than to shout for help into the void and hope someday an engine developer will fix it.
  2. You'll build transferrable skills. Learning an engine mainly builds expertise in just that engine. You'll certainly build some transferrable skills in the process, but starting with GameMaker and later moving to Unreal will feel a lot like starting over from square one. On the other hand, if you develop a fundamental understanding of the principles and techniques for building games, whether you're writing TypeScript or Odin or C, those general patterns will transfer.
  3. Control. Unity and Godot won't be around in their current forms forever. You might disagree with decisions they make that you have no control over. Breaking API changes, licensing and pricing changes, plugin incompatibility, interface updates and other changes that destabilize your workflow are common when you work within an engine with a lot of moving parts. But when you own your toolset, you get to drive the decisionmaking and have agency in how your game is built.
  4. Longevity. There's no guarantee a third party will maintain compatibility layers for future engine versions. But you'll always be able to update and run your own hand-written code.
  5. Avoiding bloat. Bloat is far less of a concern when you're distributing a native build on Steam. Players there have a much higher tolerance for long installation times. But on the web where there's no "install" step, players expect fast load times. Every Godot, Unity, and Gamemaker game on the web has a loading screen. Most handmade web games don't need one at all. Handmade games also won't be stuck advertising the engine with splash screens and logos during loading.
  6. Faster iteration. Engines are heavy programs that are slow on even the most capable hardware. When the feedback loop between making a change and seeing it run is slow, it's harder to reach a flow state. Stripping that away allows you to experiment without friction and test changes at the speed of thought. Full builds are way better, too. A default 2D web build from Unity for an empty project with no assets took over 5 minutes to complete on my M1 Max MacBook Pro. On the other hand, handmade games' incremental builds finish in milliseconds, and complete optimized production builds generally finish in a handful of seconds at most.
  7. The web is already a platform. Why build an abstraction over something already so high-level? Out of the box, browsers give you a canvas to draw to, mouse/keyboard/controller/microphone inputs, multiple ways to play audio, sandboxing, networking, persistence, cross-platform compatibility, devtools, and methods for updating and distributing your games. Instead of learning an engine's flavor of each one of these concerns, why not just learn the thing itself?
  8. You can progressively build your own abstractions. This is basically the point of this guide. Starting from first principles doesn't mean you'll always operate on lower-level code. As you build your own reusable patterns and tooling, they can follow you from project to project. Consider it an upfront investment in your own mind.

A peek at the upcoming chapters

These 16 chapters introduce the fundamental techniques used in 2D web game development. Many of them are still works in progress! If you'd like to contribute, point out mistakes, or otherwise join the discussion--stay tuned. Community involvement on GitHub and Discord is coming very soon.

1

Tooling for web games in 2026

A minimal and reusable TypeScript + Vite setup for browser games.

2

Intro to CanvasRenderingContext2D

A tour of the Context2D APIs used to draw shapes, text, and images to a canvas.

Paths & shapesTextImagesGradientsFiltersCompositingTransformsHigh-DPIPixel art
3

Game loops

A game loop that draws at the display's refresh rate while running logic at a reliable fixed timestep.

requestAnimationFrameDelta timeFixed timesteps
4

Animation, pixel art, and sprites

Building on top of the game loop with animation techniques for 2D games, covering: velocity, acceleration, derived movement, easing, springs, grid-based movement, sprite sheets, and pixel art scaling.

LerpEasingSpringsSpritesPixel art
5

Math for games

Movement, randomness, sine waves, aiming, and collision detection in 2D.

Diagonal movementModuloSeeded randomSine wavesAnglesCollisionsDot product
6

Cameras and viewports (soon!)

5%

How to extend your game world beyond the bounds of the canvas.

7

Mouse and keyboard input

Wire keyboard and mouse events into the game loop.

Continuous vs discrete eventsPointer positionHitbox testsHover cursorsRight-clickPointer lock
8

Controllers and haptics

Use the Gamepad API to read buttons, triggers, and analog sticks. Plus, haptic feedback!

DeadzonesSnappingHysteresisHaptics
9

Audio

Music, sound effects, and spatial audio with the Web Audio API.

10

Game feel and juice (soon!)

35%

Feedback that makes games feel more responsive and satisfying, with an in-depth look at particles, screen shake, and timing tricks.

11

Offline mode (soon!)

0%

Offline mode and installability with PWAs and cached assets, so repeat visits to your game load much faster.

12

Devtools (soon!)

1%

Profiling techniques and in-browser development tools for games.

13

WebAssembly (less soon)

1%

WASM for high-performance heavy computations, non-garbage-collected memory management, and compilation from low-level languages.

14

Multithreading (planned)

0%

Background work and parallelism with Web Workers.

15

WebGL and shaders (planned)

0%

GPU rendering and shaders with WebGL.

16

WebGPU (planned)

0%

Direct programmatic access to the GPU for graphics and compute.

On this page