Achter de schermen

Een leaderboard
uit het niets

Mario Kart Wii is een spel uit 2008. Geen API, geen webhook, geen enkele officiële integratie. Toch hangt er bij ons een live leaderboard in de gang dat reageert op elke race die iemand rijdt. Dit is hoe.

Hoe we hier kwamen

  1. 2016

    Studentenhuis

    Foto-placeholderHuiskamer studentenhuis
    De gemiddelde toiletsessie is precies lang genoeg voor een potje. Vraag niet hoe ik daarop kwam. Op papier bijhouden kon, maar als de nerd die ik ben was dat niet goed genoeg. Het moest en zou digitaal, met een heus online leaderboard. Maar dat lukte dus niet.
    Niels
  2. 2021

    Popup Plus

    We starten Popup Plus, een ontwikkelbureau in Utrecht. Drie makers, dingen bouwen, plezier hebben. Het leaderboard-idee schuift mee op de achtergrond.

  3. 21-24

    Pogingen

    Door de jaren heen een paar pogingen. Een camera op het scherm laten meekijken. Bestanden uit de Wii proberen te plukken. Niks dat lang genoeg overeind bleef, en allemaal te veel werk voor iets dat puur voor de lol moest zijn.

  4. 2025

    AI, en eindelijk iets dat draaide

    Niet omdat de code voor ons werd geschreven. Wel omdat zoeken naar "hoe lees ik live de positie uit een draaiende Mario Kart Wii" opeens een richting opleverde in plaats van duizend forumberichten uit 2008. Dolphin Memory Engine bleek het antwoord. Een paar avonden later draaide er een Python-scriptje op een MacBook dat voor het eerst een race-positie live uit Dolphin het scherm op rolde. Geen overlay, geen leaderboard, geen QR-code. Wel het bewijs dat het kon.

  5. 2026

    Live

    Eén MacBook in Dotslash Utrecht. Eén scherm in de gang. Buurbedrijven rijden tussen meetings door een rondje, en hun tijden staan binnen een minuut op het leaderboard. Werkt.

De uitdaging

Het idee was simpel: een race-meter waar collega's en buurbedrijven elkaar uitdagen op één race op Coconut Mall. Het probleem: het spel weet niets van het web. Wat het wél heeft is een stuk RAM van 24MB, en daar staat alles in. Positie, lap, tijd, frame counter, finish-tijd.

Dus daar zijn we begonnen.

Hoe het werkt

  1. 01

    Dolphin draait, geheugen ligt open

    Een MacBook draait Dolphin, de Wii-emulator. Een Python-proces haakt via dolphin-memory-engine live in op het geheugen van het draaiende spel. Geen tussenbestand, geen truc met de UI. Direct lezen uit MEM1, op snelheid.

  2. 02

    Geheugen lezen, Wii-stijl

    Big-endian, pointer chains, struct offsets. Allemaal conventies uit 2008. We volgen [0x809B8F70] naar de Raceinfo-struct, lopen door het spelers-array, en plukken er positie, lap, completion en finish-tijd uit. Tientallen keren per seconde, zonder dat het spel er iets van merkt.

  3. 03

    Naar de server

    De parser duwt elke update via HTTP naar een Next.js-server. De overlay bovenop Dolphin polt diezelfde server eens per seconde en rendert positie, lap-tijd en finish over het spelbeeld heen. Op het scherm in de gang draait dezelfde data, maar dan als rotating leaderboard. Coureurs, Constructeurs, en een live-view tijdens een race.

  4. 04

    QR-code, naam, klaar

    Zodra je over de finish komt verschijnt er een QR-code op het scherm. Scannen, naam en bedrijf invullen, en je tijd is geclaimd. MongoDB doet de rest.

Wat we nu lezen

Volgt 0x809B8F70 naar de Raceinfo-struct, dan de spelers-array, dan completion. Live wanneer er gespeeld wordt, anders het laatst geziene snapshot.

Component placeholderAnimatie van de pointer chain met de echte bytes en geparseerde waardes.

Hex en wat het betekent

Wat eruit komt zijn een paar bytes. Wat het betekent staat ernaast.

80 5A 7F 30  00 00 00 04
00 00 00 02  3F 80 00 00
40 40 00 00  00 00 01 0C
  • Pointer0x805A7F30
  • Position4
  • Lap2 / 3
  • Completion3.000
  • Frame268

De stack

Race-detectiePython · dolphin-memory-engine · MEM1 parser
Realtime transportHTTP push · 1Hz poll · Next.js
WebappsNext.js · React · TanStack Query
PersistenceMongoDB
HardwareMacBook · 1080×1920 wandscherm · Wii-controller
LijmVeel koffie · iets te veel zin

Meer