1-Bit Doom: Stream DOS Games to ESP32 OLED Over WiFi
31 May 2026

I just finished Doom: The Dark Ages, and after replaying all the other Doom games I was completely hooked. Around the same time I had been working on my ESP32 Mini OLED Webcam Stream project, streaming a live webcam feed to a tiny 128x64 SSD1306 OLED over WiFi. That got me thinking: what else can we stream to this thing?
The obvious answer was Doom.
But does it run Doom?#
The classic question. And before even trying to run Doom on the ESP32, I wanted to answer a more basic one: is Doom even readable on a 128x64 monochrome display? There is no point in porting an entire game engine to a microcontroller if you cannot tell what is happening on screen.
Native ESP32 Doom ports do exist. Espressif published a proof-of-concept PrBoom port, but it requires an ESP32-WROVER module with 4MB of PSRAM. The Arduino Nano ESP32 (based on the ESP32-S3) can also run it. I have a basic ESP32 DevKit without PSRAM, so running Doom natively was not an option with the hardware I had.
So instead of porting the game, I built something more generic. The project uses js-dos to run any DOS game in the browser and streams the dithered video output to the ESP32 over WebSocket. The ESP32 does not run Doom or any game. It just acts as a tiny wireless monitor. Doom was my test case, but the system works with any .jsdos game bundle you drag and drop into the browser.
This let me focus on the actual question: can you play Doom on a 1-bit screen?
Can you play Doom on a 1-bit screen?#
A single frame has to survive being cropped, downscaled to 128x64 pixels, dithered to pure black and white, and packed into 1024 bytes. That is the entire SSD1306 display buffer. Every frame.
It turned out better than expected. You can navigate levels, spot enemies, and play through the game. The screen is tiny and the dithering loses detail in dark areas, but it is surprisingly playable.
Dithering makes all the difference#
The project supports multiple 1-bit dithering algorithms: Bayer ordered dithering at 2x2, 4x4, and 8x8, plus Floyd-Steinberg and Atkinson error diffusion. Each one gives the image a different character. Bayer is fast and produces a clean pattern, good for maintaining high frame rates. Atkinson creates that classic Macintosh look with more contrast. Floyd-Steinberg sits somewhere in between.
You can switch between them in real time and see the result both in the browser preview and on the physical OLED. There are also controls for contrast, brightness, and cropping from all four sides, so you can frame just the gameplay area and cut out the HUD.
Browser-to-microcontroller streaming pipeline#
The whole streaming pipeline runs in the browser with vanilla JavaScript, zero dependencies, no build step. It captures the js-dos canvas, crops and resizes to 128x64, applies the selected dithering algorithm, packs the result into SSD1306 page format, and sends it over WebSocket. The ESP32 firmware copies the incoming bytes straight into the display buffer with memcpy. No clearDisplay, no drawBitmap, just a direct buffer write.
With backpressure protection on the WebSocket client, it sustains 15 to 20 FPS without frame buildup.
Holiday hardware constraints#
I started this project on holiday with nothing but an ESP32, the SSD1306 OLED display, and four jump wires. The same minimal setup from the webcam streaming project. No breadboard, no extra components. Just the board, the screen, and a USB cable for power. The same holiday where I built the ESP32 OLED Pinball game with the exact same hardware.
What's next#
Now that I know the display works for Doom, the interesting next step is actually running it natively on the hardware. That would mean an ESP32-S3 with PSRAM, since the existing Doom ports require it. This streaming project was the first step: proving the screen can handle the game before investing in the hardware to run it.
Frequently Asked Questions
- Does this project actually run Doom on the ESP32?
No. The ESP32 does not run any game. Doom (or any other DOS game) runs in the browser using js-dos. The ESP32 receives dithered 1-bit video frames over WebSocket and displays them on the SSD1306 OLED. It acts as a tiny wireless monitor.
- Can you run Doom natively on an ESP32?
Yes, but it requires an ESP32-WROVER with 4MB PSRAM or an ESP32-S3 board. Espressif has published a PrBoom port that runs on these modules. A basic ESP32 DevKit without PSRAM cannot run it.
- Can I stream other games besides Doom?
Yes. You can drag and drop any .jsdos file into the browser interface to load other DOS games. The streaming and dithering pipeline works the same way regardless of the game.
- Which dithering algorithm looks best for Doom?
It depends on what you value. Atkinson dithering gives the most contrast and a classic Macintosh aesthetic. Bayer 4x4 is the best balance of speed and visual quality. Floyd-Steinberg produces the smoothest gradients but can look noisy on a tiny screen.
- What frame rate does the streaming achieve?
The system sustains 15 to 20 FPS over WiFi with WebSocket backpressure protection to prevent frame buildup.
Resources
- 1-Bit Doom source code on GitHub
- Espressif ESP32 Doom (PrBoom port)
- ESP32 Mini OLED Webcam Stream
- ESP32 OLED Pinball


