A full-stack real-time multiplayer drawing and guessing game built with React, Node.js, Socket.IO, and Redis. Players take turns drawing words while others guess, with real-time synchronization, scoring, and AI-powered drawing recognition.
- Real-Time Multiplayer Gameplay: Up to 6 players per room with live drawing synchronization
- Interactive Drawing Board: Canvas-based drawing with color selection, undo functionality, and eraser tool
- Word Guessing System: Players guess the word being drawn with real-time feedback
- Scoring System: Dynamic scoring based on how quickly players guess correctly
- Room Management: Automatic room creation and player matching
- Game States: State machine pattern with Waiting, Drawing, and Finished states
- Persistent State: Redis-based game state persistence with automatic TTL management
- Responsive UI: Modern, responsive design built with React and Tailwind CSS
- Node.js with Express - RESTful API server
- TypeScript - Type-safe development
- Socket.IO - Real-time bidirectional communication
- Redis (ioredis) - State persistence and room management
- Docker - Containerization
- React 19 - UI framework
- TypeScript - Type-safe development
- Vite - Build tool and dev server
- React Router - Client-side routing
- Tailwind CSS - Utility-first CSS framework
- Socket.IO Client - Real-time communication
- Canvas API - Drawing functionality
scribble/
โโโ backend/
โ โโโ src/
โ โ โโโ app.ts # Express app configuration
โ โ โโโ server.ts # Server entry point
โ โ โโโ controllers/ # API controllers
โ โ โ โโโ apiController.ts
โ โ โ โโโ drawingGuesser.ts # AI drawing recognition
โ โ โโโ game/ # Game logic
โ โ โ โโโ game.ts # Core game class
โ โ โ โโโ gameManager.ts # Game instance management
โ โ โ โโโ roomManager.ts # Room and player management
โ โ โ โโโ states/ # Game state machine
โ โ โ โโโ gameState.ts
โ โ โ โโโ waitingState.ts
โ โ โ โโโ drawingState.ts
โ โ โ โโโ finishedState.ts
โ โ โโโ sockets/ # Socket.IO handlers
โ โ โ โโโ socketManager.ts
โ โ โ โโโ handleSocketConnection.ts
โ โ โ โโโ connectToRedis.ts
โ โ โโโ routes/ # API routes
โ โ โโโ middleware/ # Express middleware
โ โโโ config/ # Configuration
โ โโโ Dockerfile
โ โโโ docker-compose.yml
โ
โโโ frontend/
โโโ src/
โ โโโ App.tsx # Main app component
โ โโโ pages/ # Page components
โ โ โโโ Home.tsx
โ โ โโโ Game.tsx
โ โโโ components/ # React components
โ โ โโโ composed/ # Composite components
โ โ โโโ game/ # Game-specific components
โ โ โโโ DrawingBoard.tsx
โ โ โโโ ChatContainer.tsx
โ โ โโโ Players.tsx
โ โ โโโ GameLayout.tsx
โ โโโ context/ # React context providers
โ โโโ utils/ # Utility functions
โ โโโ config/ # Frontend configuration
โโโ Dockerfile
โโโ docker-compose.yml
- Node.js (v20 or higher)
- npm or yarn
- Redis (for local development) or Docker
- Docker and Docker Compose (optional, for containerized deployment)
-
Clone the repository
git clone <repository-url> cd scribble
-
Install backend dependencies
cd backend npm install -
Install frontend dependencies
cd ../frontend npm install
-
Backend Environment Variables
Create a
.envfile in thebackend/directory:PORT=5000 NODE_ENV=development CORS_ORIGIN=http://localhost:5173 REDIS_URL=redis://localhost:6379
-
Frontend Configuration
Update the socket connection URL in
frontend/src/utils/socket.tsif needed:SocketManager.instance = io("http://localhost:5000/");
Backend:
cd backend
docker-compose upFrontend:
cd frontend
docker-compose up-
Start Redis (if not using Docker)
redis-server
-
Start Backend Server
cd backend npm run devServer will run on
http://localhost:5000 -
Start Frontend Development Server
cd frontend npm run devFrontend will run on
http://localhost:5173 -
Open your browser Navigate to
http://localhost:5173
Backend:
cd backend
npm run build
npm startFrontend:
cd frontend
npm run build
npm run preview- Join a Room: Enter your name and avatar, then join or create a room
- Wait for Players: Game starts automatically when 2+ players join
- Take Turns Drawing: Each player gets a turn to draw a word
- Guess the Word: Other players try to guess what's being drawn
- Score Points: Faster guesses earn more points
- Win: Player with the highest score wins!
The game uses a state machine pattern with three main states:
- WaitingState: Waiting for players to join or between rounds
- DrawingState: Active drawing and guessing phase
- FinishedState: Game completion
- Socket.IO Events:
join-room: Player joins a game roomdraw-command: Drawing strokes synchronized in real-timeguess: Player submits a guessroom-update: Room player list updatesword-update: New word/round startscorrect-guess: Player guessed correctly
-
Redis stores:
- Game state (serialized game objects)
- Room player lists
- Player-to-room mappings
- Active rooms set
-
TTL Management: Automatic expiration (1-2 hours) for cleanup
- Command Pattern: Drawing operations use command pattern for undo functionality
- Debounced Emission: Drawing commands are debounced before sending to reduce network traffic
- Canvas Rendering: HTML5 Canvas API for drawing operations
Edit backend/config/index.ts:
gameTime: 20, // Drawing time per round (seconds)
waitTime: 10, // Wait time between rounds (seconds)Configure allowed origins in backend/config/index.ts:
corsOrigin: process.env.CORS_ORIGIN || "*";GET /api/sample- Sample data endpointPOST /api/guess- Submit drawing image for AI recognition- Body:
multipart/form-datawithimagefile - Response:
{ message: "recognized word" }
- Body:
See the "Real-Time Communication" section above for event details.
Backend:
npm run dev- Start development server with nodemonnpm run build- Compile TypeScriptnpm run watch- Watch mode for TypeScript compilationnpm start- Start production server
Frontend:
npm run dev- Start Vite dev servernpm run build- Build for productionnpm run preview- Preview production buildnpm run lint- Run ESLint
cd backend
docker-compose up -dIncludes:
- Node.js application container
- Redis container
- Automatic dependency management
cd frontend
docker-compose up -dIncludes:
- Multi-stage build (Node.js build + Nginx serve)
- Nginx configuration for static file serving
- Production-optimized build
- API Keys: The Google Gemini API key is currently hardcoded in
drawingGuesser.ts. Move this to environment variables in production. - CORS: Configure appropriate CORS origins for production
- Redis: Secure Redis instance in production (password, network isolation)
- User authentication and profiles
- Custom word lists and categories
- Private rooms with passwords
- Spectator mode
- Drawing history and replays
- Mobile app support
- Enhanced AI drawing analysis
- Leaderboards and statistics
- Custom avatars and themes
ISC
Contributions are welcome! Please feel free to submit a Pull Request.
For questions or support, please open an issue on the repository.