Play the classic 1993 FPS on your WiFi Pineapple Pager!
Darren Kitchen demoing DOOM on the Pager β watch the full video
If you have the general β Pull Payload PR payload on your pager, type PR 130 to install.
Copy the pre-built files to your Pager:
scp -r payloads/user/games/doom root@172.16.52.1:/root/payloads/user/games/Then find DOOM in: Payloads β Games β DOOM
Bring your own WADs! Only the shareware doom1.wad is included. Place your legally obtained WAD files in the wads/ directory to play the full games.
| Game | WAD File | Status |
|---|---|---|
| DOOM Shareware | doom1.wad |
β Works |
| DOOM Registered | doom.wad |
β Works |
| DOOM II | doom2.wad |
β Works |
| Final DOOM: TNT Evilution | tnt.wad |
β Works |
| Final DOOM: Plutonia | plutonia.wad |
β Works |
| Add-on | WAD File | Requires | Status |
|---|---|---|---|
| No Rest for the Living | nerve.wad |
doom2.wad |
β Works |
| Master Levels | masterlevels.wad |
doom2.wad |
β Works |
| SIGIL | sigil.wad |
doom.wad |
β Works (Episode 3) |
| SIGIL II | sigil2.wad |
doom.wad |
β Incompatible |
- Place your WAD files in the
wads/directory - Run the installer:
./install-wads.sh list # Show available configurations
./install-wads.sh install # Create payload directories
./install-wads.sh deploy # Deploy to Pager via SSH- SIGIL uses the "compat" version which replaces Episode 3 (select Episode 3 in menu)
- SIGIL II is NOT compatible (requires UMAPINFO support)
| Input | Action |
|---|---|
| D-pad | Move/Turn |
| Red | Fire |
| Power | Next Weapon |
| Green | Select (menus) |
| Green + Up | Open doors/Use |
| Green + Down | Automap |
| Green + Left/Right | Strafe |
| Green + Power | Quicksave |
| Red + Power | Quickload |
| Red + Green | ESC (Menu/Quit) |
External USB keyboards work alongside the Pager's built-in buttons. Plug in your keyboard before launching the game - input devices are detected at startup.
Connect to our public DOOM servers for multiplayer deathmatch!
Run the DOOM Deathmatch payload from: Payloads β Games
Connection Modes:
- Auto - Instant matchmaking to best available server
- Browse - Manual server selection with real-time status
- Direct - Connect to specific IP:port
Desktop players can join with Chocolate Doom:
chocolate-doom -iwad doom1.wad -connect 64.227.99.100:2342- Chocolate Doom 3.1.x protocol compatibility
- Works with vanilla Chocolate Doom server
- POSIX socket-based network layer (no SDL dependency)
./build.shThis will:
- Download the OpenWrt SDK (~400MB, cached in
build/) - Clone our doomgeneric fork (
pagerbranch) - Cross-compile for MIPS
- Deploy to Pager (if connected)
For experimental builds, use ./build.sh --dev which pulls from the dev branch and creates a separate DOOM DEV payload.
- Linux (tested on Ubuntu/Debian)
curl,git,makeqemu-user-static(on non-x86_64 hosts)
sudo apt install curl git make qemu-user-staticCapture a screenshot from your Pager's framebuffer and save it locally:
./screenshot.sh # Landscape (default)
./screenshot.sh -n # Portrait (raw framebuffer)
./screenshot.sh my_shot.png # Custom filename- CPU: MIPS 24KEc @ 580MHz (soft-float, 8-stage pipeline)
- RAM: 64MB DDR2
- Display: 222Γ480 RGB565 via SPI (~20 FPS refresh limit)
- Input: GPIO buttons via
/dev/input/event0
The vanilla DOOM engine has static limits that can cause crashes on complex maps like SIGIL. These have been increased:
| Limit | Original | Modified |
|---|---|---|
| MAXVISPLANES | 128 | 512 |
| MAXVISSPRITES | 128 | 256 |
| MAXDRAWSEGS | 256 | 512 |
Display Pipeline
- 16-bit RGB565 framebuffer support with direct writes
- 90Β° CCW rotation for portrait display orientation
- Full-screen stretched scaling with widened FOV (gameplay)
- Aspect-correct rendering with letterboxing (menus/title)
- Precomputed lookup tables for X/Y scaling (32-byte cache-aligned)
Frame Pacing
- Default 35 FPS cap matches DOOM's native TICRATE
clock_nanosleep()with absolute timing for precise frame pacing- Reduces CPU usage and heat compared to uncapped rendering
- Display limited to ~20 FPS via SPI, but 35 FPS ensures smooth game logic
Input System
- GPIO button mapping (red/green buttons)
- Button combo detection with proper state tracking
- Strafe combos: Green+Left/Right for strafing
- USB keyboard support (detected at startup)
Performance Optimizations
| Optimization | Status | Notes |
|---|---|---|
| Link-Time Optimization (LTO) | ON | Cross-module inlining, 10% smaller binary |
| GCC Auto-Prefetch | ON | -fprefetch-loop-arrays adds ~140 prefetch instructions |
| GCC 13 IPA Optimizations | ON | -fipa-pta, -fmodulo-sched, -fsched-pressure, -fsplit-paths |
| Precomputed Row Offsets | ON | Eliminates multiply in inner render loop |
| RGB565 Palette Precomputation | ON | 256-entry palette converted to RGB565 once at load |
| 4-Pixel Loop Unrolling | ON | Inner render loop processes 4 pixels per iteration |
| Cache-Aligned Tables | ON | Lookup tables aligned to 32-byte cache lines |
| DSP Indexed Loads | ON | ~1000 lbux/lwx instructions (-march=24kec auto-enables -mdsp) |
| mobj_t Cache Layout | ON | Hot fields grouped in first 2 cache lines |
| Binary Stripping | ON | ~700KB vs 1.4MB with debug symbols |
Compiler Flags (MIPS 24KEc @ 580MHz, GCC 13.3)
-O3 -flto -march=24kec -mtune=24kec -mbranch-likely
-ffast-math -funroll-loops -fomit-frame-pointer -finline-functions
-fprefetch-loop-arrays
-fipa-pta -fmodulo-sched -fsched-pressure -fsplit-paths
The payload scripts stop background services before launching DOOM to maximize available CPU and RAM:
# Services stopped during gameplay
/etc/init.d/php8-fpm stop # PHP FastCGI
/etc/init.d/nginx stop # Web server
/etc/init.d/bluetoothd stop # Bluetooth daemon
/etc/init.d/pineapplepager stop
/etc/init.d/pineapd stopAll services are automatically restored when DOOM exits.
βββ build.sh # Main build script
βββ install-wads.sh # WAD installer tool
βββ screenshot.sh # Pager screenshot utility
βββ doomgeneric/ # Engine fork (github.com/lmacken/doomgeneric-pager)
βββ wads/ # Place your WAD files here
βββ img/ # Screenshots
βββ ansible/ # Deathmatch server playbook
βββ payloads/ # Pager payload directories
βββ user/games/
βββ doom/ # Base DOOM (shareware)
βββ doom-deathmatch/ # Multiplayer
βββ doom2/ # DOOM II
βββ doom-sigil/ # SIGIL
βββ ...
- UMAPINFO support for SIGIL II compatibility
- Kernel module (
doom_fb.ko) for bypassing fbtft overhead and direct USB bulk transfers - DMA transfers for framebuffer writes (CH347 USB-to-SPI bridge currently lacks DMA)
- Dirty rectangle tracking to only update changed screen regions
- Vibrate when hit using the Pager's vibration motor
- DOOM theme ringtone using the piezoelectric buzzer
- DOOM source code: GPL-2.0
- doomgeneric: GPL-2.0
doom1.wad: Shareware (freely distributable)