← All case studies Case study

DraftEm.gg: a football management simulation built on real player data

Draft a squad from real Premier League rosters, pick a formation, and simulate a full 38-match season, scored by a player rating engine built from real match statistics rather than hand-tuned numbers.

Product DraftEm.gg
Studio Waffle Samurai
Type Full-stack product build: web app, statistical rating engine, real-world sports data pipeline

01The brief

Build a football management simulation with real depth: draft a squad from actual Premier League rosters or build one from scratch, choose a formation that has genuine tactical trade-offs, and play out a full season against a league of AI-managed clubs. The part that had to be right was the foundation underneath all of it: player ratings that come from real performance data, not numbers picked to feel balanced.

Waffle Samurai built DraftEm.gg end-to-end: the data pipeline that turns real match stats into player ratings, the match simulation engine, and the web app players draft and manage their squad in.

02What we built

A player rating engine built from real data. Every player's attributes are derived from real per-match statistics pulled from the current Premier League season (goals, assists, shots, passes, tackles, duels, and more), with a reliability correction that shrinks a player's rating toward their prior-season baseline until they've played enough minutes for the current season's numbers to be trusted. Attributes are then percentile-ranked within each position group and remapped onto a realistic 40 to 99 scale, so ratings actually spread out instead of clustering in the middle.

Squad building and formations. Players assemble a starting XI, subs, and reserves on a drag-and-drop pitch, with position-group validation so a goalkeeper can't be dropped into a striker slot unnoticed. Six formations are built as a genuine rock-paper-scissors cycle, each with exactly one hard counter and one weakness, rather than being cosmetic flavor text.

A statistically grounded match engine. Goals are drawn from a Poisson distribution seeded by each side's attack and defense ratings, home advantage, and the formation matchup. Match events are then generated afterward, weighted by each player's individual stats, so a squad's best striker is genuinely more likely to be the one who scores, not a random pick from the squad list.

03The stack

  1. Frontend

    React 19 on TanStack Start, a full SSR meta-framework built on TanStack Router, with TypeScript and Vite. Zustand handles squad-builder and in-progress season state (persisted to local storage), TanStack Query handles server-state fetching against the API. The squad-builder pitch is powered by dnd-kit for drag-and-drop with position validation.

  2. Backend

    Laravel 13 on PHP 8.3+, a lean JSON REST API. Auth runs on Sanctum, with guest play built directly into the auth layer: a full season can be played anonymously via a guest token, then claimed into a real account afterward. Unclaimed guest seasons expire automatically after 7 days via a scheduled cleanup job.

  3. Data pipeline

    Real Premier League player and match data is pulled from API-Sports via first-party Artisan commands, one to sync league, team, and per-player-per-season stats, and one to run the rating pipeline on top of them. The prior season is synced too and used purely as a statistical baseline for the reliability correction.

  4. Simulation engine

    A season is a full 20-team, 38-matchday double round-robin, generated with a circle-method scheduling algorithm so fixture pairings vary season to season. Match results come from a Poisson-distributed goal model with a formation-matchup modifier, and a five-tier difficulty system scales AI opponents' ratings only when they're facing the human player, leaving AI-versus-AI fixtures untouched.

  5. Data

    SQLite in development with Postgres and MySQL both supported as production options, via Eloquent. The schema has real relational integrity behind it: leagues, seasons, and teams feed player stats and computed ratings, while a separate game-state cluster tracks each user's squad, fixtures, and results independently.

  6. Infrastructure

    A multi-stage Docker build compiles frontend assets in a Node stage before handing off to a PHP runtime that runs migrations and serves the API. Still early-stage: no CI pipeline or orchestration layer yet, which is the honest next step rather than something we're claiming is already there.

04Why it matters

The interesting engineering in DraftEm.gg isn't the pitch UI, it's the rating pipeline underneath it. Turning raw box-score stats into ratings that feel fair took real statistical care: shrinking small-sample performances toward a reliable baseline, percentile-normalizing so ratings actually spread across their range, and weighting each position differently so a center-back and a striker are judged on what actually matters for their role. The pipeline's own documentation is honest about where it's weaker, like goalkeepers being harder to rate from the data available, which is the kind of detail that's easy to skip and matters when you don't.

  • Player ratings built from real match data, not hand-tuned numbers
  • Small-sample reliability correction so a hot streak can't spike a rating
  • Formations built as a genuine rock-paper-scissors system, not decoration
  • Poisson-distributed match simulation weighted by individual player stats
  • Guest-first play: a full season with zero signup, claimable into an account later
  • Past match results are immutable once played, so a mid-season squad change can never retroactively alter them

Want a product built with this level of statistical care?

Get in touch