A distributed image generation system that creates images with unique colored pixels through a stateless ping-pong architecture.
Two separate instances ("Ping" and "Pong") collaborate to build an image by exchanging pixels, ensuring each pixel has a unique color.
The system consists of four main components:
- Main Instance - Coordinates the image generation process
- Ping Instance - Adds pixels and forwards to Pong
- Pong Instance - Adds pixels and returns to Ping
- Frontend (React) - User interface for configuration and visualization
All instances communicate via REST API and are completely stateless.
┌─────────────┐
│ Frontend │
│ (React) │
└──────┬──────┘
│
▼
┌─────────────┐
│ Main │◄──┐
│ Instance │ │
└──────┬──────┘ │
│ │
▼ │
┌─────────────┐ │
│ Ping │ │
│ Instance ├───┤
└──────┬──────┘ │
│ │
▼ │
┌─────────────┐ │
│ Pong │ │
│ Instance ├───┘
└─────────────┘
- Django REST API backend with three separate instances
- React frontend with real-time visualization
- Stateless architecture - no data persistence between API calls
- Unique color validation for each pixel (frontend and backend)
- Real-time progress tracking via WebSocket push notifications
- Performance-optimized pixel placement (empty position tracking)
- Benchmarking system
- Docker containerization
- Docker and Docker Compose
-
Start all services:
docker compose up --build
-
Wait ~30 seconds for services to start, then access:
- Frontend: http://localhost:3000
- Main API: http://localhost:8000
- Ping API: http://localhost:8001
- Pong API: http://localhost:8002
-
Stop services:
docker compose down
cd backend
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
python manage.py migrate
# Start Main instance
INSTANCE_TYPE=main PING_SERVICE_URL=http://localhost:8001 PONG_SERVICE_URL=http://localhost:8002 python manage.py runserver 8000
# In separate terminals, start Ping and Pong:
INSTANCE_TYPE=ping PONG_SERVICE_URL=http://localhost:8002 python manage.py runserver 8001
INSTANCE_TYPE=pong python manage.py runserver 8002cd frontend
npm install
REACT_APP_API_URL=http://localhost:8000/api npm start- Initialize an M×N image (all pixels black/unfilled)
- Ping adds the first random colored pixel
- Ping-Pong loop:
- Ping adds a unique colored pixel to a random empty position
- Sends image to Pong
- Pong adds a unique colored pixel to a random empty position
- Sends image back to Ping
- Repeat until all M×N pixels are filled
- Main instance tracks progress throughout
- Maintains a set of all used RGB colors
- Generates random RGB values (0-255 for each channel)
- Checks for collisions (O(1) lookup)
- Falls back to systematic search if random generation fails after 10,000 attempts
- Provides validation endpoint to verify uniqueness
- Image state is passed as JSON in each request/response
- No database or cache required
- Instances can be scaled horizontally
POST /api/start/
Content-Type: application/json
{
"M": 56,
"N": 56
}
Response:
{
"status": "started",
"M": 56,
"N": 56,
"total_pixels": 3136
}GET /api/status/
Response:
{
"active": true,
"progress": 45.2,
"complete": false,
"error": null,
"M": 56,
"N": 56,
"benchmark": {
"total_time": 2.34,
"checkpoints": [...]
}
}GET /api/image/
Response:
{
"image_state": {
"M": 56,
"N": 56,
"image_array": [[[r,g,b], ...], ...],
"pixel_count": 1418,
"total_pixels": 3136,
"filled_positions": [[x,y], ...],
"used_colors": [[r,g,b], ...]
},
"progress": 45.2,
"complete": false
}POST /api/validate/
Content-Type: application/json
{
"image_state": {...}
}
Response:
{
"valid": true,
"pixel_count": 3136
}POST /api/benchmark/
Content-Type: application/json
{
"sizes": [[5, 5], [10, 10], [28, 28], [56, 56]]
}
Response:
{
"results": [
{
"M": 5,
"N": 5,
"total_pixels": 25,
"total_time": 0.012,
"pixels_per_second": 2083.33,
"success": true
},
...
],
"total_tests": 4
}POST /api/ping/process/ (or /api/pong/process/)
Content-Type: application/json
{
"image_state": {...}
}
Response:
{
"image_state": {...},
"complete": false
}Benchmark results for various image sizes:
| Image Size | Total Pixels | Estimated Time* | Pixels/Second* |
|---|---|---|---|
| 5×5 | 25 | ~15 ms | ~1,666 |
| 10×10 | 100 | ~50 ms | ~2,000 |
| 28×28 | 784 | ~400 ms | ~1,960 |
| 56×56 | 3,136 | ~1.6 s | ~1,960 |
| 128×128 | 16,384 | ~8.5 s | ~1,927 |
| 256×256 | 65,536 | ~34 s | ~1,927 |
| 512×512 | 262,144 | ~2.3 min | ~1,900 |
| 1024×1024 | 1,048,576 | ~9.2 min | ~1,900 |
*Performance depends on hardware and network conditions. These are estimates based on local Docker deployment.
curl -X POST http://localhost:8000/api/benchmark/ \
-H "Content-Type: application/json" \
-d '{"sizes": [[5,5], [10,10], [28,28], [56,56], [128,128], [256,256]]}'The frontend automatically displays:
- Total generation time
- Pixels per second
- Progress percentage
- Real-time visualization
The system uses:
- Random color generation with collision detection
- Empty position tracking in a set (O(1) random selection instead of O(M×N) iteration)
- NumPy arrays for fast image manipulation
- WebSocket push notifications (no polling overhead)
- Gunicorn/Daphne workers for parallel requests
- Docker networking for inter-container communication
- Set image dimensions (M and N, 1-4096)
- Click Start to begin generation
- Monitor progress via progress bar, canvas visualization, and statistics
- Real-time canvas rendering with actual RGB colors
- Pixelated rendering style
- Updates via WebSocket push notifications (real-time, no polling delay)
The frontend includes a color uniqueness validation function:
- Click "Validate Colors" button after generation
- Validates all pixels have unique colors
- Shows validation result with duplicate detection
- Works independently of backend validation endpoint
Backend:
- Django 4.2.7
- Django REST Framework 3.14.0
- Django Channels 4.0.0 (WebSocket support)
- Daphne 4.0.0 (ASGI server for WebSocket)
- NumPy 1.24.3 (image array manipulation)
- Gunicorn 21.2.0 (WSGI server for ping/pong instances)
- Python 3.11
Frontend:
- React 18.2.0
- Axios 1.6.0 (HTTP client)
- WebSocket API (real-time push notifications)
- HTML5 Canvas API
Infrastructure:
- Docker & Docker Compose
- Nginx (frontend reverse proxy)
- Stateless Architecture: No database required, easy horizontal scaling
- REST API Communication: Standard HTTP/JSON for inter-service communication
- Real-time Updates: WebSocket push notifications (no polling overhead)
- Image Representation: NumPy arrays for manipulation, JSON for API transfer
- Color Uniqueness: Set-based tracking with random generation and fallback
-
Small Image (5×5):
curl -X POST http://localhost:8000/api/start/ \ -H "Content-Type: application/json" \ -d '{"M": 5, "N": 5}' curl http://localhost:8000/api/status/
-
Color Validation:
# Generate image, then: curl -X POST http://localhost:8000/api/validate/ \ -H "Content-Type: application/json" \ -d @image_state.json
-
Benchmark Test:
curl -X POST http://localhost:8000/api/benchmark/ \ -H "Content-Type: application/json" \ -d '{"sizes": [[5,5], [10,10], [28,28]]}'
- All pixels should have unique colors
- Progress should go from 0% to 100%
- No duplicate colors in final image
- Benchmark should complete without errors
- Connection errors: Check containers are running with
docker compose psand view logs withdocker compose logs [service_name] - Slow generation: Expected for large images (>512×512) due to ping-pong architecture
- Frontend not connecting: Wait 30 seconds for services to start, check browser console for errors
- Memory errors: Large images (>1024×1024) may need 4GB+ Docker memory limit
- WebSocket support for real-time updates
- Redis cache for multi-server deployments
- Image export (PNG/JPEG download)
- Rate limiting and authentication
squaremind-takehome/
├── backend/
│ ├── config/
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── r3p/
│ │ ├── __init__.py
│ │ ├── apps.py
│ │ ├── image_generator.py # Core algorithm
│ │ ├── views.py # REST API endpoints
│ │ └── urls.py
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── manage.py
│ └── requirements.txt
├── frontend/
│ ├── public/
│ │ └── index.html
│ ├── src/
│ │ ├── App.js # Main React component
│ │ ├── App.css # Styles
│ │ ├── index.js
│ │ └── index.css
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── nginx.conf
│ └── package.json
├── docker-compose.yml
└── README.md