← All projects

Personal projectIn production

Fantasy Hockey

An eight-player league, from draft night to game day.

Fantasy Hockey season overview showing Tokyo Draft, third place in an eight-team league, roster alerts, current games, and standings.
Inside the first official season

Live usage

8 players · First official season

Running in production, with live drafting, roster management, and NHL-based scoring in one shared league.

The short version

The problem
Commissioners need a fair draft and managers need a clear view of players, rosters, and standings. Underneath is one hard problem: keeping league state consistent when people act at the same time.
What I built
A fantasy hockey app covering setup, live drafting, roster management, NHL-based scoring, and season archives. The React interface connects to Firebase, and server-side workflows enforce draft turns, roster limits, and player ownership.
Fantasy Hockey season overview showing Tokyo Draft, third place in an eight-team league, roster alerts, current games, and standings.
A season in progress

The production league overview brings season points, lineup alerts, current games, and standings together. Captured October 4, 2026; live points are provisional.

Screenshot viewer. Choose Actual size, then use the arrow keys or Page Up and Page Down to inspect the image.

A season in progress

Open original (opens in a new tab)Fitted to your screen.
Screenshot source & context

The production league overview brings season points, lineup alerts, current games, and standings together. Captured October 4, 2026; live points are provisional.

One draft, one set of rules

Snake-draft order, player search, active and reserve slots, queues, and server-controlled automatic drafting all depend on the same authoritative pick logic. A pick checks membership, team ownership, the current turn, roster capacity, season, and draft generation.

Two requests can compete for the same player, or a retry can arrive after a pick has already succeeded. Firestore transactions keep the player claim and draft state together. Repeating an accepted request can return its saved result instead of adding a second pick. Discord uses the same transaction, with signed requests and duplicate-delivery controls.

Every pick follows the same path
  1. ValidateMembership, turn and roster rules
  2. CommitPlayer claim and draft state together
  3. RecoverAccepted retries return the saved result
Completed Fantasy Hockey snake-draft board showing eight team columns and 176 of 176 picks.
Eight teams. A completed draft.

The production draft board shows all 176 selections completed across eight teams. Captured October 4, 2026.

Screenshot viewer. Choose Actual size, then use the arrow keys or Page Up and Page Down to inspect the image.

Eight teams. A completed draft.

Open original (opens in a new tab)Fitted to your screen.
Screenshot source & context

The production draft board shows all 176 selections completed across eight teams. Captured October 4, 2026.

Roster changes without rewriting history

The original draft and game-date roster history are retained separately. One-for-one free-agent replacements have exclusive reservations and a defined weekly effective time.

A replacement changes the intended future scoring period without changing who earned earlier points. The current roster and the historical scoring roster answer different questions, so the data model preserves both.

Follow the game behind the fantasy points

Game Centre brings the NHL scoreboard, player statistics, play-by-play, and an interactive shot map into the league. Managers can see which events involve their roster and inspect where attempts happened on the ice.

The interface distinguishes provisional live points from finalized season scoring. Shots without location data remain in the event list instead of disappearing from the game record.

Fantasy Hockey Game Centre showing Winnipeg versus Detroit, an interactive rink with shot locations, and a shot-event list identifying the manager's players.
From a live game to a play on the ice

The Rink view connects NHL shot locations to an event list and highlights the manager's players. Production capture, October 4, 2026; this game was in progress.

Screenshot viewer. Choose Actual size, then use the arrow keys or Page Up and Page Down to inspect the image.

From a live game to a play on the ice

Open original (opens in a new tab)Fitted to your screen.
Screenshot source & context

The Rink view connects NHL shot locations to an event list and highlights the manager's players. Production capture, October 4, 2026; this game was in progress.

Correctness with a reference to check against

My scoring validation shows exact displayed-score agreement across 143 of 143 player-seasons using an independent reference dataset. One fully reconstructable team with no roster transactions also matched at 1,053.87 points.

This validates arithmetic for the reference statistics. Twelve of thirteen scoring rules were represented in real reference data; the goalie-goal rule was covered synthetically. It does not establish every live ingestion path or an entire production season.

Decisions & evidence

Interface & product decisions

Designed around a live draft

Responsive layouts, searchable player lists, clear turn ownership, and active/reserve distinctions help managers make picks with shared state visible.

Multiple interfaces, shared authority

Web and Discord picks use the same rules. The Discord deployment is configured for one league, server, and channel; it is not presented as a self-service integration for arbitrary leagues.

Useful states beyond the happy path

The interface distinguishes empty, loading, unavailable, and error states, with light and dark themes and team identities.

Evidence & scope

Scoring validation

The app is in production with eight players in its first official season, as of October 4, 2026. Separately, the repository's scoring parity report covers 143 player-seasons. That reference-data check does not establish a fully verified live season.

Usage reflects an owner-confirmed count of eight players as of October 4, 2026. Product screenshots were captured from the production app on October 4. Scoring validation uses an independent reference dataset; it is separate from live-season usage.

Let's
talk.

Looking for someone who can build the whole thing?

Software engineering, applied AI, and thoughtful product work. I'd like to hear what you're building.