Skip to content

Examples

Every prototype under examples/ is a first-class engine consumer: a small, runnable game or harness that imports the engine only through its public paths (@pierre/ecs, @pierre/ecs/modules/*) — the same entry points an outside consumer gets. Each page below runs one in place, next to its source and the modules it exercises.

Press Restart to start over, or Stop to stop the demo. Each prototype is its own small Vite app; to run one locally, open its folder and use the scripts in its package.json. The hub app runs them all from a single page.

Built roughly in order, each to prove something the ones before it could not.

  • Snake — Arcade grid movement with event-driven growth and restart flow.
  • Asteroids — Continuous motion, thrust + rotation, bullets, rock splitting.
  • Platformer — Side-view gravity + AABB kinematics, pickups, and respawn.
  • Top-Down Shooter — Twin-stick arena: continuous mouse aim, held-fire bullets, enemy swarms at scale.
  • Card Battler — Turn-based card combat: DOM renderer, manual tick, drag-to-play — proves the renderer interface is not canvas-coupled.
  • Rhythm — Four-lane rhythm: tick source driven by AudioContext.currentTime, not performance.now — first external-clock test.
  • 3D Platformer — 3D platformer via three.js with custom 3D AABB kinematics — the defining test that @pierre/ecs is not secretly 2D.
  • Local Pong — Local multiplayer Pong with player-scoped keyboard input and score kept as game state, not entity data.
  • Tilemap (Tiled TMX) — First sprite/texture-atlas consumer: parses a Tiled TMX map (base64+zlib) and renders every tile as a sprite entity, layered via RenderOrderDef.
  • Solitaire (Klondike) — First interactive canvas scene: draw-1 Klondike with per-frame card dragging, dynamic z-order via RenderOrderDef, and world-space hit-testing over a texture atlas.
  • Top-down RPG — First camera-follow and first NPC dialogue scene: walks a Tiled dungeon (CSV + external .tsx + flipped tiles) with a follow camera, wall collision, and a nine-slice dialogue box.
  • Roguelike — Turn-based dungeon crawl on generated floors: shadowcast field of view and fog, A* chasing and line-of-sight archers from one behaviour tree, a turn cycler over every actor, floors swapped by scene transition, and checksummed, migrated saves.

One game per rung of the 20 Games Challenge, in challenge order.

  • Flappy Bird — Gravity + flap impulse, scrolling recycled pipe pairs, circle-vs-AABB collision, and score-on-pass.
  • Breakout — Circle-vs-AABB brick field with axis-of-least-penetration bounce response, paddle english, lives, escalating ball speed, and a persisted high score.
  • Jetpack Joyride — Endless right-to-left scroller with hold-to-rise gravity, script-spawned recycled zappers, distance score, machine-gun bullets and particle juice.
  • Space Invaders — Beat-stepped alien fleet that drops and reverses at the walls and speeds up as it thins, single-rocket fire, bombs the player can shoot down, destructible bunkers, a bonus mothership, lives and waves.
  • Frogger — Tile-discrete hopping across recycled traffic lanes and a river of logs and diving turtles, carried platform-rider kinematics, and five lilypads to fill.
  • River Raid — Vertically-scrolling jet fighter up a procedurally-generated river with variable-width banks, branching streams, bridges as checkpoints, enemy boats/helicopters/jets, and a draining fuel gauge.
  • Spacewar! — Two-player local space duel with star gravity, screen wrapping, torpedoes, and particles — the very first video game.
  • Indy 500 — Top-down racing for one or two cars on closed circuits: speed-dependent steering, wall and car collisions, lap timing, race / Crash & Score / Tag modes, and a steering-behaviour AI opponent.
  • Lunar Lander — Rotate-and-thrust landing on seeded noise terrain with multiplier pads: altitude-driven camera zoom, a thruster flame animation, and a checksum-verified leaderboard.
  • Pac-Man — Tile-locked maze chase: four ghosts with their own targeting, a scatter/chase clock, frightened and eaten states, tunnel wrap, fruit, and levels — every rule a state machine or a system over components.
  • Doom — First-person arena shooter — a 3D controller with verticality (stairs and a moving elevator), billboard-sprite enemies with line-of-sight AI, hitscan and projectile weapons, a health/ammo HUD, and pickups.
  • Minecraft — Seeded voxel sandbox — noise-carved terrain, caves and trees in chunk entities remeshed on edit, frustum-culled chunks, swept voxel collision, and ray-picked block breaking and placing.
  • Portal — Real 3D portals — recursive see-through rendering, momentum-preserving teleport, floor and ceiling portals, a companion cube, and a pressure-plate door.

Playgrounds where one module, or one rig, is the whole point.

  • Starfighter — Third-person space flight: aim-to-steer attitude control (quaternion orientation, rate-based turns), throttle-only motion, a banking chase camera — proves the camera rig is neither yaw-only nor first-person-locked.
  • Boids (steering) — Steering-behaviours playground: 140 boids driven purely by composed Reynolds steering — separation, alignment and cohesion plus wander, cursor-flee and food-arrive, with neighbours from a spatial hash grid.
  • Stealth Guard (FSM) — FSM playground: guards run a 5-state machine (patrol → suspicious → chase → search → return) driven by a vision cone and line-of-sight; the chase state composes modules/steering.
  • Critters (behaviour tree) — Behaviour-tree playground: critters each tick the same reactive tree — a selector over prioritised needs (flee threat > eat when hungry > sleep when tired > wander) — with a per-critter blackboard. Shows why a tree beats a state machine for layered priorities.
  • Woodcutter (GOAP) — GOAP planning playground: workers get actions (get axe, chop, deliver) with preconditions and effects and a goal, and an A* planner sequences them. After the first log a worker keeps its axe, so the planner drops the GetAxe step — the same goal, a different plan.
  • Game of Life — Conway’s Life with every live cell an entity: each generation queues thousands of births and deaths and one flush applies them together — the deferred command buffer as the double buffer, neighbours counted through the spatial index, fading ghosts on lifetimes, and age colours recomputed only for changed cells.

Not games: these measure the engine, or stress one part of it.

  • Storage stress (SoA vs Map) — Storage benchmark: the same integrate-and-wrap sim over N entities two ways — the ECS Map store against flat SoA typed arrays — with isolated sim, render and frame timings and a frame-time graph.
  • Worker offload (no stall) — Main-thread-stall demo: a heavy CPU job on the main thread freezes the page and spikes the frame-time graph; in a Web Worker via modules/worker-pool the dots keep drifting smoothly.
  • Parallel kernel (core-bound) — Core-bound benchmark: a heavy O(n·K) per-entity kernel (K attractors) run single-threaded over the columnar store. Raise entities and K until the sim dominates the frame.