Loading
Loading/Simulating...
(Please do not close window!)
x
⚠️

A week of polish: faster pages, less baggage, and a beta invite

Tino H. Tino H.

After last week’s big clear-out the work carried on, in smaller and less dramatic pieces. A few pages were still dragging, two crashes needed hunting down, and Android players now get an invitation to the beta without leaving the game.

⚡ The next batch of slow pages

  • The new monitoring did its job and pointed straight at the worst offenders: My Team, the stat leaderboards and Franchise.
  • The pattern was the same every time. The database had no suitable index to work from, so it waded through an enormous pile of rows to find the handful it actually needed.
  • The season leaderboards had a second twist. The database had two possible routes and kept picking the slower one, no matter what I added. It only sped up once I removed the bad route entirely.
  • All three pages are noticeably quicker now.

📦 How long detailed box scores stick around

  • To stop that from creeping back, there is now a retention rule. Individual game box scores — the per-player line for a specific match — are kept for the last three seasons of each save game. Older ones are cleared automatically.
  • This is the one change in this post that takes something away, so here is exactly what stays, permanently: every result, every standing, records, your players season statistics, transaction history, trophies and achievements. None of that is touched.
  • An old game still opens. You get the final score and the scoring drives — you no longer get the individual stat line for every player who was on the field.

🐛 Two crashes, both my own doing

  • A crash when advancing to the next week from certain pages. I had introduced that one myself a few hours earlier. It is gone again.
  • The Power Ranking page returning a blank screen in one specific situation.
  • Neither was reported by a player. The monitoring caught both, which is exactly the job it was built for.

🤖 Android app: closed testing continues

  • The app is still in closed testing on Google Play. I am not naming a release date while I do not have one.
  • If you play on an Android phone, you will now see an invitation to join the test inside the game.
  • It takes two steps and the order matters: join the Google group first, then open the Play testing link with the same Google account. Do it the other way round and Play will not show you the test build.

Two weeks without a single new feature — from the outside that looks like nothing happened. But a manager game where you wait on every page is not fun to play, however much is buried in it. From here on it goes back to content. If something still feels slow on your end, tell me and I will go look.

One player told me the homepage was slow. It was taking 25 seconds.

Tino H. Tino H.

A player mentioned the front page felt sluggish. I measured it, and then I measured it again because the first number looked like a mistake: almost 25 seconds before the server returned anything. That kicked off two days under the hood — and turned up something considerably worse than a slow page.

⚡ Twenty-five seconds to open one page

  • The cause was not subtle. The homepage recalculated every league-wide statistic from scratch on every single visit, for every visitor, over and over.
  • With a handful of save games that was invisible. Every new save game made the sum a little bigger, and it kept growing until it added up to half a minute of waiting.
  • Those figures are now worked out once instead of on every request. The homepage answers in a fraction of a second.

🔍 The part that bothers me more than the wait

  • That page had almost certainly been broken for weeks. Exactly one person mentioned it.
  • That is how it goes: people report crashes, but when something is merely slow they close the tab and do not come back. There is no bug report for that.
  • So there is now automatic monitoring. The game times itself and tells me when a page takes too long, whether or not anybody complains.

🧹 Six million rows that should not exist

  • Cleaning up the database turned up more than six million rows belonging to save games that were deleted long ago.
  • The reason was a bug of mine, and not a small one. Deleting a save game cleared 19 of the 28 tables that hold its data. The one it skipped happened to be the largest: per-match player statistics.
  • So every deleted save left its full match history behind — and because the save itself was then gone, the nightly clean-up could never find those leftovers again either.

🗄️ What changed

  • The delete now reads the table list from the database itself instead of following a list I have to remember to update. It cannot fall behind again.
  • The nightly routine also sweeps up old leftovers now — data whose save game no longer exists.
  • The largest table dropped from roughly 20 million rows to about 9 million, and around 1.8 GB went back to the server.
  • You will notice this indirectly more than directly: a smaller database is a faster one.

Two days of work and not one new thing to click — and still the best-spent time in a while. If a page feels slow on your end, do tell me. The game catches a lot on its own now, but nowhere near everything.

Football Franchise is coming to the Google Play Store — the Android app is in closed testing

Tino H. Tino H.

It is official: Football Franchise is coming to Android as a native app on the Google Play Store. Right now it is in closed testing — the final step Google requires before a new app can go live for everyone. Here is what is coming, how the process works, and how you can get in early.

📱 What the app brings

  • Football Franchise on your home screen — one tap, full screen, no browser address bar. Its own app icon and a custom splash screen with the mascot.
  • The same game, every feature: draft, trades, salary cap, simulation, Hall of Fame — the full depth of the web version, tuned for playing on the go.
  • A leaner app UI: streamlined header and footer, bigger touch targets, built for phone-first play.

🧪 Why “closed testing”?

  • Google now requires new developer accounts to run a closed test with at least 12 testers over 14 days before an app can be promoted to production — the public release.
  • That is exactly where we are: real testers are playing the app, we are gathering feedback and polishing the last rough edges. A lot of the small fixes shipped over the past weeks came straight out of this testing.
  • Once the test period is cleared and Google signs off on the final review, the app goes officially live.

🙌 Get in early

  • Want the app on your phone before everyone else? Become a tester. Join our Discord — that is where we share the opt-in link for the closed test.
  • Join, install the app, play a few real sessions — every active tester moves us closer to approval.
  • Android first. An iOS version is on the roadmap once the Android app is stable in the wild.

The browser version keeps running exactly as before — the app is an addition, not a replacement. But for everyone who would rather run their franchise from the couch, the train, or a lunch break: there will soon be a 🏈 tap for that. We will keep you posted here the moment the Play Store link is live.

You can't coach what you can't measure: tracking all-time player growth

Tino H. Tino H.

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 oldstaerke recorded 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 localStorage per 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 BY on the computed alias re-evaluated it across every player. Refactored to a single pre-aggregated GROUP 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_session cookie (2h TTL, refreshed on every demo-page hit). ?demo=1 sets 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 to error_log when 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.php partial (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 strictly draft=1 (active draft pool only)
  • EOS forecast: the End-of-Season balance preview on franchise.php now 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_priority and the list locks at W21 (when Phase 3 has consumed it) instead of W22
  • Sticky tabs after dismissing a notification: tab bars on draft.php and team.php stayed mid-screen on scroll-up because their updateStickyTops function was scoped inside an IIFE and never exposed on window. The notification dismiss handler walks window.update.*Sticky keys — 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 grund column contains server-built <font color="green">…</font> markup. team_pcard.php and player.php were escaping it with htmlspecialchars, 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.

Why we killed DataTables: how a unified card system rescued the mobile experience

Tino H. Tino H.

For most of this game's life, every list page leaned on the same crutch: a jQuery DataTable with horizontal scroll, fixed left columns, and a tiny pagination footer. It worked fine on a 1920×1080 monitor. On a phone it was a nightmare. Twenty-seven columns of player stats turn into a swipe-and-squint mini-game when the viewport is 380 px wide.

Over the last two weeks we deleted that pattern. Not minor restyling — actually deleted it, across fourteen pages, and replaced it with a unified card system designed mobile-first. This post is the story of how the pieces fit together and what we learned along the way.

The problem with tables

A table answers one question well: how does this row compare to that row on every column? Spreadsheet thinking. When you actually use the player search on a phone, you don't want to compare 50 players across 27 columns. You want to see one player at a time, with the data that matters, in a layout that reads top-to-bottom.

The 27-column DataTable was solving a problem only desktop users had — and it was solving it poorly there too, because horizontal scroll inside a vertical scroll page is a usability footgun.

One chrome to rule them all

The first decision was visual. Every card across the entire game now shares the same outer shell:

  • 2 px #c8d0dd border — solid enough to separate cards visually without competing with content
  • Soft 0 3px 10px rgba(0,0,0,0.09) shadow — depth without drama
  • Hover lifttranslateY(-1px) + a stronger shadow on hover, instant feedback that this is clickable
  • User-team highlight via a single CSS variable pattern: border-color: var(--row-bg) + inset shadow. Set --row-bg on the article once and the whole card recolors

Player cards, schedule cards, standings cards, draft picks, trade history, achievements, news events, watchlist entries, coins history, ticket sales — they all read as one family now. The eye learns the language once and applies it everywhere.

The sticky chrome stack

Tables had a giant tradeoff: scroll past the header and you forget what column is what. We replaced that with a three-layer sticky stack that follows you down the page:

  1. The team-color tab strip at the very top (Offense / Defense / Special, or seasonal phases on schedule.php)
  2. A position-filter row (QB · RB · WR · TE · OL · DL · LB · CB · S · K · P pills) below the tabs
  3. The sort bar below that, with the active sort highlighted gold

Each layer reads the height of the layer above through CSS variables: top: calc(var(--team-sticky-top) + var(--t5-tabs-h) + var(--pcard-filter-h)). A small JavaScript IIFE measures the page chrome (header + news ticker + notification bar) and writes the root variable. No magic numbers, no broken stacks when the news ticker collapses, no jitter on tab switches.

The inline mini-pager

The full pager at the bottom of a paginated list is fine when you reach the bottom. The problem was getting there: 50 player cards is a lot of scroll. So the sort bar now carries a tiny ‹ X / Y › mini-pager on the right edge — same prev/next handlers as the full pager, but always in your thumb's reach because the sort bar is sticky.

This is the kind of detail you don't notice when it's present and immediately miss when it's gone. Two-finger swipe to scroll down used to mean a long swipe to the bottom and back. Now it's one tap on the sticky chrome.

Mobile-first compaction

The card chrome looks the same on desktop and phone, but everything inside shrinks below 640 px:

  • Player photo: 44 px → 34 px
  • Position badge: 0.85 rem → 0.72 rem
  • Character icons: 19 px → 16 px
  • Toolbar padding: 0.65/0.85 rem → 0.35/0.45 rem
  • Sort pills: 0.32/0.7 rem padding → 0.2/0.55 rem

End result: a fully populated player card with OVR, POT, age, value, salary, team and a CTA drops from ~200 px tall to ~135 px. You see two and a half cards in a viewport instead of one and a half. That's a 65% jump in information density without resorting to a horizontal scrollbar.

The team tab strip got the same treatment — Offense / Defense / Special / Practice / Stats no longer dominate half the phone screen on its own.

Shared renderers, not copy-paste

The temptation when building 14 different card pages is to copy the markup and tweak per page. We resisted, and the codebase is better for it:

  • players_pcard.php renders one player card and is included by players_cards_ajax.php, freeagents_cards_ajax.php, draft_cards_ajax.php, players_stats_cards_ajax.php, and the synchronous server-render on players_watchlist.php
  • _player_leaders_card.php exports both a render function and a standalone CSS emitter — so sister card families that reuse the .pll-* classes (the MVP card, for instance) can guarantee the styles are on the page without rendering a leader-card themselves
  • _game_mvp_card.php was extracted when we realized halloffame and player_stats_leaders were drifting. Same helper, same chrome — the only difference is an optional saison pill that only renders on the multi-saison Hall of Fame view
  • _schedule_cards.php handles every game-list grid: last week, this week, team schedule, full schedule, the trade-history cards even borrow its week pill

When a visual tweak lands (border thickness, hover behavior, mobile compaction), it lands once and propagates everywhere. The alternative — hunting through 14 pages for a copy-pasted style — was a maintenance trap we'd already fallen into twice. Never again.

Special cases that earned their own treatment

  • Power Ranking opens with a podium of the league's top three teams, then every team's card surfaces a prominent power-rank badge top-left and an expandable breakdown of every factor (11 position chips + weights) feeding the formula
  • Trade History mimics the simresult overlay's "Top Trade" card: team-color gradient, ⇄ separator that rotates 90° on mobile so the two sides stack vertically but still read as a comparison, gold "Total Value" pill that drives the sort
  • News events get a four-pixel colored top border per category (player_pos green, player_neg red, finance amber, etc.) so a quick scroll tells you what kind of story is on each card before you read a word
  • Coins History uses a sign-coded left border — green for income, red for spend — for ledger-style glanceability
  • Tickets & Merchandise color-codes home vs. away (green/blue left border) and gold-tints the side that earned your revenue

What we kept

Not everything became a card. The cap-summary table on the Contracts page, the per-team season-stats matrix on team.php, the Hall of Fame trophy wall — these are still tabular because tabular is genuinely the right answer for "compare these N rows on every column." The point was never "no tables ever," it was "stop using a table when a card-per-entity is what the user actually wants."

The phone build is finally usable. The desktop build kept all its information density. Filter, sort, and pagination behave the same on every page in the game. And the next time we ship a new list view, the answer to "how should it look" is already on disk — include pcard_styles.php, drop in players_pcard.php, add a sort bar, you're done.

If you've been playing on mobile, this is the update where the experience stops being a compromise.

Draft Scouting Reborn: the new Coverage Model

Tino H. Tino H.

The biggest system overhaul since the salary rework: the old sampling scouting (one prospect every few weeks, with a random outcome) is gone. In its place sits a coverage model that distributes your scouting hours fairly across the entire draft class, phase by phase — with clear levers, visible probabilities and a cinematic Combine reveal in Week 25. If you take the draft seriously, you finally have real knobs instead of dice.

🧮 Coverage instead of sampling

  • Every scout produces 18 hours per phase. With the maximum of 10 scouts that's 180 h per phase — spread across the ~396 draft prospects in the default "All positions" filter it lands at roughly +11% accuracy per player
  • Hours are distributed via a water-fill algorithm: less-scouted prospects take priority over already-known ones, so the class is raised to an even baseline before you drill deeper
  • Three layers share the budget: Priority (a flat +30%, see below), then your filter (All / Top Team Need / Top Estimate / Unscouted only / Manual), and finally random fill for any leftover hours
  • Weekly cost = season total / 26, booked separately as "Draft Scout Department" on your finances. Down-sizing your scout count is only allowed in Phase 1 (W1–8); upgrades any time

⏳ Four phases, four reports

  • Phase 1 (W1–8) — initial scan. Report drops in W8
  • Phase 2 (W9–16) — deepens coverage. Report drops in W16. The Top Estimate and Unscouted only filters unlock here
  • Phase 3 (W17–21) — Priority Players become active. Report drops in W21
  • Phase 4 (W22–25) — Combine runs at the start of W22. Final report + Combine recap in W25
  • At the end of every phase a teal Interim Report overlay opens: total players per confidence bucket (100% / 75–99 / 40–74 / 1–39%), the Top-5 by OVR estimate, plus a teaser for the next phase. A bell-style notification on every page links you straight in

⭐ Priority Players (Phase 3+)

  • Star your favorite prospects directly on the Big Board (Draft Players tab) or enable Auto-pick
  • Slot limit: scouts × 2 plus bonus slots from the Scout Director (+2 / +4 / +6 at lvl 2 / 3 / 4)
  • Priority players gain a flat +30% accuracy per phase (capped at 100%), independent of the filter. A pick sitting near 30% at the start of Phase 3 typically lands at ~60% after Phase 3 and ~90% after Phase 4 — almost fully scouted, but with a residual surprise built in
  • The list stays editable through W17–W21 and only locks at W22 once Phase 4 has consumed it. A hard block in W16 prevents accidentally simulating into Phase 3 with an empty list — either star prospects, or enable Auto-pick

🏃 Combine in W22 — reveal in W25

  • Invitees: every priority player + scouts × 3 top prospects by current estimate (no team-need bias, so the best athletes show up)
  • Signed shift distribution: -3 (1%) / -2 (3%) / -1 (10%) / 0 (59%) / +1 (20%) / +2 (5%) / +3 (2%). Applied directly to the player's real OVR — no trick, no temporary modifier
  • The Combine column on the Big Board stays hidden until W25 so the reveal moment lands in the final interim report (with severity colors: green for positive shifts, amber/red for drops)

🎯 Big Board & UI

  • Every prospect shows OVR + POT as range pills (e.g. "78–84" with 56% confidence). At 100% scouting the range collapses to a single value
  • The pick-reveal overlay is auto-skipped once confidence = 100% — no noise when you already know everything
  • Mock Drafts in W8 (#1, round 1 only), W16 (#2, all rounds) and W21 (#3, final) give context for the league-wide perception

Coverage instead of sampling, visible phases instead of a black box, Priority + Combine as the final levers: the new draft scouting rewards preparation — and turns every season finale into a small reveal event. Give it a try, the Big Board finally feels like a real front-office tool.

Tutorial pagination, W16 hard block, Top-3 podium and clean lang keys

Tino H. Tino H.

Alongside the big draft scouting rework (see the feature article), a whole batch of smaller improvements has landed: the tutorial gets full pagination + a table of contents, the Phase 3 transition is locked down, the Power Ranking page opens with a fresh Top-3 podium, and the German tutorial text is finally fully translated.

📚 Tutorial: pagination + table of contents

  • Tutorial steps are no longer one endless wall — every step is its own page with "Last Step"/"Next Step" buttons and a counter at the top ("Tutorial Step X of Y")
  • Step 1 now hosts a full table-of-contents grid across all 17 steps — jump straight into any section via "Open"
  • Step 6 (Franchise) and Step 10 (Draft & Scouting) have been fully rewritten — they now match the current UI with all cards (Partners, Staff, Facilities, Finances) and the new coverage model
  • 105 missing DE/EN language keys added — the German tutorial no longer falls back to English in places like "Top 3 Overview" or "1) Scouting Department"

🛑 W16 → W17 hard block

  • The "you haven't set any priority players" notice in W16 used to be a soft overlay that could be dismissed with a click — it's now a real blocker
  • If scouts exist, Scout Director ≥ lvl 1, and Auto-pick is off: no simulation from W16 into W17 without at least one priority star or Auto mode enabled
  • Symmetric fix: the priority list now stays editable through W17–W21 and only locks at W22 — previously it could accidentally "snap shut" after the first star toggle

🥇 Top-3 podium on the Power Ranking page

  • Power Ranking now opens with a gold / silver / bronze podium of the three strongest teams: logo, effective team OVR, division and current record at a glance
  • Quick benchmark "where does my team stand vs. the contenders" before you scroll into the full table
  • A per-team quote under the podium highlights each team's strongest factor (team strength, offense, QB talent, O-line, draft pick capital and so on)

🔧 Under the hood

  • Three new idempotent DB migrations (049 column cleanup, 050 manual positions, 051 signed Combine shift) — safe to re-run on production deploys
  • Saisonwechsel reliably resets scouting_set_pN to "all" and generates the draft class with a factor of 6 (instead of 8) — synchronized with startgame.php, no more 523-player bug
  • Legacy Combine kicker removed that was crashing OVR ranges to "1–81"
  • The footer sim warning is now refreshed live via AJAX after slider changes and priority toggles — no more stale hints
  • Apache request-header limit bumped to 32 KB + a cookie-reset endpoint for the rare oversized-session-cookie case

Lots of small screws, but the tutorial actually feels navigable now, the Phase 3 hand-off is watertight, and the league overview opens with a bit of shine. Pull recommendation: yes.

A Manager's Review of the 2026 Pro Football Draft

Tino H. Tino H.

The 2026 pro football draft was always going to be a quarterback class. What nobody quite expected was how heavily the second day would tilt toward the trenches — particularly interior offensive linemen, who came off the board in unusually concentrated waves between the late second and early fourth rounds. From a manager's perspective there are three story lines worth pulling on: the QB sorting at the top, the run on guards and centers in the middle rounds, and the surprising depth of cornerback talent that fell into Day 3.

The top of the board: quarterbacks went where they belonged

  • Three quarterbacks came off the board in the first eight picks. None of them were the consensus number one heading into the combine, but the order made sense by draft night — pocket presence and second-reaction athleticism beat pure arm talent in the eyes of the rooms that picked highest.
  • The teams that traded up did so cheaply by historical standards. The cost of moving from 12 to 7 was a future first and a Day 3 swap, which suggests the league at large valued the third QB roughly the same as the rebuild teams holding higher picks.
  • For franchises that didn't take a quarterback in round one, the second-tier names sat through Day 2 and were available as developmental prospects in the third round — a pattern that has become more common as teams get more comfortable letting rookies sit and learn.

Day 2: the year of the interior lineman

  • Eleven interior offensive linemen — guards and centers — came off the board between picks 33 and 110. That is unusually concentrated, even adjusting for class strength.
  • The cause is downstream of the QB premium. With more teams paying franchise money to their starting quarterbacks, protecting that investment with a competent interior has become a top-three roster priority. Drafting the position now is cheaper than free-agency repair later.
  • The teams that resisted the run and waited until round four for guards mostly did so because they have an entrenched starting line and were buying depth, not starters. That is a defensible strategy when your unit is already top-ten.

Day 3: the cornerback class that wouldn't end

  • Day 3 produced an unusually deep run on outside cornerbacks. Several prospects who would have come off the board in the third round in a normal year sat into the fifth and sixth.
  • The board pile-up was partly explained by a thin tackle class behind the top six, which pushed teams away from corners early. Whatever the reason, the class will produce more late-round starting corners than usual — managers picking late should treat their fifth- and sixth-round corner picks more seriously than typical Day 3 fliers.
  • Best-value pick of the day, by widespread consensus among draft analysts: a slot corner taken in the sixth round who ran a 4.36 at his pro day and was quietly on a top-50 board for half the league.

Three takeaways for managers planning their own draft

  • Don't fight the QB premium. If your franchise hasn't solved the position, every other draft decision is a partial answer. Move up, take a swing on Day 2, or sit and reload — but don't pretend the question is already answered.
  • Interior offensive line is no longer a Day 3 luxury. The market has shifted. Plan to spend a Day 2 pick on the interior every two-to-three drafts.
  • Day 3 corners are real assets in this class. The board fell strangely; the value is genuine. Hit on one and you have a nickel starter for the next four years on a sixth-round contract.

Most drafts read the same in retrospect: a couple of clean hits at the top, a chaotic middle that the analytics community spends three months unpacking, and a Day 3 with two or three legitimate steals nobody saw at the time. The 2026 class fits that shape with one wrinkle — the trench premium is now a tier above where it was even three years ago, and the teams that adjusted are going to be reaping the dividends through 2030.

How the Pro Football Salary Cap Actually Works

Tino H. Tino H.

The salary cap is the most influential rule in pro football and the one fans understand the worst. It is not a bank balance. It is not a payroll ceiling in the way a household budget is. It is a multi-year accounting structure with a hard limit, deferred liabilities, and a handful of legal levers a smart front office uses to bend the rules without breaking them. Once the structure clicks, every contract decision a team makes starts to look obvious instead of mysterious.

The hard limit: what it actually constrains

  • The cap is an annual ceiling on the sum of every player's cap charge. The cap charge is not the same as the player's base salary. It includes proration of past signing bonuses, restructure money pushed forward from previous years, and any incentives likely to be earned.
  • If the league cap is, say, $250M, the sum of all 53 players' cap charges (plus practice squad and dead money) cannot exceed $250M on the day rosters are submitted. That ceiling is hard. There is no accounting trick that legally goes over it; only tricks that move the charge from one year to another.

Signing bonuses: the cap's most important lever

  • A signing bonus is paid to the player up front in real cash. For cap purposes, however, it is prorated over the length of the contract, up to a maximum of five years.
  • Example. A four-year deal with a $20M signing bonus charges $5M against the cap each year, regardless of how the base salary is structured. Bonus dollars hit the player's bank account immediately; cap charges trickle in.
  • This is why teams open big deals with enormous signing bonuses and tiny first-year base salaries. Year-one cap charge is small, the player gets paid up front, and the back of the contract carries a charge the team plans to deal with later.

Restructures: how a contract changes shape mid-flight

  • A restructure converts a current-year base salary into a signing bonus, which is then prorated forward. The player gets the same money in the same year, but the cap charge gets pushed into future years.
  • This is the lever teams pull to clear cap space without cutting players. It works — until you run out of years to push to. Teams that restructure aggressively in years one and two of a contract often find themselves with a brutal cap charge in year four with no levers left.

Dead money: the cost of being wrong

  • If a team cuts a player whose signing bonus is still being prorated, all the remaining proration accelerates onto the current cap. That accelerated charge is called dead money. It is the largest hidden cost in pro football roster management.
  • Example. A player signed to a five-year deal with a $25M signing bonus is cut after year two. The remaining three years' worth of proration ($15M) hits the next cap as dead money — money the team is paying for a player who isn't even on the roster.
  • This is why long-term deals look cheap on the front and expensive on the back. The math is the same; the timing is what changes.

The rookie wage scale: the cap's best deal

  • Rookies under their initial four-year contract are paid on a fixed scale set by the collective bargaining agreement. A first-round pick costs less than a second-tier free agent at the same position.
  • For first-round picks the team also has a fifth-year option — a one-year extension at a position-specific salary. That fifth-year option contract is functionally the most valuable contract structure in the entire league. A starting-caliber player on a fifth-year option is the closest thing to free production the cap allows.
  • This is why teams that build through the draft can sustain success. Cheap rookie contracts at premium positions create the cap room to pay everyone else market rate.

Five rules of cap management

  • Pay premium positions; don't pay premium players at non-premium positions. Top-of-market deals at quarterback, edge rusher and left tackle are usually justified. Top-of-market deals at running back, off-ball linebacker and safety usually aren't.
  • Don't restructure unless you have to. Every restructure is a loan from your future self at high interest. A team that restructures every contract every year is borrowing against a championship window that may not arrive.
  • Cut declining stars before the dead-money curve gets ugly. The cliff is sharper than fans want it to be. Letting a beloved player walk one year early is almost always cheaper than two years late.
  • Use the rookie wage scale aggressively. First-round picks at premium positions are the foundation. Stack them.
  • Plan two years out, not one. Today's cap room is a snapshot. Tomorrow's cap room is the question that matters.

Once you can read a contract and see all four numbers — base, signing bonus, cap charge, dead-money exposure — the cap stops looking like a wall and starts looking like a chess board. Most fans see only the wall. Good general managers see the board, and play several moves ahead.

How and Where Footballs Are Actually Manufactured

Tino H. Tino H.

For an object that gets thrown around on television by tens of millions of dollars' worth of athletic talent, the football itself is built almost the same way it was a hundred years ago — by hand, in two factories on opposite sides of the world, by people whose job titles haven't changed in three generations. The supply chain is short, the craft is precise, and the difference between a competition-grade ball and a backyard toy is measured in tenths of a millimetre.

The two factories that supply the world

  • Almost every competition-grade football used at the elite level is made in one of two facilities: a hand-stitching plant in Ada, Ohio, and a high-volume manufacturing complex in Sialkot, Pakistan. The Ohio plant supplies the top professional level in the United States. The Sialkot operation produces the overwhelming majority of every other tier — collegiate, high school, training balls and the export market.
  • The two operations overlap in process more than in geography. Both are hand-stitched. Both work from the same broad raw materials. The difference is volume: the U.S. plant produces around 4,000 balls a day; the Sialkot complex produces millions per year.

What goes into a single ball

  • Four leather panels, each cut from premium cowhide. The leather is sourced from American tanneries, tanned to a specific weight and pebble texture, then shipped in flat sheets to whichever factory will assemble it.
  • A polyester-cotton blend lining glued to the inside of each panel. The lining is what gives the ball its shape stability — without it, the bladder would simply expand into a sphere.
  • A vulcanised rubber bladder that holds the air. Inflation pressure for elite play is between 12.5 and 13.5 PSI, but the bladder itself can hold considerably more before it fails.
  • One lace, traditionally also leather, threaded through the seam over the bladder valve. The lace serves two purposes: it pulls the seam closed during construction, and once the ball is in play, it gives the quarterback's fingertips something to grip on a long throw.
  • Branding stamps, usually applied with a heated press before assembly so the ink penetrates the leather rather than sitting on top of it.

The hand-stitching step that nobody has automated

  • Each ball is sewn by a single person using a curved needle, a waxed thread, and roughly 250 stitches per ball. The seam is sewn inside-out: the panels are joined while flipped, then the whole assembly is reversed at the end through the lace opening, leaving the seams hidden inside.
  • The reason this hasn't been automated is that the leather panels stretch slightly during stitching, and an experienced stitcher compensates as they go — pulling tighter on one side, easing off on another. A machine that could match a skilled stitcher's feel for tension exists in theory and has never been deployed at scale.
  • A skilled stitcher in Sialkot can complete a competition-grade ball in roughly twenty to thirty minutes. The Ada plant, working at lower volume but to the highest spec in the league, takes considerably longer per unit.

Quality control: the part you don't see on television

  • Every elite-tier ball is weighed, measured and inflated on a calibrated rig before it leaves the factory. Weight tolerance is plus-or-minus a fraction of an ounce. Long-axis circumference must fall within a tight band. Inflation is checked twice — once at the factory and again when the ball reaches the league's officials.
  • Game balls used by professional teams are broken in at the team facility before kickoff. The leather is brushed, conditioned with a specific compound, and rubbed by hand for hours to soften the surface and reduce gloss. A ball that comes out of the box and goes straight onto the field is a ball nobody wants to throw.
  • Each ball used in elite play carries a unique identifier so that, if a ball is removed from play for any reason, its origin and history can be traced.

Why this matters for the rest of the world

  • The vast majority of footballs you have ever held in your hands were stitched in Sialkot. The factories there supply training balls to colleges, to youth programs, to international leagues, and to every retail aisle from sporting-goods chains to grocery-store seasonal displays.
  • Pakistan also dominates the global market for soccer balls and many other inflatable sporting goods, for the same reason: the local industry built up enormous expertise in hand-stitched ball construction over the second half of the twentieth century, and no other region has caught up on either cost or quality.
  • The result is a strangely concentrated supply chain. Two facilities, on two continents, produce the overwhelming majority of the world's footballs — and have done so for longer than most modern sports brands have existed.

Every quarterback who steps onto a field at the highest level is throwing an object that started as a flat sheet of cowhide, was cut and stitched by hand in one of two factories, and arrived at the stadium as the end product of a craft tradition older than most of the leagues that play with it. It's a small, quiet detail, but it's also a useful reminder: in a sport built on cutting-edge analytics and hundred-million-dollar contracts, the ball itself is still made the same way it was when your grandfather watched the first pro games on a black-and-white screen.

Tab Revolution, Stadium Yard View & Monthly Season Ranking

Tino H. Tino H.

The biggest UI jump in a while: long scroll wastelands across nearly every gameplay page collapse into tidy tab views, the franchise page gets its own top-down stadium yard visualisation and an 8-seat staff conference room, sponsors / TV / equipment / insurance move into a hero box with custom SVG logos, and a brand-new monthly Season Ranking arrives as a competitive leaderboard per difficulty.

🏟️ Yard & Staff as a stadium-style view

  • New top-down yard visualisation on franchise.php with a 12×8 grid: stadium, training complex, gym, sports academy, medical/therapy center, merch store, office building and datacenter — each building rendered as generative SVG with per-level features (stands, floodlights, corner flags, …), level badge top-right, cost overlay on click
  • Click opens the unified upgrade overlay showing current vs. next-level benefit, cost and balance preview — works for all 9 facility types via shared modal logic
  • Above the yard, the new staff conference room layout: 8 staff members (HC/OC/DC/SC, Scout, Marketing, Physio, Doctor) as portraits around a meeting table — generative SVG heads with hair, team-coloured suits and a VAKANT marker at L0
  • CPU teams see the same yard + conference room read-only (no upgrade overlays)
  • New lang strings + benefit copy for L6-L10 (DE/EN), DB column fallback when a lang key is missing

🤝 Partners & Contracts: hero box instead of 4 DataTables

  • New fpc-hero box replaces the old 4 sponsor / TV / equipment / insurance tables: sponsors full-width (row 1) with all 7 bonuses visible directly (per match · per season · 8 wins · playoffs · conference final · SB · SB win), plus maximum payout and ambition badge (Contending / Retooling / Rebuilding)
  • TV partners / equipment / insurance in row 2 as a 3-column panel grid — compact cards with hover tooltip, click to sign
  • New generative SVG logos per brand (ChipsFresh = chip bag, JellyFish = jellyfish, MyTube = red play button, Lovely Cat = cat face, …) — no more PNG mush
  • Confirm overlay shows balance now → −cost → balance after with green/red accents. Enter = Sign Contract, ESC or × top-right = cancel
  • Sponsor classification by variance ratio (`summax/summin`) auto-derives the right ambition tier, with manual overrides for JellyFish and Shirts4Friends

🎟️ Ticket-price slider + fanbase in the hero

  • Ticket price now set via a slider + number input (50–500$, 1$ steps) instead of 6 separate +/− anchors; a yellow tolerance band visualises the marketing manager recommendation (band shrinks as marketing level rises)
  • Standalone fanbase block dropped — fanbase number + ℹ️ history modal now lives directly in the hero stat tile

📑 Tab views everywhere in the same style

  • Unified tab system (color2 bar background, color1 active tab, contrast-safe text) rolled out across 11 pages: team.php (5 tabs), franchise.php (5), trade.php (4 with team logos), schedule.php (6 from preseason → super bowl), players_watchlist.php (3), achievements.php (11), halloffame.php (3), draft.php (3 incl. post-draft summary), player_stats_leaders.php (4), conference.php/division.php/table.php (2 for AFC/NFC), seasonranking.php (4)
  • Active tab persists in localStorage per page; hash-based activation still works (e.g. an „extend contract" redirect with #playerN auto-opens the offense tab and scrolls to the row)
  • DataTables column widths recompute via columns.adjust() on tab switch — no more 0-px columns after switching
  • On mobile the tab bar wraps to 2 rows instead of horizontal scrolling

🏟️ Conference + Division as a hero card grid

  • On conference.php + division.php the old 1-row list gets replaced by a 4-card grid per division — every card uses the same „th-card" look as the team hero on team.php (diagonal gradient color1 → dark → color2, animated sheen, semi-transparent team logo as background)
  • Per card: logo, name, colour swatches, strategy badge (Contending/Retooling/Rebuilding), saison record, OVR/OFF/DEF/SPE rating circles, and average age (team + 3 position groups)
  • Your team gets a white outline ring so it pops in the grid
  • Sorted by saison record (wins desc, losses asc), tie-break alphabetical

🎨 Icons + title-case sweep across the whole app

  • Matching emoji icons before every <h1> and section <h2>: 💰 Finances · 🎟️ Tickets & Merch · 🤝 Partners · 👔 Staff · 🏟️ Yard · 🟢 Offense · 🔴 Defense · 🟡 Special Teams · 🩹 Practice Squad · 📊 Stats · 🏆 Top League Players · 📈 Power Ranking · 🏛️ Hall of Fame · 🔍 Player Search · 🆓 Free Agents · 🎯 Draft · 📋 Contracts · 🪙 Coins · 📰 News · 📖 Glossary — long list
  • All block-caps lang strings (DE + EN) normalised to title case: „PLAYER WATCHLIST" → „Player Watchlist", „SEARCH PLAYERS" → „Search Players", „TOP LEAGUE PLAYERS" → „Top League Players", „SCHEDULE" → „Schedule" — no more shouting headers
  • Close × consistently top-right in every confirm overlay (yard, staff, partners)

🏆 New monthly Season Ranking

  • New page seasonranking.php with 4 tabs: Easy / Medium / Hard filtered to franchises started in the current calendar month — the new season auto-rolls on the 1st at 00:00; plus All-Time for the eternal leaderboard across all difficulties
  • Full DataTable with paging, search, sortable columns — same score formula and columns as the index.php Top-10 box (SB · CF · Playoffs · Achievements · Peak OVR · Saisons · W-L-D · Trades · Drafted · Balance)
  • Easy/Medium/Hard ship with „Data: Fictive" preselected; All-Time has both filters (difficulty + data) like the landing page
  • Reachable via the gold button under „🏆 Top 10 Franchises (All-Time)" on index.php or via the sidebar inside the game
  • Works with and without an active game id — public header outside, ingame header as soon as a game is active

📝 Developer blog on the landing page

  • New 📝 button next to the Discord banner (same height) opens the developer blog
  • Right below: an auto-updating teaser block of the latest 3 articles — tag, date, title, 50-word excerpt + „Read more »" link with deep-link anchor to the post
  • Single source of truth: _blog_posts.php defines the order — prepend new IDs and the teaser + blog.php auto-update

Day one feels like a fresh coat of paint on every screen you visit regularly. Tab bars trim the scroll, hero cards turn raw tables into visual stories, and the new monthly Season Ranking adds a fresh competitive hook for anyone who likes measuring their score against the community.

Onboarding polish: validated custom imports, tutorial step indicator, Discord CTA

Tino H. Tino H.

This drop focuses on onboarding and custom games: custom league imports get server-side validation (with i18n error messages), custom team logos render as SVG with a transparent PNG fallback, the tutorial gets a clear step counter, and a fresh Discord CTA beneath the existing-games box invites everyone to the community channel.

📥 Custom imports: file upload + validator

  • Import page now accepts direct CSV file uploads (teams, players) instead of URL-only entry — much faster onboarding for league imports from tabletop or your own tools
  • Server-side validator on upload: column count, required fields, value ranges (OVR 0–100, age 18–45 etc.) and a slimmer schema variant with fewer required columns
  • Error messages in DE + EN with locale-specific thousand separators (e.g. „Zu wenig Fans (1.000.000) — Mindestwert 1,5 Mio." vs. EN „Fanbase too low (1,000,000) — minimum 1.5M")
  • Off-by-one bug in the CSV templates on the first player record fixed — templates now load cleanly
  • nfl-import53.py generator synchronised with the slimmer schema

🛡️ Custom game logos now as SVG

  • Custom game saves now render team logos as SVG by default (instead of PNG) — crisp at any size, smaller footprint
  • Pre-cache before startgame.php: as soon as the logo URL is known, the SVG is fetched in the background; a generic fake-SVG fallback is staged in case the download fails
  • .htaccess rewrite redirects missing .svg requests to .png automatically — old custom saves without an SVG asset still work
  • Permanently failed downloads are skipped on retry, parallel retries are bundled — clean custom-game onboarding even with flaky source CDNs

🎓 Tutorial polish

  • New step indicator directly under the tutorial nav: shows „Step X of Y" at all times so it's obvious how much is left
  • EN typo „+5%% OVR" → „+5% OVR" fixed
  • Updated roster depth screenshot in tutorial step 4
  • DE wording on franchise.php: „Konto" → „Balance" for the EN version so vocabulary stays consistent across languages

💬 Discord CTA placed prominently

  • New Discord banner directly below the existing-games block on the landing page — instantly visible for anyone opening the site
  • The feedback overlay also gets a Discord CTA below the submit button — bug reports and feature wishes get a direct live channel
  • Asset grafiken/discord.png shipped

🎨 Team polish

  • teams.php: new „Team Colors" column with a small gradient chip (color1 → color2) — sortable + searchable
  • 12 fictional teams with too-light color2 get a contrast bump so white text on the secondary colour stays reliably readable — no more grey-white player names in the trade or roster overlay

🤝 Trade cap consistency

  • trade.php gets a 3-pick cap per side as a counterpart to the existing 5-player cap — prevents giant pick packages that would later blow the draft-room limit
  • checkTeamNeeds() respects the cap lock: already-limited checkboxes are no longer wrongly re-enabled when the needs highlights re-render
  • Selected players are now reliably counted from the idstring instead of :checked — works even after DataTable filter changes that detach unmatched rows from the DOM

Onboarding day: custom imports get more defensive, the tutorial gets clearer, custom logos get prettier, and the Discord entry point is visible to everyone. Plus the last gaps in the trade cap system are closed so pick packages no longer spiral out of control.

Hall of Fame Relaunch: Award Hero Cards, Trophy Wall & Saison-Stats

Tino H. Tino H.

The halloffame.php page graduates from a static tabular graveyard into its own stage: the current title holders show up at the top as award hero cards in team-color gradients, complete with position-specific saison stats, scout-aware OVR/POT visuals and a brand-new Trophy Wall for the league's last 5 champions. The same hero block appears in week 26 on player_stats_leaders.php, and a stubborn bug in the saison-recap overlay that turned 88-90 OVR rating circles orange is finally green.

👑 Award Hero Cards on HOF + Player Stats

  • New shared partial _player_awards_hero.php renders 5–7 trophy cards (MVP, SBMVP, OPY, DPY, ORY, DRY, OCPY, DCPY) in the same po-stage-bg style as the simresult W26 awards box — team-color gradient with a dark midpoint, animated sheen stripe, crosshatch texture, gold-bordered MVP/SBMVP cards
  • Each card shows a position-specific stat strip for the award saison: QB → PA YDS / PA TD / QBR · RB → RU YDS / TD / YPR (yards per rush) · WR/TE → RE YDS / REC / TD · DL/LB → TKL / SACK / INT · CB/S → TKL / INT / SACK · K → FGM / FG% · P → PUNTS / AVG YDS
  • OVR and potential star icons inside the cards significantly enlarged (14px → 32px) so they match the OVR rating circle — no more visual imbalance
  • The user team's card gets a blue glow border so your own award winners pop instantly
  • SBMVP fallback: if no dedicated "sbmvp" row exists, the box automatically pulls the game MVP of the actual Super Bowl game
  • On halloffame.php permanently visible (W1-25 = previous saison's winners, W26+ = current saison's winners) — on player_stats_leaders.php only in W26 with the freshly announced winners

🏆 Trophy Wall on the Hall of Fame

  • New block above the Teams table: shows the last 5 saisons with Super Bowl, AFC and NFC champion in an fh-cabinet wooden display (same look as on the franchise page)
  • One glass shelf per saison with a saison pill as label, three trophy cards side by side (Super Bowl gold, AFC red, NFC navy) including the winning team's logo badge — every element clickable to its team.php
  • Older than 5 years? A subtle hint banner below the cabinet ("Only the last 5 saisons are shown …") prevents the cabinet from growing infinitely tall in saison 12+
  • Fully responsive: viewports under 540px switch to a 120px tile grid with smaller trophies

📅 W26 Announce-Gating Now Consistent

  • Award winners now consistently surface only from week 26 onwards — matching the official ceremony, which happens at exactly that point in the simresult overlay
  • HOF DataTable, hero box and trophy wall all respect the same rule: saison N is only shown once the saison is past W26 (or a later saison has already started)
  • Game MVPs on player_stats_leaders.php now always visible — no longer week-26-only
  • The redundant legacy "Season Awards" table on player_stats_leaders has been removed — the hero box fully supersedes it

🐞 Saison Recap Overlay: Rating Colour Finally Correct

  • Inside the "🔮 Season Outlook" block, conference-favorite circles stubbornly rendered orange-yellow at OVR 88-90 instead of green — the root cause was a builder path in saisonwechsel.php that didn't populate the derived bereich/color fields
  • The render site no longer falls back to r70; it now always derives the rating class + colour fresh from the displayed OVR — colour and number can no longer go out of sync, regardless of which builder produced the data

🧹 Smaller Polish

  • Header news ticker: $logos_ext wasn't captured by the closure → warnings on every page, fixed
  • simresult W26 awards box: team logos for award winners now also work in custom games (logos_custom/game-id path with the correct extension)
  • Menu item + h1: DE "Teamstärken" → "Power Ranking", aligning the German label 1:1 with its English counterpart
  • Stat label "YPC" → "YPR" (yards per rush), plus new language keys stat_pa_yds, stat_qbr, stat_tkl & co. for proper translatability

The Hall of Fame finally feels like a real hall of fame — with a hero stage for current champions, a clickable trophy wall for recent league history and position-specific stats that show why the MVP became the MVP. And the nagging orange-vs-green bug in the season recap is — three attempts later — finally history.

Achievements as Collectible Cards, Power Ranking Podium & AFC/NFC Redesign

Tino H. Tino H.

The achievements page becomes a collectible card album, the power ranking gets a top-3 podium above the table, and the conference logos move to fresh SVGs — including swapped colour palettes between AFC and NFC so the look matches the real NFL 1:1. Plus a larger trade refactor that freezes asset values at trade time instead of recomputing them after the fact.

🏅 Achievements as a Collectible Card Grid

  • Brand-new look: achievements render as a card grid with tier accents (Bronze, Silver, Gold, Platinum) — every card with its own icon, progress bar and a coloured border that matches the tier
  • Locked achievements get noticeably stronger desaturation + dimming so unlocked ones stand out at a glance
  • Sort order: achievement families stay together (e.g. all "Trade Master" tiers next to each other), unlocked first, ascending by value within the family — no more hunting for the next tier
  • DE wording pass: redundant "mal" in staff and facilities labels removed ("3 mal aufrüsten" → "3× aufrüsten")

🥇 Power Ranking — Top-3 Podium Above the Table

  • Right below the page heading there's now a hero podium for ranks 1, 2 and 3: gold card larger and centred, silver on the left, bronze on the right (on mobile, gold automatically jumps to the top)
  • Each podium card carries a contextual quote per team ("This season is ours" / "We're hungry"), the rank pill is sized up to 2.5rem and the power score renders as a .rating circle in the same OVR look as the rest of the game
  • DE: "Team-OVR" in the podium quote renamed to "Team-Stärke" — matches the rest of the German vocabulary

🆕 AFC/NFC Logo Redesign + SB Hero Box

  • New hand-drawn SVG logos for AFC and NFC (replacing the old PNGs) — sharper on retina, smaller in the repo, scales cleanly on mobile
  • Colour palettes between the two conferences swapped so AFC red / NFC navy match the real NFL 1:1
  • Dedicated hero box for the Super Bowl on the conferences page with both champion teams + the SB trophy
  • Consistent sweep through all .png references — remaining PNG paths migrated to SVG

📦 Trade Value Snapshot Instead of Live Recompute

  • New column userteamtradehistory + per-asset snapshot: the value of a player / pick at the trade time is frozen and persisted, instead of being derived live from today's OVR after the fact
  • The render layer on the trading block and in the trade history now reads from the snapshot — historical trades show exactly the values that were in effect at the trade date
  • CPU trades: an off-by-one in the pick selection that used to drop team 2's first pick + inflate the value is now fixed — the trade engine evaluates cleanly
  • Provisional pick numbers in the trade history get a footnote hint so "unclear" doesn't come across as "broken"

🎨 Polishing Custom Games + Fictional Modes

  • Custom games now automatically copy the league SVG assets (AFC, NFC, Super Bowl, Pro Bowl) into logos_custom/<game-id>/ — no more 404 on the first call to a fresh custom save
  • A heal script detects missing SVG assets in existing custom games and back-fills them — older saves get the redesign, too
  • New column team.name_kurz_fake: in fake mode every team can carry its own short codes (NYE / NYS / STR) that differ from the real ones — clean separation between real and fake league
  • Index Top10: the ranking box now pulls fake names from team_start instead of the live table — canonical SVG path even for not-yet-started saves

Achievements feel like a real trophy cabinet now, the Power Ranking gets its champagne stage right at the top, and the AFC/NFC look finally matches NFL reality. Plus a trade refactor that preserves historical values cleanly — looking back at the trade history actually shows what the assets were worth at the time.

Tutorial Expansion, Top-3-Trades Box & Fresh Screenshots

Tino H. Tino H.

The tutorial got a full pass: 17 steps with a step counter, fancy button-style navigation, fresh screenshots from the current build and a brand-new Events step that walks you through the sim-result overlay in its own stage. In parallel, the sim-result overlay ships a new Top-3 Trades box — you instantly see which CPU trades just reshaped the league across the weeks you simulated.

📚 Tutorial Expansion

  • New Events step in the tutorial tour: the sim-result overlay gets its own stage with explanations for the news-of-the-week box, Top-3 Trades and the Super Bowl stage
  • Steps 6–9 (Trading Block, Direct Trade, Free Agents, Draft) significantly expanded — new sub-sections for the CPU offer overlay, FA negotiation, mock drafts and the cinematic pick overlay
  • Step counter in the top right shows "Step X of 17" at all times — no more getting lost in the tour
  • Fancy button nav: the plain Next/Stop links became proper action buttons in the in-game style
  • Body background switched from grey to white — tutorial content now reads with significantly better contrast
  • Brand-new screenshots from the current build (instead of synthetic placeholders), plus precise DE-wording fixes across multiple steps

📰 Top-3 Trades Box in the Sim Result

  • New CPU-only box inside the sim-result overlay right next to the news block: shows the three highest-value trades between CPU teams across your simulated weeks
  • Logos and team names are linked, every player ships with scout-aware OVR + potential, picks with season + round + slot
  • Perfect for spotting which rivals are rebuilding around you — before the next sim run catches you off guard

🛠️ news.php "All" Filter Fix

  • After a game switch the "All" filter on news.php sometimes showed an empty table — typical after switching between two active saves
  • Fix re-evaluates the current game context cleanly so all news of the active save reappear

🏆 Footer Awards Refresh

  • Award cards in the footer now ship with: name on its own row, meta row underneath, equal card height across the row
  • Instead of generic placeholders the cards now quote fictional press outlets ("GridironGazette", "PressboxWeekly", …) — much more atmosphere on the public landing page

The tutorial now feels of one piece — with real screenshots, clean step logic and a dedicated Events step that explains the most important sim moment of the week. And the new Top-3 Trades box brings the league chatter straight into the sim-result overlay so you never miss what really matters.

Cinematic Draft: Pick Overlay, Featured-Pick Stage & Mock-Draft Weeks

Tino H. Tino H.

The draft now gets its big moment: every pick opens a cinematic overlay with player photo, pick number and live grade — and the strongest value pick of a sim run gets its own featured-pick stage. On top of that, three mock-draft weeks (17 / 21 / 25) drop into the season, the pre-draft banner has been hyped up, and the mock-draft box itself ships with a team-color header and a responsive prospect-card grid.

🏈 Pick-by-Pick Overlay

  • Pre-draft welcome banner with on-the-clock card frames the entry into the draft sim — the overlay opens directly on the first pick
  • Cinematic single-pick overlay: large player photo, stamp-in pick-number animation (stays visible after the stamp), team logo, OVR/POT rings and a live grade — all in a clean, readable stack
  • Trade-pick preselect: when a trade workflow is active, the relevant pick is auto-selected, no more hunting through the pick list
  • Welcome icon de-duplicated — the header now shows the logo cleanly once per visit

🎬 Featured-Pick Stage & Closing Box

  • For multi-pick sims (e.g. simulating a full round) the highest-value pick gets its own cinematic stage with a highlight animation — labelled "Best Pick of the Sim Run"
  • Closing box at the end of the sim: value-gain feature with team-by-team uplift, a champion strip with the three best draft classes and a wrap-up card
  • The featured pick is shown regardless of pick order — even a round-3 steal can become the star of the run

🎯 Mock Drafts in Weeks 17 / 21 / 25

  • Three round-1 mock drafts now generate automatically in week 17 (trade-deadline mock), week 21 (mid-season) and week 25 (final mock) and link straight from draft.php
  • Pre-draft banner significantly hyped up: bigger hero block with countdown vibe, clearer hierarchy on the draft page
  • Draft-class, players and order links are now consistently localized (DE/EN)

🪟 Mock-Draft Box Polish

  • Mock-draft box header now uses the user team's color1 + a 📋 clipboard icon — a visual anchor that matches your team
  • Header text stays left-aligned, even with long box titles
  • Responsive prospect-card grid: cards collapse cleanly on narrow screens, with no broken OVR/POT rings or stars
  • Thinner OVR/POT rings and bigger stars in the mock-draft cells — more focus on the content, less UI chrome

🧹 Smaller Polishing

  • news.php "All" filter showed an empty table after a game switch — fix re-evaluates the current game context cleanly so all news of the active save reappear
  • Footer awards: name on its own row, meta row underneath, equal-height cards — and fictional press outlets for more atmosphere

The draft sim now feels like its own event moment — with welcome banner, cinematic pick overlay, a dedicated stage for the best value pick and a closing card that frames your draft class. Plus three mock-draft weeks across the season so the hype starts well before week 25.

Salary-System Rework, Real NFL Guides & Weekly-Sim Safety Net

Tino H. Tino H.

The big cap re-balance has landed: player salaries are now hard-capped at 25M for veterans and 7.5M for the #1 rookie pick. Base salaries by difficulty were recalibrated (2.0 / 2.2 / 2.4M), and the weekly sim now carries a cap-fallback safety net for user teams in auto mode as well. In parallel, the two SEO guides salary-cap-guide.php and draft-guide.php were rewritten end to end — with real NFL content instead of game-specific numbers.

💰 Hard Salary Caps

  • New global constants FF_MAX_PLAYER_SALARY = 25,000,000$ and FF_MAX_ROOKIE_PICK1_SALARY = 7,500,000$ in functions.php (available on every entry path)
  • Cap is applied in: game start, CPU contract renewal, user renewal, quick re-sign, rookie-draft salaries, reset script and every UI preview
  • Goal: at salary cap 200M and roster 53, even superstar contracts can no longer blow up the budget — and the CPU reliably extends its stars instead of dumping them into free agency

⚖️ Base Salary Rebalance

  • Easy: 2.0M (was 2.2)
  • Medium: 2.2M (was 2.4)
  • Hard: 2.4M (was 2.6)
  • Applied in header_connect.php (game start), saisonwechsel.php (backfill defaults) and the difficulty overlay on index.php

🛡️ Weekly-Sim Cap Fallback for the User

  • At the week transition (3 → 4 and every subsequent one), the full safety net now also runs for the user team when depthchart_mode != manual: PS optimizer → depth-chart recompute → cap enforcement → lineup refresh
  • The enforcer receives the user team as no_release: demotions to PS are allowed, releases remain strictly user-only
  • After the enforcer, update_lineupuserteam_bymode() runs again so any demotions land in the lineup and cap space shows cleanly > 0

📚 Real NFL Guides (GEO/SEO)

  • salary-cap-guide.php rewritten: signing-bonus proration, dead cap, June 1 designation, franchise & transition tags, rookie wage scale, 5th-year option, cap carryover, restructures and void years — with cap history 2020–2025 and the real 279.2 M USD figure for 2025
  • draft-guide.php rewritten: pick order with slots 1–30, compensatory-pick formula, 5th-year option, Jimmy Johnson and Chase Stuart trade value charts, scouting-combine drills and the underclassman-declaration deadline
  • Both guides now ship FAQ schema and Article schema with correct datePublished/dateModified and cross-link each other

🧹 Smaller Polishing

  • Header: grafiken/beta.png icon removed (both next to the user team name and next to the conference logo)
  • Footer version bumped to v1.0-20260424
  • team.php: transaction history table no longer shows "Practice Squad" type rows — they're already in the "Roster Moves" table one section above

With hard salary caps, a steadier base-salary rebalance and the new weekly-sim safety net, the cap economy is now robust enough for long franchise runs — and the two new NFL guides deliver real football content on the SEO side so Google & co. find genuine editorial value.

Cap Enforcer Deep Dive: Injury Swaps, Roster Trim & User Safety Net

Tino H. Tino H.

A deep dive into the salary cap enforcer: a local test save (Game 206, season 3, week 1) exposed players the enforcer was silently missing — leaving teams with up to 58 actives against a 53-man limit and a negative cap space of over 26M. This round introduces three new enforcer phases, shields user teams from unwanted releases, and closes a stubborn blind spot in the roster query.

🔍 The Enforcer Blind Spot

  • The enforcer's roster query was filtering AND karriereende=0 AND draft!=2 — well-intentioned, but the salary-paying column team.salarycap counts every player
  • Result: the enforcer saw 53 players against a real roster size of 58 and calculated ~189M in salaries while the true total was 228.7M
  • Fix: filter removed, enforcer now sees the full reality — including players with imminent retirement or the draft-in-progress flag

🏥 Phase 0A: Injury Swaps

  • New phase that runs before the roster trim: injured active players get swapped 1:1 with the strongest healthy non-retired PS player at the same position
  • Runs in a loop until no more swaps are possible — stable even with multiple injuries per team
  • Phase 2 (promotion) now explicitly skips injured and retiring PS players so they never get pulled back up

📉 Phase 0: Roster Trim to maxroster (53)

  • Explicit demote-to-PS logic when roster size > maxroster, demoting the highest-paid over-optimal players first
  • Fallback: if no position is over its optimal, it demotes from positions above min_lineup — guaranteeing a playable roster
  • Resolves the 58/53 case (6 CB at optimum 5, 5 QB at optimum 3, 2 P at optimum 1) in a single pass

🛡️ User-Team Safety Net (no releases!)

  • New $no_release_tids parameter on enforce_cpu_salary_cap() — teams on this list may only be demoted to PS by the enforcer, never released
  • The user team is always added to this list when depthchart_mode != 'manual': releases stay strictly a user-driven action
  • New action branch act_demote_above_min kicks in when other actions are blocked for protected teams

🎚️ Depth Chart Mode Toggle as Trigger

  • Switching from manual to any auto sort (e.g. "Strength descending") now triggers the optimizer + cap enforcement so the roster lands under the cap immediately — with zero user releases
  • Language key autosort_auto_disabled_hint refined: "…switch the mode above or in the side menu to „Manual""

The enforcer is markedly more precise now, user teams can no longer lose players unwillingly, and injured players land where they belong — on the practice / injury squad. A big step forward for the balance of all franchise modes.

New Page Structure, SEO Polish & Multi-Game Safety

Tino H. Tino H.

A major restructuring has landed: index.php is now a pure public landing page, while the in-game home has moved to the new start.php. On top of that: three safety nets preventing a user from ever having two active games at once in the DB, a critical canonical fix for Google and 19 additional pages running in no-game mode for the AdSense integration.

🏠 New Landing & Home Architecture

  • index.php now runs exclusively as the public landing page (SEO header, game selection, new-game form) — even with an active gameid, the page stays visible as the landing page via $is_public_page = true
  • The new start.php is the central in-game home and contains all former in-game homepage elements (money EOS, expiring contracts, standings, player leaders, etc.)
  • Menu item "START", clicks on the team name in the header and the home icon in the icon menu now link to start.php
  • "Play" and "Start" buttons correctly redirect to start.php once a game is active — startgame.php and all in-game error redirects were adjusted accordingly

🛡️ Multi-Active-Game Safeguards

  • Three layers of defence prevent a user from ever having two games marked active at the same time in the database:
  • Continuegame handler: now bulk-deactivates all of the user's cookie-owned games in a single SQL statement before activating the chosen one — no more race condition window
  • Newgame handler: before the INSERT, every pre-existing game in the user's cookie is also deactivated
  • Gameid resolution: if more than one active game is detected nonetheless, the extras are automatically deactivated and logged as MULTI-ACTIVE GUARD in the error log

🔗 Canonical URL Fix

  • Google Search Console flagged /index.php and / as two separate URLs emitting different canonicals — even though both served the same content
  • header.php now normalises /index.php/ for the <link rel="canonical"> tag, on both footballfranchise.de and football-franchise.com
  • The www-vs-non-www canonicalisation was already correct — visits to www.footballfranchise.de/index.php now consistently emit canonical → https://footballfranchise.de/

🕸️ AdSense-Ready: 19 More Pages

  • The $allow_nogame_ingame flag was rolled out to all central in-game pages: franchise, tradingblock, trade, players, freeagents, draft, teams, table, conference, division, schedule, players_stats, player_stats_leaders, halloffame, powerranking, players_watchlist, tradehistory, achievements, coins
  • Every one of them now renders its full HTML scaffold with empty tables when visited without an active gameid — perfect for the AdSense crawler to reference block IDs for ad slot placement

🧹 Cronjob Protection

  • cron_cleanup_old_games.php now protects game ID 1 (the seed/demo game) from being auto-deleted after 30 days of inactivity
  • Belt & braces: a WHERE id <> 1 clause in the SELECT plus an additional hard guard inside the delete loop

With the clean split between public landing page and in-game home, plus the multi-active-game safeguards, the app has become substantially more robust. In parallel, the crawler can now reach every important page — a huge step toward a productive SEO and AdSense integration.

Trade Rules, Tutorial Hints & SEO Groundwork

Tino H. Tino H.

The past few days were all about small but impactful improvements: rookies early in their careers are now trade-protected, the tutorial explains more clearly which players are greyed out and why, and behind the scenes the groundwork for a clean AdSense integration has been laid. On top of that, a reworked robots.txt lets Google crawlers fully index the game.

🔒 Rookie Trade Protection

  • Rookies in their 1st and 2nd year after the draft can no longer be traded — they are meant to develop with the team that drafted them
  • Rookies in their 3rd and 4th year remain tradeable
  • Affected players are automatically greyed out (opacity 0.4, checkbox disabled) in trade.php and tradingblock.php, with an explanatory tooltip
  • CPU trade offers no longer include young rookies either — for both the user and CPU side

📚 Tutorial Hints

  • Tutorial step 6 (Trades) now explicitly mentions the rookie trade block and explains that players may be greyed out based on roster size, position needs and strength needs
  • Tutorial step 7 (Trading Block) received the same matching hints
  • All new texts are maintained via language keys in both DE and EN

🕷️ AdSense Preparation

  • team.php is now fully reachable without an active gameid — every <div> container and block ID stays in place, DataTables render without data
  • A new $allow_nogame_ingame flag was introduced, hooked up in header.php, footer.php and header_connect.php, providing default stubs for $game, $team, $userteam, etc.
  • This allows the AdSense crawler to see the page structure and reference block IDs for ad slot placement

🤖 Google Crawler Allowlist

  • robots.txt restructured: all Google bots explicitly allowlisted (Googlebot, Googlebot-Image, Googlebot-News, Mediapartners-Google, AdsBot-Google, AdsBot-Google-Mobile, APIs-Google, Google-InspectionTool, GoogleOther)
  • All other bots remain fully blocked (User-agent: * / Disallow: /)
  • Sensitive endpoints (header_connect.php, functions.php, startgame.php, /db_migrations/, /.claude/, etc.) stay blocked even for Google

The rookie trade protection adds a meaningful layer of realism to the trade logic — and with the AdSense groundwork now in place, the path is clear to keep the game ad-funded and free forever.

Roster Management, Salary Cap & Balancing

Tino H. Tino H.

The most comprehensive gameplay update so far is live: a full Roster Composition Optimizer automatically balances your lineup, CPU teams now strictly adhere to the salary cap, and Practice Squad player development has been made more realistic. Plus plenty of quality-of-life improvements.

🧩 Roster Composition Optimizer

  • New system automatically balances players between active roster and Practice Squad — based on the optimal number per position
  • Works for CPU teams (always by overall rating descending) and for the player (based on chosen depth chart mode: rating, potential, age or value)
  • Injured players are automatically moved to Practice Squad, healthy replacements are promoted
  • The optimizer now runs both before and after game calculation — new in-game injuries are handled immediately

💵 Salary Cap Enforcement

  • CPU teams must stay under the salary cap from week 4 onwards — no longer just on cut day
  • All roster moves (PS promotions, swaps, optimizer) now check the salary cap before executing
  • New function enforce_cpu_salary_cap() as a weekly safety net: releases players until the team is under the cap
  • Release fees are calculated based on difficulty setting when players are cut

📈 Practice Squad Development

  • PS development is now capped at a maximum of +4 OVR per season
  • Higher-rated players benefit less from PS time — an 80 OVR player gets at most +1 to +2, while a 67 OVR player can receive the full +4
  • Fixes the issue where young PS players received disproportionately large upgrades

📊 Fanbase & Balancing

  • Fanbase growth/decline per season capped at a maximum of ±10% (previously up to +25%/-12%)
  • Prevents unrealistic fanbase explosions after consecutive winning seasons
  • Free agent pool at game start increased by approximately 30% across all positions

⏩ Sim Button & UI

  • The sim button now shows week-specific labels: e.g. "Sim Week 4 (RS #1 + Cut)", "Sim Week 21 (PO Wildc.)" or "Sim Week 24 (SuperBowl)"
  • Preseason roster limit is now checked directly in the sim overlay — the confirm button is disabled when over the limit

With the Roster Optimizer and Salary Cap Enforcement, roster management now feels significantly more realistic. CPU teams act more economically and the automatic roster optimisation takes a lot of micromanagement off the player's hands in non-manual mode. Onwards!

Development Update: Game Simulation & Bugfixes

Tino H. Tino H.

The past few days have been all about stabilising the game simulation and squashing some persistent bugs that surfaced during multi-season testing. The weekly simulation now runs far more reliably and financial calculations finally match across all team views.

🎯 Game Calculation

  • Critical bug fixed: simulating multiple weeks at once skipped games in weeks 9-11 (all showed 0:0). Root cause was a PHP type-juggling issue in the branching logic of spielberechnung.php
  • The three execution paths (single game, full season, weekly sim) are now cleanly structured as an if / elseif / else chain

💰 Finances

  • End-of-season balance on franchise.php and teams.php now shows identical values — previously there was a discrepancy of up to 120M because franchise.php was using the logged-in player's data instead of the viewed team's data
  • The EOS calculation on index.php now correctly filters by the current season — previously it counted games from all past seasons, inflating the home game count by 4x
  • CPU teams can no longer upgrade buildings and staff when their projected end-of-season balance would not allow it

🏆 Award Notifications

  • Season number now displays correctly in the notification bar (e.g. "Season 3 Most Valuable Player" instead of just "Most Valuable Player")
  • Duplicate award notifications fixed — players with awards across multiple seasons caused duplicates
  • All award texts properly localised for both German and English

📋 Depth Chart

  • Roster size now highlighted in red when over the maximum or below 40 players
  • Practice Squad count shown in red when exceeding 16 players

These fixes lay the foundation for the next batch of bigger features. Getting the game calculation rock-solid was long overdue and finally makes multi-season testing truly reliable.

Development Update: March 2026

Tino H. Tino H.

Football Franchise has been evolving rapidly over the past weeks — and this update is proof of just how much ground we've covered. From a full bilingual language system to legal compliance pages, from a redesigned responsive header to a brand-new blog, the game has taken some significant steps forward. Performance has been a major focus as well, with database query counts slashed dramatically across key pages. This post summarises the most important changes and improvements made during our March 2026 development sprint. More features and refinements are already in the pipeline!

🌍 Language System

  • Full DE/EN language system with flag switcher added to the header
  • Language selection persists across pages via cookie (ff_lang)
  • After switching language, the user stays on the current page — no redirect to home
  • All UI strings migrated to language keys in lang/en.php and lang/de.php

⚖️ Legal Pages

  • Imprint (imprint.php) fully rewritten — §5 TMG compliant, fully bilingual
  • Privacy Policy (privacy.php) fully rewritten — 7 sections, Art. 6(1)(f) GDPR, Google Analytics, supervisory authority

📱 Responsive Header

  • 5 breakpoints implemented: 1-row layout (≥1600px) down to 4-row layout (<600px)
  • Dynamic header height via JS — content no longer overlaps the fixed header
  • Fixed hamburger menu alignment at mid-range viewport widths

🏠 Start Page

  • Screenshots gallery (2×2 grid) added below the game description
  • Difficulty modal redesigned to match the site's shared modal style
  • Trade Factor info button now uses the unified .ff-info-btn style
  • Version bumped to v1.0-20260331-beta, copyright year updated to 2026

⚡ Performance

  • game.php: 5 individual queries consolidated into 1 JOIN query
  • index.php: ~550 queries reduced to ~10 (Money EOS, schedule loops, division standings)
  • team.php: ~350 queries reduced to ~18 (aggregates, player stats, trade history)
  • DataTables sort bug fixed — JS was blocking click events on desktop viewports

This has been one of the most productive development sprints so far. With a solid foundation now in place — language system, legal compliance, performance and responsive design — we can turn our focus to gameplay depth and new features in the weeks ahead. Stay tuned!