THE SEASON, phases 1-4: the front door is the fixture, and the club remembers

The tournament is the canonical path, so the game finally says so. The splash's
primary button names the next cup fixture and enters the draw; the poster wall
moved one tap down and deals three named rooms (the season, the training, out of
competition) with the cup at the top. Two profile fields remember every attempt
— rounds ever reached per league, and the body that put you out — so a lost cup
is a line on the board instead of a null event, and the training court offers
that body first, marked. The promotion names what waits in the new league.

Overlays consolidated in the same pass: three modal drawers became one box with
a masthead, hairline-separated rows and a real footer button (any tap still
dismisses), and the run-end summary wears the same box — headline, xp, mark, and
the fixture with ENTER THE DRAW beside PLAY AGAIN. The cup's own exit is a
ceremony now: OUT IN THE QUARTER-FINAL, your best standing beside it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-31 11:14:25 +02:00
1 parent 063b01d2a5
commit 5c7521f867
10 files changed
+603 -204

No files matched your search

+36 -5
View File
@@ -846,13 +846,25 @@ export const MODES = [
// opens its own second step — classic deals the difficulty chips, zombie tennis deals its two
// sub-mode cards (arcade / the cup), gore just IS gore. A row either points at a run mode in MODES
// (`mode`) or carries its own card and the MODES ids it fans out to (`kids`).
// THE ROOMS, NOT A SHELF (2026-08-31, THE SEASON). The wall used to deal five posters as equals
// with the career hidden two taps inside ZOMBIE TENNIS, so nothing on screen said what any of them
// was FOR — Oliver: "alles ist irgendwie beliebig". Three named groups answer that before a single
// caption is read: one path up, a room to practise in, and a room where nothing counts. A `group`
// row is a heading (main.buildTops), not a poster.
//
// The cup left the ZOMBIE TENNIS pocket for the top of the wall — it is the canonical path, and a
// canonical path does not live behind a fan-out. Its two former siblings (the climb, the training
// court) stand on their own in the training group, which also cost the second step its only other
// job: CLASSIC's difficulty chips are all that still fan out.
export const MENU = [
{ mode: 'classic', diffs: true },
// the WAY-UP ribbon shows on THIS level too, so the click path to the promotion is marked
// from the first screen of the picker (main.banner reads `tag`)
{ name: 'ZOMBIE TENNIS', sub: 'THE DEAD CLUB PLAYS YOU', art: 'mode_zombie', kids: ['zombie', 'cup', 'train'],
tag: 'THE WAY UP' },
{ group: 'THE SEASON', sub: 'THE ONLY WAY UP THE CLUB' },
{ mode: 'cup' },
{ group: 'THE TRAINING', sub: 'SHARPEN UP · NOTHING HERE MOVES YOUR LEAGUE' },
{ mode: 'zombie' },
{ mode: 'train' },
{ group: 'OUT OF COMPETITION', sub: 'NO LEAGUE, NO RECORD, NO STAKES' },
{ mode: 'gore' },
{ mode: 'classic', diffs: true },
// NETPLAY (prototype): a poster with no run mode of its own — its second step is HOST / JOIN,
// and either chip starts classic tennis against the other phone (beats.startNetVs + src/net.js)
{ name: 'VS A FRIEND', sub: 'LIVE 1V1 · REAL TENNIS · TWO PHONES', art: 'mode_vs', net: true },
@@ -941,6 +953,25 @@ export const cupRoundsFor = lg => {
return rounds.concat([{ name: 'THE FINAL', band: [hi], need: 2 }]);
};
// THE SEASON (2026-08-31, PROJECT.md "THE SEASON"): what the club has you down for next. The
// tournament is the canonical path and every screen that points at it — the splash's front door,
// the run-end handover, the promotion's second beat — says the SAME sentence, because three
// screens drifting apart on its wording is exactly how the story stopped reading as one. Pure
// descriptor: it starts nothing, it only names the fixture.
export const cupFixture = (lg, champion = 0) => {
const rounds = cupRoundsFor(lg), first = rounds[0], foe = matchFoe(first.band[0]);
const held = champion && lg >= LEAGUES.length; // the champion has nothing above him left
return { lg, league: leagueOf(lg), rounds, rung: first.band[0], foe,
title: held ? 'DEFEND THE TITLE' : 'LEAGUE ' + lg + ' · THE CUP',
line: rounds.length + ' ROUNDS · ' + first.name + ': ' + foe.name };
};
// How far a cup record reads, in the rounds' own words: 3 of 4 rounds reached is THE SEMI-FINAL.
export const cupRoundName = (lg, reached) => {
const rounds = cupRoundsFor(lg);
return reached >= rounds.length + 1 ? 'WON' : (rounds[reached - 1] || rounds[0]).name;
};
export const TOURS = [
// `kit` — HOW this tour's art takes a colour, because the two sets are dressed differently and the
// same operation cannot serve both.