Center-out wallchart layout (computeWallchartLayout), radial orbit view with circular flag tokens, and mobile rounds pager with button navigation (Steps 1–3). Stadium-night art direction, SVG connectors, fit-to-chart zoom, escalating card heat toward the Final, dual gold-real/blue-sim champion celebration paths. Adds bracket view toggle with persistent wc2026_prefs.bracketView storage. |
||
|---|---|---|
| .agents | ||
| .github/workflows | ||
| assets | ||
| data | ||
| .gitignore | ||
| complement-spec-worldcup2026-en.md | ||
| favicon.ico | ||
| how-refresh-data.md | ||
| how-update.md | ||
| index.html | ||
| manifest.json | ||
| README.md | ||
| world-cup-2026-hub-spec-en.md | ||
World Cup 2026 Hub
A static, single-page hub for the FIFA World Cup 2026 (Mexico · USA · Canada, 48 teams): full match schedule, live group standings, an interactive knockout bracket with a prediction/simulation mode, and a stadium guide. Built with vanilla HTML/CSS/JS — no backend, no framework, no build step. All content lives in JSON files.
UI languages: English / Português (toggle in the header, auto-detected on first visit).
Features
- Schedule — all 104 matches with filters (date, group, phase, team, stadium), free-text search, date sorting, and a "My matches" favorites filter.
- Groups — standings computed live from results (3/1/0 points, goal difference, goals for), qualification highlights.
- Knockout bracket — generated dynamically from standings +
bracket-config.json; hover highlights a match's full path; mouse-wheel/pinch zoom; drag to pan. - Simulation mode — pick winners and scores for unplayed knockout matches; picks propagate through the rounds, persist locally, and never touch the JSON data.
- Bracket challenge — once real knockout results land, your saved picks are scored ("X of Y picks correct", per phase).
- Share prediction — copy a link that carries your bracket picks (base64 in the URL).
- Favorites — star teams anywhere; their matches get highlighted across the app.
- Time zones — show kickoff times in your local time or the stadium's time.
- Add to calendar — download any match as an RFC 5545
.icsfile. - Match modal — details for every match, with space reserved for future stats.
- Stats — a sub-navigated screen (Overview · Teams · Records · Comparator): tournament-to-date aggregates and goals-by-stage/round charts; a verdict hero (champion + podium) that takes over once the final is played; a final ranking 1–48 by stage reached; team record cards (biggest win, win streak, champion's path); a "format debuts" band; and an A-vs-B team comparator. Sections appear only when they have data (graceful degradation).
- Responsive (mobile / tablet / desktop), keyboard-accessible, honors
prefers-reduced-motion.
Run locally
python -m http.server
# open http://localhost:8000
Any static file server works. A server is required — opening index.html directly
from disk fails because browsers block fetch() of local JSON files.
Deploy to GitHub Pages
- Push this repository to GitHub.
- Repository Settings → Pages → Source: deploy from branch,
main/ root. - Done — the site works under
https://<user>.github.io/<repo>/because every asset and data path in the code is relative (never start a path with/when editing).
Project structure
worldcup2026/
├── index.html SPA shell (header, tabs, hero, panels, modal root)
├── assets/
│ ├── css/ style.css · bracket.css · animations.css
│ ├── js/ app.js (entry) · schedule.js · groups.js · bracket.js
│ │ modal.js · stadiums.js · storage.js · i18n.js · calendar.js
│ └── images/ flags/*.svg · stadiums/*.svg (placeholders)
└── data/ ← the only thing you edit to maintain the site
├── teams.json 48 teams: { id, name, flag }
├── groups.json { "A": [4 team ids], … } × 12
├── matches.json 104 matches (UTC times; knockout uses bracketRef)
├── results.json one entry per match: scores + status (+ penalties)
├── stadiums.json name, city, capacity, image, IANA timezone
└── bracket-config.json Round-of-32 slots + best-third assignment
Maintaining the data
The current files contain mock data (real country names, fictional results) so every feature can be exercised. Replace them with real data as the tournament unfolds — no code changes needed.
Updating a result
Edit the match's entry in data/results.json:
{ "matchId": 74, "homeScore": 1, "awayScore": 1,
"penalties": { "home": 4, "away": 3 }, "status": "finished" }
status:scheduled→live→finished. Standings and the bracket only countfinishedmatches.penaltiesis optional — only for knockout draws.
Adding / changing matches
data/matches.json. All times are UTC (the UI converts to local or stadium
time). Group matches carry homeTeam/awayTeam; knockout matches carry a
bracketRef (R32-1…R32-16, R16-1…, QF-…, SF-…, THIRD-PLACE, FINAL)
and their teams are resolved automatically.
After the group stage: fill the third-place slots
data/bracket-config.json is the only file to edit once the 8 best
third-placed teams are known. Map each slot to a group letter:
"thirdPlaceAssignment": { "1": "C", "2": "A", "3": null, … }
A slot's team becomes standings[group][3rd]. Slots left null show a
"Best 3rd #N" placeholder. The 16 round32 entries define the bracket order
(array position = bracket position) — they normally never change.
Teams, stadiums, images
teams.json—flagis a path relative toassets/images/(e.g.flags/bra.svg).stadiums.json—timezonemust be a valid IANA name (e.g.America/Mexico_City); it drives the "stadium time" display and stays correct across DST.- Replace the placeholder SVGs in
assets/images/with real artwork keeping the same file names (or update the JSON paths).
UI labels (EN/PT)
Every UI string goes through t(key) — add new labels to both dictionaries
in assets/js/i18n.js. Data values (team/stadium names) are not translated.
Local storage
| Key | Content |
|---|---|
wc2026_simulation |
{ "R32-6": { "winner": "FRA", "score": "2-1" }, … } |
wc2026_favorites |
["BRA", "MEX"] |
wc2026_prefs |
{ "lang": "en"|"pt", "timeMode": "local"|"stadium", "lastTab": "bracket" } |
Clearing site data resets picks, favorites, and preferences — the JSON content is never modified by the app.
Acceptance criteria (spec §18)
- All matches are loaded via JSON
- All results are loaded via JSON
- The bracket is generated dynamically (config + standings + winner pairing)
- Works on GitHub Pages (all paths relative, no server-side code)
- Works on desktop and mobile (≤767 / 768–1439 / 1440+ breakpoints)
- Allows knockout-stage simulation (persisted, never mutates JSON)
- Smooth animations (entry, hover, bracket line-draw; reduced-motion safe)
- No backend dependency — fully static, works offline after first load
Performance: total JS ≈ 74 KB across 9 ES modules (budget: < 300 KB), no external dependencies, no blocking third-party requests.
Roadmap (spec §19)
PWA install, dark/light theme, real-time statistics, results API, FIFA ranking, World Cup history, team comparison, push notifications.