Test task · Voodoo · Playable ad · 2026
A real 3D crowd running at sprite performance — in a browser, in one file under 5 MB.
Frame rate read from an on-screen counter on the target device; drops traced with the Unity Profiler.
A test task for Voodoo: build a playable ad of Mob Control that runs as a single HTML file in any browser, under five megabytes, in one week. Unity and C# on the authoring side, Luna Labs to transpile it to the web.
The differentiator
Playable ads fake crowds with sprites because real ones do not fit the budget. I wanted actual 3D units, which meant proving they could run on the slowest device anyone would open this on — a 1 GB Amazon Fire 7.
The straightforward approach died on measurement: one game object per unit gave ten frames a second at eight hundred units. So the crowd stopped being objects.
Units render from a vertex animation texture with a genuinely baked walk cycle, merged into batches of two hundred, with a separate texture carrying per-unit state. Colour space moved from linear to gamma, which is what brought the Fire 7 back to life at all.
The result was sixty frames a second at eight hundred units and forty-seven at fifteen hundred, on the cheapest tablet in the room.
Scope
Gameplay: a stream of enemies with mutual attrition on a grid, multiplier gates up to ten with a zone query and a guard against recursive re-entry, a tower with health, a damage zone, a wall, a blocker, a fever bar, and a champion unit with its own skinning and a fan of gate clones.
Presentation: a window system for menu, game, win and lose with end cards, transitions on DOTween, a two-light MatCap setup with a pastel palette and distance fog, and contact shadows — a blob under the cannon and a planar silhouette under the tower and gates through a single-pass per-caster shader with stencil and edge clipping, plus a shadow for the crowd drawn through the same batch as the crowd itself.
Effects and feel: wheel smoke, muzzle flash, tower explosion, idle glints on the gates, spawn and death animations driven through the state channel of the crowd texture, an audio system with a voice pool, music from the first tap, and a tutorial sequence rebuilt from the reference.
The transpiler had its own rules. Some maths functions do not survive it, so crowd rotation had to be re-encoded as a direction vector after a bug that existed only in the web build.
The last day was a performance session: shadows reinstated, champion pooling, culling of crowd batches, simulation gated while in the menu, and a warm-up pass on load. Combat holds thirty frames on the Fire 7.
I built this one end to end. These are the parts worth naming.