Skip to content
Back to work
ActiveReal-time Systems2025

Velodrome

Real-time multiplayer typing race

Socket.io
Realtime
3
Difficulty modes
20 races
Analytics window
2 Hz
WPM chart
Live preview
velodrome-mu.vercel.app

Overview

A typing race game with live multiplayer over Socket.io, ghost replays of your personal best, and per-key analytics that surface the characters slowing you down.

The problem

Typing trainers are either single-player drills with no stakes, or laggy multiplayer toys. I wanted something that felt competitive and instant, gave you a real opponent to chase even when offline, and actually told you why you were slow rather than just showing a WPM number.

Approach

  • A single useGame state-machine hook owns all timing, scoring, and keystroke logging so race logic lives in one predictable place.
  • Ghost Racer records the keystroke timeline of your personal best and replays it as a translucent opponent; beating it overwrites the ghost.
  • Live multiplayer uses 4-letter room codes; Socket.io broadcasts progress and detects the winner across players in real time.
  • Per-key analytics track mistyped characters over the last 20 races to highlight your problem keys.

Architecture

  • React 18 + Vite front end styled with Tailwind; a Canvas layer renders the live WPM chart sampled twice per second.
  • Node.js + Express signaling server with Socket.io managing rooms, progress broadcast, and winner detection.
  • Local-first storage: race history, personal bests, and ghost data persist in localStorage for fully offline play.
  • Leaderboard backed by MongoDB, degrading gracefully to in-memory storage when no database is configured.

Challenges solved

Replaying a ghost without a second simulation

Re-simulating a past race in parallel would have doubled the game loop and risked drift.

Instead the ghost's position is derived by binary-searching the recorded keystroke timeline against the current race clock, so the replay is exact and nearly free.

Keeping multiplayer honest

Browser typing games are trivial to cheat with paste or autofill.

Paste and drag-and-drop are blocked during races, and losing tab focus mid-race is flagged so suspicious runs stand out.

Performance & optimizations

  • Canvas-based WPM chart sampled at 2 Hz keeps the live graph smooth without re-rendering React on every frame.
  • Standard WPM definition (one word = five correct characters) computed incrementally from the keystroke log.
  • Local-first persistence means the whole single-player experience runs with zero network round-trips.
  • Leaderboard falls back to in-memory storage so the app runs even without MongoDB provisioned.

What I learned

  • A single source-of-truth state machine made an interactive, timing-sensitive game far easier to reason about.
  • You can fake a convincing 'opponent' with recorded data and a binary search, no extra simulation required.
  • Local-first design removes a whole class of latency and reliability problems before they start.

Future work

  • Persisted accounts and global ranked leaderboards.
  • Spectator mode for live rooms.
  • Richer analytics: bigrams and finger-level heatmaps, not just single keys.

Tech stack

ReactViteJavaScriptSocket.ioNode.jsExpressTailwind CSSMongoDB
Next project

Delhi AQI Prediction

Spatio-temporal air quality forecasting