How We Built a Massive Online Game in Just One Night!
It was a calm evening, two days before Christmas. I was relaxing in front of my computer, scrolling for the perfect movie to watch, when I…
It was a calm evening, two days before Christmas. I was relaxing in front of my computer, scrolling for the perfect movie to watch, when I suddenly got a WhatsApp group call. It was from two of my friends: the vice chairperson and the publicity committee lead for SLIoT 2026. At the time, I was the technical committee co-lead. The call seemed important, so I joined and invited the other technical committee members as well.
The publicity committee wanted something special for Christmas. “We need to do something that no one in the history of SLIoT has ever done before,” said the publicity committee lead. We totally agreed. He envisioned a marketing campaign to promote SLIoT on Christmas Day — some kind of game where we could award gifts to the winners at the end.
Their initial idea was a treasure hunt-style game, where we’d hide clues on the official website and let players find them. It sounded great, but we didn’t think it was feasible. How could we effectively hide hints on a website? If we got too technical, it might turn into a CTF-style challenge, which our target audience — school children and university students — would find too difficult.
Instead, we suggested creating a classic game on the website with a point system, allowing us to rank players on a live leaderboard. With that, we shifted our focus to finding the perfect game.
The Hunt for the Best Game
Obviously, we didn’t have much time to invent a novel game mechanic, so we planned to clone an existing one. However, choosing the right game was a challenge. It needed to be easy enough for anyone to play, yet difficult enough that not everyone could win (or at least claim first place). Most importantly, the experience had to be fair for players on phones versus computers.
We started brainstorming ideas:
- Sudoku? — Too hard.
- Snake or Candy Crush? — Too easy, and a dopamine overload.
- Minesweeper? — Fun, but with a steep learning curve.
- 2048? — Similar to Candy Crush, with no real math involved.
So, what did we choose? After an hour of research, we landed on the perfect fit: the Memory game.
The name might be generic, but I bet you’ve played it before.

The concept is simple: There’s a deck of cards, and you flip them one by one to reveal their markings and memorize them. The goal is to find matching pairs, which stay face-up once revealed.
The Challenge
The game itself was so straightforward that anyone with a decent AI tool could build it in 10 minutes. But the real challenge was making it multiplayer, especially since the rewards were real-money gifts. Players would do anything — even cheat — to win.
Our main focus became building the game with a secure anti-cheat system. And time was against us: We had only two days to develop, QA test, and ensure it was reliable and bug-free, all before launching on Christmas Day.
The Masterplan
Before diving into development, we crafted a solid plan to maximize security. My friend Charindith — a technical committee member and one of the best security experts I know — and I started drafting it.
Securing the Client Side
We knew securing a web client would be the toughest part. Any script kiddie could open developer tools, inspect the site’s internals, view our JavaScript logic, or even modify variables in memory via the console. The attack surface was massive, and plugging every hole seemed impossible.
The big idea: What if we used WebAssembly? It’s much harder to reverse-engineer; attackers would only see incoming and outgoing requests, and most wouldn’t bother decompiling the WASM. So, we decided to build the client in WebAssembly using Kotlin Multiplatform.
Securing the Requests
Next up: Protecting the requests. There was no point in securing the frontend if someone could intercept and modify outgoing requests, tricking the server into recording false results. Or worse, replay the same request multiple times.
The solution: HMAC (Hash-based Message Authentication Code)
We implemented HMAC, which uses a hash and a secret key to generate a code for each request. This allowed the server to verify authenticity and detect tampering. To prevent replays, we added a nonce system: On game start, the server sends a nonce, and each subsequent request includes it while receiving a new one in response. This chains the requests, blocking replay attacks.
Zero Trust
Even after these measures, we remained paranoid. So, we adopted a Zero Trust approach, decoupling the frontend from the game logic. “The frontend should never handle game logic — it should just act as a terminal, sending user inputs and receiving outputs from the server,” we agreed.
This brought new challenges: If we simulated games server-side, how could we handle thousands of simultaneous sessions without lag?
WebSocket and Redis
Storing sessions in memory was impractical — it risked data loss on crashes or memory overload with high traffic. Postgres wasn’t suitable either. Instead, we used Redis to store sessions as JSON objects, keyed by user ID and session ID. For latency, we switched to WebSocket, slashing input delay from 300ms to 20ms.
The Sleepless Night
We kicked off development around 10 PM, right after the call with the vice chair. After planning, Charindith tackled the backend using Elysia — a high-performance TypeScript framework powered by Bun.
I handled the frontend with Kotlin Multiplatform for WebAssembly, Ktor for networking, and Kamel for image loading.
We worked through the night on a WhatsApp voice call, designing API endpoints, testing requests, and squashing bugs. It was an exhilarating experience — we got so absorbed that time flew by. By around 1 AM, we had our MVP frontend ready.

We spent the next couple of hours fixing bugs, and by 3 AM, we had a fully working game.

After adding images, a live leaderboard, and polishing the UI, we ended up with a sleek, secure game. The sleepless night felt totally worth it.



New Day — New Challenge
The next day, we met again with the SLIoT chairs. They loved the game but noted that the average playtime was too short (about 2 minutes). They wanted something harder and more addictive.
Back to brainstorming, we settled on Sokoban as our second game.
New Changes
Our existing security approach worked well, so we kept most of it for Sokoban. But we had to rethink Zero Trust. Server-side state management suited the Memory game, but for Sokoban — where arrow-key presses need instant grid movement — even minor delays could frustrate players.
The solution: Manage game state client-side for responsiveness, but verify wins securely. Instead of sending a simple “game finished” signal (which could be faked), we sent an array of all player moves.
The server would then replay those moves in its own engine to confirm legitimacy. This approach proved highly effective.
Finally, we added a game selection screen and published the site.


Conclusion
Today, I’m proud to have been part of this experience and grateful for taking on the challenge. If I’d given up, I never would have learned so many new concepts while building this amazing game.