DEV Community

Cover image for How I Built a Real-Time Multiplayer Prediction Game with Next.js, Node, and BigInt Suffix Scaling
Alex Degerman
Alex Degerman

Posted on

How I Built a Real-Time Multiplayer Prediction Game with Next.js, Node, and BigInt Suffix Scaling

I started building a browser-based, real-time prediction game called RPS League about 4 months ago. What began as a static developer take-home assignment has evolved into an active, concurrency-aware betting loop.

The application resolves global matches every 5 seconds, synchronized across all connected players via Server-Sent Events (SSE). To make it scale into massive incremental numbers, I had to solve a series of interesting technical challenges:

  1. Managing High-Frequency SSE Buffering

Real-time events were lagging in production. I bypassed proxy buffering entirely by configuring my Express backend to dispatch the X-Accel-Buffering: no header, ensuring sub-second delivery of match results. To maintain active visual feedback, the main activity feed splices real user bets and simulated traffic. Real user predictions inject instantly at index 0 of the staging queue, while a weighted generator fills the gaps during low-activity windows to ensure consistent interface motion without burying real actions.

  1. The BigInt-First Suffix Engine

Because standard IEEE 754 floats lose precision beyond 9 quadrillion, compounding multipliers quickly corrupted calculations. I refactored the entire stack: unconstrained NUMERIC fields in PostgreSQL, native BigInt operations in Node, and a unified string-serialized formatter on the frontend. The engine takes large numbers, converts them to short-scale suffixes (M, B, T, up to Sextrigintillion and beyond), and maps them directly to animated CSS visual tier classes.

  1. Stateful URL Routing & Bulk Leaderboard Queries

The leaderboard is a unified ranking engine supporting both Predictor and Player profiles. It maintains a stateful URL link structure, parsing parameters (tab, sort, dir) dynamically on client mount. To prevent N+1 database thrashing when rendering large lists with achievement badges, the system first pulls raw ranks, then executes a single bulk transaction (fetchAchievementsBulkBadges) to fetch and map current badge metadata. This queries all required assets in one round-trip, displaying up to 5 curated badges max per row. It also supports custom row overrides (like rainbow or mythical fluid animations) based on specific profile accomplishments.

  1. Page Visibility Tab-Guards for Idle Betting

Completing your first lap unlocks an Idle Auto-Predict mode. Because browsers aggressively throttle timeouts and intervals in hidden/backgrounded tabs, leaving the tab open would normally cause a massive backlog of auto-predictions to fire simultaneously upon tab return, flooding the API. I bound the loop execution directly to document.visibilityState. It immediately pauses all prediction handlers on hide, and safely resynchronizes with the live server state upon tab focus.

  1. Securing a Low-Latency RAG Pipeline

To build the interactive Oracle guide, I integrated the Gemini API behind an Express endpoint with several security layers. Each request combines a TypeScript knowledge base covering relic drop tables, PWA configuration, and user FAQs with live SQL metrics before generating a response. To reduce abuse, the endpoint applies custom local rate limiting, falls back between models if needed, detects financial cashout requests for virtual handling, and uses strict system prompts with input validation to help prevent prompt extraction and SQL injection attempts.

A short showcase demonstrating the visual event systems, seasonal progression tiers, and live-service content developed for RPS League:
https://www.youtube.com/shorts/gEePdwCo-0Y

Live Game: https://rpsleague.fi/
GitHub Repository: https://github.com/AlexDegerman/rps-league-app/

Top comments (0)