All case studies

DEV3 Technologies · own product

MacMan: a browser maze-chase game with arcade-accurate ghost AI on a deterministic TypeScript engine

Our own free game: an HTML5 maze-chase arcade game in Phaser 3 and TypeScript, with four ghost personalities driven by target tiles, arcade difficulty tables, three original mazes and keyboard, gamepad and touch controls, all on one deterministic, fully tested rules engine.

Industry
Games & interactive

Live project preview

DEV3 Technologies · own product — screenshots
Open live demo
Level 1 on the Neon maze: Blaze and Frost close in while Pixie and Ember leave the house

Level 1 on the Neon maze: Blaze and Frost close in while Pixie and Ember leave the house

The challenge

Maze-chase games look simple, and that is why players notice every flaw. Ghosts that simply chase the player by shortest path all form one queue behind you, which is boring; the classic game feels alive because each ghost aims at a different tile and the four combine into an ambush. The movement has to be forgiving too: a grid game that only turns when you press exactly at a junction feels broken on a keyboard and unplayable on a phone. On top of that, the game had to run identically at 60, 120 and 144 Hz, work with a keyboard, a gamepad and three styles of touch control, and stay small enough to load instantly.

Our solution

We built MacMan as a TypeScript monorepo whose core is a deterministic rules engine with no DOM or Phaser dependency. The browser renders it; the tests drive it directly.

Key design decisions

  • Ghost personalities as target tiles. Every roaming ghost decides only at tile centres: it never reverses voluntarily and takes the exit whose next tile is closest to its target, breaking ties Up, Left, Down, Right. The four personalities differ only in chaseTarget(): the player's tile, four tiles ahead, a vector doubled from the red ghost, or the player's tile unless within eight tiles. Coordinated-looking ambushes come out of these simple rules.
  • A real state machine. Scatter and Chase alternate on a per-level schedule that pauses while ghosts are frightened, and every switch reverses the ghosts. Frightened ghosts turn using the seeded PRNG, and eaten ghosts follow a precomputed BFS distance field to the door, then run a scripted path into the house, revive and leave. House release uses personal dot counters, a shared counter after a lost life, and a no-eating timer.
  • Forgiving controls in the engine, not the UI. A pressed direction is buffered for 0.6 seconds, turns are accepted up to 0.42 tiles before or after a centre, and the off-axis error is absorbed while moving. The input layer also latches taps, so a key pressed and released between two simulation ticks still counts.
  • Fixed timestep, interpolated rendering. The simulation always advances in 1/60-second ticks. The renderer draws actors between the last two ticks, so motion stays smooth on high-refresh screens and the game never speeds up or slows down with the frame rate.
  • Data-driven difficulty. Speeds, fright times, flash counts, the red ghost's speed-up thresholds, mode schedules and fruit values are tables in one config file, following the arcade originals.
  • No asset pipeline. The neon maze is traced from the tile grid with rounded convex and concave corners and a glow pass; sprites are painted with Canvas 2D at the screen's own tile size and packed into one atlas; sounds are synthesised. Everything stays sharp from phones to 4K.

Architecture

packages/shared holds the maze loader and validator, movement, ghost targeting and state machine, house rules, scoring, fruit, the level tables and a BFS autopilot used for the menu demo and soak tests. apps/client is Vite and Phaser 3 (WebGL with Canvas fallback) behind a responsive HTML/CSS shell for menus, HUD, pause and game over, with a LeaderboardProvider hook for local and online scores. apps/server is a small Express API that validates, rate-limits and stores high scores, and serves the built game in production.

Results

MacMan ships as a complete game and a free download. By the numbers, counted from the source and the test runs:

  • 4 ghost personalities, 4 ghost states and 3 original 28 × 31 mazes
  • 8 fruit, ghost streaks up to 1600 points, and a difficulty table that reaches its hardest settings at level 21
  • 3 input methods, with 3 touch styles: swipe, joystick and d-pad
  • 46 Vitest tests and 6 Playwright browser tests, including gamepad emulation and mobile touch
  • A steady 60 FPS at 720p and 1080p in headless Chromium with software rendering
  • About 365 KB gzipped for the whole client, with zero image or audio files

Play the browser demo or get the free source code on the DEV3 marketplace.

Related case studies