Ghost Squad • Game Design Spec

Type: Product Requirements Document Status: Draft for review Series: Do villain things (sibling of minelayer) Deliverable target: single offline HTML file

1. Background and Goals

Concept. Ghost Squad is a reversed Pac-Man: instead of guiding Pac-Man away from the ghosts, the player commands the four ghosts to hunt an AI-controlled Pac-Man. It is the second title in the reversed-games series, following minelayer (reversed Minesweeper, where the player lays mines and an AI sweeper solves the board).

Why this game, why now. Design research within the series established three selection criteria, all met by this concept:

Differentiating mechanic. All four ghosts are human-controllable at once, each bound to its own keyboard cluster (WASD, ↑←↓→, IJKL, numpad 8456). One player realistically attends to about two ghosts at a time; uncontrolled ghosts fall back to the original arcade chase AI. Two to four friends sharing one keyboard bring more ghosts under human control. Difficulty therefore emerges from human attention bandwidth rather than from AI knobs alone, and the game gains a couch co-op mode at zero netcode cost.

Goals (observable outcomes).

2. Product Contract

ElementDefinition
Primary userA casual player in a browser, alone or with friends physically present
TriggerOpening the game's HTML file (double-click or browser URL); the game boots straight into the title/attract screen with no loading of external resources
Core jobCommand the four ghosts to catch the AI Pac-Man before he clears the maze of dots
Completion condition (round won)Pac-Man is caught 3 times (his lives exhausted) before all dots are eaten
Failure condition (round lost)Pac-Man eats every dot in the maze
Trust boundariesEverything runs locally in one HTML file; no network calls, no external assets, no accounts; best scores persist only in localStorage

3. Scope

P0 — required for the smallest complete game P0

P1 — valuable, not blocking P1

Explicitly excluded OUT

4. Game Model

4.1 Objects

ObjectCanonical definition
MazeThe single fixed playfield: tile grid, walls, dots, 4 power pellets, ghost house, side tunnel. Replicated from the arcade original's layout.
Pac-Man (AI)The autonomous opponent. Goal: eat all dots. Has 3 lives per round. Behavior = shared movement core + one active Personality (SR-3).
Ghost × 4Player-controllable hunters. Each has its arcade identity, color, spawn point in the ghost house, scatter corner, and fallback chase behavior:
Shadow (Blinky) — fallback: targets Pac-Man's current tile
Speedy (Pinky) — fallback: targets 4 tiles ahead of Pac-Man
Bashful (Inky) — fallback: flank vector off Shadow
Pokey (Clyde) — fallback: chases when far, retreats to corner when close
Dots234 regular dots + 4 power pellets (count follows the replicated arcade maze). Pac-Man's win progress; visible on the maze at all times.
Control mode (per ghost)Each ghost is independently in HUMAN or AUTO mode at any moment (SR-2). Displayed above each ghost and on the HUD.
PersonalityA named parameter bundle for the AI Pac-Man, drawn once per round and telegraphed to the player (SR-3).
Difficulty tierOne of Beginner / Intermediate / Expert, selected before the round; tunes only the AI Pac-Man's physical parameters (speed, cornering boost, empowerment duration, personality pool) — decision quality is identical on all tiers (SR-4).

4.2 Round state machine (canonical)

ATTRACT ──(any key / click Start)──▶ TIER SELECT ──▶ READY (personality reveal, ~2.5s) ▲ │ │ ▼ │ ┌── PAC-MAN CAUGHT ── lives > 0 ──▶ PLAY (respawn) └──── round end ◀───────┤ ▲ (WIN or LOSS) └── lives = 0 ──▶ WIN │ dots = 0 ──────▶ LOSS ───────────────┘ PLAY ──(Esc / window blur)──▶ PAUSED ──(Esc / Resume)──▶ PLAY

States in capitals are the only legal states; transitions not shown are prohibited (e.g., no path from ATTRACT directly into PLAY, no restart mid-catch animation).

5. Functional Requirements

FR-01Arcade-faithful presentation and movement

Purpose. The reversal only reads instantly if the original is reproduced faithfully. This series' convention (set by minelayer's Windows XP fidelity) applies here to the 1980 arcade original.

FR-02Round loop, win, and loss

AspectRule
TriggerPlayer selects a difficulty tier on TIER SELECT (click or 1/2/3)
Ready phase~2.5 s: maze shown with dots refilled, characters at spawn, active Personality revealed by name, icon, and trail tint (SR-3). No input accepted.
CatchA ghost in HUMAN or AUTO mode overlaps Pac-Man while he is not empowered → Pac-Man loses a life. If lives remain: brief catch animation, all characters return to spawn, sub-ready (~1 s), play resumes with dots as they were. If none remain: WIN.
ClearPac-Man eats the final dot → LOSS.
Round endWIN or LOSS banner with final score, best score for the tier, and a prompt: Enter = same tier again, Esc = back to TIER SELECT. Dots and positions fully reset on replay.
PersistenceBest score per tier saved to localStorage; shown on TIER SELECT and round end.
ExceptionsBrowser tab hidden or window blurred during PLAY → automatic PAUSED (fair-play and input-safety rule, SR-5).

FR-03Four-cluster keyboard control

Purpose. Let one keyboard seat one to four players; make human attention the difficulty dial.

GhostPrimary clusterAlternate cluster
ShadowWASD—
Speedy↑←↓→—
BashfulIJKL—
Pokeynumpad 8456TFGH (laptops without numpad)

Interactive demo — FR-03 claim / FR-04 idle fallback

Focus the dark panel (click it), then press any cluster. A ghost you touch becomes HUMAN; leave it unattended and it reverts to AUTO (fallback AI) — the exact SR-2 rule.

AUTO
Shadow
fallback AI
W A S D
AUTO
Speedy
fallback AI
↑ ← ↓ →
AUTO
Bashful
fallback AI
I J K L
AUTO
Pokey
fallback AI
num 8 4 5 6 · T F G H
Idle timeout is shortened to 3 s in this demo (game value: see SR-2). Escape clears all.

FR-03aTouch controls (mobile)

Purpose. Make the full game playable on devices without a keyboard, preserving the exact SR-2 claim/idle semantics of FR-03.

FR-04Fallback AI for unattended ghosts

FR-05AI Pac-Man: heuristic core + personality roster

Purpose. Supply a convincing, learnable, varied opponent with zero network dependency.

FR-06Difficulty tiers

FR-07Power pellets (reversed risk)

FR-08Scoring and HUD

FR-09Audio

FR-10Result sharing (community layer, phase 1)

6. Shared Rules

SR-1 · Input and fairness

Inputs are taps queued per ghost; no action requires holding keys. All four clusters plus Esc (pause), Enter (confirm), M (mute), and 1–3 (tier select) form the complete input set. Any key press on ATTRACT advances to TIER SELECT. On touch devices the virtual d-pads (FR-03a) provide the identical input set through on-screen controls — same claim path, same queueing, same fairness rules; touch input never grants abilities keyboard lacks.

SR-2 · HUMAN/AUTO control rule (canonical)

Each ghost is in exactly one mode. Cluster key press → HUMAN immediately. No key press on its cluster for 2.0 s of gameplay time → AUTO. Mode changes never interrupt movement and never cost score. The mode of every ghost is always visible on the sprite outline and HUD. Coordination bonus: when 2 or more HUMAN-mode active ghosts exist simultaneously, each receives a +15% speed bonus. This rewards multi-ghost coordination and team play without making single-ghost play easier — the bonus does not activate for solo 1-ghost control.

SR-3 · Personality roster (canonical)

PersonalityBehavior signatureCounter-play for huntersTier pool
GluttonHigh dot greed, short flee radius — takes dots even with ghosts nearbyPunish greed: collapse on his feeding laneAll tiers
SkittishLarge flee radius, high threat weight, extra caution vs HUMAN ghostsHerd him: drive him toward a waiting ghostAll tiers
Pellet HunterLunges for power pellets whenever a ghost is near; hunts aggressively during empowermentGuard pellet corners; retreat on empowermentIntermediate+
Tunnel RatPrefers corridors dense with dots; commits to eating through a laneCut off his lane exits ahead of himIntermediate+
TricksterBaits: approaches a committed chaser (4–6 tiles), then doubles back the moment separation strictly grows; occasionally jukes to a near-equal routeHold intersections; don't over-commitExpert only

One personality is drawn uniformly from the tier's pool at READY and stays fixed for the whole round. Name, hint line, and trail tint are shown at reveal; tint persists during play.

SR-4 · Difficulty tiers (canonical)

TierPac-Man speedCornering boostEmpowermentPersonality pool
Beginner85% of ghost speed×1.084 sGlutton, Skittish
Intermediate95%×1.125 s+ Pellet Hunter, Tunnel Rat
Expert100%×1.226 sAll five

Decision logic (FR-05) is identical on every tier — tiers alter only the opponent's physical parameters, never ghost speed, maze, or pellet count.

SR-5 · Pause and focus

Esc toggles PAUSED; gameplay time (including the SR-2 idle timer) freezes. Window blur or tab hidden forces PAUSED. PAUSED dims the maze and shows controls; no game state is lost.

7. Exceptions and Boundaries

CaseBehavior
Small viewport / mobile portraitPlayfield scales proportionally; below a usable minimum, show "rotate or enlarge your window" notice (touch is P1, so phones are not P0 targets)
Keyboard without numpadPokey's alternate cluster TFGH always active
Hardware key ghosting in 3–4 player co-opNot detectable; mitigated by tap-based input and matrix-distant cluster placement (FR-03)
Autoplay-blocked audioAudio engine initializes on first user gesture; game is fully playable silent
localStorage blockedSession-only best scores, no error surfaced (FR-08)
Mid-round cluster conflict (two friends fight over one ghost)Most recent press wins; no lockout — physical negotiation is part of couch co-op

8. Open Questions

9. Testing and Difficulty Validation

9.1 Deterministic test suite (bug detection)

A dedicated test suite lives at tests/ghost-squad/ with 40 tests across 9 files. The harness loads the real index.html in-memory with stubbed browser APIs (DOM, canvas, audio) and drives the game loop frame-by-frame with deterministic entity placement. The game file is never modified.

FileTestsCovers
01-ai-movement.test.js7Pincer trap escape, U-turns for dots behind (near & far), 1-dot endgame routing (all-personality sweep), calm dithering, turn-into-dots overshoot
02-state-machine.test.js6Boot→attract→ready→play, catch→respawn, 3 catches = ghosts win, all dots cleared = end, Enter restarts / Esc → tier
03-combat-empowerment.test.js5Empowerment flip, eating ghosts, re-emergence in AUTO, normal contact costs a life, empowerment expiry
04-input-claim-idle.test.js4WASD/arrow cluster claim, per-ghost independence, idle→AUTO fallback, queued direction applied
05-tunnel-waves.test.js4Side-tunnel wrap for Pac-Man and ghosts, ~0.55× tunnel slowdown, scatter/chase wave alternation
06-empowerment-hunt.test.js4Hunting frightened ghosts, pellet weaponization, guarded-pellet safety, resume clearing after eating all four
07-ghost-house.test.js3Eyes return path, house release timers, ~3 s out-of-play minimum after being eaten
08-misc-soak.test.js4Pause/resume immutability, 4-player simultaneous claims, 400/800/1200 catch scoring, 5-sim-minute Expert soak with per-frame invariants
09-difficulty-sim.test.js3Full-game baseline simulation: all-AUTO ghosts × 3 runs per tier, tracks win rate, catch count, dot-clear %, timing

Conventions: every AI movement test corresponds to a bug observed and fixed during development. Scenario tests pin one personality via G().setPersonality(name) to eliminate RNG-draw flakiness; behavior-sweep tests iterate all five personalities explicitly. Ghost control uses mode:'human' with no queued input so ghosts march deterministically.

9.2 Lower-bound test (Pac-Man strength verification)

Purpose: verify that the AI Pac-Man is strong enough that all-AUTO ghosts (no human input) cannot trivially beat him. If AUTO ghosts win easily, the human player has no reason to participate — the game plays itself.

Method: run a full round with all 4 ghosts on AUTO (no keyboard input) for 5 runs per tier. Track catch count, dot-clear percentage, and outcome.

TierAll-AUTO win rateTypical catchesPac-Man clear %Verdict
Beginner100% (5/5)357–89%Ghosts too strong without human — acceptable on easiest tier
Intermediate60% (3/5)1–370–100%Balanced — human input matters
Expert0% (0/5)1–2100%Pac-Man dominant — human required, as designed

Expert at 0% all-AUTO win rate is intentional: it confirms the AI Pac-Man is strong enough that a human player is strictly necessary to win on the hardest tier. The lower bound validates Pac-Man's decision quality, not difficulty tuning.

9.3 Upper-bound test (human playability verification)

Purpose: verify that a human player controlling 1 ghost can realistically beat the AI Pac-Man. Record all moves, measure APM, and evaluate whether a real human — especially a new player — could repeat the performance.

Method: simulate a human player claiming Shadow (ghost 0, WASD). Every 300 ms (average human) or 200 ms (skilled), re-evaluate direction via BFS pathfind toward Pac-Man's predicted position (3 tiles ahead in current heading). Other 3 ghosts stay on AUTO. Record every keypress and outcome. 5 runs per tier to account for personality variance.

Tier300 ms reaction (avg human)200 ms (skilled)APM requiredReclaims
Beginner5/5 (100%)5/5 (100%)~114/min (1.9 keys/s)0
Intermediate3/5 (60%)4/5 (80%)~114–150/min0
Expert1/5 (20%)1/5 (20%)~120–144/min0

Key findings (single-ghost):

9.4 Upper-bound: multi-ghost challenge curve

Purpose: verify that controlling more ghosts rewards skill — the win rate should increase (or at least not decrease) when players add ghost control, for both team play (N humans) and solo multi-ghost (1 human cycling through N ghosts).

Method: each controlled ghost uses a role-specific BFS interception target: ghost 0 chases Pac-Man's current tile, ghost 1 cuts off 4 tiles ahead, ghost 2 traps from 4 tiles behind, ghost 3 guards the nearest pellet. Decisions every 300 ms. 5 runs per configuration to account for personality variance.

Team play (N humans, 300 ms reaction each)
Tier1 ghost2 ghosts3 ghosts4 ghosts
Beginner100%100%80%100%
Intermediate60%60%40%80%
Expert20%0%20%20%
Solo multi-ghost (1 human cycling N ghosts)
Tier2 ghosts3 ghosts4 ghosts
Beginner100%80%100%
Intermediate0%60%40%
Expert0%0%0%

Key findings:

Conclusion: The baseline curve had Expert flat at 10–20% (multi-ghost skill not rewarded). A comprehensive sweep of 11 configurations × 10 runs × 3 tiers × 4 ghost counts (1,320 simulated games) tested every option individually and in combination. None of the flat speed bonuses produced the desired wide range — they all pushed 1-ghost Expert too high (50–60%) while keeping 4-ghost at the same level, resulting in a narrow 50–70% range.

The solution is a coordination bonus: when 2+ HUMAN-mode active ghosts exist simultaneously, each receives +15% speed. This is the only mechanism that creates a wide Expert range without making 1-ghost too easy, because the bonus does not activate for solo 1-ghost control. Combined with IDLE_S increased from 1.5 to 2.0 s (for solo multi-ghost viability), the final configuration is:

Team play — final verified curve (20 runs)
Tier1 ghost2 ghosts3 ghosts4 ghosts
Beginner100%100%100%100%
Intermediate80%85%55%80%
Expert25%40%35%55%

Beginner is perfectly flat at 100%. Intermediate ranges 55–90% — viable for any team size. Expert ranges 25–55% — a significant improvement over the baseline 10–20% flat curve. The 1-ghost rate (25%) is close to the design target of ~20%, and the 4-ghost rate (55%) rewards team coordination. The 3-ghost dip (35%) is a known limitation of the BFS simulation — real human teams would coordinate better with 3 players. The coordination bonus is the key innovation: it rewards multi-ghost skill without inflating 1-ghost difficulty.

Tuning methodology: all individual options and combinations were tested with 10–20 runs per configuration per tier per ghost-count (1,320+ simulated games total across 11 configs, plus 20-run verification of the final config). The coordination bonus was tested at +10%, +15%, and +18% — +15% produced the smoothest curve. See tests/ghost-squad/curve_sweep.js, tests/ghost-squad/expert_tune.js, tests/ghost-squad/expert_tune2.js, tests/ghost-squad/expert_tune3.js, tests/ghost-squad/expert_tune4.js, and tests/ghost-squad/verify_curve2.js for the full sweep scripts and tests/ghost-squad/README.md for documentation.

10. Internationalization

Engine. All user-visible text is served by the shared, offline i18n engine public/shared/i18n.js plus a per-page dictionary. Ghost Squad is registered as page id ghost and its translations live in public/shared/lang/ghost.js (namespace window.RG_I18N_DICT.ghost). English is stored in the dictionary like any other language (the en block) and doubles as the default: when the active language has no entry for a key, the en entry is served. The markup's own text and the T(key, EnglishDefault) second argument remain as last-resort fallbacks.

AspectDefinition
Languages8: en, zh, es, de, fr, ru, ja, ko
Detection orderlocalStorage 'rg.lang' → browser language (navigator.languages / navigator.language; exact id, then 2-letter prefix) → en
Static markup patterndata-i18n="ghost.<key>" on an element holding the pre-init English text; RG_I18N.init('ghost') swaps in the translation for the active language — English included, from the dictionary — and captures the original once as the last-resort fallback; covers the document <title> as well (key doc_title)
Dynamic text patternT = window.RG_I18N ? function(k,d){ return RG_I18N.t('ghost',k,d); } : function(k,d){ return d!=null?d:k; }, always called as T('ghost.<key>', 'English default') — used for the canvas HUD, tier cards, the attract best table, the personality banner, and the end overlay
Re-render on language changeJS-built DOM registers RG_I18N.onChange(...) which re-renders the attract best table, the tier cards, the "TONIGHT'S OPPONENT" banner (while visible) and the end overlay (while visible); the engine re-applies every data-i18n element itself
SwitcherThe engine injects a fixed top-right <select> language switcher; the choice persists in localStorage 'rg.lang'

The test harness is unaffected. The deterministic suite in §9.1 loads only the inline <script> block with a stubbed DOM, so window.RG_I18N is undefined there. The guarded boot if(window.RG_I18N) RG_I18N.init('ghost') is skipped and T() returns its English default, so all 40 tests keep passing and the game logic, tuning constants, RNG, boot sequence, and canvas drawing math are untouched.