Play a Game Boy inside Minecraft using ComputerCraft. This project streams frames from a Python WebSocket server running a Game Boy emulator (PyBoy) to a ComputerCraft/CC:Tweaked client written in Lua. The client renders frames on a monitor and sends button presses back to the emulator.
Works either locally or via Docker for the server. The ComputerCraft client can be hosted on Pastebin for easy installation in‑game.
- Server: Python app runs PyBoy on a ROM, converts each screen frame to an NFP palette, compresses it with zlib, and streams it over WebSocket.
- Entry:
main.py - WebSocket:
websocket_server.py(default0.0.0.0:8081in Docker) - Frame conversion:
screen_converter.py(palette inconfig.py:20) - Input handling:
button_handler.pyviaACTION_MAPinconfig.py:36
- Entry:
- Client:
gameboy.luaconnects viahttp.websocket, decompresses frames usingLibDeflate.lua, loads NFP viasurface.lua, draws to the main monitor, and sends touch‑based button events from a second “controller” monitor.
- Server (if not using Docker):
- Python 3.9+
- Packages:
pyboy,websockets,numpy
- Docker (optional): Docker installed
- Minecraft side:
- ComputerCraft or CC:Tweaked with HTTP and WebSocket enabled in the mod config
- One computer with two attached monitors:
- Main screen: on the
topside - Controller screen: on
front,back,left, orright
- Main screen: on the
- Internet access from the CC computer to fetch Pastebin raws (or pre‑bundle the libs)
- Prepare a ROM folder and copy your ROM file (example
pokemon.gbc):- Create and place under
roms/next to this repo
- Create and place under
- Build the image:
docker build -t ccboy .
- Run the server, mounting your ROMs and exposing the port:
docker run --rm -p 8081:8081 -e ROM_FILE=pokemon.gbc -v $(pwd)/roms:/app/roms ccboy
- Note the WebSocket endpoint for the client:
ws://<your-docker-host>:8081
Environment defaults are defined in config.py and the Dockerfile sets sane defaults for container use.
- Install dependencies in a venv:
python -m venv .venv && source .venv/bin/activatepip install pyboy websockets numpy
- Put your ROM in
roms/and set env vars as needed, then start:export ROM_FILE=pokemon.gbcexport ROM_PATH=$(pwd)/romsexport WEBSOCKET_HOST=0.0.0.0export WEBSOCKET_PORT=8081python main.py
On start you should see “WebSocket server started on …” in the console.
- Script:
gameboy.lua - Libraries auto‑downloaded by the client (Pastebin IDs embedded in the script):
LibDeflate.lua(zlib decompression):fN3HFQ9fsurface.lua(rendering):QiaQ2KBr
Two recommended ways to install the client on a CC computer:
-
Pastebin one‑liner (host
gameboy.luayourself):- Upload the contents of
gameboy.luato Pastebin and note the ID, then on the CC computer run: pastebin get <YOUR_PASTE_ID> startup- Reboot the computer so it auto‑starts the client.
- Upload the contents of
-
Manual copy (if you can paste directly):
- Create a file named
startupon the CC computer and paste the contents ofgameboy.lua.
- Create a file named
Before first run, edit the script endpoint if your server isn’t on the CC computer:
- Open
gameboy.lua:6and setbase_urlto your server, for example:local base_url = "ws://192.168.1.50:8081"
Attach monitors:
- Main display monitor on
topof the computer - Controller monitor on one of:
front,back,left,right
Start the CC computer. The client will:
- Connect to the WebSocket, receive compressed frames, and render to the main monitor.
- Draw a simple controller layout on the second monitor. Touching zones sends:
up,down,left,right,a,b,select,start.
- Touch the controller monitor zones to send inputs.
- The client lowercases inputs internally; mapping is defined in
config.py:36.
Environment variables read in config.py:
ROM_FILE: ROM filename insideROM_PATH(defaultdefault.gbc)ROM_PATH: folder where ROMs are stored (default/app/roms)WEBSOCKET_HOST: bind host (Docker default0.0.0.0; local defaultlocalhost)WEBSOCKET_PORT: bind port (default8081)EMULATION_FPS: PyBoy tick rate (default60)SCREEN_UPDATE_RATE: frames pushed per second (default15)COMPRESSION_ENABLED: zlib compression toggle (always used by current server build)
Color palette and nearest‑color logic used for NFP conversion live in config.py:20 and screen_converter.py.
- The server uses PyBoy headless mode (
window="null") so no GUI is shown on the host. - The Game Boy screen is centered on the CC monitor. Large monitors improve readability.
- If the CC modpack blocks HTTP/WebSocket, enable them in the CC/CC:Tweaked config or whitelist Pastebin/raw URLs.
- If connection fails on CC, verify
base_urlpoints to the server and that port8081is reachable from Minecraft. - Dockerfile references
requirements.txt. If absent, create one with at least:pyboywebsocketsnumpy
main.py: Starts emulator + WebSocket serverwebsocket_server.py: Client handler and frame streamingemulator.py: PyBoy wrapper and button queuingscreen_converter.py: RGB frame to NFP charactersbutton_handler.py: Maps commands to emulator inputsconfig.py: All tunables and mappingsgameboy.lua: ComputerCraft clientlib/LibDeflate.lua,lib/surface.lua: Lua dependencies for the clientDockerfile: Container image for the server
- This repository is under the GNU AGPL v3 License (
LICENSE).