DIY Arcade Machine
June 26, 2026 · View on GitHub
A complete mini arcade system that runs on hardware, desktop, and in the browser: play a collection of classic-inspired games on a 64×64 RGB LED matrix (HUB75 + MicroPython), on your computer with a PyGame emulator, or directly in the browser via WebAssembly (pygbag).
Features
- Triple Runtime Support
- MicroPython + HUB75 LED Matrix: Runs on RP2040-based boards (Interstate 75)
- Desktop (CPython) + PyGame: Full emulator for development and testing
- Browser (WebAssembly) + pygbag: Play directly in any modern browser, no install needed
- 40+ Built-in Games: Classics, puzzle games, racers, shooters, reflex challenges, and compact original arcade games built for the 64×64 matrix
- Intro Screen: Animated logo display on startup
- 64×64 Display Layout
- 58-pixel playfield (rows 0-57)
- 6-pixel HUD at bottom (score + clock)
- High Score System: Persistent scores with 3-letter initials entry
- Memory-Optimized: Buffered framebuffer, packed grid storage, lazy font loading
- Controller Support
- MicroPython: Wii Nunchuk-style I2C controller (with auto-detection for variants)
- Desktop: Keyboard emulation (arrow keys + Z/X)
Table of Contents
- Quick Start
- Web build (Pygbag)
- Hardware Requirements
- Software Requirements
- Installation
- Make Commands
- Game List
- Controls
- Usage
- Architecture
- Troubleshooting
Quick Start
Run on desktop
pip install pygame-ce # or: make install
python main.py # or: make run
Test in browser locally
pip install pygame-ce pygbag==0.9.2 # or: make web-install
python -m pygbag . # build + serve at http://localhost:8000
# Safari: make web-safari (adds required COOP+COEP headers)
Deploy to GitHub Pages
Push to main — the GitHub Actions workflow builds the
WebAssembly bundle with python -m pygbag --build . (Python 3.11) and deploys it to GitHub Pages automatically.
Web build (Pygbag)
Local preview (build + serve at http://localhost:8000):
pip install pygame-ce pygbag==0.9.2
python -m pygbag .
CI / offline bundle (writes to build/web/):
python -m pygbag --build .
GitHub Pages: in your repo go to Settings → Pages → Source and select GitHub Actions. Every push to main triggers the workflow which builds and deploys automatically.
Hardware Requirements
For Physical Arcade Machine
- Interstate 75 (W) by Pimoroni (PIM584) - RP2040-based HUB75 driver board
- 64×64 Pixel RGB LED Matrix with HUB75 connector
- Controller (one of):
- Wii Nunchuk + Breakout Adapter
- Compatible I2C joystick module
- Power Supply: 5V adequate for LED matrix (typically 2-4A)
- Optional:
Software Requirements
MicroPython Hardware
- MicroPython Firmware (Pimoroni build recommended)
- Optional: Thonny IDE for uploading files
- Optional:
mpy-crossfor compiling to bytecode (reduces boot RAM usage)
Desktop
- Python 3.7+
- pygame-ce 2.x (Community Edition — drop-in replacement for pygame)
Installation
Desktop Setup
-
Install dependencies:
pip install pygame-ce -
Run the game:
make run # or manually: python main.py
A 640×640 window will appear showing the emulated LED matrix (10× scale).
Browser Setup (pygbag)
pygbag packages the game as WebAssembly so it runs in any modern browser — no Python installation needed.
-
Install dependencies:
pip install pygame-ce pygbag==0.9.2 # or via make: make web-install -
Build and serve locally:
python -m pygbag . # build + serve at http://localhost:8000 make web # same, via Makefile (Chrome / Firefox) make web-safari # Safari (adds required COOP+COEP headers) make web-ios # iPhone/iPad fullscreen-oriented variant make web-ios-safari # iOS/Safari variant with COOP+COEP headers -
Controls in browser: same keyboard mapping as desktop — Arrow Keys,
Z/Spaceto confirm,X/Escapeto cancel. On touch devices the browser build exposes an on-screen D-pad plusA/Baction buttons; tapping the game canvas triggers the primary action, and swiping the canvas sends directional taps.
Browser support: Chrome and Firefox work out of the box. Safari requires
Cross-Origin-Isolationheaders (make web-safarihandles this automatically).iOS fullscreen: the iOS build keeps the game logic at the original 64×64 matrix resolution and scales the canvas fullscreen with safe-area-aware touch controls. This avoids rewriting every game for a new coordinate system while still filling the phone or tablet screen. On GitHub Pages it is published under
/ios/; locally usemake web-ios-safarifor the closest Safari/iOS behavior.Automated deployment: every push to
maintriggers the GitHub Actions workflow which builds the regular WebAssembly bundle plus the/ios/variant and deploys both to GitHub Pages automatically.Note: High scores are stored in-memory while the page is open and reset on page reload.
MicroPython Setup
Quick Method (Recommended)
The project now uses a tiny bootstrap approach to avoid on-device compilation memory errors:
-
Install
mpy-cross(optional but highly recommended):brew install micropython # macOS # or: pip install mpy-cross -
Connect your Interstate 75 via USB
-
Upload with Make:
make upload # or manually: ./upload.shThe script will:
- Auto-detect connected devices
- Compile
arcade_app.py→arcade_app.mpy(ifmpy-crossavailable) - Upload both
main.py(tiny bootstrap) and the compiled module
-
Reboot the device - games start automatically
Manual Method
If you prefer manual upload via Thonny or ampy:
- Flash MicroPython firmware to Interstate 75
- Upload
main.py(tiny bootstrap file) - Upload
arcade_app.pyorarcade_app.mpy(the main application) - Optional: Upload
highscores.jsonif you want to preserve scores
Make Commands
For ease of use, a Makefile is provided with the following commands:
make install: Installs desktop dependencies (PyGame)make run: Runs the PyGame emulator locally (python main.py)make web-install: Installs pygbag for browser/WebAssembly buildsmake web-build: Builds the regular browser version intobuild/web/make web-ios-build: Builds the fullscreen-oriented iOS version intobuild/ios/make web-pages-build: Builds the Pages artifact with the regular version at/and the iOS version at/ios/make web: Builds the WebAssembly version and serves it athttp://localhost:8000make web-ios: Builds and serves the iOS fullscreen-oriented version athttp://localhost:8000make web-ios-safari: Serves the iOS build with COOP+COEP headers for Safarimake upload: Compiles and uploads the code to the hardware (./upload.sh)make build: Precompilesarcade_app.pyinto bytecode (arcade_app.mpy)make clean: Cleans up previous build artifacts and pycachemake clean-all: Cleans up all files and the python virtual environment
Game List
The arcade includes demo animations and over 30 games. Each game is documented in detail in the Game Documentation with gameplay notes and technical descriptions.
Detailed per-game documentation is available in docs/games.
| Game ID | Name | Description |
|---|---|---|
DEMOS | Demo Showcase | Zero-player demos: Snake, Life, Cube, Spark, Plasma, Orbit, Warp, Bounce, Tunnel, Matrix, Fire, Spring, Cradle |
2048 | 2048 | Sliding tile puzzle with merge scoring |
AIRHKY | Air Hockey | Fast puck-and-mallet game with CPU or 2-player support |
ARENA | Arena | Top-down wave survival with movement and shooting |
ARTILL | Artillery Simulator | Turn-based angle-and-power shell duel with wind and deforming terrain |
ASTRD | Asteroids | Rotate, thrust, shoot asteroids in space |
BEJWL | Bejeweled | Match-3 gem swapping puzzle |
BILLI | Billiards | Pool/Snooker-style table game with cue aim, pockets, rails, and ball collisions |
BOMBER | Bomber | Timed bombs, block clearing, and maze enemies |
BRKOUT | Breakout | Brick breaker with rainbow bricks and optional powerups |
BTLZON | Battlezone | Atari-style vector tank combat with radar, rocks, projectile shots, and waves |
CATCH | Catch | Catch stars, avoid bombs, and keep the basket moving |
CAVEFL | Cave Flyer | Tunnel navigation (starts wide, narrows progressively) |
CENTI | Centipede | Atari-style segmented shooter with mushrooms and waves |
CGOLG | Conway's Game of Life Game | Competitive Life battle with directed gliders and spaceships |
CITY | City Chase | Top-down city driving with jobs, traffic, police heat, and drop-offs |
CLIMB | Climber | Platform-jumping tower climb with scrolling height |
DEFUSE | Defuse | Cut colored wires in sequence before the timer expires |
DODGE | Dodge | Avoid falling blocks, dash to dodge |
DOOMLT | Doom Lite | Mini raycaster FPS with rotating levels and enemy sprites; also powers the WINMAZE demo renderer |
FLAPPY | Flappy Bird | Navigate through moving pipe gaps |
FROGGR | Frogger | Hop across traffic lanes and advance through harder levels |
GOLF | Golf | Tiny minigolf courses with aim, power, bounces, and obstacles |
INVADR | Invaders | Shoot marching alien waves, protect shields, hit saucers |
KEEN | Keen | Platformer with jumps, gems, keys, enemies, and exit doors |
KERBAL | Kerbal Arcade | Launch, circularize, and optionally return in a tiny orbital flight sim |
LANDER | Lunar Lander | Multi-level landing challenge plus optional scrolling v2 route mode with fuel powerups |
LASER | Laser | Mirror-rotation puzzle: guide the beam into the target |
LOCO | LocoMotion | Rotating railway puzzle with train routing |
MAZE | Maze Explorer | Fog-of-war maze with gems, enemies, shooting |
MINES | Mines | Minesweeper-style reveal puzzle for the LED matrix |
PACMAN | Pac-Man | Collect pellets, avoid ghosts, power pellets |
PAIRS | Pairs | Memory card matching on a 4x4 board |
PINBAL | Pinball | Plunger launch, flippers, bumpers, targets, and multipliers |
PITFAL | Pitfall Runner | Endless runner with snakes, pits, treasures (safe start zone) |
PONG | Pong | Paddle vs. CPU or optional 2-player paddle duel |
QIX | Qix | Territory capture, avoid the enemy |
RACING | Top-Down Racing | Overhead circuit racer with curved road, boost, laps, and traffic |
RAYRCR | Ray Racer | Raytrace-style anti-grav racing with boost, energy gates, and rival hovercars |
REVRS | Othello/Reversi | Board game with simple CPU opponent |
RTYPE | R-Type Shooter | Side-scrolling endless shooter |
SABOTR | Saboteur Stealth | Sneak through multiple patrol maps and reach the objective |
SIMON | Simon Says | Memory sequence game with colored quadrants |
SKYWAR | Sky War | Helicopter battlefield shooter with air and ground targets |
SNAKE | Snake | Classic snake with red/green targets, wraparound |
SOCCER | Championship Soccer | Atari-style soccer with direction-based passes and shots |
SOKO | Sokoban | Multi-level crate-pushing puzzle campaign |
STACK | Stacker | Timing game: trim and stack moving blocks |
TETRIS | Tetris | Falling blocks with line clearing |
TRON | Tron Lightcycle | Leave a trail, steer 90° turns, dodge CPU or optional second player |
TWRDEF | Tower Defense | Build towers across rotating road and open-field layouts |
UFODEF | UFO Defense | Missile Command-style defense with turret/base and wave/time settings |
WINGS | Wings | Carrier strike game with fuel, ammo, targets, and landing |
WORMS | Worms Mini | Turn-based team artillery with destructible terrain and CPU/2-player settings |
Each game tracks high scores with optional initials entry.
Controls
Common Controls
Menu Navigation:
- Up/Down: Navigate menu
- Z (or Space/Enter): Start/Confirm
- C (or X/Escape): Open game options when available; otherwise Back/Cancel
In-Game:
- Directional movement: Arrow keys / Joystick
- Primary action (jump/shoot/rotate): Z button / Space / Enter
- Secondary/Back: C button / X / Escape
Desktop Keyboard Mapping
| Action | Keys |
|---|---|
| Move | Arrow Keys |
| Confirm/Action | Z, Space, or Enter |
| Back/Cancel | X or Escape |
| Player 1 Move in 2P | W, A, S, D |
| Player 1 Action in 2P | Shift where used |
| Player 2 Move in 2P | Arrow Keys |
| Player 2 Action in 2P | Z, Space, or Enter where used |
Game Settings Highlights
AIRHKY:PLAYRswitches between1Pand2P;GOALSsets the match length.BILLI:RULEswitches betweenPOOLandSNOOK;AIMchanges the aim guide length.PONG:PLAYRswitches between1Pand2P.TRON:PLAYRswitches between CPU opponent and2P.CITY:JOBSsets mission count;TRAFtoggles civilian traffic.KERBAL:MISNswitches between orbit-only and return mission;ASSTtoggles arcade flight assist.LANDER:MODEswitches between classicV1and scrollingV2with route pads and fuel pickups.RACING:LAPSsets race length;TRAFtoggles traffic cars.WORMS:PLAYRswitches between CPU opponent and2P;TEAMsets two or three worms per side.
MicroPython Controller
- I2C Address: 0x52 (standard Nunchuk)
- Pins: SCL=21, SDA=20 (configurable in code)
- Buttons:
- C button: Back/Cancel
- Z button: Confirm/Action
- Analog stick: 8-directional movement (includes diagonals)
The code auto-detects controller variants including the "new signature" controllers (A0 20 10 00 FF FF).
Usage
Start the app, select a game with Up/Down, and press Z to launch it. If a game
has settings, press C on the game list to open the shared settings menu before
starting the game.
High scores are stored per game ID. The shared game-over menu offers retry, high-score view, and return-to-menu actions.
Architecture
Developer notes are documented in docs/ARCHITECTURE.md. Per-game gameplay and implementation notes are documented in docs/games/README.md.
The short version:
GameSelect.GAME_REGISTRYcontrols which games appear in the selector.GameSettings.DEFINITIONSdeclares per-game settings for the shared settings menu.- Games that accept a constructor context read settings with
get_context_setting(). - Games report final results through
set_game_over_score()so the shared lost/won and high-score flow can handle them.
Troubleshooting
- If the browser build appears blank, rebuild with
python -m pygbag .and check the console for import or asset errors. - If settings do not appear for a game, confirm the game ID in
GameSettings.DEFINITIONSexactly matches the ID inGameSelect.GAME_REGISTRY. - If a game class exists but is missing from the menu, add it to
GameSelect.GAME_REGISTRY. - If desktop input behaves differently from the cabinet, check the keyboard mapping
in the Controls section and the joystick/button helper functions in
arcade_app.py.
