A collaborative real-time pixel art canvas inspired by r/place, where users can work together to create collective artwork by placing pixels on a shared canvas.
- Multiple Canvas Sizes: Choose from 64x64, 128x128, 256x256, or 512x512 pixel canvases
- Real-time Collaboration: See other users' pixels appear instantly as they place them
- 10-Minute Cooldown: Anti-spam protection with cooldown system and visual timer
- Optimized Performance: HTML5 Canvas rendering with smooth zoom and pan controls
- 16-Color Palette: Curated color selection for vibrant pixel art
- Recent Changes Feed: Live-updating pixel placement history with timestamps
- Responsive Design: Works seamlessly on desktop, tablet, and mobile devices
- Username System: Set your artist name to get credit for your contributions
- Canvas Statistics: View total edits, unique artists, and real-time online count
- Enterprise Security: Zero log injection vulnerabilities with secure logging
- Debug Mode: Comprehensive debugging tools for development (disabled in production)
- Auto-reconnection: Resilient WebSocket connections with automatic retry logic
- Node.js 18+
- Go 1.21+
- PostgreSQL database
- npm or yarn package manager
-
Clone the repository
git clone https://github.com/Vitminee/PixelTogether.git cd PixelTogether -
Set up backend
cd backend go mod tidy -
Set up environment variables
Backend - Create a
.envfile in the backend directory:DATABASE_URL=postgres://username:password@localhost/pixeltogether?sslmode=disable PORT=8080 DEBUG=true # Enable debug logging (set to false for production)
Frontend - Create a
.env.localfile in the frontend directory:NEXT_PUBLIC_WS_URL=ws://localhost:8080/ws NEXT_PUBLIC_DEBUG=true # Enable debug logging (optional) -
Install frontend dependencies
cd frontend npm install -
Start the backend server
cd backend go run .
Backend runs on http://localhost:8080 (configurable via PORT env var)
-
Start the frontend development server
cd frontend npm run devFrontend runs on http://localhost:3000
-
Open your browser Navigate to http://localhost:3000
- Framework: Next.js 15 with App Router
- Language: React 19, TypeScript
- Styling: TailwindCSS v4
- Fonts: Geist Sans & Geist Mono
- Build Tool: Turbopack for fast development
- Language: Go 1.21+
- WebSocket: Gorilla WebSocket
- Database: PostgreSQL
- Real-time: WebSocket-based hub pattern
pixeltogether/
โโโ frontend/ # Next.js frontend application
โ โโโ src/
โ โ โโโ app/ # Next.js App Router
โ โ โ โโโ [size]/ # Dynamic canvas size routes
โ โ โ โโโ globals.css # Global styles
โ โ โ โโโ layout.tsx # Root layout
โ โ โ โโโ page.tsx # Homepage
โ โ โโโ components/ # React components
โ โ โ โโโ CanvasPage.tsx # Main canvas interface
โ โ โ โโโ OptimizedCanvas.tsx # Canvas rendering engine
โ โ โ โโโ ColorPalette.tsx # Color selection
โ โ โ โโโ CooldownTimer.tsx # Placement timer
โ โ โ โโโ ... # Other UI components
โ โ โโโ hooks/ # Custom React hooks
โ โ โโโ useCanvasSync.ts # Real-time canvas synchronization
โ โ โโโ useCooldown.ts # Cooldown management
โ โ โโโ useWebSocket.ts # WebSocket connection
โ โโโ package.json # Frontend dependencies
โโโ backend/ # Go backend server
โโโ internal/
โ โโโ database/ # Database operations
โ โโโ types/ # Type definitions
โ โโโ websocket/ # WebSocket hub and client handlers
โโโ main.go # Server entry point
โโโ go.mod # Go dependencies
- Select Canvas Size: Choose your preferred canvas size from the dropdown
- Pick a Color: Click on any color from the palette on the left
- Place Pixels: Click anywhere on the canvas to place your colored pixel
- Wait for Cooldown: After placing a pixel, wait 5 seconds before placing another
- Zoom & Pan: Use mouse wheel to zoom, Shift+scroll or middle-click to pan
- Set Username: Enter your artist name to get credit for your contributions
- Left Click: Place pixel
- Mouse Wheel: Zoom in/out
- Shift + Mouse Wheel: Pan canvas
- Middle Click + Drag: Pan canvas
- Zoom Controls: Use the +/- buttons or home button to reset view
# Start development server with Turbopack
npm run dev
# Build for production
npm run build
# Start production server
npm start
# Run ESLint
npm run lint# Run development server
go run .
# Build binary
go build -o pixeltogether.exe .
# Run tests
go test ./...
# Install dependencies
go mod tidyThe backend provides a WebSocket endpoint at ws://localhost:8080/ws for real-time communication:
place_pixel- Place a pixel on the canvasget_canvas- Request canvas data for a specific sizecheck_cooldown- Check user's placement cooldown statusupdate_username- Update user's display name
pixel_update- Broadcast when any user places a pixelstats_update- Live canvas statistics (total pixels, unique users)recent_changes- Updated list of recent pixel placementsonline_count- Current number of connected users
- Go Backend: High-performance WebSocket server with concurrent client handling
- Sparse Pixel Storage: Only stores non-white pixels in database for efficiency
- HTML5 Canvas Rendering: Optimized rendering instead of SVG for large canvases
- Real-time Hub Pattern: Efficient WebSocket message broadcasting to all clients
- PostgreSQL Indexing: Optimized database queries with proper indexing
- Non-blocking Operations: Goroutine-based architecture prevents client blocking
- Zero Log Injection: All user input is sanitized and never logged directly
- Secure Logging: Production logs contain only safe, validated data
- Input Validation: Comprehensive validation on both frontend and backend
- CORS Protection: Configurable origin restrictions for WebSocket connections
- Rate Limiting: Cooldown system prevents spam and abuse
- Safe Error Handling: Error messages don't expose internal system details
Enable comprehensive logging for development:
Backend:
DEBUG=true go run .Frontend:
NEXT_PUBLIC_DEBUG=true npm run dev- Detailed WebSocket Logs: Connection events, message types, and state changes
- Canvas Operations: Pixel placement tracking and validation steps
- Database Operations: Query execution and result verification
- Performance Metrics: Connection timing and retry attempts
- Error Tracing: Detailed error context for troubleshooting
For production, ensure debug logging is disabled:
# Backend
DEBUG=false
# or simply omit the DEBUG variable
# Frontend
# Omit NEXT_PUBLIC_DEBUG or set to false- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
This project is open source and available under the MIT License.
If you enjoy PixelTogether, consider supporting the project:
Found a bug or have a suggestion? Please open an issue on GitHub.
Made with โค๏ธ by the PixelTogether community