Real-Time Multiplayer Game
-
Features: Real-time communication between players, game state synchronization, leaderboard.
-
Technologies: WebRTC (media plane), React, Bun, TypeScript.
-
Description: Develop a multiplayer game website where players can compete in real-time. Use WebRTC for player communication and state synchronization.
-
Game engines, RTC, Server state management, Distributing via APKs, Operational — Figuring out licenses:
ludo.jsis GPL-class (copyleft on distribution, relevant to APK shipping); our chess implementation is self-written; reference repos are MIT-class. Decision due before Phase 7 — seeroadmap.md. -
Example:
-
Ludo app where you can also bet, connect over webrtc like a video call, have a user auth and profile, can see your history; lib-ludo.js
-
Chess app with onCall game, user auth, and collect user stats similar to chess.com, impl
- lib-chess.js : our own implementation
-
checkers
Tic-Tac-Toe you may use this also
This repo is a Turborepo monorepo with two workspace roots:
playmesh/
├── apps/
│ ├── server/ ← main server (Bun, HTTP): auth bootstrap, history, gateway resolution
│ ├── ws-gateway/ ← WebSocket gateway (Bun): rooms, engines, matchmaking, bot fill
│ └── web/ ← Next.js frontend
└── packages/
├── protocol/ ← envelope + message types (protocol.md)
├── types/ ← shared domain types (Player, Room, Match, Seat)
└── engines/
├── core/ ← GameEngine interface + registry
├── chess/ ← lib-chess.js lives here
└── ludo/ ← ludo engine lives here
Two processes, one seam: apps/ws-gateway handles everything live over the
WebSocket (room state in memory, engine sessions, delta buffer) and writes
matches/events to Postgres directly; apps/server handles the cold path
(auth, history, gateway resolution). Redis is the ephemeral glue — presence,
matchmaking queues, dedup, room→gateway routing. See docs/architecture.md.
This is where lib-chess.js would be developed and published as a workspace package:
packages/engines/chess/
├── package.json ← { "name": "@playmesh/chess" }
├── src/
│ ├── index.ts ← exports: Chess, Move, GameResult, etc.
│ ├── engine.ts ← core state machine
│ ├── moves.ts ← move generation/validation
│ └── types.ts ← shared types (FEN, Move, GameState)
├── tests/
└── README.md
The apps/* and packages/* globs in root package.json:25-28 automatically link these workspaces together.
The ws-gateway (apps/ws-gateway/) declares the dependency in its own
package.json:
{
"dependencies": {
"@playmesh/chess": "workspace:*"
}
}Usage in a room session (the gateway holds one engine instance per active
room; on GAME_ACTION it validates seat/turn, applies, and broadcasts the
produced events):
// pseudocode — one session per room in the gateway
class ChessSession {
engine: GameEngine; // created via the engine registry
// on GAME_ACTION from seat s:
// const { events, state, gameOver, result } = this.engine.applyAction(this.state, s, action)
// → bump stateVersion per event, buffer, broadcast, persist batch
}
### 3. Client Consumes It
The web app (`apps/web/`) also declares the workspace dependency:
```json
{
"dependencies": {
"@playmesh/chess": "workspace:*"
}
}Used for:
- Rendering the board from
GAME_STATEFEN - Highlighting legal moves locally (
engine.legalMoves(square)) - Optimistic UI pre-validation (server is still the authority)
const engine = new Chess(serverFEN);
const moves = engine.moves({ square: fromSquare, verbose: true });
// pass moves to UI layer for highlight renderinglib-chess.js exports types that the protocol layer also uses:
export type { Move, FEN, GameState, GameResult };The protocol package (packages/protocol/) can import these so GAME_ACTION and GAME_STATE schemas stay in sync with what the engine actually produces/consumes — no duplicated type definitions.
| Layer | Consumes @playmesh/chess |
Purpose |
|---|---|---|
packages/engines/chess |
— | Defines and exports the engine |
apps/ws-gateway |
workspace:* |
Authoritative validation, state, bot AI |
apps/web |
workspace:* |
Rendering, move preview, UX validation |
packages/protocol |
workspace:* |
Types for message schemas |