Tap a stone spot to build a tower.
Bastion playable ad demo · PixiJS · tower defense
A 30-second tower defense: build archer, cannon and frost towers on stone spots along a winding road, upgrade them with gold from kills, and hold the castle against three waves and a boss. Everything — art, effects, sound — is generated in code, so each network build is a single self-contained HTML file.
Builds
| Network | Single HTML | gzip | Budget | |
|---|---|---|---|---|
| Loading… | ||||
Each build ships exactly one adapter: FbPlayableAd.onCTAClick() for Meta, ExitApi.exit() for Google, mraid.open() with ready/viewable handling for MRAID networks (Unity Ads, AppLovin…). The build fails if a file exceeds the budget or references anything external.
Under the hood
- A core that knows nothing about rendering. Road, waves, creeps, towers, gold, castle and the ad scenario are plain JS; a test greps the core for Pixi, DOM and network calls, and a whole battle is replayed in Node without a single sprite.
- Entities with doors. Gold can't go negative, a spot holds one tower, a dead creep can't be hit — every write returns
{ ok, code, detail }and a refusal changes nothing. - Variants by replacing a node. Targeting (first on the road, first un-chilled) and impact (single, splash, chill) are small objects named in a table; a new tower is a config row, not a branch.
- One observation channel. The core announces milestones; HUD, sound, sparks, tutorial and the network adapter subscribe in one place at the assembly point.
- Zero allocations in the frame loop. Projectiles live in a slot pool backed by typed arrays; creep sprites are leased from a pool and returned after their death animation.
Source on GitHub Open full screen with perf overlay All projects →