Running the example server
The repo ships a runnable example: a reference signaling server, a host page and a phone page.
git clone https://github.com/MaanavKrishna/couchpad
cd couchpad
npm install
npm run examplenpm run example bundles examples/host/host.ts and examples/phone/phone.ts with esbuild into examples/dist, then starts examples/server/server.mjs on http://localhost:8787.
- Open
http://localhost:8787on the computer. It shows a room code. - On a phone on the same Wi-Fi, open
http://<your-computer-ip>:8787/phone.html?room=CODE. - Move the stick. The status line on the phone shows
connected (direct)orconnected (relay).
Set PORT to change the port:
PORT=9000 npm run exampleTilt and vibration need HTTPS
A LAN IP is not a secure context, so tilt falls back to a joystick. Put the server behind an HTTPS tunnel, or use a local certificate, to test tilt.
What the server does
server.mjs is about 100 lines on top of ws, and covers the whole protocol:
- Rooms in memory, with 4-letter codes from the same alphabet as
ROOM_CODE_RE, and a limit of 8 players. - Random 12-byte hex tokens for the TV and for each player.
room.joinwith a matchingrejoinTokenreuses the player's seat andplayerId.- Phones may only address
'tv'. The server stampsfromitself. - When the TV socket closes, every phone gets
tv.left. Onroom.resumewith the right token, every phone getstv.back. - WebSocket frames are capped at 128 KB (
maxPayload).
Going to production
The example keeps rooms in memory on one process. Cadabra runs the same protocol on API Gateway WebSocket, Lambda and DynamoDB. That is why relay payloads are chunked at 28 KB: API Gateway frames cap near 32 KB. Things to add for production:
- Persist rooms and tokens (DynamoDB, Redis) so a deploy does not end every game.
- Rate-limit joins and relays per connection and return
room.rateLimited. - Expire idle rooms.
- Run your own TURN server, or accept the relay as the fallback (see the FAQ).