01Overview
fifa-rivals started as a joke to make FIFA games with my office friends more competitive. Every match gets recorded in a single data.json file, and everything else — leaderboard, streaks, head-to-head, club aggregates — is computed in the browser from that data.
02What Was Built
- ELO leaderboard — base 1200, K=32, computed in date order. Deterministic: same data, same ratings every time
- Two leagues — ELO, form, and streaks are computed per league. Cross-league matches count as Exhibitions: shown in history, but move no ELO
- Head-to-head — full matrix of all players plus per-pair duel details
- Club stats — per-club aggregates (global and per player) with real club crests
- Stat cards — each player can download a 1080×1350 PNG stat card, share-ready for Instagram and WhatsApp
- Records — longest winstreak, biggest win, highest-scoring match, most frequent rival
03Making ELO Fair
This was the part that took the most tries. A plain ELO formula is easy to write, but getting ratings that everyone at the office accepted as fair was not. Where it landed: ratings are recomputed from scratch in date order so the result never depends on when you look, each league keeps its own ELO, and cross-league matches count as exhibitions that move no rating.
04Why No Framework
It is a for-fun project, so it should stay light. The whole site is plain HTML, CSS, and vanilla JS — no build step, no dependencies, no backend. Stats live in a pure computation module (stats.js) shared between the browser and a plain Node test file. Updating the site means editing one JSON file and pushing — Caddy serves it straight from disk.