Picnic Heist! – a sneaky ant colony game in three.js (instanced ants, tilt-shift macro look, mobile)

Hi everyone! I made a small game about a colony of tiny masked robber ants raiding a family picnic. You draw pheromone trails from the anthill to the snacks, the ants team up to carry them home (a sandwich takes 12 ants, the birthday cake 22), and you hold FREEZE whenever someone glances down. A sandwich that stands still is just a sandwich.

:play_button: Play (free, desktop and mobile): Picnic Heist! – Play free online | Glowbit Games

There are 12 picnics in 4 places (park, beach, backyard BBQ, moonlight camp). You dodge a kid’s stomping sneaker, a seagull, a dog and a raccoon that steal unguarded snacks, beach waves and a lawn sprinkler. There is also a Feast mode and a Picnic Planner where you can build picnics and share them as text codes.

Some technical bits

  • One InstancedMesh for the whole colony: up to 150 chibi bandit ants (big head, robber mask, round gaster) are one InstancedMesh. The legs, antennae, body bob, “bonk” squash and the wet tint from the sprinkler are animated in the vertex shader from one per-instance vec4 (walk phase, walk amount, squash, wet). A second instanced mesh carries the colony’s hat.
  • Shader overlays on the ground: pheromone trails are glowing ribbons with dots flowing towards the snack. The family’s gaze is drawn as a dashed circle while they are about to look, then a bright pool with a suspicion ring while they look. The shoe shadow and the thief’s target ring are decals too.
  • Macro photo look: Poly Haven HDRIs for image-based lighting, a soft sun shadow, N8AO ambient occlusion on High, and a postprocessing tilt-shift blur that makes the picnic feel tiny, plus bloom, AgX tone mapping, SMAA and vignette. Auto quality steps the pixel ratio, shadows and AO down when the frame rate drops.
  • Render-free simulation: ants, trails, carrying, the family’s glances and suspicion, stomps, thieves, waves and the sprinkler are plain TypeScript with no three.js, deterministic for a given seed. Unit tests and a headless bot run in Node, and a test checks that the bot gets at least 1 star on every level. Tapping a snack routes a trail around the obstacles automatically.
  • Two postprocessing gotchas I hit:
    • The composer only marks the last added pass as renderToScreen. With a high and a low effect pass both added, set renderToScreen yourself, or the canvas stays transparent.
    • A disabled N8AO pass that was still in the composer hid every opaque object. I add and remove the pass instead of toggling enabled.
  • Sound: all procedural Web Audio. There is a swung “sneaky heist” jazz combo (walking pizzicato bass, brushes, vibraphone, a clarinet motif) that turns to suspense while the family looks and goes muffled while the colony freezes. There are also tiny ant voices (“hup!”), formant-synth family voices (“Hmm?”, “Hey!”), gulls, barks and waves.

Stack: three.js r186, TypeScript, Vite, postprocessing, N8AO. The JS is about 375 KB gzipped, plus about 3 MB of textures and HDRIs.

I’d love to hear how it runs on your devices, and how many snacks your colony can steal!