Felix AnderssonSenior Fullstack Engineer, home

Montevideo

Résumé
All work

06 / 07

LOLIMPACT

Which lane decided your League game, and which enemy to watch before the next one starts.

Role
Solo: product, statistics, design, frontend and backend
Year
2026
Interface
English and Spanish, light and dark

The public deploy is running without a Riot API key right now, so the match screens here come from a local run.

The story

The story

A win-probability model for League of Legends, trained on recent Emerald+ LAS solo queue games. You load your Riot ID and each game opens with its conclusion: which lane decided it, how your team’s chances moved minute by minute, and which enemy was the biggest threat at each minute. Held-out accuracy climbs from 62.8% at minute 8 to 74.9% at minute 20.

The hard part was honesty. A model with one slope per champion turned out to be unidentifiable, so slopes are grouped by role and champion class, and one finding survived the audit: an enemy marksman turns gold into wins faster than anyone else in their role. The draft tool and every game name that marksman as the win condition before the first minute. Everything else comes with its range, and a plain “not sure” where the data can’t tell.

In the screenshot
LoLImpact match view: recent games on the left, each with a one-word story such as Lead lost; the open game says “You lost mainly through mid lane.” above a chart of the team’s win chance by minute, with its margin of error as a grey band.LoLImpact match view: recent games on the left, each with a one-word story such as Lead lost; the open game says “You lost mainly through mid lane.” above a chart of the team’s win chance by minute, with its margin of error as a grey band.
  1. Every game gets a one-word story, read from how its win chance moved.
  2. The conclusion comes first: which lane decided the game, in plain words.
  3. Hand-built SVG timeline: 50% and 95% bands around each minute, keyboard navigable.

Engineering

Three things worth a closer look

  1. 01

    One model per minute

    Logistic models at minutes 8, 10, 12, 15, 18 and 20, trained on a time-based split with regularization picked on a validation slice. Each exports its full covariance matrix, computed from the Hessian.

  2. 02

    Uncertainty without an ML runtime

    Error bars come from the delta method at request time. Percentiles use 201 precomputed quantiles instead of a 130 MB CSV, so production only needs FastAPI, pydantic and numpy.

  3. 03

    A Riot client that respects limits

    Thread-safe rate limiting (20 per second, 100 per two minutes), key rotation tied to the key that issued each ID, Retry-After on 429, backoff on 5xx, atomic cache writes and a degraded mode.

  • Svelte 5
  • TypeScript
  • Vite
  • Python
  • FastAPI
  • numpy
  • scikit-learn
  • Riot API
  • Vercel

More screens from LoLImpact

Select a screen to enlarge it

Draft and win condition
On a phone

Build sheet

Stack
Svelte 5, TypeScript, Vite, Python, FastAPI, numpy, scikit-learn, Riot API, Vercel
Scale
  • 6 per-minute models
  • ~4,200 lines
  • 21 Svelte components
  • Light and dark
Typefaces
  • Martian Mono
  • Geist
Palette
#E7E5E1#F2F1ED#0D0D0F#D62828#9A9A9A