Minimal browser multiplayer template:
- Phaser renders a top-down scrolling world.
- Colyseus keeps an authoritative shared room state.
- Two or more players can move around the same map.
- The world contains randomly placed boxes that block movement.
npm install
npm run devThen open http://localhost:5173 in two or more tabs.
In local dev the browser UI is served by Vite on port 5173, and it connects to the Colyseus server on port 2567.
The project source is now TypeScript across client, server, and shared code. The server uses Node 24's TypeScript transform support, so use Node 24.x locally as well.
The Raspberry Pi can now host the complete game from the Node/Colyseus server itself. The Docker image builds the frontend, stores it in dist/, and the server serves those files directly.
On the Raspberry Pi:
docker compose up --build -d --force-recreateThen open this in a browser on any device in the same network:
http://YOUR_PI_IP:2567
To stop it:
docker compose downTo view logs:
docker compose logs -f serverThe server is configured to bind to 0.0.0.0 inside the container, so Docker can publish it on the Raspberry Pi host.
If the page is reachable with npm run dev on your laptop but not through Docker on the Pi, debug the Docker publish path first:
docker compose down
docker compose up --build -d --force-recreate
docker compose ps -a
docker ps
ss -ltnp | grep ':2567'
docker port amongus-server
curl -v http://127.0.0.1:2567/health
curl -I http://127.0.0.1:2567/How to interpret that:
- If
docker compose upreportsaddress already in use, another process is already bound to port2567on the Pi. - If
docker compose ps -ashowsCreatedorExitedinstead ofUp, the container never became healthy enough to serve traffic. - If
ss -ltnpshows a non-Docker process on:2567, that process is blocking Docker from publishing the port. - If
curl http://127.0.0.1:2567/healthworks on the Pi but other devices still cannot connect, the container is fine and the remaining issue is outside the app/container.
To identify a conflicting process on port 2567:
sudo lsof -iTCP:2567 -sTCP:LISTEN -n -P- When the built app is served by the Pi on port
2567, the browser automatically connects back to that same origin. - When you use Vite locally on port
5173, the client automatically targetshttp://<current-host>:2567.
WASD- Arrow keys
- The Colyseus server runs on
http://localhost:2567 - The Vite client runs on
http://localhost:5173 - In Docker on the Pi, the server also serves the built frontend from
dist/ npm run typecheckchecks the whole project withtsc