A real-time collaborative drawing application where multiple users can draw together on a shared canvas.
Production: https://collaborative-canvas-sgee.onrender.com
Note: Due to Render's free tier, the application has a cold start of 10–15 seconds when accessed after ~10–15 minutes of inactivity.
Application interface showing the drawing canvas and tools panel with brush/eraser tools, color palette, brush size control, and collaboration features
- Clone and setup:
git clone https://github.com/<owner>/collaborative-canvas.git
cd collaborative-canvas
npm install
npm start- Access options:
- Open http://localhost:3000 in multiple browser windows/tabs
- Visit https://collaborative-canvas-sgee.onrender.com
- Works across the internet
- Note: Expect 10–15s cold start after inactivity (free tier limitation)
- Real-time drawing updates from all users
- Other users' cursors in their assigned colors
- Online users count in real-time
- Try undo/redo and clear to verify global operations
See Architecture.png for the system's technical architecture.
- Users get unique IDs and colors on connection
- Cursor positions are ephemeral (not stored)
- Cursors auto-hide after 2 seconds of inactivity
- User list updates in real-time as people join/leave
- Server-side authoritative implementation
- Global scope (affects all users)
- Operations sequence:
- Undo: moves last stroke to redoStack
- Redo: restores stroke from redoStack
- New stroke clears redoStack
- Clear canvas operation is undoable
-
Canvas resets when server restarts (no persistence)
- Cause: drawing state is stored only in-memory on the server
- Impact: all strokes and history lost on restart
-
No rate limiting on WebSocket messages
- Cause: no per-connection throttling
- Impact: potential bandwidth saturation and lag
Total time spent: ~12-16 hours
Authoritative undo/redo is performed server-side (global scope). When undo is requested:
- Server pops last stroke from
operationsintoredoStack. - Broadcast includes updated
canvasStateso each client clears canvas and replays remaining operations. - Redo reverses this by popping from
redoStackback tooperations.
Edge Cases:
- Undo/redo on an empty history returns
null– no broadcast aside from potential button state update. - New stroke after undo clears the
redoStack(standard behavior in editors). - Clear canvas preserves previous operations in
redoStackenabling "undo after clear".
onlineUsers is a Map keyed by userId. Updated whenever users join or leave. Broadcasted lists intentionally include the caller (who filters themselves client-side for UI separation).
Cursors are ephemeral: positions are not stored – only broadcast. Each client manages a timeout to hide inactive cursors after 2 seconds.
The application is deployed on Render's free tier. Please note that due to free tier limitations, the application experiences a cold start delay of 10-15 seconds when accessed after a period of inactivity (10-15 minutes).