The server-authoritative, real-time multiplayer backend and procedural level generator for the rhythm platform brawler game Beat Bouncers.
This backend is built as a decoupled service, communicating with the frontend clients using standard Fastify REST endpoints and real-time Socket.IO WebSockets.
- Server-Authoritative Physics (60Hz): Complete collision logic, knockback physics, damage accumulation, and blast-zone boundaries computed entirely on the server.
- Real-time Matchmaking: Redis-backed player grouping queues with customizable minimum/target sizes and timeouts.
- Procedural Rhythm Level Generator: Seeded, deterministic level generator placing platform paths and hazard locations (spikes, pulses, orbs) dynamically synchronized with audio beat analysis.
- Asynchronous Processing Workers: Distributed background workers (
BullMQandRedis) downloading audio withyt-dlpand normalising tracks to compliant MP3 formats via secureffmpegchild processes. - Production-Grade Security:
- Distributed Redis rate limiters for REST routes and level download endpoints.
HelmetHTTP headers and CORS configuration.- Sanitized exception filters redacting local filesystem paths and hiding stack traces.
- Clamped Fastify request payload sizes (1MB max).
- Runtime: Node.js 22 (TypeScript)
- Framework: NestJS (using the fast
Fastifyadapter) - Cache & Broker: Redis (via
ioredisandBullMQ) - Media Handling: yt-dlp & FFmpeg
- Containerization: Docker / Docker Compose
Create a .env file in the root directory (based on .env.example):
PORT=3001
NODE_ENV=development
FRONTEND_ORIGIN=http://localhost:5173
REDIS_HOST=localhost
REDIS_PORT=6379
MATCH_MIN_PLAYERS=2
MATCH_TARGET_PLAYERS=4
MATCH_MAX_PLAYERS=5
MATCHMAKING_TIMEOUT_SECONDS=20
GAME_TICK_RATE=60
STATE_BROADCAST_RATE=20
MAX_MEDIA_DURATION_SECONDS=600
MEDIA_STORAGE_PATH=./storage/media
LEVEL_STORAGE_PATH=./storage/levels
YTDLP_TIMEOUT_SECONDS=180Ensure Redis is running on port 6379 locally, then execute:
# Install dependencies
npm install
# Run in development watch mode
npm run start:dev
# Run automated tests
npm run testStarts the NestJS API container alongside a Redis container automatically:
# Build and start services in the background
docker compose up -d --build
# View real-time container logs
docker compose logs -fThe backend service will listen on http://localhost:3001 and Redis will bind its host port to 6380 (internal 6379).
GET /health- Verifies server availability and uptime metrics.
GET /api/config/public- Returns active configurations (WebSocket URL, limits, duration thresholds).
POST /api/media/generate-level- Queue a level generation task for a YouTube track.
- Body:
{"url": "YOUTUBE_URL", "difficulty": "normal"} - Returns:
{"jobId": "JOB_ID"}
GET /api/media/jobs/:jobId- Checks background worker job state (e.g.
active,completed).
- Checks background worker job state (e.g.
GET /api/media/levels/:levelId- Retrieves generated beat locations, platform layouts, and hazard configurations.
GET /api/media/audio/:mediaId- Streams normalized MP3 audio track directly to client canvas games.
- Client Events:
client:joinQueue: Enters matchmaking queue.client:leaveQueue: Exits matchmaking queue.client:ready: Marks player as ready in game lobby.client:input: Sends user control packets (keys:left,right,jump,dash).
- Server Events:
server:queueStatus: Broadcasts updated player counts in queue.server:roomCreated: Broadcasts matchmaking success and room identifier.server:matchCountdown: Broadcasts countdown ticks.server:matchStart: Signals match start and client simulation setup.server:state: Transmits authoritative brawler coordinates at 20Hz.
This project is licensed under the MIT License.