Making match day feel live without lying about it
Match day is the theatre. If the scoreboard just flips to full time while you are looking at something else, then as far as you are concerned the afternoon never happened. I wanted a fixture you could sit through. What I did not want was to pretend the maths was running live when it wasn't.
The engine side came first: a data-driven commentary registry. Weighted variants with anti-repetition, so the same phrase doesn't come round twice in ten minutes. Token expansion for player and team names. Multi-line sequences for open-play shots and goals, because a goal is a build-up and a finish, not one sentence. And — the part I am most pleased with — commentary draws from its own isolated RNG. The words can never nudge the result. Add an optional match seed and the same inputs reproduce the same events, the same stats and the same wording, which makes the whole thing testable instead of vibes. Tactical settings got tightened in the same pass, so opponent-relative effects actually bite rather than sitting there as decoration.
The product side is the trick. Competitive matches simulate ahead of kickoff and get stored. Anything that would spoil the result stays hidden until the broadcast window closes. Then from the scheduled kickoff, every client walks the stored timeline minute by minute, on its own, deterministically — same match, same minute, same words, for everyone watching. No websockets, no streaming, no heroics. Friendlies sit out of all this: they simulate at kickoff, publish straight away, and a cosmetic replay if you want one. Freezing the league UI because someone arranged a bounce game would be a silly way to punish them.
The load-bearing decision was making the API gating and the client reveal share one timing model. Two clocks would mean two ideas of what minute it is, and then "live" becomes an argument. The nice thing about doing the reveal client-side is that it costs nothing to scale and looks identical to everyone. The less nice thing is that anyone who can read the wire still needs the server to withhold scores and events during the window, so that withholding is part of how the product behaves, not an afterthought.
I never seriously considered true realtime simulation streaming. It is romantic and it is a lot of operational weight for a game where you are mostly making decisions before and after the whistle. This gets you the feeling for a fraction of the cost. And the pieces are now in place for something more ambitious later — matches already exist minute by minute, so a proper replay is a presentation problem rather than an engine one. 😁