Changelog
April 24, 2026
Night-Before Teams, a Playbook, and Expanded Profiles
Teams now auto-assign the night before each game — you get an email with your color (Black, White, or Blue) and your roster, and the game detail page flips from a flat roster into three bordered team cards. The Playbook moves to its own page covering both on-court rules and off-court community standards. Profiles pick up pronouns, an Instagram handle, and a private gender field used only to help balance teams.
Auto Team Assignment
- About 24 hours before each game (10–12 or 15–18 signups), an algorithm assigns players to Black, White, and Blue teams using height, a skill signal (highlights per past game), positions, gender distribution, and past-team variety across the last 5 games
- Every assigned player gets one email with their team color and teammates. The subject reads
You’re on Team Black for Apr 27; the body shows the team color block, a teammate list, and a link to the game page - Roster changes between assignment and tip-off (late signups, cancellations) trigger a stability-first rebalance — only players whose color actually changed get an update email
- At T−1h, admins get a “final teams” email summarizing the roster, sub counts, and late changes
- Admins can regenerate or clear any game’s teams from the admin win-recording page, which now also prepopulates the winning team picker with the auto-assigned teams
- A plain-language explanation of how the algorithm picks teams lives in
TEAM_MATCHING.mdin the repo
Team Cards on the Game Detail Page
- When teams are assigned, the game page now shows three bordered cards — Black, White, Blue — each with a 2px team-color border, the orange-triangle-style corner accent (in the team’s color instead), a hairline kicker bar, and the team’s roster
- Before teams are assigned, the roster consolidates into a single Rostercard with the site signature blue border + orange triangle. As the week goes on, this one card evolves into the three team cards — same chrome family throughout
- A note under the team name in the team-assignment email clarifies that team names match jersey colors. The page repeats the note below the card grid so first-timers know what to grab at the gym
- Mobile orders the Teams card above the Details card so the changing content surfaces first
Pronouns, Instagram & Gender
- Pronouns— a free-text field (placeholder
she/her, he/him, they/them) that shows on your public profile under your name when set. Moved up to slot 03 in the profile editor since it relates to how you’re addressed - Instagram handle— optional, with an Instagram glyph on your profile that links out. When we share highlight clips on our Instagram account, we’ll tag the handle. Clear it to stop tagging
- Gender(Woman / Man / Nonbinary / Prefer not to say) — optional and always kept private. Used only as one of several signals the team balancer uses to spread non-male players evenly across teams. Never shown on your profile
- Height is now requiredwhen you save your profile, since the balancer can’t work without it. Existing profiles without a height stay as-is until they next edit
- Username section renamed and reworded so it no longer reads as “claim your Instagram handle” after the new IG field
The Playbook
- New /playbook page with two sections. The On the court section has the existing house rules (first to 7, foul calls, sub rotation, disputes)
- The Off the courtsection is new — Respect, Harassment, Privacy, Consequences, and Reporting. Spells out the behavior standards and a warning → suspension → permanent-removal ladder
- Linked from the game-detail Questions card, the game-confirmation email, the team-assignment email, and every email footer
- Replaced the inline playbook on the thank-you ticket with a “Read the full playbook” link so the rules have a single canonical home
Policy Updates
- Privacy Policy now covers the new profile fields, including an explicit note that gender is private and never displayed. A new Automated Team Matchingsection discloses the algorithm’s inputs, that gender isn’t surfaced, and how admin override works. A Your Choices section explains how to edit or clear any field
- Terms pick up a Community Conduct section referencing the Playbook and a Profile Content section noting that pronouns, Instagram handles, and photos are public
- Effective date bumped to April 24, 2026
Faster Avatars
- The dashboard and games list now use the optimized avatar component everywhere — no more broken-image placeholders when clicking through pages quickly
- Optimized avatar variants cache at the Vercel edge for a week. The first player to load a page warms the cache; everyone else gets a near-instant hit after that
- The first six avatars on each game row load eagerly so you don’t see them fade in after the page renders
- When a player uploads a new avatar, the previous file is now removed from storage instead of sitting there orphaned. Cleans up historical orphans on the next upload too
Details & Roster Refactors
- The Details section on upcoming games is trimmed from four cards to two (Location, Questions). Date and Time were duplicative of the game-ticket hero above; time window is now a small caption under Location
- Location card has a small map pin icon next to “Upper East Side” — clicking still opens Google Maps with the full venue + street
- Questions card picks up a Playbook link next to WhatsApp and Email
- Past games drop the “Hoopers” H2 and gray tray around the roster — the bordered ROSTER card stands on its own alongside the video
Smaller Things
- Email template app-name prefix removed from subject lines (the sender address already carries the brand) — “Monday Hoops NYC: You’re playing Apr 27” becomes “You’re playing Apr 27”
- Test-mode email redirect helper (
EMAIL_REDIRECT_TOenv var) routes every outbound email to a single inbox, so testing team-matching against the prod database can’t notify real players - README rewritten with current stack, dev setup, architecture overview, and a documentation index pointing to the SIM files, TEAM_MATCHING.md, and the rest of the docs
- Two new scripts for one-off inspection:
scripts/inspect-team-balance.tsprints per-team balance for a game;scripts/profile-coverage.tsreports what percentage of active players have each balancer field filled in