[ 001 · LIVE PRODUCT · WORLD CUP 2026 ]

Gran DT Mundial

My WhatsApp group wanted a simple prediction pool for the World Cup. I offered them something bigger: a full fantasy league. It kept six friends in three countries talking every single day for a month.

[ ROLE ]
Design · build · live ops, solo
[ STACK ]
Cloudflare Workers + D1 · vanilla JS
[ SEASON ]
Jun 11 – Jul 19, 2026 · 104 matches
[ LEAGUE ]
6 teams signed up · 4 played every round
[ DATA ]
3 sources, matched by shirt number + name
Gran DT home screen on mobile: 418 total points, first place, and the final standings
[ 1' · KICK-OFF ]

It started as a prode.

The group chat wanted a score-prediction pool, the kind every Argentine group runs during a World Cup. I counter-offered: what if I build us a real fantasy game (budget, transfers, captains, live scoring) and we play it like a job?

Six friends signed up. Four played every single round. That's the entire user base. Real people with real emotional money on the table, on a tournament clock that doesn't wait for anyone's bugs: when a match kicks off at 21:00, the lineup lock works or the game is broken in front of everyone you know.

With the group scattered across three countries, the league became our shared timezone. Everyone woke up to the same table, argued the same transfers and blamed the same referee.

[ CONDITIONS — BUDGET $0 · FREE TIER — ON CALL: 1 — WINDOW: LIVE TOURNAMENT ]

Gran DT Mundial landing screen: 'Build your team. Beat your friends' league. World Cup 2026', with sign-in form

Mobile-first from day one. The whole league played from their phones.

[ 25' · THE GAME ]

Squad, market, prode,
match center.

Team building with a budget, a transfer market, a prediction pool riding on every match and a live match center, in a dark scoreboard UI with a floating tab bar designed for thumbs.

[ 9' · SQUAD ]

Your team on a real pitch

15 players, a $205M budget, seven formations, two captains. The pitch is the interface: tap a position to sign, tap a player to arm the captain. A photo of your XI is saved for every played round, receipts for the group chat.

Team screen: 3-4-3 formation on a pitch with Kane, Mbappé and Messi up front, $199.5M of $205M budget used

[ 27' · PRODE ]

Two games in one

The prediction pool the group originally asked for lives inside the league: exact score +3, right winner +1. Each round's best predictor earns +2 fantasy points, so the two games feed each other instead of splitting the group.

Prode standings with scoring chips: +3 exact score, +1 winner, +2 best of each round feeding into Gran DT points

[ 63' · MATCH CENTER ]

Every match, accounted for

Goals, cards and substitutions on a two-column timeline, the real XI on the pitch. Once the whistle blows, every fantasy point is itemized per player: minutes, goals, assists, clean sheets, MVP. Nobody ever had to ask why they got 43.

Match detail: Argentina's lineup on the pitch with fantasy points per player, including a red card at minus one point

[ 88' · KNOCKOUT ]

A bracket that fills itself

The knockout tree resolves automatically as group results land: teams, kickoff times and venues written in by the sync engine, never by hand. The one view designed wide-first, because a bracket is a wall chart.

Knockout bracket from the round of 32 to the final: Spain 1–0 Argentina, with France–England for third place

[ SCREEN · DESKTOP — THE ONE VIEW THAT EARNS THE WIDTH ]

[ 45' · DECISIONS ]

Three decisions with real trade-offs.

[ DEC 1 · LIVE ]

Show the match live. Score it when it ends.

During a match you see the real starting XI and every goal as it happens, but fantasy points stay hidden until full time. Live data is provisional data: a goal gets reviewed, an assist gets reassigned. Publishing points mid-match means retracting them mid-match.

[ REF'S NOTE ] Less dopamine during the 90 minutes, zero retractions after them.

[ DEC 2 · DATA ]

Three sources, matched by shirt number.

Results reconcile across three independent sources, matched by shirt number plus name, never name alone. Anything ambiguous goes to a manual review queue instead of into the standings. A wrong score in a friends' league isn't a bug, it's a scandal.

[ REF'S NOTE ] Points sometimes arrive minutes late. They never arrive wrong.

[ DEC 3 · CRAFT ]

Professional standards nobody asked for.

WCAG-minded accessibility, and an admin panel where every destructive operation runs as a dry-run first and takes a backup before executing. For four players, none of it was necessary. I was the only one on call, so the rails were for me.

[ REF'S NOTE ] Days of work no player ever sees, until the one time it saves the tournament.

[ 60' · THE VAR ]

How a result becomes a result.

The result pipeline is the part of the product players never see and completely depend on. It ran unattended every 30 minutes around each match, built like a VAR: it can be slow, it can't be wrong.

[ 78' · CRAFT ]

The team sheet.

1Accessibility

aria-live toasts, modals with real focus management and Escape, AA contrast on the dark palette, reduced-motion respected globally, screen-reader labels where emoji carry meaning.

10Share card

A canvas-drawn 1080×1350 card of your team, one tap from the home screen. Designed for the group chat, which is where this league actually lived.

9Web Push

Push notifications hand-rolled on the Worker (VAPID plus encryption, verified before deploy). One reminder about two hours before each round's first match: enough to save a friend's lineup, not enough to be spam.

[ 90'+ · FULL TIME ]

[ INCIDENT · DISCIPLINARY ]

One friend, sinking in the table, declared the app itself was mufa (bad luck) and started fielding players who played against Argentina, purely to jinx them.

On July 19, Spain beat Argentina 1–0 in the final. The last matchday ran, the pipeline scored it, and the table settled.

Segurola y HabanaYerba Mala Nunca Muere

[ LAST ROUND · FIRST TIE ALL TOURNAMENT · NO TIEBREAKER ]

After 104 matches and eight scoring rounds, the top two teams, mine and a friend's, finished dead level on 418 points. We had never been tied before, at anything, all tournament. The game has no tiebreaker, so it ends exactly like that: shared.

One footnote, for honesty: the prode went to a third friend, 90 points to our 84 and 84. The tie is the fantasy table only.

[ DESIGNED, BUILT AND OPERATED SOLO · AI AS A DEVELOPMENT TOOL ]

The tournament ended.
The app didn't.

Gran DT Mundial is still live. It's a private league, so the door shows a login, but everything you just read is running behind it. If you want a walkthrough, I'll happily give you the tour.

Let's talk LinkedIn ↗ Live app ↗