A fully static, retro-style Pac-Man browser game with responsive canvas rendering and mobile-friendly controls.
- Overview
- Core Features
- Tech Stack
- Architecture
- Quick Start
- Configuration
- Scripts
- Contributor Testing Guide
- Deployment
- Website Health Check
- Security/Quality Notes
- Roadmap
This repository contains a classic Pac-Man style game implemented with plain HTML, CSS, and JavaScript.
- No build system or backend is required.
- The game runs entirely in the browser via a
<canvas>. - Gameplay includes arcade-style ghost personalities, Cruise Elroy phases, per-level scatter/chase parity tables, challenge modes, replay playback, and cutscene transitions.
- Desktop and mobile input are both supported (keyboard rebinding, touch buttons, virtual stick, and gamepad support).
- Classic maze layout (
44 x 31tiles) with walls, pellets, power pellets, and side-wrap tunnels. - Responsive canvas scaling with device-pixel-ratio support for crisp rendering.
- Pac-Man movement with wall collision checks and tunnel wrap logic.
- Arcade-accurate ghost behavior with per-ghost targeting logic:
- Blinky (direct chase), Pinky (ambush ahead), Inky (vector-based), Clyde (distance-based scatter/chase).
- Scatter/chase cycle schedule with frightened overrides and ghost-house release rules.
- Level progression with per-level speed/difficulty tuning, fruit table scoring, and bonus-life milestones.
- Full round-state flow: start screen, ready phase, death phase, intermission, and game-over state.
- Attract mode: automatic demo playback starts after start-screen idle timeout.
- Classic-style level cutscenes with Start-key skip support.
- HUD upgrades: level indicator, ghost mode indicator, fruit label, ghost-eat point popups, and overlay improvements.
- Configurable settings panel with:
- Volume control, mute, key rebinding, challenge mode select, and mobile input mode selection.
- Accessibility controls: color-blind/high-contrast palette, reduced motion, and large HUD text.
- Assistive updates via a lightweight live region for phase/score/life announcements.
- Settings import/export JSON for moving control/accessibility presets across devices.
- Optional ghost debug overlay showing target tile and path intent.
- Persistent settings via
localStorage.
- Replay system:
- Deterministic run seed + per-frame action capture.
- Replay button to rerun the last completed attempt.
- Versioned replay schema with migration support for older payloads.
- Export/import replay JSON plus shareable URL hash links.
- Deterministic simulation debugger:
- Seed inspector with apply/copy controls.
- Pause/step frame controls for deterministic debugging.
- Challenge modes:
- Classic, Time Attack, No Power Pellets, and One Life.
- Daily challenge mode with date-based seed, local history, and streak tracking.
- Local leaderboard by mode+seed with best score and best run time.
- Expanded input support:
- Keyboard, touch buttons, swipe, virtual stick, and gamepad.
- Remappable gamepad action buttons and one-handed accessibility mode.
- Mobile UX upgrades:
- Adaptive control sizing, orientation-aware layout tuning, and optional haptic feedback.
- Runtime/performance updates:
requestAnimationFramegame loop targeting smooth 60 FPS.- Cached wall tiles and reduced per-frame overhead in hot paths.
- Frame-pacing guardrails with stutter detection and analytics hooks.
- Frame-time budget regression coverage in Playwright (
tests/e2e/performance.spec.js). - Optional Lighthouse baseline budget checks for the landing shell.
- Audio polish:
- Per-channel mixer controls (master/SFX/music), looped synth bed, and SFX-driven ducking.
- PWA support:
- Installable app via
manifest.webmanifest. - Offline caching with versioned static/runtime caches.
- In-app update-ready prompt wired to
skipWaiting.
- Installable app via
- CI/release upgrades:
- Unit + e2e test workflows.
- Optional visual snapshot Playwright specs.
- Visual regression lane + flaky-test quarantine workflow.
- Deployable site artifact workflow.
- Stable-tag (
v*) static deployment workflow for GitHub Pages. - Manual release tagging with semantic-version validation, alpha/stable channels, categorized changelog, and rollback guide.
- HTML5
- CSS3
- Vanilla JavaScript (ES6+)
- HTML5 Canvas API
- Static asset deployment (GitHub Pages-compatible)
index.html: Page shell, canvas, sprite assets, and script loading.css/style.css: Retro UI styling, responsive layout, and touch-control presentation.scripts/game.js: Global game state, level progression, ghost AI orchestration, round phases, controls, settings, audio, PWA hooks, and rendering loop.scripts/gameplay-utils.js: Shared gameplay helpers (AI targeting math, collision helpers, level tuning, scoring, and state utilities).scripts/game-storage.js: Local persistence helpers for settings, high score, daily state, and leaderboard state.scripts/replay-tools.js: Replay serialization/parsing codec utilities.scripts/perf-guardrails.js: Frame-time analysis and runtime pacing monitor helpers.scripts/pacman.js:Pacmanclass (movement, collision, direction change, pellet consumption, draw logic).scripts/ghost.js:Ghostclass (personality-driven target selection, house-release lifecycle, chase/scatter/frightened/eaten states, movement, draw logic).scripts/lint.js: Built-in lint checks (syntax + structural gameplay checks).tests/*.test.js: Node-based unit/regression tests for gameplay utilities and structure.tests/e2e/*.spec.js: Playwright browser regression tests.playwright.config.js: Playwright config with local static web server..github/workflows/ci.yml: Lint + unit tests on push/PR..github/workflows/quality-checks.yml: Lint/unit/e2e checks + upload site artifact..github/workflows/release.yml: Manual tag + changelog + GitHub release workflow..github/workflows/deploy-stable-site.yml: Automatic static deployment for stable release tags.lighthouse-budget.json: Optional landing-shell Lighthouse budget baseline.scripts/lighthouse-baseline.js: Optional local Lighthouse runner (LIGHTHOUSE_RUN=1) with optional external-server mode (LIGHTHOUSE_SKIP_SERVER=1).
game.jsinitializes map state, actors, level tuning, replay seed, and UI handlers.- Each animation frame advances a fixed-step simulation (
update) then renders (draw). updateruns input (keyboard/touch/gamepad/replay), phase transitions, challenge timers, AI mode updates, collisions, and scoring.drawrenders map layers, entities, HUD, popups, cutscenes, and overlays.
flowchart LR
A["Input Sources (Keyboard/Touch/Gamepad/Replay)"] --> B["update() Fixed Step"]
B --> C["Phase State Machine"]
C --> D["Gameplay Systems (AI, Collisions, Fruit, Scoring)"]
D --> E["Replay Recorder + Challenge Rules"]
E --> F["draw()"]
F --> G["Canvas + HUD + Overlays"]
- Clone this repository.
- Open
index.htmlin a modern browser.
git clone https://github.com/KamranBoroomand/PacMan.git
cd PacMan
python3 -m http.server 8080Then open http://localhost:8080.
npm ci
npx playwright install chromium firefox webkitUse lockfile-driven installs (npm ci) for deterministic environments. If dependencies change, regenerate and commit package-lock.json.
Primary gameplay/config constants live in scripts/game.js.
| Constant | Default | Purpose |
|---|---|---|
fps |
60 |
Main game loop update/render frequency (fixed-step updates via requestAnimationFrame). |
oneBlockSize |
20 |
Tile size used by movement, collision, and rendering. |
lives |
3 |
Starting lives per run. |
ROUND_READY_MS |
1800 |
“Ready!” phase duration before active movement. |
INTERMISSION_MS |
1500 |
Stage-clear intermission duration. |
BONUS_LIFE_STEP |
10000 |
Score interval for bonus lives (1UP). |
GHOST_MODE_SCHEDULE |
Classic schedule | Scatter/chase timing cycle for ghost AI. |
FRUIT_TABLE |
8 classic fruits | Per-level fruit score table. |
MIN_FRUIT_SPAWN_DISTANCE |
8 |
Minimum tile distance between Pac-Man and spawned fruit. |
MIN_GHOST_INITIAL_SPAWN_DISTANCE |
7 |
Minimum initial ghost spawn distance from Pac-Man. |
SWIPE_THRESHOLD_PX |
24 |
Minimum swipe distance to trigger mobile direction change. |
SETTINGS_STORAGE_KEY |
pacman.settings.v1 |
Local persistence key for settings. |
HIGH_SCORE_STORAGE_KEY |
pacman.highScore |
Local persistence key for high score. |
Quality scripts are available through npm:
npm run lint
npm test
npm run test:e2e
npm run test:e2e:chromium
npm run test:e2e:mobile
npm run test:e2e:perf
npm run test:e2e:visual
npm run test:lighthouse
npm run check
npm run check:all
PLAYWRIGHT_VISUAL=1 npm run test:e2e
LIGHTHOUSE_RUN=1 npm run test:lighthouse
LIGHTHOUSE_RUN=1 LIGHTHOUSE_SKIP_SERVER=1 npm run test:lighthousenpm run lint: Syntax + structural lint checks (scripts/lint.js).npm test/npm run test:unit: Unit/regression tests (tests/*.test.js) using Node's built-in test runner.npm run test:e2e: Browser end-to-end tests with Playwright (tests/e2e/*.spec.js).npm run test:e2e:chromium: Desktop Chromium-only e2e lane.npm run test:e2e:mobile: Mobile Chromium viewport/profile e2e lane.npm run test:e2e:perf: Frame-time budget regression lane (Chromium desktop profile).npm run test:e2e:visual: Runs Playwright withPLAYWRIGHT_VISUAL=1for snapshot checks.npm run test:lighthouse: Optional Lighthouse baseline runner (setLIGHTHOUSE_RUN=1; starts a local static server unlessLIGHTHOUSE_SKIP_SERVER=1is set).PLAYWRIGHT_VISUAL=1 npm run test:e2e: Enables visual snapshot assertions intests/e2e/visual.spec.js.npm run check: Runs lint + unit tests.npm run check:all: Runs lint + unit + e2e tests.
- Run fast checks before every commit:
npm run check
- Run browser regression checks before opening a PR:
npm run test:e2e
- Run visual snapshot checks when UI/animation/HUD changes:
PLAYWRIGHT_VISUAL=1 npm run test:e2e
- If visual tests fail after intentional UI change, update snapshots with:
PLAYWRIGHT_VISUAL=1 npx playwright test --update-snapshots - Validate release readiness locally:
npm run check
- Optional landing-shell baseline (if Lighthouse tooling/network is available):
If you already have a server running on
LIGHTHOUSE_RUN=1 npm run test:lighthouse
LIGHTHOUSE_PORT(default4173), reuse it with:LIGHTHOUSE_RUN=1 LIGHTHOUSE_SKIP_SERVER=1 npm run test:lighthouse
This project is static and can be deployed to any static host.
Current production domain is configured via CNAME:
pacman.kamranboroomand.ir
Typical GitHub Pages flow:
- Push repository changes to the branch configured for Pages.
- Ensure root files (
index.html,css/,scripts/,images/) are published. - Keep
CNAMEin the deployed root to retain custom-domain routing.
Stable release tags (v*) now trigger .github/workflows/deploy-stable-site.yml, which runs checks, bundles static assets, and deploys to GitHub Pages automatically.
Last checked: February 28, 2026.
package-lock.jsonremains the source of truth for deterministicnpm ciinstalls in CI.npm run checkpassed (lint + 46 unit/regression/static checks).npm run test:e2epassed across desktop Chromium/Firefox/WebKit and mobile Chromium profiles (visual snapshot specs remain opt-in viaPLAYWRIGHT_VISUAL=1).LIGHTHOUSE_RUN=1 npm run test:lighthousenow fails fast with actionable startup errors when the local static server cannot bind/start.
- No backend is used; gameplay runs fully on the client.
- No authentication or user data processing is present in this codebase.
- Client-side score/state can be modified by end users (expected for arcade-style browser games).
- High scores are stored locally in the browser via
localStorage(pacman.highScore). - User settings are stored locally in the browser via
localStorage(pacman.settings.v1). - App can be installed and played offline using service-worker caching.
- Tooling uses Node.js plus Playwright for browser regression testing.
- License: MIT (
LICENSE).
The active roadmap is maintained in ROADMAP.md.
Snapshot:
- Core gameplay, replay, challenge modes, PWA support, and CI/release automation are in place.
- Next priorities focus on maintainability, broader e2e/browser coverage, and deployment hardening.
