DEV Community

Cover image for how I revived and scaled Vim Royale, a pvp vim based multiplayer game to 200+ users
Jitesh Kumar Sahoo
Jitesh Kumar Sahoo

Posted on • Edited on

how I revived and scaled Vim Royale, a pvp vim based multiplayer game to 200+ users

GitHub “Finish-Up-A-Thon” Challenge Submission

Vim Royale: The Project I Kept Postponing Until I Finally Shipped It

This is a submission for the GitHub Finish-Up-A-Thon Challenge

What I Built

Vim Royale is a competitive PvP Vim editor game where players race to fix the same broken code snippet using real Vim motions in a real editor. First one to finish wins.

At a glance, it sounds like a simple idea: take the speed, precision, and muscle memory of Vim, then turn it into a head-to-head game.

In practice, it became a much bigger and more interesting project than I expected.

What started as “just a Vim game” grew into a full competitive platform with:

  • Realtime 1v1 gameplay
  • Match replays
  • Tournament creation and invites
  • Live spectator mode
  • Vim keybinding import, including .vimrc-style mappings
  • Leaderboards and persistent player progress

The stack behind it:

Layer Tech
Frontend React + TypeScript (Vite) + CodeMirror + Vim mode
Backend Go + Gin + WebSockets/SSE
Database PostgreSQL
Infra Docker

Live app: vimroyale.com

Demo: YouTube

GitHub Repo: GitHub

Why I Wanted to Build This

I’ve been using Vim for the last 4 years, and at some point I realized something: practicing Vim is usually a solo activity.

You read tutorials, repeat motions, maybe go through vimtutor, and slowly improve over time. That works, but it doesn’t capture the part that makes games fun: pressure, feedback, rivalry, and replayability.

I wanted to build something that made Vim practice feel competitive.

Not “gamified” in the shallow sense, but actually game-like. Two players. Same challenge. Same starting point. Pure execution. You either move faster, think cleaner, and make fewer mistakes, or you lose.

That idea stayed in my head for a long time.

The Comeback Story

This project had been sitting with me since last year.

My first serious attempt was in Elixir/Phoenix. I got much farther than most abandoned side projects ever do, and for a while I thought that version would be the one I shipped.

But I kept running into friction, especially around frontend/editor-heavy work. Integrating npm-based editor tooling into that setup was possible, but it constantly felt heavier than it should have. I was writing too many JS hooks and too much glue code just to get basic editor behavior and UI pieces working the way I wanted.

That kind of friction is dangerous for side projects.

Not because it makes the work impossible, but because it slowly drains momentum. You stop building the product and start wrestling the stack. Then you postpone decisions. Then you pause for a few days. Then suddenly weeks are gone.

A few weeks ago, I finally made the decision I should have made much earlier:

Stop overthinking and switch to the stack that would let me finish.

So I rebuilt it using:

  • React for frontend flexibility and access to the npm ecosystem
  • Go + Gin for a simple, predictable backend
  • PostgreSQL for durable match, tournament, and user data
  • Docker to keep local setup straightforward

That switch changed everything.

The moment I moved to a setup that matched the problem better, progress sped up. CodeMirror became a huge unlock. React made the editor and UI integration much smoother. Go gave me a backend that was easy to reason about for realtime systems.

Instead of fighting the framework, I could focus on the actual game.

What Went Into Building It

Once the foundation felt right, the scope expanded naturally.

I didn’t just want a proof of concept where two people could type in a shared room. I wanted it to feel like a real competitive product. That meant building around the core match loop, not just the loop itself.

Some of the biggest pieces were:

Realtime Match Flow

This is the heart of the project.

Two players enter a match, receive the same broken snippet, and edit in real time with Vim controls. The game has to stay responsive, synchronized, and fair. That meant handling live editor updates, match state transitions, win conditions, and reconnect edge cases cleanly.

Realtime features are always more work than they sound. Even when the idea is simple, the system around it usually isn’t.

Match Replays

Replays were one of the features I was most excited about because they make improvement visible.

It’s one thing to know you lost. It’s another to actually watch how the other player solved the problem faster, where you hesitated, and which motions cost you time.

That required storing enough gameplay data to reconstruct the session meaningfully, not just saving the final result.

Spectator Mode

Competitive games are more fun when other people can watch.

Live spectating adds a lot of energy to matches, especially when you imagine friends joining a room, watching a tournament round, or seeing someone pull off a clean solution under pressure.

It also changed how I thought about the app. Once you support spectators, you’re no longer building just a tool for players. You’re building an experience around the match.

Tournaments

Tournaments made the whole project feel more complete.

A one-off duel is fun, but tournament structure creates stakes. Brackets, invites, lobby flow, event updates, and progression all make the game feel more like something people can organize around rather than just try once.

Vim Keybinding Import

This was one of the most niche features, which is exactly why I wanted it.

People who use Vim seriously often have custom mappings that shape how they play. Supporting .vimrc-style keybinding import made the experience feel more personal and more authentic. It also made the game feel less like “Vim-inspired controls” and more like actual Vim muscle memory.

The Hardest Part

The hardest part wasn’t writing a single specific feature.

It was building something that felt true to both sides of the idea:

  • It needed to feel like a game
  • It also needed to feel like Vim

If it leaned too far toward “game,” the editor experience would feel fake.

If it leaned too far toward “editor simulator,” the product would feel dry and intimidating.

The balance was important. The UI had to stay approachable. The gameplay had to stay fast. The editing had to feel legitimate enough that actual Vim users would enjoy it.

That tension shaped a lot of product decisions.

Working with GitHub Copilot

Copilot helped most in the places where momentum usually dies: repetitive scaffolding, context switching, and debugging weird issues.

A few areas where it genuinely helped:

Day-to-day autocomplete

It sped up implementation across React components and Go handlers, especially when I was wiring similar state, props, API types, and response shapes repeatedly.

Generating boilerplate

Scaffolding component structure, helper functions, and repetitive glue code got faster. That matters more than it sounds. A lot of side projects stall not because the hard parts are impossible, but because the boring parts pile up.

Single-player mode starter code

Instead of starting from a blank file every time, I often had something usable to react to and adapt.

Learning React while building

This was my first serious React project. Copilot helped me understand patterns faster and debug issues without constantly dropping out of flow to read docs from scratch.

The useEffect double-fire mystery

This was a real time sink. useEffect was running twice in development but not in production, which made it feel like a ghost bug. Copilot pointed me toward React Strict Mode behavior, and that saved me from chasing the wrong explanation for hours.

Copilot did not build the project for me.

But it absolutely helped me keep moving, and for a project like this, momentum was everything.

What Finishing Taught Me

The biggest lesson from Vim Royale was simple:

The best stack is usually the one that reduces friction enough for you to keep going.

I spent too long treating stack choice like a theoretical optimization problem. In reality, the most important thing was whether the tools matched the shape of the project and kept me in motion.

Once I accepted that, things clicked.

The second lesson was that unfinished ideas don’t become real through better planning. They become real through reducing resistance and shipping smaller pieces until the project has a heartbeat.

For a long time, Vim Royale was just a concept I liked talking about.

Now it’s live. People can play it. They can invite friends, spectate matches, replay sessions, and compete.

That difference means a lot to me.

What’s Next

There’s still a lot I want to explore.

Some ideas I’m excited about:

  • More game modes
  • Better progression and ranking systems
  • More replay and analysis tooling
  • More snippet variety and challenge design
  • Stronger onboarding for players who are curious about Vim but not advanced yet

The nice thing is that now those ideas have a real home. They’re not floating around as “maybe someday” concepts anymore.

Closing Thoughts

Vim Royale means a lot to me because it combines something I genuinely enjoy using with something I genuinely enjoy building.

It took longer than I wanted. I changed stacks. I lost momentum. I restarted. But I finished it, and that matters more than the version history of how I got there.

If you enjoy Vim, competition, or weird coding games on the internet, give it a try:

vimroyale.com

And if you check it out, I’d love to hear what you think I should build next.

Top comments (1)

Collapse
 
jitesh117 profile image
Jitesh Kumar Sahoo

would love y'all's feedback on vim royale!
check it out at vimroyale.com