Skip to main content

Every point has a story

Bowman World Cup Pool

My family wanted to know what each match changed for their teams and whether they could still catch the leader.

View original
Stephen's owner scoreboard with rank, total points, remaining teams, and points by team

Your place in the pool and the teams behind it. The inspected application was showing bundled snapshot scores, as labelled beside the fixture status.

Source: Original capture of Bowman World Cup Pool · 17 September 2026

My decision

Keep the agreed draw fixed, show each owner their teams, and let them inspect the points behind their place.

The design change
I replaced draw regeneration and manual score entry with an owner-centered sports desk, directing Claude, Codex, and Cursor through shared design rules and browser reviews.
What happened
The delivered app explains points and possible finishes. The archived build record and later snapshot captures show different moments, labelled throughout this story.
Contribution
Product design and AI-assisted development
Facts
Build story
June–July 2026 · from a team draw to a tournament companion
My work
Product direction, interface design, and development with coding agents
Built with
React, TypeScript, and Vite
Data
ESPN's unofficial public endpoints, local cache, and a bundled snapshot

A few teams to make every match personal

After years running pools on Easy Office Pools, ESPN, and Yahoo, I wanted more than another standings table. I wanted the family pool to answer the questions around the television: who owns that team, what did that result change, and is there still a way to catch the leader? Ten owners and a shared draw gave the tournament a smaller, more personal story.

The first version was a team generator. On June 11, the family agreed one canonical draw, BOWMAN-EJA7C2. The next day I removed regeneration. A new draw could change everyone’s position after the agreement; the site’s job was now to follow that agreement, not offer another roll.

How to read the captures

  1. June–July 2026 · building the pool

    Original project artifacts show the draw, design iterations, and finish-state reviews. Their captions distinguish design targets from implementations.

  2. 20 July 2026 · the recorded archive

    The build record describes a deliberate freeze, and the product’s Story page labels its record archived. This does not establish that every route or refresh job stopped.

  3. 17 September 2026 · the portfolio review

    New browser captures show bundled snapshot values while ESPN was unavailable. They document the fallback interface, not verified tournament results or a successful live refresh.

The draw became the starting point

View original
The original draw grid assigns four teams to each owner across four tiers

The draw made the competition personal: four teams to follow, with the rank and slot behind each assignment.

Source: Original draw artifact · project archive

Start with the person following the tournament

A tournament table tells you who is winning. A family pool needs another layer: which teams are yours, what their results earned, and how far you are from the leader.

I organized the experience around owner pages. Each page brings rank, total points, the gap to first place, and team status into one overview. From there, you can inspect individual teams without losing the context of your place in the pool.

Open the score and see where it came from

At first, the plan still depended on a scorekeeper. I removed a dormant shared scoresheet, then went further: why ask someone to type results that were already public? The next decision removed manual score entry and derived points from match data.

That shifted the work from maintaining totals to making the rules understandable. A family pool needs a score people can question and an explanation they can find.

A total you can inspect

View original
Brazil's expanded points breakdown with seven scoring events adding to 23 points

Opening Brazil's points breakdown reveals match results, group placement, and advancement bonuses. These seven entries account for the displayed 23 points in the captured snapshot.

Source: Original capture of Bowman World Cup Pool · 17 September 2026

A single total hides the rules. I put the scoring events behind an expandable summary, keeping the overview short while making the calculation available when someone wants to check it.

The scoring model derives points from match results and tournament progression. It replaces manual score entry with a shared set of rules applied to the tournament data.

Inspect the original scoring rules

The rules were part of the interface

View original
Original scoring card listing match and advancement points and the fixed draw seed

The early rules card put the point values and draw seed where everyone could inspect them. This is an earlier rule version, not a reference for the current calculation.

Source: Original rules artifact · June 2026 project archive

The first design was not the last word

The early Night Match interface leaned into the atmosphere of a sports broadcast. As standings, fixtures, player data, and research accumulated, the page needed a clearer reading order. I moved toward a light sports desk with quieter styling and more direct labels.

The iteration changed more than the palette. “Pool pressure” gave way to “Today at a glance.” I kept standings beside matches, retained the direct owner links, and simplified the language around them.

Compare the two visual directions

Earlier: a broadcast-style dashboard

View original
Early dark World Cup interface with a pressure summary above the leaderboard and match desk

The earlier Night Match design used a dense pressure summary, colored owner chips, and broadcast styling. This historical render contains a different scoring state from the later design.

Source: Earlier interface preserved in the project’s Story assets

Later: standings beside their explanation

View original
Later light sports desk with owner navigation, standings, match results, and a latest-points list

The later sports desk pairs standings with the matches that explain them. Owner navigation stays close to the top; the points trail and rules support a deeper read. Historical capture; displayed scores are snapshot values.

Source: Original desktop capture · July 2026 project archive

I wrote the visual standard into the repository so the next coding session had the same reference. Tokens, page hierarchy, and copy guidance made the design direction available to every agent.

Who can still win, and what has to happen?

Near the end of a tournament, the useful question changes. Knowing who leads is less interesting than knowing whether anyone can catch them. I added a possible-finishes view that connects the remaining match outcomes to the final pool table.

The scenario engine enumerates the two semifinal winners, the champion, and the third-place winner. With all four matches still open, that creates sixteen result paths. Each path runs through the same scoring model as the actual standings, then contributes to each owner's best and worst finish, points range, and number of winning paths.

Inspect the finish-scenario capture

From tournament outcomes to family standings

View original
Possible finishes view pairing owner finishing ranges with semifinal, final, and third-place selections

The scenario interface in its completed snapshot state. All four results are fixed, so the choices are disabled and only one standings path remains. The sixteen-path behavior for unfinished matches was reviewed in source, not exercised in this capture.

Source: Original capture of Bowman World Cup Pool · 17 September 2026

The number of winning paths is a count of possibilities, not a probability. The engine does not assume every outcome is equally likely. Completed matches constrain the remaining paths, and the interface can identify a locked podium or a fully settled table.

That makes the bracket personal. A match matters because of what it can change for the people in the pool, rather than simply because it occupies a slot in the tournament.

Follow a team into the match behind the points

The application extends beyond the leaderboard into group tables, team pages, match previews, and player statistics. Owner markers connect that wider tournament information back to the pool.

In the match-preview implementation, the owners' stakes appear before recent form, head-to-head history, and likely lineups. Additional match statistics and research events carry their own source notes. Missing context has an explicit unavailable state.

The statistics area separates scoring and assists from physical performance and research datasets. Speed, distance, expected goals, and team possession answer different questions, so their labels and units travel with the values. These are source-reviewed capabilities; availability depends on the corresponding feed.

Inspect the match and player detail crops

Make the matchup personal

View complete original
Phone-width match page showing Jake’s Spain versus Emily’s Argentina before form and lineups

Jake’s Spain versus Emily’s Argentina: the owners’ connection comes before form, past meetings, and lineups. This detail shows the owners and recent form; the complete original includes past meetings and lineups. Values belong to the archived application’s match data.

Source: Original 390px match capture · July 2026 project archive

Keep exploring beyond the table

View complete original
Phone-width player statistics with scoring tabs and owner names beside players

The player desk connects individual performances back to the pool with owner labels. This detail shows the view tabs and first three player rows; the complete original retains the full table. Scoring, running, and research remain separate views. Values belong to the archived snapshot.

Source: Original 390px player capture · July 2026 project archive

Add context without changing the score

Keep supplementary match and player data separate from the pool calculation. A richer preview should never silently change the rules behind someone's points.

Three coding agents still needed a design director

I worked with Claude, Codex, and Cursor. My contribution was deciding what to build, setting the visual direction, reviewing the result, and deciding what needed another pass. Shared repository guidance, scoped tasks, and verification checks made those decisions usable across sessions.

The build record documents a blank page despite passing automated checks. The lesson changed the process: inspect the actual page at desktop and phone widths, and keep screenshots beside the review. A passing check could no longer stand in for seeing the interface.

How I kept three coding agents building one product

The app’s build story records the rules behind the work. I kept tokens, visual references, voice, and decisions in tracked repository documents so Claude, Codex, and Cursor could work from the same standard. I owned direction and review; the agents implemented scoped changes.

Parallel work also needed boundaries. Start from current main, give contested files one owner, and give each task an acceptance check. A near-loss of an uncommitted redesign made checking git status before cleanup a written rule. Decisions to decline additional data sources stayed recorded so the next session did not reopen them.

The blank-page incident changed the finish line. Typecheck, lint, and tests were useful, but I also required the rendered page at desktop and 390px, console and overflow checks, and screenshots beside a human review. The comparison below is evidence from that review process.

A review changed what “finished” looked like

View original
Finish Ledger review comparing an approved final-state target with an implementation showing only two locked podium places

Target on the left; implementation on the right. The target shows three podium labels, but the reviewed implementation awards only the two places already locked. Third place keeps its numeric gap.

Source: Original target and implementation comparison · 15 July 2026 design review

Target detail: three podium labels

View complete original
Target podium rows showing Emily as Pool Winner, Jake as Runner-up, and Will as Third Place

Enlarged target detail. All three places have podium labels, including Third Place beside Will. The complete comparison remains available above and through the original-image link.

Source: Detail of original target · 15 July 2026 design review

Implementation detail: third place stays open

View complete original
Implementation podium rows showing Emily as Pool Winner, Jake as Runner-up, and Will with a minus 28 gap

Enlarged implementation detail from the same review. Pool Winner and Runner-up are awarded; Will still has a −28 gap. The unfinished result prevents a third-place label.

Source: Detail of original implementation · 15 July 2026 design review

The same decision at phone width

View original
Phone-width review capture with Winner and 2nd labels while third place still shows a 28-point gap

A closer view of the reviewed behavior: the first two places have labels, while third still shows a gap. The mobile layout shortens the labels without announcing an unsettled result.

Source: Original 390px implementation review · 15 July 2026

The Finish Ledger is a specific example. The target pictured a complete podium; the implementation had to respect an unfinished competition. The July 15 review approved winner and runner-up labels while third place retained a gap. Celebration had to wait for the scoring model to establish the result.

I also recorded decisions to decline additional data integrations. Those written decisions kept later sessions from repeatedly reopening the same scope questions.

One set of results has to tell the whole story

Combining feeds created a less visible design problem. One source might know a match had finished while another still had yesterday's group table. Mixing them could award result points while losing the qualification bonuses that belong to the same tournament state.

I kept results, qualification, and final group placement together in one tournament object for scoring. The documented contract requires the fallback snapshot to contain both matches and group rows. Static fixture metadata can enrich the page, but it does not decide whether a match is final or a team has advanced.

This is the engineering behind a simple promise in the interface: the total and its explanation should agree. The same calculation supports the owner page, standings, and hypothetical finish paths. Repository guards and integration tests encode that boundary.

The application reads ESPN's unofficial endpoints in the browser. It keeps a local cache and a bundled snapshot as fallbacks. That avoids a separate scorekeeping backend, but makes the age and source of the displayed scores part of the interface.

The September portfolio review encountered the fallback state: owner totals and scoring details remained available, with a snapshot label and Retry. That recovery behavior is distinct from the deliberate archive described on the product’s Story page.

Make the source visible beside the score

Preserve the last available view and explain its status. A readable scoreboard should not imply that its data is current when the feed is unavailable.

Let assistants read the record without changing it

The project also exposes five read-only tools: get_standings, get_owner, search_players, get_match, and get_routes. They read the committed pool record, with a route catalog and matching text digest. An assistant can answer an owner’s question without inventing a second copy of the standings.

That integration stays outside the family app. The recorded boundary excludes an in-app agent runtime, score mutation, and draw regeneration. Agents can inspect the record; they cannot change the agreement or points.

Give the pool an ending worth keeping

As the remaining possibilities narrowed, the interface changed from following a competition to remembering it. The finish view replaced gaps with locked podium labels and kept the path through the results available.

The build record describes a deliberate July 20 freeze, and the product’s Story page labels its record archived. The live-data fallback remains a separate behavior in other inspected views. Preserving that distinction matters: an old score can be a recovery state or an intentional record.

Inspect the recorded archive screen

The final screen remains part of the story

View original
Preserved home screen with settled podium labels and no scheduled fixtures

The preserved finish screen gives the pool an ending: settled places and no scheduled fixtures. This older capture still carries a live badge; the current Story page separately labels its record archived.

Source: Original finish-state capture · project Story assets

What began as a draw became a place to follow your teams, question the score, and explore what could happen next. The strongest lesson for me was that the product kept improving when I changed the question—from “what else can I add?” to “what does someone watching this match need now?”

Results

  • A deployed family-pool application connecting the fixed draw, owner standings, scoring receipts, match context, and possible finishes.
  • A documented design evolution from the early dark interface to the lighter sports desk, with target-to-implementation reviews.
  • An archived build story preserving the product’s decisions, iterations, and finish state.

Evidence limit

Original project artifacts and September 2026 browser captures are shown alongside the build record and source review. Images contain application snapshot values, not independently verified tournament results. Historical targets, implementations, and current deployment states are labelled separately. Scenario enumeration and scoring contracts were reviewed in source; the upstream test suite was not rerun. No adoption, uptime, or measured usability improvement is claimed.

Resume and contact