velxio/test/pico_doom_demo
davidmonterocrespo24 5742ed0146 feat(examples): Pico Doom — Wolf3D-style raycaster on RP2040 + ILI9341
A new entry in the games category for the Raspberry Pi Pico. Renders
a first-person 3D corridor à la Wolfenstein / early Doom using a
column-wise DDA raycaster — 160 rays per frame drawn straight to a
320×240 ILI9341 TFT via drawFastVLine, no framebuffer. 16×16 tile map
with 5 wall palettes (slate, blood, brown, toxic green, bronze door),
darkened on NS faces so corners read in 3D. Forward / back move,
two more buttons turn the player. 40-px HUD bar.

Why a demo, not the canonical id Software Doom: Graham Sanderson's
rp2040-doom port shoehorns DOOM1.WAD into 2 MB of flash with custom
compression and pushes video out over PIO-driven DVI / VGA — none of
that survives the rp2040js emulator (no PIO accuracy, no flash
mapping for huge assets). A raycaster reproduces the *visual* of
early Doom using only ~67 KB of flash and 9 KB of RAM, which the
emulator runs perfectly.

Pre-flight: arduino-cli compile against rp2040:rp2040:rpipico
already verified inside the Velxio backend container — 3 % flash,
3 % RAM. The Adafruit_GFX + Adafruit_ILI9341 libs the example
declares are already in the gallery's auto-install list.

Bundled:
  test/pico_doom_demo/arduino_sketch.ino — source of truth sketch
  test/pico_doom_demo/README.md          — what + why + pin map
  test/pico_doom_demo/compile_check.sh   — operator script that
    runs arduino-cli against the same FQBN the prod backend uses
  frontend/src/data/examples.ts          — gallery entry (boardType
    raspberry-pi-pico, category games, difficulty advanced, 5
    components, 14 wires)
  frontend/src/__tests__/examples-pico-doom.test.ts — 10 vitest
    assertions: example is registered exactly once, target board /
    category / difficulty match, libraries declared, all four
    pushbuttons present, every wire endpoint references a real
    component id, SPI pin mapping matches the sketch's #define
    block, every button has a GND wire, the renderFrame loop is
    still present in the embedded code.
2026-05-13 22:54:35 +02:00
..
README.md feat(examples): Pico Doom — Wolf3D-style raycaster on RP2040 + ILI9341 2026-05-13 22:54:35 +02:00
arduino_sketch.ino feat(examples): Pico Doom — Wolf3D-style raycaster on RP2040 + ILI9341 2026-05-13 22:54:35 +02:00
compile_check.sh feat(examples): Pico Doom — Wolf3D-style raycaster on RP2040 + ILI9341 2026-05-13 22:54:35 +02:00

README.md

Pico Doom — pre-flight compile test

A column-wise raycaster that produces a Wolfenstein / early-Doom-style 3D corridor on the Pi Pico + ILI9341 TFT. Lives here as the canonical source of the sketch + a one-shot compile check the operator can run before exposing the example in the gallery.

What the sketch does

  • Reads four pushbuttons (forward, back, turn left, turn right) on GP10-13 with INPUT_PULLUP.
  • Draws a title splash on the ILI9341, waits for FWD.
  • Casts 160 rays per frame (every other column, 2-px stripe) through a 16×16 tile map using DDA, paints walls straight onto the TFT with drawFastVLine — no framebuffer.
  • Renders a fixed 40-px HUD bar at the bottom (HP / armour / ammo).
  • Caps the frame rate at ~10 fps so the SPI bus has room to breathe.

Why this is a "demo" and not the real id Software Doom

The canonical Pico port — Graham Sanderson's rp2040-doom — ships the shareware DOOM1.WAD inside the flash with custom compression and pushes pixels out via PIO-driven VGA / DVI. None of that survives the rp2040js emulator (no PIO accuracy, no flash mapping for the WAD blob), so what you'd see in the simulator is a boot loop.

A Wolf3D-style raycaster reproduces the visual experience — first- person 3D corridor with textured walls, free rotation, smooth forward/strafe movement — using the same tools that fit on a 264 KB chip. That's what this sketch does, and it survives emulation fine.

How to run the pre-flight check

The sketch must compile against the Pico FQBN with only the libraries the Velxio compile pipeline already auto-installs (Adafruit_GFX, Adafruit_ILI9341). Run:

cd test/pico_doom_demo
./compile_check.sh

The script:

  1. Checks arduino-cli is in $PATH.
  2. Verifies rp2040:rp2040 core is installed (installs it if not).
  3. Confirms Adafruit_GFX and Adafruit_ILI9341 are installed (lib install if missing).
  4. Runs arduino-cli compile --fqbn rp2040:rp2040:rpipico . and asserts a non-empty .uf2 output.

A successful run prints the binary size and exits 0. Sketch size should sit comfortably under 80 KB — well below the Pico's 2 MB flash ceiling — so this isn't a "will it fit" test but a "compiles cleanly with the gallery's lib set" test.

frontend/src/data/examples.ts registers an entry with:

  • id: 'pico-doom-raycaster'
  • boardType: 'raspberry-pi-pico'
  • category: 'games'
  • difficulty: 'advanced'
  • libraries: ['Adafruit GFX Library', 'Adafruit ILI9341']
  • Components: 1 ILI9341 + 4 pushbuttons + the Pico board
  • Wires: SPI bus (SCK/MOSI/CS/DC/RST/LED) + 4 button pulls to GP10-13

The unit test frontend/src/__tests__/examples-pico-doom.test.ts validates that the registered example has those fields and that every wire endpoint references a component id that actually exists.

Pin map (printed here so it's obvious during hardware bring-up too)

Function Pico GPIO Note
SPI0 SCK GP18 Adafruit_ILI9341 uses SPI0 by default.
SPI0 MOSI GP19
TFT CS GP17
TFT D/C GP20
TFT RST GP21
TFT LED GP22 Backlight, always HIGH.
Button FWD GP10 INPUT_PULLUP, active LOW.
Button BACK GP11
Button LEFT GP12 Turn anticlockwise.
Button RIGHT GP13 Turn clockwise.