mirror of
https://github.com/LucasKalil-Programador/world-2026-hub.git
synced 2026-07-04 17:41:28 -03:00
docs: update architecture for bracket redesign (Steps 1–3)
Document wallchart center-out geometry engine, radial orbit layout with flag tokens on rings, rounds pager infrastructure, view toggle persistence, and art direction (stadium-night, escalating heat). Note retirement of CSS equal-height connector invariant. Update TODO with Step 4 (champion celebration + polish + v1.1.0 version bump).
This commit is contained in:
parent
c246117545
commit
caec00689f
3 changed files with 107 additions and 5 deletions
|
|
@ -98,6 +98,25 @@ champion path, debuts champion) once the final lands. The **data-layer stages (G
|
|||
|
||||
---
|
||||
|
||||
## 8. Bracket redesign (2026-07-03, spec settled via /grill-me — see project-memory)
|
||||
|
||||
Two switchable chart layouts (wallchart default + radial) + mobile round pager; stadium-night art
|
||||
direction; built directly on master, one approval gate per step.
|
||||
|
||||
- [x] ~~Step 1 — Foundation + wallchart: center-out layout engine (`computeWallchartLayout()`),
|
||||
SVG connectors + path highlight, stadium-night backdrop, tiered cards with microlines,
|
||||
fit-to-chart zoom (fit = "100%"), sim/challenge/share preserved~~ (2026-07-03)
|
||||
- [x] ~~Step 2 — Mobile round pager (default ≤767px) + view-toggle infrastructure~~ (2026-07-03;
|
||||
reworked same day per user feedback: **button navigation only** — scroll-snap swiping removed —
|
||||
and max 2 columns on desktop)
|
||||
- [x] ~~Step 3 — Radial layout (second chart view on the toggle)~~ (2026-07-03; redesigned to the
|
||||
user's reference image: circular flag tokens on rings + trophy center = "orbit" view, gold real /
|
||||
dashed-blue sim route lines, tooltips for names/scores)
|
||||
- [ ] Step 4 — Champion celebration (gold real / blue sim), polish pass (a11y/i18n/reduced-motion),
|
||||
`APP_VERSION` → v1.1.0, README note
|
||||
|
||||
---
|
||||
|
||||
## Quick final checklist
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -41,7 +41,11 @@ worldcup2026/
|
|||
│ ├── css/
|
||||
│ │ ├── style.css ★ Palette variables, glassmorphism base, layout,
|
||||
│ │ │ components — mobile-first
|
||||
│ │ ├── bracket.css Bracket columns, connectors, highlight states
|
||||
│ │ ├── bracket.css Knockout views: stadium-night stage, wallchart cards
|
||||
│ │ │ (heat toward the Final) + SVG connectors, radial orbit
|
||||
│ │ │ tokens (tk-* states, route lines), rounds-pager cards
|
||||
│ │ │ + chips, view switch, path highlight, sim/challenge
|
||||
│ │ │ styles; all motion gated by reduced-motion
|
||||
│ │ ├── stats.css Stats tab: hero "pulse", overview cards, goals-by-stage chart
|
||||
│ │ └── animations.css Entry (fade-in, slide-up/left) + interaction
|
||||
│ │ (hover-scale/glow, pulse, line-draw)
|
||||
|
|
@ -65,7 +69,12 @@ worldcup2026/
|
|||
│ │ ├── groups.js Standings computation (3/1/0, GD, GF) + group tables
|
||||
│ │ ├── stadiums.js Stadium cards + "view matches" cross-link
|
||||
│ │ ├── bracket.js ★ Bracket tree resolution, resolveBracketTeams(),
|
||||
│ │ │ simulation, challenge score, share prediction
|
||||
│ │ │ simulation, challenge score, share prediction;
|
||||
│ │ │ 3 switchable views (wc2026_prefs.bracketView):
|
||||
│ │ │ computeWallchartLayout() center-out wallchart,
|
||||
│ │ │ computeRadialLayout()+radialInnerHTML() orbit view
|
||||
│ │ │ (flag tokens on rings, trophy center), rounds pager
|
||||
│ │ │ (button-only); fit-to-chart zoom (fit = "100%")
|
||||
│ │ ├── modal.js Match detail modal (ARIA dialog)
|
||||
│ │ ├── storage.js localStorage wrapper — wc2026_* keys, auto-JSON
|
||||
│ │ ├── i18n.js EN/PT-BR dicts + t(key), lang toggle
|
||||
|
|
|
|||
|
|
@ -99,9 +99,12 @@ automated tests / linter (explicit spec constraint).
|
|||
match (group or knockout); reused by schedule cards, modal, and search/team filters (so knockout
|
||||
matches become searchable/filterable once resolved). `getBracketTree()` → `{ rounds, third,
|
||||
nodesByRef, champion }`.
|
||||
- **CSS connectors depend on an equal-height invariant:** all columns share height with `flex:1`
|
||||
- ~~**CSS connectors depend on an equal-height invariant:** all columns share height with `flex:1`
|
||||
slots, so pair children sit at 25%/75% and the next node at 50%; pure-CSS stubs meet exactly.
|
||||
Column gap = 2 × stub (44px desktop / 36px ≤767). **Breaking equal height breaks the lines.**
|
||||
Column gap = 2 × stub (44px desktop / 36px ≤767). **Breaking equal height breaks the lines.**~~
|
||||
**RETIRED 2026-07-03** by the wallchart redesign — see "Bracket redesign (2026-07-03)" below;
|
||||
connectors are now SVG paths generated from the same JS geometry as the cards, so no CSS
|
||||
invariant exists anymore.
|
||||
- **Simulation:** `decide()` applies only real finished results; `applySimulation()` overlays user
|
||||
picks afterwards and **never overrides a real result** (so `simulated:false` ⇒ real). Stale entries
|
||||
(winner no longer resolved) are silently ignored. Eligible nodes (both teams resolved, real result
|
||||
|
|
@ -115,6 +118,67 @@ automated tests / linter (explicit spec constraint).
|
|||
`loadPredictionFromURL()`; stripped from the URL (`history.replaceState`) whether applied or not;
|
||||
unknown refs rejected wholesale. **Challenge** card scores sim vs real finished knockout results.
|
||||
|
||||
### Bracket redesign — center-out wallchart (2026-07-03, Step 1 of 4)
|
||||
Full redesign spec settled via /grill-me: **two switchable chart layouts** (center-out wallchart =
|
||||
default, radial = Step 3) + a **mobile round pager** default ≤767px (Step 2), stadium-night art
|
||||
direction, lean escalating cards, fit-whole-chart initial framing, gold-real/blue-sim champion
|
||||
celebration (Step 4), built **directly on master** (deploy still gated on user-approved push).
|
||||
Step 1 (shipped): wallchart replaces the old left-to-right columns.
|
||||
- **`computeWallchartLayout()` in `bracket.js` is the single geometry source:** absolute px
|
||||
positions for every card/title/champion box (`GEO` constants; R32 1–8 left half, 9–16 right,
|
||||
later nodes at feeder midpoints) **and** the SVG bezier connectors + champion stem derived from
|
||||
the same numbers — cards and lines cannot drift apart. Tree/sim/share/challenge logic untouched;
|
||||
DOM contract preserved (`data-ref`, `data-match-id`, delegation, keyboard activation).
|
||||
- **Fit-to-chart zoom:** geometry is computed (never DOM-measured); a `ResizeObserver` on
|
||||
`#bracket-wrap` computes `view.fit` when the panel becomes visible (hidden panel = clientWidth 0)
|
||||
and re-fits on resize unless the user zoomed. **Zoom label "100%" = fit**, reset returns to fit,
|
||||
clamp = [fit, 2]. The wrap carries an inline `aspect-ratio: W/H` from the engine so the fit view
|
||||
is never letterboxed (capped `max-height: min(80vh, 840px)`).
|
||||
- **Cards:** lean two-row + microline (`.bk-meta`: kickoff via `kickoffShort()` honoring the
|
||||
Local/Stadium toggle — bracket now listens to `timemodechange`; LIVE pulse; FT = `t('bracket.ft')`,
|
||||
new i18n key EN/PT). Tier classes `bk-r32…bk-final` escalate size/heat; the Final hero card also
|
||||
shows venue (`.bk-venue`). Champion box: `has-champion` gold; **`is-sim` = blue + SIM chip**
|
||||
(a simulated champion must never read as real — same rule as the stats verdict; previously the
|
||||
old champion box showed sim champions in gold).
|
||||
- **Path highlight** now also lights SVG connectors: a path turns gold when **both** its
|
||||
`data-from`/`data-to` endpoints are in `pathRefs()`; the champion stem carries FINAL→FINAL.
|
||||
- **Motion:** cards rise + connectors draw (`pathLength="1"` + dash animation), staggered by round,
|
||||
all inside `@media (prefers-reduced-motion: no-preference)`; replays on each tab open (display:none
|
||||
restarts CSS animations) — intentional "chart assembles" effect.
|
||||
- ~~**Interim states until later steps:** mobile ≤767 shows the pinch-zoom wallchart (pager = Step 2);
|
||||
no view toggle yet (registry lands with the second view).~~ Superseded same day — Steps 2+3 below.
|
||||
|
||||
### Bracket redesign — Steps 2+3: view toggle, rounds pager, radial "orbit" (2026-07-03)
|
||||
- **View toggle:** segmented `Fases | Chaveamento | Radial` in the toolbar; explicit choice persists
|
||||
in `wc2026_prefs.bracketView`; with no stored pref the default follows the breakpoint (≤767px →
|
||||
rounds pager, else wallchart; a `matchMedia('change')` listener re-renders while unset). Zoom
|
||||
controls render only for chart views. `render()` dispatches: pager / `chartHTML` →
|
||||
`wallchartInnerHTML` | `radialInnerHTML`. Switching chart layouts resets to a fresh fit
|
||||
(`view.layoutId` check in `initInteractions`).
|
||||
- **Rounds pager — button navigation ONLY (user decision):** the first build used a scroll-snap
|
||||
swipe track; the user rejected horizontal scrolling, so pages are plain sections toggled with
|
||||
`hidden` by the chips (`initPager` ~15 lines, no ResizeObserver/height-clamp needed). Grid is
|
||||
**max 2 columns** (≥700px) — 3–4 columns made cards too narrow (user feedback). Opens on the
|
||||
first round with an unfinished match (`firstOpenPage`); `pagerIndex` survives re-renders. Cards
|
||||
(`.bk-pcard`) carry venue·city + status row and reuse `teamRowHTML` + the same
|
||||
`data-ref`/`data-match-id` delegation (modal + sim editor work unchanged).
|
||||
- **Radial = "orbit" view, redesigned to a user-supplied reference image** (circular predictions
|
||||
bracket with the trophy at center). NOT rectangular cards: **circular flag tokens** on concentric
|
||||
rings — outer ring = 32 entrants, each ring inward = a round's **winner slots** (a match's winner
|
||||
slot doubles as the next match's participant), trophy centerpiece (= the FINAL's winner slot,
|
||||
champion flag + name when decided, sim-blue when simulated), third-place = small labeled pair
|
||||
below the circle. `TGEO` radii chosen so adjacent/consecutive rings never collide (validated with
|
||||
an automated pairwise-overlap eval in preview — keep doing that after any radius change).
|
||||
**Semantics:** elbow route lines (radial segment + bend dot) turn **gold = real advancement**,
|
||||
**dashed blue = simulated pick**; eliminated entrants grey out (`tk-out`), TBD slots are striped
|
||||
discs (`tk-tbd`); names/scores live in the shared app tooltip (`has-tip`/`data-tip`, delegation
|
||||
in app.js `initTooltips`) and the modal. **Sim affordance lives on the winner slot** (`opts.slot`,
|
||||
not `opts.winner` — a TBD slot is exactly the simulatable one; that inversion was a shipped-then-
|
||||
fixed bug). Path highlight generalized: `showPath` lights ANY `[data-ref]` element + `.bk-le`
|
||||
endpoints; hover/focus delegation uses `closest('[data-ref]')`.
|
||||
- **Toolbar gotcha:** `.bracket-tools-left` holds 6 controls — needs `flex-wrap: wrap` or it forces
|
||||
~500px of page overflow at 375px (found via body scrollWidth sweep on mobile).
|
||||
|
||||
### Modal (`modal.js`)
|
||||
- **Native `<dialog>` + `showModal()`** → focus trap, Esc, `::backdrop` come free. Backdrop click =
|
||||
`event.target === dialog`. Focus restored to the opener on close. Card→modal is **event delegation
|
||||
|
|
@ -209,6 +273,11 @@ automated tests / linter (explicit spec constraint).
|
|||
viewport emulation desyncs the capture surface. At emulated widths > native, navigate via
|
||||
`preview_eval` + `navigateTo()` and verify geometry via eval/inspect; trust screenshots only at
|
||||
widths ≤ native. `preview_resize preset: desktop` resets it.
|
||||
9. **`aspect-ratio` + `min-height` can transfer size INTO width** (bracket wallchart, 2026-07-03) —
|
||||
on a box with `width: auto`, a violated `min-height` transfers back through the ratio and widens
|
||||
the element past its container (on mobile the 220px min became 585px of page overflow). Fix: give
|
||||
the box a definite width (`width: 100%`); then the ratio only drives height and min/max-height
|
||||
clamp it without transfer.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -491,7 +560,12 @@ supersedes the old "768–1439 single-row header" note.
|
|||
|
||||
## Current State
|
||||
|
||||
**Updated 2026-07-02.** Data: **R32 underway** — group stage COMPLETE (1–72) + R32 matches **73
|
||||
**Updated 2026-07-03.** **Bracket redesign Steps 1–3 shipped on master (not yet pushed):** the
|
||||
Knockout tab has 3 switchable views — center-out wallchart (desktop default), radial "orbit" (flag
|
||||
tokens per the user's reference image), rounds pager (mobile default, button-only navigation, ≤2
|
||||
columns). See Architecture → "Bracket redesign" (both entries). Pending: Step 4 champion
|
||||
celebration + polish pass + version bump to v1.1.0.
|
||||
Data: **R32 underway** — group stage COMPLETE (1–72) + R32 matches **73
|
||||
(RSA 0–1 CAN)**, **74 (GER 1–1 PAR, PAR 4–3 pens)**, **75 (NED 1–1 MAR, MAR 3–2 pens)**, **76
|
||||
(BRA 2–1 JPN)**, **77 (FRA 3–0 SWE)**, **78 (CIV 1–2 NOR)**, **79 (MEX 2–0 ECU)**, **80
|
||||
(ENG 2–1 COD)**, **81 (USA 2–0 BIH)** and **82 (BEL 3–2 SEN, AET)** finished (82/104 total);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue