How mirza-mohammad24/scribblitz works
Purpose and Runtime Topology
Scribblitz is a multiplayer drawing-and-guessing game. It is a pnpm/Turborepo monorepo with three Node.js services: Next.js browser UI, Express/Socket.IO authoritative game server, and BullMQ AI worker. Shared contracts prevent client/server event drift.
• apps/web/src/app/page.tsx
• apps/game-server/src/server.ts
• apps/worker/src/index.ts
Client Application and UI Control
The Next.js app renders the home, lobby, and active-game experiences. ArenaOrchestrator is the top-level game UI router: it consumes socket-driven state from Zustand and selects lobby versus arena views; arena components isolate canvas, chat, HUD, leaderboard, overlays, emotes, and voice controls.
• apps/web/src/components/Arena/ArenaOrchestrator.tsx
• apps/web/src/store/gameStore.ts
• apps/web/src/hooks/useGameSocket.ts
Authoritative Room and Game Lifecycle
The game server owns ephemeral room membership, host assignment, player sessions, reconnect grace periods, and all gameplay transitions. RoomManager manages in-memory rooms; GameFSM permits the lobby → word selection → drawing → round end/game end lifecycle. Socket handlers enforce role/state guards before invoking this domain layer.
• apps/game-server/src/rooms/RoomManager.ts
• apps/game-server/src/rooms/Room.ts
• apps/game-server/src/fsm/GameFSM.ts
Socket Boundary and Shared Contracts
Socket.IO is the primary control and realtime data plane between browser and game server. Handler groups separate lobby/configuration, gameplay, messages/guessing, canvas, voice, and emotes. Incoming payloads are runtime-validated with Zod; types, event names, game states, and constants are workspace-owned.
• apps/game-server/src/socket/handlers/gameHandlers.ts
• packages/types/src/events.ts
• packages/validation/src/game.ts
Drawing Synchronization and Recovery
The drawer locally buffers pointer operations and sends batched canvas events; the server immediately relays them to peers and persists/retrieves history through Redis. Canvas logic stays client-local, while server handlers enforce drawer and round permissions. Redis Streams support reconnect/late-join replay but do not store authoritative room state.
• apps/web/src/hooks/useCanvasDrawing.ts
• apps/game-server/src/socket/handlers/canvasHandlers.ts
• apps/game-server/src/lib/redis.ts
External Services and Background Work
Redis backs both canvas streams and BullMQ. Hosts request themed words through the game server; it enqueues work and the worker calls Google Gemini, then validates/filter results before completion is reflected in room configuration. Voice is separate: the game server mints scoped LiveKit tokens, while browsers carry audio directly over WebRTC to LiveKit.
• apps/game-server/src/services/aiQueue.ts
• apps/worker/src/index.ts
• apps/game-server/src/services/voiceService.ts
Persistence and Deployment Boundaries
PostgreSQL/Prisma provides schema and migrations for persistent entities such as users and game results, though active games remain process-local. Docker Compose provisions local dependencies and production services; each runtime has a Dockerfile. The architecture is currently single-instance because rooms are not distributed via a Socket.IO Redis adapter.
• prisma/schema.prisma
• docker-compose.yml
• docker-compose.prod.yml
Main entry points: gameHandlers.ts Socket handlers · ArenaOrchestrator.tsx Arena UI · useGameSocket.ts Game socket hook · index.ts AI worker
Components 20
Browser client
- Arena UI · Routes home, lobby, and active-game views.
apps/web/src/components/Arena/ArenaOrchestrator.tsx - Game state store · Socket-driven client game state.
apps/web/src/store/gameStore.ts - Game socket hook
apps/web/src/hooks/useGameSocket.ts - Canvas drawing · Buffers and batches local pointer operations.
apps/web/src/hooks/useCanvasDrawing.ts
Game server
- Socket handlers · Guards and validates lobby, game, message, canvas, voice, and emote events.
apps/game-server/src/socket/handlers/gameHandlers.ts - Room manager · Owns membership, hosts, sessions, and reconnect grace periods.
apps/game-server/src/rooms/RoomManager.ts - Room · Process-local active game and player state.
apps/game-server/src/rooms/Room.ts - Game lifecycle · Controls lobby through game-end transitions.
apps/game-server/src/fsm/GameFSM.ts - Canvas handlers · Authorizes drawer events and serves replay.
apps/game-server/src/socket/handlers/canvasHandlers.ts - Redis integration · Stores canvas streams and connects BullMQ.
apps/game-server/src/lib/redis.ts - Word AI queue · Enqueues themed-word requests from hosts.
apps/game-server/src/services/aiQueue.ts - Voice token service · Mints scoped browser voice tokens.
apps/game-server/src/services/voiceService.ts
Background & external
- AI worker · Generates, validates, and filters word results.
apps/worker/src/index.ts - Google Gemini
- LiveKit · Browsers send audio directly over WebRTC.
Data & contracts
- Redis · Canvas replay storage and BullMQ backend.
- Shared event contracts · Shared event names, states, and constants.
packages/types/src/events.ts - Payload validation
packages/validation/src/game.ts - PostgreSQL / Prisma · Persists users and game results, not active rooms.
prisma/schema.prisma - Docker Compose · Provisions local and production service dependencies.
docker-compose.yml
Connections 22
- Arena UI → Game state store: renders state from
- Arena UI → Game socket hook: connects through
- Game socket hook → Socket handlers: Socket.IO events
- Game socket hook → Game state store: updates
- Canvas drawing → Canvas handlers: batched canvas events
- Socket handlers → Room manager: authorized commands
- Room manager → Room: manages
- Room → Game lifecycle: advances with
- Canvas handlers → Redis integration: persist and replay strokes
- Redis integration → Redis: canvas streams
- Socket handlers → Word AI queue: themed word request
- Word AI queue → Redis: enqueue job
- AI worker → Redis: consume jobs
- AI worker → Google Gemini: generate words
- Socket handlers → Voice token service: voice token request
- Voice token service → LiveKit: mint scoped token
- Arena UI → LiveKit: direct WebRTC audio
- Socket handlers → Shared event contracts: uses events
- Socket handlers → Payload validation: validates payloads
- Socket handlers → PostgreSQL / Prisma: records persistent results
- Docker Compose → Redis: provisions
- Docker Compose → PostgreSQL / Prisma: provisions