James Randall Musings on software development, business and technology.
Vektrix: Building a psychedelic twinstick shooter with WebGPU in 2 days

You can play the game online.

I was looking for a twin stick shooter and nothing quite scratched the itch — nothing in my Steam library anyway. I fired up Geometry Wars, enjoyed it, but it still wasn’t quite what I wanted. What it did give me was the spark to build my own.

I’ve always loved the vector aesthetic (Rez remains a favourite), and I knew I only had a couple of days — in total, perhaps a day and a couple of early mornings — so whatever I built had to be simple, fast, and focused.

The game can be played online or the video below will give you a taste of what I ended up with:

Although it’s still fairly new I’ve done a reasonable amount with WebGPU (and quite a bit with Metal, WebGL and a spot of Vulkan) so that was the obvious choice for rendering. Futzing around with the clunky WebGL interface isn’t fun, and with WebGPU I figured I could handle the particle effects entirely on the GPU in a compute shader.

To accelerate development — and because even modern APIs like WebGPU involve a lot of boilerplate — I used Claude Code for a significant portion of the scaffolding.

If you’ve seen my YouTube series on building an 8-bit virtual console, you’ll recognise my approach: spec first, review critically, and iterate fast. That worked particularly well here.

In fact it supported a real fast iteration speed which is ideal for game development where things are very much about the “feel”. I got the grid up and running fast and from there I built out player movement and eventually enemies which is where the fun really began.

As I worked my way through gameplay concepts I solidified on the idea that the game was about relentless pressure - the iteration speed helped me get there fast. I tried and discounted a bunch of things:

  • Mines - too strategic
  • Black holes / gravity wells - slowed things down, though these got repurposed into mass spawners
  • Shields - too defensive

Basically if it slowed things down or didn’t serve the intensity and pressure directly in some way I discarded it. The sheer lack of sunk cost made it really easy to do this without that nagging sense of “well this took 3 days… maybe I should keep it” and I ended up with a stripped back game that’s all about pressure and chaos.

From the start I’d set off wanting to lean into an almost psychedelic vibe and as I worked on the game I ramped this up, dialled it back in areas, ramped it up again trying to pitch things just on the right side of comprehendible. Mostly I dialled it up! There was a lot of tweaking of bloom, of the fairly subtle CRT effect, and the phosphor trails. Then tinkering with particles - volume, speed, etc. WebGPU really helped with this - the particles running on the GPU leaves loads of room on the CPU for a high entity count and collisions etc.

I set up the data using an array based entity system that will play nicely with web workers. My original intention was to run some parts of the engine on workers but I’ve had no need: things seem to absolutely scream on my MacBook and gaming PC - though both are pretty powerful bits of kit and so I might need to do some tuning if people play this on lower end kit (I have none readily to hand).

The music came from Pixabay which fortunately has a large selection of permissively licensed dance tracks. The sound effects are just procedurally generated.

So what’s next? The endgame ramps a bit too aggressively and I think I could pace that better with some more enemy types. If people play it and find it struggling on lower end kit I might spend some time on optimisation. Perhaps spend some time on the sound effects… they are still a bit anaemic.

The source code for this project can be found on GitHub here.

Built by James Randall — tool-maker, system builder, and occasional cyclist. Walking the hills with my four-legged friend when I'm not building worlds.
© 2025