{"id":51695877,"url":"https://github.com/danielmackay/pacman","last_synced_at":"2026-07-16T05:05:15.688Z","repository":{"id":342944776,"uuid":"1175720220","full_name":"danielmackay/pacman","owner":"danielmackay","description":null,"archived":false,"fork":false,"pushed_at":"2026-03-08T04:29:44.000Z","size":164,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-08T09:48:37.706Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://pacman-navy-xi.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danielmackay.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-08T04:25:33.000Z","updated_at":"2026-03-08T04:31:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/danielmackay/pacman","commit_stats":null,"previous_names":["danielmackay/pacman"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/danielmackay/pacman","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielmackay%2Fpacman","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielmackay%2Fpacman/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielmackay%2Fpacman/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielmackay%2Fpacman/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danielmackay","download_url":"https://codeload.github.com/danielmackay/pacman/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielmackay%2Fpacman/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35531189,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-16T02:00:06.687Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-16T05:05:15.082Z","updated_at":"2026-07-16T05:05:15.679Z","avatar_url":"https://github.com/danielmackay.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pac-Man\n\nA modern browser-based Pac-Man clone built with React, TypeScript, and the Web Audio API. Runs at 60fps with canvas rendering, synthesized audio (no audio files), and three unique maze layouts.\n\n![Gameplay](public/screenshot-gameplay.png)\n\n![Menu](public/screenshot-menu.png)\n\n## Features\n\n- Classic Pac-Man gameplay with faithful ghost AI (Blinky, Pinky, Inky, Clyde)\n- Three maze layouts that cycle as levels progress\n- Three modern power-ups beyond the classic energizer:\n  - **Speed** (cyan) — 2× Pac-Man speed for 5 seconds\n  - **Freeze** (silver) — ghosts stop moving for 3 seconds\n  - **Magnet** (gold) — pulls nearby ghosts and auto-eats on contact for 4 seconds\n- Synthesized audio via Web Audio API — no audio asset files\n- Particle effects on dot/ghost/power-up interactions\n- Leaderboard with high score tracking\n\n## Tech Stack\n\n- **React 18** — UI overlays and menus only (not the game loop)\n- **TypeScript** (strict mode)\n- **Zustand** — low-frequency game state (score, lives, phase)\n- **Canvas 2D** — all game rendering at 60fps\n- **Vite 5** + **Bun**\n\n## Getting Started\n\n```bash\nbun install\nbun run dev       # http://localhost:5173\n```\n\nOther commands:\n\n```bash\nbun run build     # type-check + production build\nbun run preview   # preview production build\nbunx tsc --noEmit # type-check only\n```\n\n## Controls\n\n| Key | Action |\n|-----|--------|\n| Arrow keys / WASD | Move Pac-Man |\n| P / Escape | Pause |\n| Enter | Start / confirm |\n\n## Architecture\n\nThe game uses a strict boundary between the game engine and React:\n\n- **`gameRef`** — a plain mutable JS object (`pacman`, `ghosts`, `particles`, `tileState`, etc.) mutated every frame by the RAF loop. React never sees this object.\n- **Zustand store** — holds only low-frequency state: `phase`, `score`, `lives`, `level`, `leaderboard`. Updated only on meaningful events (dot eaten, death, level complete).\n- **Canvas** — sized to 448×496px (28×31 tiles at 16px each). Never touched by React.\n\n### Ghost AI\n\nGhost movement is tile-crossing based. Each ghost moves freely until crossing into a new tile, at which point it snaps to the tile center and picks the next direction using minimum Manhattan distance to its target (no 180° reversals). Each ghost has a classic targeting strategy:\n\n- **Blinky** — directly chases Pac-Man\n- **Pinky** — targets 4 tiles ahead of Pac-Man\n- **Inky** — Blinky-relative double vector\n- **Clyde** — chases when far, scatters when close\n\n### Maze Format\n\nMazes are flat `TileType[]` arrays (28 cols × 31 rows, row-major). A separate `Uint8Array tileState` (same length) tracks which eatables remain (1 = present, 0 = eaten). The layout array never mutates during play.\n\n## Project Structure\n\n```\nsrc/\n├── types/           # game.ts, entities.ts, maze.ts\n├── constants/       # game.ts, ghosts.ts, difficulty.ts\n├── mazes/           # maze1 (Classic), maze2 (Open Arena), maze3 (Labyrinth)\n├── store/           # gameStore.ts (Zustand)\n├── engine/\n│   ├── ai/          # blinky/pinky/inky/clyde + dispatcher\n│   ├── gameLoop.ts  # master RAF loop\n│   ├── collision.ts # tile helpers, tileToPixel, manhattanDistance\n│   ├── movement.ts  # Pac-Man movement\n│   ├── modeTimer.ts # chase/scatter/frightened cycle\n│   ├── powerups.ts  # 3 modern power-ups\n│   └── scoring.ts   # points, combos\n├── rendering/       # drawMaze, drawPacman, drawGhosts, drawPellets, drawParticles\n├── particles/       # pool (512 slots), effects presets\n├── audio/           # audioContext, synthesizer, sounds facade\n├── hooks/           # useGameCanvas, useInputHandler, useGameLoop\n└── components/      # GameCanvas, HUD, screens (Menu/Pause/LevelComplete/GameOver)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielmackay%2Fpacman","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielmackay%2Fpacman","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielmackay%2Fpacman/lists"}