StarPath Football's building in the night town from the home page, its billboard playing the app
All work

StarPath Football

Live a footballer's whole career, from 16-year-old prospect to retirement.

Built solo · 499 commits · 1,900+ automated tests · private repo

What I built, in one look

  1. Deterministic, renderer-free match runtime
  2. Kick solver with spin and execution error
  3. One rule for every chance event
  4. Crash-safe, versioned saves
  5. Cross-system effects tested end to end
Read how each one works

How it fits together

  1. Preact UICareer, training, life screens on signals
  2. Match runtimeDeterministic and renderer-free, seeded
  3. Kick solverSpin, power and execution error
  4. Phaser 2.5D rendererDraws what the runtime decides
  5. Versioned savesSHA-256 checksums, crash-safe writes
  6. Electron, Capacitor, PWAOne build for desktop, mobile and web

What it is

StarPath Football is a football career and life simulation. You create a 16-year-old player and live their career week by week: train, play matches, negotiate contracts, earn and spend money, and look after relationships, health and stress. Matches are simulated minute by minute, and at the key moments the game hands you control. A counter-attack, a free kick, a header at the back post, a one-on-one in goal, a penalty in the 90th minute: you play each one in real time with a joystick, taps and swipes, and your attributes decide how well it comes off.

Off the pitch, small choices carry through. A night at the casino before a match day makes you start tired and can cost you your place in the starting XI. A loyal agent gets you a better contract. Neglect your family and your composure suffers when you take the next penalty. The world around you runs its own seasons, leagues, cups, transfers, awards and national-team call-ups. When the career ends, a Legacy mode lets you start again as the child of your retired star.

Key features

  • 33 playable match moment types (counters, 1v1s, free kicks, corners, headers, dribbles, blocks, interceptions, goalkeeper saves, sweeps and penalties), each played in real time on a 2.5D pitch.
  • Stat-driven outcomes: every contested action uses one published rule (+1 % chance per attribute point, capped between 5 % and 85 %), so the stats you train show up in the moments you play.
  • Play outfield or in goal, with keeper moments covering dives, rushing out, wall setup and reading a penalty taker.
  • Week-by-week career: playable training drills, a perk tree, squad role and manager trust, contract negotiation, transfers, national-team call-ups and season awards.
  • Life simulation: happiness, health, stress and discipline; relationships with family, partner, team-mates, manager, agent, press and fans; a bank, assets, businesses, sponsors and social media.
  • A casino with blackjack, European roulette, slots, horse racing and dice, built on honest house-edge maths, with a daily loss limit and an addiction meter that feeds back into the career.
  • A large library of event cards and dilemmas whose choices echo weeks later.
  • Legacy (New Game+): start a new career as the child of a Hall of Fame player.

Take a penalty

The same model as the game: swipe from the ball toward the goal. Length and speed set the power, so a flick that is too hard sails over the bar. The keeper commits once, a moment after the strike.

Swipe the ball to shoot.

0 / 0

How it’s built

Preact UIPhaser match sceneCareer & life simulation60 Hz match runtimeSwipe-to-kick physicsProcedural art & audioChecksummed savesCapacitor · Electron · PWA product machinery

StarPath is a single TypeScript codebase (about 130,000 lines of non-test source) that ships to web, desktop (Electron) and mobile (Capacitor for Android and iOS). It is split into a pure simulation layer and a presentation layer. sim/ holds the deterministic game: sim/world generates a fictional football world (leagues, cups, national teams, referees, transfers) and runs AI-vs-AI fixtures with a Poisson goal model (quickSim.ts). sim/match/engine.ts simulates the hero’s matches minute by minute (fatigue, substitutions, possession, chances with an xG-like quality, cards, injuries, extra time and shootouts) and pauses when a hero highlight is scheduled. sim/career and sim/life model progression, contracts, relationships and the economy, and sim/game/calendar.ts advances time in slots, days and weeks, running the weekly tick for every system. All randomness goes through a seeded, serializable sfc32 generator (core/rng.ts), so a career, a match or a single moment can be reproduced from its seed.

The match moments are the main engineering piece. HighlightRuntime (game/runtime.ts) is a renderer-independent loop that runs fixed 60 Hz steps with bullet-time scaling and owns the agents, ball, AI, rules, outcome resolution and the replay buffer. Ball flight comes from game/physics.ts, a deterministic 2.5D integrator with gravity, quadratic drag relative to wind and Magnus lift from spin. game/kick.ts turns a swipe into a kick: it reads power from swipe length and peak speed, curl from how far the path bends, then solves the launch velocity iteratively so the ball reaches the aimed point under spin, and finally adds an execution error sized by the kicker’s skill, composure and pressure. Because input recording and replay (game/inputReplay.ts) feed the same deterministic runtime, a moment can be reproduced exactly for bug reports and regression tests. A noisy “human bot” (game/humanBot.ts) plays moments at novice-to-expert skill levels for balance measurement.

MatchScene.ts (Phaser 4) only renders: it projects pitch coordinates into an angled 2.5D view and adds a spring-damped follow camera with look-ahead (camera.ts), timed bullet-time ramps (bulletTime.ts), a verlet-cloth goal net (netCloth.ts), slow-motion goal replays and WebM clip export (clipExport.ts). The game uses no image or audio asset files for this: player figures are small 3D skeletons projected and painted to sprite sheets at load time (figures.ts), kits, crowd and pitch are drawn procedurally (art.ts), and all music, UI sounds and the stadium crowd are synthesised in WebAudio (audio/). The crowd textures are rendered in a Web Worker.

The career UI is Preact with signals; ui/backend/ connects screens to the simulation. Saves go through a crash-safe layer (state/save.ts): each write is checksummed into a versioned envelope, written to a staging key, read back and verified, then promoted while the previous save rotates into a ring of backups. Loading falls back to the newest valid backup and runs schema migrations. Underneath is a small key-value interface backed by IndexedDB on web and the Capacitor filesystem on mobile. A cross-system “butterfly” test suite (sim/game/butterfly.test.ts) builds pairs of careers from the same seed, changes one small action, and checks that the effect shows up weeks later.

Tech stack

Language and build
  • TypeScript 6
  • Vite 8
  • ESLint (typescript-eslint)
Match and training scenes
  • Phaser 4.2.1
  • custom 2.5D physics
  • procedural canvas art
UI
  • Preact 10
  • @preact/signals
  • Fontsource (Inter, Barlow Condensed, Teko)
Audio
  • WebAudio synthesis (no audio files)
  • Web Worker for crowd textures
Platforms
  • Electron 44 with electron-builder (Windows, macOS, Linux); Capacitor 8 for Android and iOS (Filesystem, Preferences, Haptics, Status Bar, Splash Screen, Keyboard, Keep Awake); PWA service worker for web
In-app purchases
  • @capgo/native-purchases
Storage
  • IndexedDB (web)
  • Capacitor Filesystem (mobile)
  • SHA-256 checksums via WebCrypto
Testing
  • Vitest 5 with V8 coverage (262 test files)
  • Playwright with @axe-core/playwright for accessibility checks
CI
  • GitHub Actions (typecheck, lint, i18n literal-string lint, tests with coverage, build size budgets, Playwright e2e, Android debug APK, nightly soak run)
Localisation
  • English and Turkish string tables with a pseudo-locale for overflow testing

Engineering highlights

  • Deterministic, renderer-free match runtime. All moment logic runs headless at fixed 60 Hz with bullet-time scaling; Phaser only draws it, and recorded inputs replay a moment exactly. game/src/game/runtime.ts, game/src/game/inputReplay.ts, game/src/game/physics.ts
  • Kick solver with spin and execution error. Swipe length, speed and bend become power and curl; the solver iterates launch heading and vertical speed against Magnus drift until the ball meets the aim point, caps the bend by the kicker’s Curve, and only then applies a skill- and composure-based direction error. game/src/game/kick.ts (analyzeSwipe, swipePower, planKick, solveLaunch)
  • One rule for every chance event. Tackles, take-ons, aerial duels, first touches and penalty reads all use statChance: +1 % per attribute point, the opponent’s points above 50 subtracted, input timing adding or removing points, capped between 5 % and 85 %. Physics such as ball speed or keeper reach is never rolled. game/src/game/statChance.ts, game/src/game/chanceEvents.ts
  • Crash-safe, versioned saves. Checksummed envelopes, a staged write with read-back verification, three rotating backups, season-start milestone copies and schema migration on load. game/src/state/save.ts
  • Cross-system effects tested end to end. A systems map documents who writes and reads every state value, and a test suite runs paired careers from the same seed to confirm that a single changed action has a measurable effect weeks later. docs/SYSTEMS-MAP.md, game/src/sim/game/butterfly.test.ts, game/src/sim/life/echoes.ts