Official Timing, Part 3: League Nights

October 19, 2026 11:07am

FDTV meets my 2011 online league: replays saved by a dedicated server, a modern set of TV graphics with renders of the real cars, a new battle graphic, and a director that no longer misses a spin.

In part one my GTR2 replays got their 1990s TV graphics. In part two they got a TV director that reads the whole race in advance and works the camera for me. Both were tried on races I drove offline against the AI, in replays saved on my own PC.

This part is about the races that mattered more: league nights. In 2011 I raced online, against people instead of AI, in a league I co-founded: the United Racers League. Its races ran on a dedicated server, which kept a replay of every round, and those files have been sitting in an archive folder ever since. This week FDTV learned to read them, got a second, modern set of graphics, a new way to show a fight, and a director that no longer misses a crash.

The league started on a forum. I had joined TF1S, The F1 Society, a Formula 1 forum run by Mansell, to talk about the races. At some point we started holding hotlap competitions there, and those turned into mini championships inside the forum. The idea grew so big that Mansell and I set up a website and forum of our own to host a proper league: the United Racers League.

Modern full-screen starting grid for URL-1 Season 01, round 2 of 8 at Road Atlanta: Fernando Horta on pole for Monster Racing Team, with the car's render on the right

Road Atlanta, 24 September 2011, round 2 of 8. Fifteen years later, the pole position finally gets its TV graphic.

Replays from the server

A replay saved by GTR2 on a player's PC and one saved by a dedicated server look like the same kind of file. They are not, and the differences showed up one at a time.

The first one was the clock. Every replay frame carries a timestamp, and the decoder from part one already knew several layouts for it, found in replays from different years and game versions. The server's replays use one of their own. Until the decoder knew it, the file read as a race with no timed frames at all.

The second was the numbering. On a server, each car keeps the number of the slot its driver joined in, and slots can be empty: in the first round, nobody was in slot 3. The overlay packed its lists of names and cars without the gap, while the positions kept the slot numbers, so every car after the gap wore its neighbour's name. The cars are now renumbered once, before anything else reads them.

The third was people who never raced. Our server had stewards: league staff who joined the races (every round of Season 01, and the odd single-class race in later seasons) to act as the safety car if one was ever needed, and to hand out warnings and penalties live. Stewarding only after the race was a complaint all of us shared, and in GTR2 you have to be in a car to see anything, so the stewards sat in their cars in the garage the whole race. As far as I remember, neither job was ever needed: there was never a safety car call, and our drivers were very well behaved in a very friendly league. But they are cars as far as the replay is concerned, and parked in the pit lane they can be "ahead" of the real field. On the first import they showed up on the front row of the grid, in the scoring tower and in the results. They are hidden now, but not deleted, because the director still needs them: GTR2 lists them in its own driver list, and the director clicks that list by row.

Then the start. A server race does not begin when the replay begins. The cars appear at the centre of the world for a couple of seconds, drop onto the grid, wait out a countdown of up to two minutes while everybody joins, and then take a standing start. The decoder read that as a formation lap, or as a start at 0.1 seconds. It now looks for the moment a third of the field moves off together from a standstill, and on most URL races it lands within a second of the start time in the race log. Dijon is still about three seconds late, because only two cars got away cleanly; I can live with that.

And one I did not expect: GTR2 itself crashes when you rewind a server replay, with or without FDTV running. So for these races FDTV never goes backwards. Go live asks me to reopen the replay instead of sending the game back to the beginning.

Session preview: United Racers League URL-1 Season 01, round 2 of 8, Road Atlanta, September 24th 2011, race distance 34 laps, 135.2 km, with the track outline
Session preview for round 5 of 8 at Dijon-Prenois, November 4th 2011, 36 laps, 133.9 km

The new session preview opens every recording: championship, round, track, date and distance, read from this site's own race records.

The site knows better than the replay

The replay knows where every car was. It does not know much about who was driving it. Names in a server replay are whatever the drivers typed that night, team names come from the car files, and car numbers were reused from one season to the next. The first Road Atlanta import showed a team from another season on one of the cars, because the overlay had looked the team up by car number across every season in the database.

The answer was already on this site. Every URL race is in the racing section, with its classification, grid, teams, penalties and points. FDTV now asks the site first: it finds the race by its date and time, matches every car in the replay to its row in the results (by driver, then by car number within that race only), and takes the name, team, car and country from there. The replay supplies what only the replay has: where everyone was, at every moment. When I correct something on the site later, the race rebuilds itself the next time it goes on screen. For anything the site cannot fix, there is a small fixes panel on the control desk, where I can rename a car, change its team or hide it, for one race only.

The championship comes from the same place. "Round 2 of 8" counts the rounds not raced yet as well, and the standings after the race are worked out by the site's own scoring, not by a copy of it that could drift.

Road Atlanta finish: Jon Wathen's Gulf car passing the grandstand with the winner card, Wathen 39:04.089, and the modern tower showing the finish order with Klempnauer out

The finish at Road Atlanta. I started from pole and finished second; the reason is further down.

A modern look

Part two already had a modern scoring tower down the side of the screen, as an alternative to the classic banner. Everything else still had the classic look, the one F1 television used from 1994 until the early 2000s: the driver caption, the fastest lap, the grid, the classification. Now the modern display has a full set of its own, in the style of current F1 coverage: a driver card that slides in at the bottom, a fastest-lap card in purple, a winner card that stays on from the flag until the results, and full-screen tables for the grid, the race and both championships.

I had one firm rule for the look: colour is for the person, not the list. The team colour goes on the car number and the surname on the cards, and on the big block at the right of the tables (pole, winner, championship leader). The rows of the tables stay plain white. A table with ten team colours in it reads like a box of crayons.

Modern race classification at Road Atlanta: Wathen, Horta, Goggles X two laps down, Klempnauer DNF, with points, and the winner block with Wathen's number 30 and his Gulf car

Drivers' championship after round 2: Horta 94, Wathen 85, Klempnauer 72, Goggles X 63, Funnell 32, Flores 30
Teams' championship after round 2: Gulf 115, Jagermeister Racing 104, Monster Racing Team 94, D2 Motor Gruppe 63

Second place was enough to keep the championship lead. The teams' table pages in after the drivers'.

The cars in those tables are not screenshots. GTR2 keeps its cars in its own 3D and archive formats, and even the usual modding tools could not open the textures properly for me. Claude and I decoded the formats from scratch and wrote a small renderer that puts a car together from the game files, with its team's paint. More than nine in ten of the 517 car models in my install render cleanly; the odd mod that does not is left out rather than chased. The teams get a picture of their own car, and the overlay uses it wherever a car makes sense: the grid, the winner, the championship leader, and the new battle graphic below.

The driver card also tells a story now: from lap 2, if a driver is not where they started, the card says where they started and where they are now.

Dijon, lap 2 of 36: modern tower with Klisch leading, and the purple fastest lap card for Michal Klisch, lap 1, 1:21.389
Dijon finish: Michal Klisch's D2 Porsche on the straight with the winner card, 46:04.324

Dijon, round 5: Klisch's fastest lap on lap 1, and his win 36 laps later.

Two ways to show a fight

The battle graphics from part two compare two drivers' lap times, then show the live gap between them. They were good, with one flaw I had already spotted: on the first laps there are no lap times to compare, so the card showed dashes. Now the lap times wait until both cars have completed two laps; before that, the graphic goes straight to the gap.

Then came a different idea: the two cars facing each other, side on, with the gap in the middle and an arrow showing who is closing. That became the Alternate battle graphic, in both styles, built on the car renders. The classic one goes back even further than the rest of the classic display, to the battle graphics F1 used in 1992 and 1993; the modern one is a bar at the bottom in the style of current F1 coverage, with each driver's place, name and team either side of the gap.

In the modern bar, the gap is coloured by its trend, not by the last tenth of a second: green when the chaser is closing, red when the gap is growing, white when it is holding. The first version compared the gap moment to moment and flickered between colours up to ten times in a fifteen-second battle. Comparing the average of the last two seconds with the same two seconds six seconds earlier brought that down to three changes at most. After seven seconds, the caption under the gap changes to the chaser's last lap compared with the car ahead.

I could not decide which version I liked better, so there is a third setting, Alternating: each new battle uses the other layout, starting with the standard one. Every screen agrees on which is which, so the graphics on the recording and the ones on my control desk always match.

Classic standard battle bands at Road Atlanta: Breed in 2nd and R Joubert in 3rd, a live gap of 0.444 seconds
Classic alternate battle: side renders of Horta's car in 1st and Wathen's in 2nd, a gap of 5.155 seconds with a green arrow

Classic style: the standard bands (an offline race at Road Atlanta), and the Alternate version from the URL round, with the car renders facing each other.

Modern standard battle at Dijon, lap 3: Battle for 1st in the tower, Flores leading Klisch by 0.434, and a Last 2 laps table comparing their laps
Modern alternate battle bar at Dijon: Juliano Flores in 1st, Michal Klisch in 2nd, current gap +0.851 seconds in green

Modern style at Dijon: the battle for the lead in the tower with the last two laps, and the Alternate bar with the gap in green, because Klisch was closing.

The championship prediction changed too. In the modern display it no longer takes over the whole screen in the middle of a race: a small "live drivers' championship" table at the bottom shows the top four as they would stand if the race ended now, with each driver's points from this race and the places gained or lost.

A director that does not miss a crash

The director from part two was trained on AI races with twenty or thirty cars, where something is always happening somewhere. League races are different. The URL rounds had four to ten cars, often spread out over the lap, and the director's habits did not fit.

The first round, at Jacarepagua, showed it. The leader was never challenged, and I was out on my own too. Both of us got bonus points in the director's scoring, so between us we took 91% of the air time, while fights for other places that lasted between two and ten minutes got between 1% and 7%. My own words in the notes from that day: on an eventless race, the biggest crime is making it duller by showing the same car doing nothing for ages. So the rules changed. Fights come first. The leader and I only get our bonus when there is another car within three seconds of us. A car that is not fighting gets 75 seconds at most, and then the camera goes to the best fight elsewhere, or to a car we have not seen for a while.

Road Atlanta showed the next problem. On lap 13 I spun from the lead, Wathen went past, Klempnauer spun as well, and Goggles X stopped. With four cars in the race, the director showed almost none of it. It only knew about passes, lead changes and retirements, and a spin with the cars spread out is none of those. Worse, the stewards parked side by side in the garage looked like a close fight, and one of them got almost five minutes of air time. My note that day: missing an accident with only four cars on track, with the power of knowing the whole race in advance, is not acceptable.

The stewards went first. For incidents, the director now compares every car with its own pace: a moment under half its usual speed that costs four seconds or more is trouble, and a car that went backwards along the track spun. That works for any car on any track, including a slow hairpin, which costs the same second or two on every lap and so never counts. The camera arrives on the car six seconds before the incident, stays through it, and after a long stop comes back five seconds before the car moves off again, to see it rejoin.

The latest step reads more from the replay itself. The decoder now saves which way each car's nose is pointing and where the car is compared with the edges of the road and the pit lane. With that, the director knows a slide from a spin, a moment off the track from a car taking a wide line, and a real pit stop from a slowdown. Pit stops were the oldest gap in the director, and now they have their own shot: on the car six seconds before it stops until four seconds after it leaves, for the front half of the field and for me.

Modern race classification at Dijon: Klisch, Flores, F@RGO one lap down, Horta DNF

Dijon, the other side of the story: second on the grid, out of the race on the opening laps. I still left Dijon leading the championship, with Wathen absent from that round.

The to-do list from part two

Part two ended with a short list. All of it is done:

  • A hide button. One press on the phone blanks every graphic on every screen, so I no longer have to remember to switch the overlay back on in OBS.
  • Recording from the phone. FDTV talks to OBS directly. Go live can start the recording, three seconds before the session preview appears, and stops it a few seconds after the director has finished.
  • A see-through window on the game PC. The graphics now also run in a transparent, always-on-top window over the game, which clicks pass straight through, so I can watch the broadcast while it records instead of picturing it. It is left out of the recording, so OBS still draws the graphics only once.
  • Pit stops, covered above.

The weather card is built as well, with the track state and the air and track temperatures, but it is still waiting for its data: the weather is somewhere in the replay file, and I have not found where yet.

Next: part four, no hindsight

Everything so far works on races that are over. That is the director's superpower: it reads the whole replay before the first frame and has the camera in place five seconds before an overtake. The last item on the list from part two is the one that takes that superpower away: FDTV graphics on a race that is happening right now.

A live race has no replay file to decode. The data would have to come from GTR2's memory while the game runs, read many times a second by the same small companion program that already drives the replay camera. Part of the map is already drawn. The replay clock sits at a fixed address, the same on both of my PCs, and there is one block of memory per car, starting with the driver's name. The running order, the laps, the gaps and the lap times are still unknown territory. If that works, the scoring tower, the battle graphics and the track map could follow a live race, with a different kind of director that has to decide what to show without knowing what happens next, like a real one. And once the memory is mapped, other ideas get much closer, such as a throttle, brake and steering display for the car on screen.

That is part four.

Results and learnings

  • Replays saved by a 2011 league server now get the full broadcast: the decoder knows the server's own timestamp layout, empty slots, stewards, a two-minute join countdown, and a game that crashes when you rewind.
  • The replay knows where everyone was; the site knows who they were. Asking the site first fixed the wrong names and teams for good, where every rule built on the replay alone had fixed one race and broken another.
  • The modern display has its own grid, results, championship tables, cards and battle bar, with renders of the actual cars, made from the game's own files.
  • A director tuned on full grids of AI did not fit small online races. Real races, recorded and watched, gave it its new rules: fights first, no long shots of nothing, and every spin seen.
  • A car's own pace is a better yardstick than any fixed number. "Half its usual speed" means the same thing on a hairpin and on a straight.
  • Small visual details need their own tuning. A gap colour that changes every tenth of a second is correct and unwatchable; a two-second trend is what a viewer can actually read.

As before, this was built with Claude as my pair programmer. I recorded the races, wrote down what was wrong in each one, and set the rules for the look and the director; Claude worked out the server replays, the renderer and the code. The rule I keep coming back to is the same one as in part two: when a shot or a graphic looks wrong, name the rule it breaks first, and only then change the code.

In 2011 these races existed only as a results table and a few memories. Now they come back as television: the same grid, the same mistakes, the same spin on lap 13, with someone finally in the director's chair.

go to racing