Everything lives in a single file: index.html. There is no build step, no bundler, no dependencies, and no package manager. Open the file directly in a browser to run it.
index.html is divided into three sections inline:
CSS (inside <style>) — dark Minecraft-style theme. Responsive breakpoints at 820 px (two-column grid, H2H card full-width) and 600 px (single column). Rank colors are applied via inline style attributes generated in JS, not CSS classes.
HTML — static shell only. The #results div is fully replaced by innerHTML on every compare. The match history table (#mh-tbody, #mh-load-more, #mh-count) are the only elements mutated after initial render (by loadMoreMatches()).
JavaScript (inside <script>) — all vanilla, no frameworks. Organised as:
| Layer | Functions |
|---|---|
| API fetch | fetchProfile, fetchVersus, fetchMatches, fetchSharedMatches |
| Data helpers | eloToRank, fmt, fmtTime, fmtRate, fmtDate, countryFlag |
| Match parsing | eloChange, parseMatch, parseSharedMatch |
| HTML builders | buildCard, buildH2HCard, buildMatchesHtml, buildMatchRows, buildMatchHistorySection |
| Orchestration | compare() (main entry point), loadMoreMatches() |
Base URL: https://api.mcsrranked.com
| Endpoint | Used for |
|---|---|
GET /users/{nickname} |
Player profile, ELO, rank |
GET /users/{n1}/versus/{n2} |
Head-to-head win counts |
GET /users/{nickname}/matches?type=2 |
Recent matches for each player card |
GET /users/{n1}/versus/{n2}/matches?type=2&page={n} |
Shared match history table (paginated, 10/page) |
All responses are { status: "success", data: … }. Only fetchProfile throws on failure; the others return safe empty values.
Profile (/users/{nickname}):
data.uuid,data.nickname,data.eloRate,data.eloRank,data.country- Stats live at
data.statistics.season.{field}.ranked— e.g.data.statistics.season.wins.ranked - Fields:
wins,loses,playedMatches,bestTime(ms)
Match object (from both match endpoints):
match.players— array of{ uuid, nickname }match.result—{ uuid: winnerUuid, time: ms }match.changes— array of{ uuid, change }(ELO delta per player)match.date— Unix timestamp in secondsmatch.forfeited— boolean
Versus (/users/{n1}/versus/{n2}):
data.results.ranked— object keyed by player UUID with win counts, plus atotalkey
eloToRank(elo) maps ELO to { name, color }:
null→ Unrated- 0–599 → Coal I/II/III (100-wide bands within Coal, Coal spans 0–599)
- 600–899 → Iron I/II/III
- 900–1199 → Gold I/II/III
- 1200–1499 → Emerald I/II/III
- 1500–1649 → Diamond I, 1650–1799 → Diamond II, 1800–1999 → Diamond III
- 2000+ → Netherite
mhState is a module-level variable reset on each compare() call:
{ name1, name2, uuid1, uuid2, page, hasMore, loaded }name1/name2 are the raw input strings (used as URL path segments for the versus/matches endpoint). uuid1/uuid2 are kept for ELO change lookup in parseSharedMatch.