Retrospective

Started as a C assignment. Rebuilt from scratch 13 years later.

In the spring of 2013, two students spent a semester building a Tron light-cycle game in C — SDL for the screen, FMOD for the sound, a Makefile, and a lot of doxygen comments nobody wanted to write. In 2026, one of them rebuilt it in the browser, porting the simulation function by function.

One semester, in C

LIF7, Université Claude Bernard Lyon 1. A shared SVN repo, then git. The commit messages, verbatim:

  1. 13 Mar 2013

    Premier ajout du projet

  2. 19 Mar 2013 · matthieu

    Ajout de l'uml *.dia — the module diagram that the header files then had to match.

  3. 2 Apr 2013

    Les motos Bougent et créent leur Mur...Ca MAAARCHE!!

  4. 9 Apr 2013 · matthieu

    les angles des virages sont propres — the turn geometry, pivoting the bike around a corner.

  5. 14 Apr 2013

    Ajout du Bonus fonctionnel, nettoie grille Manette semi-fonctionnel Joueur init à N joueurs.

  6. 1 May 2013 · matthieu

    début de l'IA

  7. 5 May 2013 · matthieu

    On est théoriquement capable de calculer la distance entre deux points de la grille, mais avec 28 000 ! appels ...

  8. 7 May 2013 · matthieu

    algo de M.**** pour le calcul des distances sur toute la grille depuis un joueur ... OK — the flood fill.

  9. 24 May 2013 · matthieu

    Sans les créations de fichiers annexes on fait tourner 7 IA à l'aise Blaise !

  10. 27 May 2013

    On continue avec l'amélioration des commentaires Doxygen, c'est passionnant

  11. 28 May 2013

    Fin de la Fucking Doc

  12. 3 Jun 2013 · matthieu

    IA plus agressive de près. · Code terminé

  13. 4 Jun 2013 · matthieu

    Vrai dernière modif avant presentation.

— then nothing. A README in 2015. Thirteen years of the repo sitting still. —

Rebuilt, 2026

Same feel, same mechanics. A deterministic fixed-step simulation with a Canvas renderer — no engine, no framework.

  1. v0 — the simulation

    bike, trail, collision, match — ported from the C, each module citing the function and line it came from (bougeMoto at Jeu.c:234).

  2. v0.5 — couch play

    Title / setup / countdown / round screens. A menu, instead of editing Constantes.h and recompiling.

  3. v0.7 — the soul

    The three bonuses, the "graze" grace mechanic, gamepads, up to eight players.

  4. v0.8 — feel

    Bloom, screen shake, explosion particles, and sound — every effect synthesised in the browser, since the 2013 soundtrack was commercial music.

  5. v1 — the AI, minus 400 lines

    The same coarse danger grid and BFS distance maps. A new brain: score the three legal moves, pick the best.

Then / now

What the port actually changed.

2013

  • C89 + SDL 1.2 + FMODLinux only, built with a Makefile in Code::Blocks.
  • Constantes.hRecompile to change the player count or the win score.
  • srand(time(NULL))Called all over — the RNG reseeded mid-game.
  • choisieDirection~450 lines of nested if/else for the AI.
  • clock()CPU-time frame pacing that drifted on fast machines.
  • Daft Punk, TRON: Legacy OSTStreamed through FMOD.

2026

  • TypeScript + CanvasRuns anywhere with a browser. Built with Bun.
  • a setup screenPick players, humans, AI level, rounds — no rebuild.
  • one seeded RngThreaded through the tick. Same seed, same game.
  • brain.tsA scored evaluator over three moves. ~90 lines.
  • fixed 20 Hz stepDecoupled from an interpolated render.
  • a synthwave bedOscillators and filtered noise, generated live.

The AI, before and after

Both versions do the same thing: flood-fill the grid, find the nearest reachable opponent, choose a turn. Only the choosing changed.

Jeu.c — choisieDirection
if(directionCourante==HAUT){
  if(colonne1>=distanceSecurite){
    for(i=1;i<=distanceSecurite;i++){
      if((*grilleDistance)[ligne1][colonne1-i]==-1){
        boolDistanceValide=0;
      }
    }
    if(boolDistanceValide==1){
      JeuActionClavier(joueurIA,GAUCHE, ...);
    }
    else{
      if(ligne1<=distanceSecurite){
        JeuActionClavier(joueurIA,DROITE, ...);
      }
      else{
        /* ...four more levels... */
      }
    }
  }
}
else{ if(directionCourante==BAS){ /* ... */ } }
brain.ts — computeAiMove
for (const { dir, move, straight } of candidates) {
  const clear = clearAhead(danger, headIdx, dir, margin);

  let score;
  if (clear < margin) {
    score = -1e9 + clear * 1000;        // unsafe
  } else {
    score = floodFill(danger, enter, distMove);   // room
    if (chasing) score += (maxDist - dist[enter]) * weight;
    if (straight) score += straightBias;
  }

  if (score > bestScore) {
    bestScore = score;
    bestMove = move;
  }
}

≈ 450 lines of branches → one scored loop. The tree was a specific answer for every board state someone could think of. The loop is a general one: how much room does this move leave, and does it close on the target.

Artefacts

Three things that survived the move.

Condensed UML module diagram from the 2013 project
The module diagram, 2013. Drawn in Dia before the code. The header files had to match it — that was the assignment. The remake keeps the same shape: Moto, Mur, Grid, Bonus, Jeu.
The 2013 game's title screen
The 2013 title screen. "TRON — The Grid v2.6".
The 2026 web remake in play, showing neon trails and the scoreboard
The 2026 remake. The trails still fade, the bikes still accelerate forever, the three bonuses still do what they did.

Now playable

Enter the Grid →

2013 — Antoine Caron & Matthieu Billet
2026 — Antoine Caron
source — github.com/Slashgear/projet-tron (the original)