You can't coach what you can't measure: tracking all-time player growth
Pro football front offices spend a fortune tracking how players develop year over year — who outgrew the projections, who plateaued at 24, who never quite became what the scouts promised. In this game we already store every season-end strength bump in player_progression; we just never gave you a place to see those numbers across the whole league at once. players_development.php is that place. And around it, a fistful of smaller fixes that finally make potential ceilings visible at every Scout Director level, kill the last legacy DataTables on game.php and player.php, and stop demo visitors from getting trapped in an empty saved game.
📈 The new headline: all-time player growth
- New side-menu entry under "League Leaders": Player Development renders every active player in the league (excluding the draft pool and players in their career-end year) as a card grid with their cumulative OVR delta since their first season
- The "starting OVR" for each player is the oldest
oldstaerkerecorded for them in the progression table — i.e. the value they had right before their very first Week 26 → Week 1 transition. Current OVR minus that gives you a coloured Δ chip on every card: green for growth, red for decline, grey for stalled - Position filter pills, sort pills (Growth / OVR / POT / Start OVR / Age / Name), mini-pager in the toolbar, large pager below the grid, state persisted to
localStorageper the standard players-page UX. Default sort: Growth ↓ so the biggest risers in the league land first - The original draft of this page took 5+ seconds to load and froze the UI on every sort click — the start-OVR was computed as a per-row correlated subquery and the
ORDER BYon the computed alias re-evaluated it across every player. Refactored to a single pre-aggregatedGROUP BY player + MIN(id)derived-table join that materialises the column in one pass. 5s → <100ms - Five-step inline tutorial (pill next to the heading) with an explicit fresh-game caveat: if no season has transitioned yet, every card reads "+0" because no progression rows exist. The text describes what users will see, not what's on screen on day one
🎯 Max-Potential chip everywhere
- Spotting a player who's already hit his ceiling used to require either Scout Director Level 4 (so you could see both numeric ratings) or the one-shot Week 26 progression message — and the latter vanished after a single viewing
- Now: whenever
staerke >= potential, a small gold-amber 🎯 Max Pot. chip sits in the player's badge cluster next to Rookie / Retire / Injury. Visible at every scout level, on every page that renders a player card (Players, Team, Contracts, Player Detail hero, Expiring Contracts) - The chip is a binary signal — it tells you a player is done growing without revealing the exact potential number, so it doesn't leak the value that the Scout Director gate would otherwise hide
🃏 The last DataTables are gone
- game.php — Game Summary: the 25-column team-stats DataTable is now a head-to-head comparison card. Each stat row reads
[Away value] ━━━ [Home value]with a colour-split bar that mirrors each team's share. Section dividers separate Defense, Special Teams and Injuries so the long list of numbers scans as grouped sections instead of one undifferentiated scroll - game.php — per-team player stats: the six DataTables (three per team for OFF/DEF/SPE) collapse into one filterable card grid per team. Toolbars cover Position, Position group (OFF/DEF/SPE colour-coded), Stat filter ("show only players with ≥ 1 of this stat") and Sort. Per-card stat pills hide when their value is 0 — a kicker doesn't need an empty "Ru Yds" pill
- player.php: seven legacy tables (Renewal Offers, Player BIA, Awards, Statistics, Development, Injury History, History) became card grids. The old "Player BIA" strip — which duplicated everything the hero card already shows — is gone entirely; all the action buttons (Sign FA, Trade Offer, Quick Resign, Negotiate, Release, Persuade, Favorite) now live directly inside the hero card, surfaced contextually based on ownership
- game.php dev box: the local-only debug panel now pulls team strengths from the schedule-row snapshot when a game has been played, instead of the live team values. Previously the hero card showed OVR 82 while the debug block reported "staerkegame 73.89" for the same team — the sim numbers had drifted because the live values are updated by injuries, trades and depth-chart edits, but the chance-count formulas were never re-anchored against them
🔍 Demo mode for visitors who have a save
- The demo game (id 418 on production) used to be reachable only by visitors with a completely empty game cookie. Anyone with a stale or broken save id in their cookie would land on an empty shell — even after clicking
?demo=1, the next click would drop them back into the broken save - Replaced with a sticky
ff_demo_sessioncookie (2h TTL, refreshed on every demo-page hit).?demo=1sets it, every subsequent navigation stays in the demo, and three explicit paths clear it:?exitdemo=1(banner CTA), the game switcher (?continuegame=ID) and creating a new game (?newgame=…) - Bonus safety net in
header_connect.php: if the player's own game id is technically valid but the game has zero player rows (hollow shell from a wiped save), it's treated as not owned and the demo fallback fires. Logs toerror_logwhen triggered so we can spot patterns of broken saves
📋 Contracts page + expiring contracts list
- The Contracts overview now shows career-ending players too — their remaining contracts still count against the cap, so leaving them out under-reported the obligation. They're flagged with a desaturated frame + diagonal hatch overlay + the retire badge so they're obvious at a glance
- The shared
_contracts_blocks.phppartial (used by both Start page and the Team page) migrated to the pcard vocabulary: 📋 Expiring Contracts row carries Negotiate / Quick Resign / Release; 🪦 Career-ending row carries only Release + Persuade (gold CTA when the player can still be talked out of retirement)
🐛 Smaller fixes worth calling out
- Players search: new "exclude Draft Players" + "exclude Free Agents" checkboxes paired with the existing "Draft only" / "FA only" toggles. Picking "Draft only" + "FA only" together used to return zero (the AND filter contradicted itself) — now correctly OR'd so you get both pools
- "OVR ? n/a": freshly drafted rookies (
draft=2) were incorrectly routed through the draft-scout v2 renderer and showed "?" instead of their real strength. The gate now matches strictlydraft=1(active draft pool only) - EOS forecast: the End-of-Season balance preview on
franchise.phpnow includes the Draft Scout Department weekly cost for the remaining season. For teams paying for multiple scouts this had been under-counting expenses by several million - Scouting v2 auto-priority: enabling the auto-pick toggle before Phase 3 used to apply the boost silently — but the UI still showed "0 / 24 slots in use". The Phase 3 generator now materialises the auto-picked ids into
team.scouting_priorityand the list locks at W21 (when Phase 3 has consumed it) instead of W22 - Sticky tabs after dismissing a notification: tab bars on
draft.phpandteam.phpstayed mid-screen on scroll-up because theirupdateStickyTopsfunction was scoped inside an IIFE and never exposed onwindow. The notification dismiss handler walkswindow.update.*Stickykeys — adding the assignment fixed the snap-back - Team Schedule highlight at season end: when there was no upcoming game, the "highlight the next game" code fell back to highlighting every played game in team color2. Fixed: explicit single-row mode means zero highlight when the chosen id doesn't exist
- Negotiation overlay: POT showed "?" instead of the star rating at Scout Director Lvl 2-3 — the gate was off-by-one compared to every other player card. Fixed
- Player Development reasons rendered as raw text: the
grundcolumn contains server-built<font color="green">…</font>markup.team_pcard.phpandplayer.phpwere escaping it withhtmlspecialchars, so the user saw raw HTML tags. Both call sites now echo verbatim and reasons render as coloured chips
Pulling together a season's worth of player development was the missing piece for long-term roster planning — pair the new Growth page with the Max Pot. chip and you can tell at a glance which young guys are still climbing, which veterans have stalled, and which trades make sense before contracts run out. And with game.php and player.php off the DataTables train, the entire in-game shell now reads with the same card vocabulary on a phone as it does on a desktop.