Project

+- 13

An arcade dodger built in 13 KB with WebGL2 SDF rendering and radiance cascades.

TypeScript / WebGL2 / Web Audio / Webpack Game design, rendering, audio, engineering Visit project

+- 13 is a JS13K 2024 arcade game about chasing or avoiding a moving 13, depending on the wave. The visuals are built entirely from signed distance fields, then lit using a multi-pass radiance-cascade renderer that runs in raw WebGL2.

Player feedback

"Very cool visual effect. I remember from last year, your games are very technical, which is interesting. Would like to have a look at the postmortem." -- Isaac Benitez

"This is my favorite 'need to take it apart and learn how it's done' game this year." -- Mark Vasilkov

"Impressive lighting effects! Gameplay is simple but funny. Having a music is cool too!" -- Jonathan Vallet

"The lighting was impressive." -- Jasper Renow-Clarke

Rendering pipeline (SDF + radiance cascades)

  • df.fragment.glsl builds the whole scene with SDF primitives: capsules for the stick figure and custom digit glyphs for the 1-13 tiles.
  • Tile data is packed into a mat4 u_boxes[13] uniform array (position, velocity, value, color, radiance) to keep WebGL uniforms compact.
  • The distance field is rendered into a float texture via an offscreen framebuffer.
  • rc.fragment.glsl raymarches the distance field in multiple cascades, merging lower-resolution radiance probes into higher detail levels for soft global illumination.
  • Each cascade pass feeds the next via u_lastTexture, mipmaps, and a ping-pong FBO setup.

Game simulation and collisions

The update loop runs at requestAnimationFrame cadence and handles:

  • 13 roaming tiles that spawn off-screen, drift toward the center, and bounce off each other.
  • A wave rule that alternates between "avoid 13" and "hunt 13".
  • Player collision with SAT-style polygon checks (rotated stickman vs. axis-aligned boxes).
  • A "super mode" shield that spends charge to let you collect any tile safely.

Input, UI, and scoring

  • Keyboard input (WASD or arrows) drives inertial movement with capped acceleration and smoothing.
  • The UI is HTML/CSS layered over the canvas for timer, score, lives, and shield charge.
  • Local storage keeps a top-10 scoreboard, with scores normalized by screen resolution.

Audio synthesis

Two procedural systems handle audio:

  • sound.ts builds short SFX buffers from custom wave formulas and plays them on demand.
  • music.ts schedules chords, melody, bass, and drums with increasing tempo every wave, using Web Audio oscillators, filters, and a convolution reverb.

Build and size constraints

The pipeline uses TypeScript + Webpack, GLSL minification, and JS13K-friendly compression:

  • webpack-glsl-minify for shader shrinking.
  • Roadroller and AdvZip in build-final to squeeze the final bundle into the 13 KB contest limit.