The handoff stays on disk, not in the repo

The prototype ships a copy of thirty repo assets and the zip is a second copy
again — a megabyte of duplicate art in the history for a document whose
decisions now live in PROJECT.md and in the code. The folder is ignored, not
deleted: it is still there to read.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-31 14:41:50 +02:00
1 parent a331a1ae37
commit 3184752512
36 files changed
+5 -3573

No files matched your search

+5
View File
@@ -13,3 +13,8 @@ promo/clips/
# ios/.gitignore already keeps the copied web payload, Pods and Xcode's per-user junk out of it.
node_modules/
www/
# design hand-offs: read, built, and recorded in PROJECT.md — the prototype, its copy of the
# assets and the zip do not belong in the image or the history (they are ~1 MB of duplicate art)
design_handoff_*/
*.zip
Binary file not shown.
File diff suppressed because it is too large. Load diff
@@ -1,242 +0,0 @@
# Handoff: Menüführung — Text reduzieren (Splatter Tennis)
## Overview
Die funktionalen Screens von Splatter Tennis (Splash, PICK A GAME, MATCH SETUP, DIFFICULTY,
TRAINING, VS A FRIEND und die In-Game-Modals) tragen heute mehr Text als eine Entscheidung
braucht — auf `PICK A GAME` rund 60 Wörter, verteilt auf drei Rubriken mit Straps plus sechs
Poster mit je einer Regelzeile. Das Ergebnis dieser Session: eine reduzierte Fassung aller
funktionalen Screens (~12–18 Wörter auf der Wand) und ein Wechsel der aufrechten Display-Schrift
von **Bungee** auf **Jersey 15**.
Gameplay, Stats-Screens und Canvas-HUD sind bewusst NICHT Teil dieses Pakets.
## About the Design Files
`Menues.dc.html` ist eine **Design-Referenz in HTML** — ein Prototyp, der Aussehen und Struktur
zeigt, kein Produktionscode zum Kopieren. Splatter Tennis ist Vanilla JS ohne Build-Step
(`CLAUDE.md`, Punkt 5: „Zero dependencies, no build step, no framework"), also wird die Fassung
in der bestehenden Umgebung nachgebaut: DOM-Menüs in `index.html` + `src/main.js`, Canvas-Modals
in `src/render.js`, Texte in `src/config.js`. Kein neues Framework, keine neuen Dateien ausser
der Schriftdatei.
Die Datei enthält mehrere Runden untereinander, neueste oben. Verbindlich ist **Runde 5**
(„GESETZT — ALLE SCREENS IN JERSEY 15"). Darunter liegen als Historie: Runde 4 (Schrift-Kandidaten
Bebas Neue / Oswald / Jersey 15), Runde 3a (derselbe Satz in Bebas), Runde 2 (Bungee vs. Bangers),
Runde 1 (die zwei Grundrichtungen) und ganz unten der **IST-Stand**, pixelgenau aus dem heutigen
`index.html` nachgebaut — nützlich als Vor/Nach-Vergleich.
## Fidelity
**High-fidelity.** Palette, Masse, Schriftgrössen und Copy sind aus dem Repo übernommen
(`index.html` CSS, `config.MODES` / `MENU` / `COURTS` / `LEAGUES` / `OPPONENTS`, `beats.js`
Modal-Payloads). Alle Sprites/Poster im Prototyp sind echte Repo-Assets. Übernahme darf 1:1
erfolgen.
## Die drei Register (die eigentliche Entscheidung)
| Rolle | heute | neu |
|---|---|---|
| benennen — Screen-Titel, Rubriken, Karten- und Poster-Namen | Bungee | **Jersey 15** |
| rufen — einmal pro Screen: Fixture, Primär-Button, Modal-Headline | Bangers | Bangers (unverändert) |
| informieren — Zahlen, Labels, Chips | Silkscreen | Silkscreen (unverändert) |
Begründung Bungee → Jersey 15: Bungee ist Single-Weight und sehr fett/blockig; Jersey 15 sitzt
auf demselben Pixelraster wie Silkscreen (wirkt als Schriftfamilie mit der Sprite-Art), läuft
proportional und deutlich leichter. Beide sind SIL OFL.
**Grössen-Umrechnung Bungee → Jersey 15: ca. +40 %** (Jersey sitzt tiefer im Kasten und läuft
leichter). Konkrete Werte im Abschnitt „Design Tokens".
## Schrift einbauen
1. `Jersey15-Regular.ttf` von Google Fonts holen, wie Bungee subsetten (`pyftsubset`, Befehl
steht in `PROJECT.md`) → `assets/fonts/Jersey15-Subset.ttf`.
2. In `index.html` das `@font-face` von Bungee ersetzen (`?v=` mitziehen wie bei den anderen drei):
```css
@font-face { font-family: 'Jersey 15'; font-weight: 400; font-display: block;
src: url('assets/fonts/Jersey15-Subset.ttf?v=87') format('truetype'); }
```
3. Alle `Bungee`-Vorkommen in `index.html` auf `'Jersey 15'` umstellen (Liste unten),
`Bungee-Subset.ttf` und `Bungee-OFL.txt` löschen, `Jersey15-OFL.txt` daneben legen.
4. `main.js?v=N` in `index.html` bumpen (`CLAUDE.md`, Punkt 4).
## Screens / Views
### 1 — Splash (`#splash` in index.html)
**Zweck:** Eintritt; die Plakette zeigt wer du bist, der Primär-Button das nächste Fixture.
Änderungen:
- **Plakette (`#plaque`)** wird eine Zeile statt vier Grid-Areas: Wappen links (50px), rechts
Name + `LEVEL 12` in einer Baseline-Zeile, darunter der XP-Balken mit der Ziel-Zahl rechts.
**`#plGoal` entfällt komplett** — „WIN THE CUP TO REACH LEAGUE 4" sagt der Fixture-Button
darunter schon. Grid-Areas `name/lv/bar/goal` werden zu einem Flex-Row mit zwei Spalten.
- Name: Jersey 15 21px, `#ccd7ca`, `letter-spacing:0.5px` (war Silkscreen 700 13px)
- `LEVEL 12`: Silkscreen 700 10px, `#bcd455` (war Bangers 26px als `#plLv` — der Ruf gehört
dem Button unten, nicht der Plakette)
- Balken unverändert (6px, `#2c4238` Rahmen, Gradient `#3f9560 → #bcd455 55% → #e8b23a`)
- **Fixture-Button (`#mStart`)** bleibt Bangers 26px; die zweite Zeile (`#msLine`) verliert das
Rundenpräfix: `ROUND ONE: THE STRAWBERRY SELLER` statt
`4 ROUNDS · ROUND ONE: THE STRAWBERRY SELLER`. → in `config.cupFixture` die `line` kürzen
(`rounds.length + ' ROUNDS · '` fällt weg; die Rundenzahl steht im Modal).
- **`#mOther`** verliert seinen Strap (`<i>CLIMB · TRAINING · GORE · A FRIEND</i>` löschen),
Label auf Jersey 15 19px.
- **`#mStats` / `#mRanks`**: Straps ersetzt durch je eine Zahl aus lokalem Stand —
`STATS / 4 812` (Kill-Count, wie heute) und `BOARD / BEST 612` (eigener Bestwert; **kein**
Weltrang, der Splash lädt `/data/scores.json` nicht). Label Jersey 15 16px, Zahl
Silkscreen 700 10px `#bcd455`.
- Logo, Slogan (`Fifteen. Thirty. Forty. Dead.`), `#build` unverändert.
### 2 — PICK A GAME (`#stmode` / `#modeList`, gebaut in `main.buildTops`)
**Zweck:** einen Modus wählen. Das ist der Screen, der „erschlägt".
- **Rubriken** (`#modeList .mgroup > header`) verlieren ihren Strap (`<i>`) und werden ein Wort:
`THE SEASON → SEASON`, `THE TRAINING → TRAINING`, `OUT OF COMPETITION → CASUAL`.
Jersey 15 17px, `#bcd455`, `letter-spacing:2px`. → `config.MENU`: `sub` der drei `group`-Rows
löschen, `group`-Text kürzen; in `main.buildTops` das `<i>` aus dem `header`-Template nehmen.
- **Poster** tragen nur noch den Namen — `<i>${card.sub}</i>` fällt in `main.banner()` weg.
Damit werden die `sub`-Felder in `config.MODES` für die Wand irrelevant (Aufbewahren lohnt:
die Modals nutzen dieselben Sätze).
- **Hero-Poster** (das Fixture, `mode:'cup'`) ist der einzige mit einer zweiten Zeile und dem
einzigen Ruf: Name in **Bangers 32px**, darunter die Fixture-Zeile in Silkscreen 10px
`#f0cfc4`. Höhe 142px. `.way`-Ribbon („THE WAY UP") unverändert.
- **Übrige Poster** in Jersey 15, Höhe gestaffelt statt einheitlich 148px:
- TRAINING-Raum: zwei Poster **nebeneinander**, je `flex:1`, Höhe 106px, Name 27px
- CASUAL-Raum: drei Poster gestapelt, Höhe 84px, Name 30px
- **Regeln, die wirklich anders sind, bleiben als Chip** (`.last`-Optik, Silkscreen 8px, acid,
`rgba(0,0,0,0.72)` Grund): `18 RUNGS` auf TRAINING, `LAST` auf dem zuletzt gespielten.
- Ergebnis: der ganze Wall passt in 844px (heute zwei Bildschirme). Gerechnet mit
Header 64 + Padding 14 + 142/106/84 + Gaps 17/8.
### 3 — MATCH SETUP (`#setup`)
- `<h3 id="s01">01 · PLAYER</h3>` / `02 · COURT` → Rubrik-Zeile wie auf der Wand:
Jersey 15 17px acid, Text `PLAYER` / `COURT`. Die Nummerierung entfällt (es sind zwei Blöcke
auf einem Screen, keine Schritte).
- Über der Platzliste steht die Legende **einmal**: rechts in der Rubrik-Zeile
`BOUNCE · PACE` (Silkscreen 8px, dim).
- **Platz-Zeilen** (`#courtList button.court`) verlieren `<i>${court.sub}</i>` — Name
(Jersey 15 19px) plus die zwei Meter, die dasselbe wortlos sagen. Bildhöhe 66 → 60px.
- **Gesperrte Plätze** (`.court.lock`) behalten Bild und Namen, statt einer Erklärung nur
`LEAGUE 4` in `#cf5a4e`, Silkscreen 9px.
- **Tour-Tiles**: `MEN'S SINGLES` / `WOMEN'S SINGLES` → `MEN'S` / `WOMEN'S`, Jersey 15 16px.
- **`#sSum`** (die Zusammenfassungszeile über SERVE UP) entfällt — alle drei genannten Werte
sind auf dem Screen sichtbar markiert.
- `SERVE UP` bleibt Bangers 26px auf `#a4231f`.
### 4 — DIFFICULTY (`#stsub` / `#modeSub button.chip`, aus `config.DIFFS`)
- Chip wird zweispaltig: Name links (Jersey 15 30px), **drei Pips** rechts (je 10×10px, kein
Radius) — 1/2/3 gefüllt. EASY/MEDIUM acid `#bcd455`, HARD `#cf5a4e`; leere Pips
`rgba(255,255,255,0.12)`.
- Kein Erklärtext. Padding 26px/16px, `gap:10px`.
- `LAST`-Chip bleibt oben rechts im gewählten.
### 5 — TRAINING (`#train` / `#trainList`, gebaut in `main.buildTrain`)
- `<h3>PICK YOUR OPPONENT<span>ONE GAME · GO AGAIN</span></h3>` entfällt — der Screen-Titel
`TRAINING` genügt.
- **Revanche-Tile** (`profile.prof.out`) wird eine **breite Zeile über dem Raster**: Kopf 52px
links, Name (Jersey 15 24px), darunter `PUT YOU OUT` (statt `PUT YOU OUT OF THE CUP`) in
`#e08a7c`, Chevron rechts. Rahmen `#a4231f`, Grund `rgba(164,35,31,0.16)`.
- **Übrige Rungs** bleiben das 2-spaltige Raster: Kopf 44px, Name Jersey 15 17px zentriert,
Rangnummer zweistellig (`01`, `02`, …) statt `No. 1` — Silkscreen 8px dim.
- **Letzte Kachel** ist ein Ziel, keine Liste: gestrichelter Rahmen `#2c4238`, `LEAGUE 4` und
`13 — 15` in `#4a5a52`. (Heute endet die Liste einfach am Band-Cap.)
### 6 — VS A FRIEND (`#vs` / `#vsPick`)
- Die drei `<h3>` mit Straps (`01 · YOUR NAME / ON THEIR SCOREBOARD`, `02 · HOST A MATCH /
THEY COME TO YOU`, `OR JOIN THEIRS / WITH THEIR CODE`) werden drei Wörter:
**`YOU` / `HOST` / `JOIN`**, Jersey 15 17px acid.
- Host-Buttons: `CLASSIC TENNIS` / `DEATH MATCH` → `CLASSIC` / `DEATH MATCH` nebeneinander,
Jersey 15 19px, Padding 20px.
- Join-Zeile: Code-Feld plus Button `GO` (statt `JOIN` — daneben steht die Rubrik JOIN),
Feld-Letterspacing 6px.
- `#vsErr`-Meldungen unverändert (`THE CODE IS FOUR LETTERS`).
### 7 — In-Game-Modals (`render.drawModal`, Payloads aus `beats.js`)
Die Box-Sprache aus dem 2026-08-31-Pass bleibt (`MODAL_PAD 14`, `MODAL_GAP 13`, `MODAL_BTN 30`,
`MODAL_FOOT 8`, Breite `min(W-44, 244)`, Fill `rgba(8,22,16,0.93)`, Edge `rgba(120,150,130,0.45)`,
Rules `rgba(120,150,130,0.22)`). Reduziert wird der **Inhalt einer Row**:
- **Eine Regel pro Row, keine Unterzeile.** Heute rendert `modalRows` pro `m.rules`-Eintrag
`lead` + `sub`; der `sub` formuliert in fast allen Fällen den `lead` nur um
(`YOUR LEAGUE, ROUND BY ROUND` / `WIN IT ALL — MOVE UP A LEAGUE`). Neu: **eine** Zeile, die
das Ergebnis nennt — `WIN IT ALL — MOVE UP A LEAGUE`. Also in `beats.js` die `rules`-Arrays
auf je einen String reduzieren und `modalRows` entsprechend vereinfachen; `m.body` bleibt als
Fallback unverändert.
- **Blut ist Pips, kein Satz**: Row `POINTS DRAW BLOOD` (gekürzt von `ITS POINTS DRAW BLOOD`)
plus `TUNE.matchPlayerHp` Pips **in derselben Zeile rechts**, statt Zeile + Unterzeile
(`AT ZERO YOU ARE EATEN`) + Pips darunter.
- **Masthead**: Titel Bangers 27px in der Modal-Farbe, darunter EINE Silkscreen-10px-Zeile.
Beim Rules-Modal ist das die Sachzeile (`LEAGUE 3 · 4 ROUNDS`) — hier landet die Rundenzahl,
die aus `cupFixture.line` genommen wurde. Beim Walk-on bleibt es `foe.line`
(`CREAM WITH THAT?`).
- **Walk-on** (Gegner): Kopf-Sprite 56px, Name, `foe.line`, dann EINE Row mit den zwei Leveln
gegenüber (`LEVEL 14` hot links, `YOURS 12` dim rechts) — statt zwei Textzeilen plus
Split-Figur.
- Footer-Button unverändert (`WALK ON` / `GOT IT` / `PLAY ON`, `m.btn` überschreibt).
### 8 — Quit-Modal (`#qAsk` / `.qBox`)
Unverändert übernehmen — es ist schon lean. Nur `LEAVE THE MATCH?` von Silkscreen 12px auf
**Bangers 20px** (es ist eine Frage, die ruft), `PLAY ON` auf Jersey 15 17px.
## Interactions & Behavior
Keine Änderung an Navigation oder Zustandslogik. Alles Bestehende bleibt:
- `go(stage)` / `#intro[data-stage]`, ein Overlay, vier Panels
- Tap auf ein Poster antwortet UND geht weiter (`main.buildTops`), `pickMode` schreibt
`localStorage.mode`
- Die Deal-in-Animation (`#intro.deal`, `dealIn` 0.28s `cubic-bezier(0.34,1.56,0.64,1)`,
Delays 0.02/0.09/0.16/0.23/0.30s, `.mgroup`-Staffel 0.09/0.17/0.25s) gilt weiter — die
Rubriken bleiben `<section class="mgroup">`, damit sie greift
- `prefers-reduced-motion: reduce` schaltet sie weiter ab
- Modal-Dismiss-Regeln unverändert (`m.in < 1` schluckt die Gesture, Tap überall entlässt,
`G.seen.<key>` gated)
- Swipe-links-zurück im Shell bleibt unberührt
## State Management
Nichts Neues. Zwei Werte werden neu GELESEN, beide existieren schon:
- `profile.prof.out` (der Rung, der dich aus dem Cup geworfen hat) → Revanche-Zeile; wird
bereits von `buildTrain` genutzt
- der eigene Bestwert für die BOARD-Kachel → aus `stats` (lokal), **nicht** vom Server
## Design Tokens
Unverändert aus `index.html`:
```
--ink #0e1714 --panel rgba(42,62,54,0.42) --line #2c4238
--acid #bcd455 --cream #ccd7ca --dim #6c7f74
--red #a4231f --bad #cf5a4e --solid #16211d
Poster-Veil: linear-gradient(0deg, rgba(6,10,8,0.94) 0%, rgba(6,10,8,0.86) 22%,
rgba(6,10,8,0.5) 58%, rgba(6,10,8,0) 100%) — Höhe 52–62 % je Kachelhöhe
Modal: fill rgba(8,22,16,0.93) · edge rgba(120,150,130,0.45) · rule rgba(120,150,130,0.22)
Rahmen: 2px überall in den Menüs, 1px im Canvas-Modal
```
Typografie neu (Bungee-Wert → Jersey-15-Wert):
```
Screen-Titel (.hdr h2) 23px → 33px/1 letter-spacing 1px
Rubrik / Raum-Label 15px → 17px letter-spacing 2px
Poster-Name, Hero — → Bangers 32px/0.95 (der eine Ruf)
Poster-Name, TRAINING-Paar 17px → 27px/1
Poster-Name, CASUAL-Stapel 19px → 30px/1
Karten-/Platz-Name 15px → 22px
Difficulty-Chip 22px → 30px
Training-Tile-Name 12px → 17px/1
Sekundär-Button 13px → 18px
Zahlen, Labels, Chips Silkscreen 8–10px (unverändert)
Primär-Button Bangers 26px (unverändert)
```
## Assets
Alle Assets im Prototyp stammen aus dem Repo, unverändert — nichts muss neu gezeichnet werden:
`assets/logo.png`, `menu_bg.png`, `mode_cup|arcade|train|gore|classic|vs.png`,
`court_clay|hard|grass|gloom.png`, `badge_l3.png`, `z_{sh,bb,sp,gk,rm,st,ma,ru,sb,sg,lj,cu}head.png`,
`fonts/{Silkscreen-Regular,Silkscreen-Bold,Bangers-Regular}.ttf`.
NEU nötig: `fonts/Jersey15-Subset.ttf` (Google Fonts, SIL OFL) — ersetzt `Bungee-Subset.ttf`.
## Files
- `Menues.dc.html` — der Prototyp. Runde 5 oben ist verbindlich; darunter Runde 4 (Schriftwahl),
3a (Bebas-Fassung), 2 (Bungee vs. Bangers), 1 (Grundrichtungen), IST-Stand.
- `support.js` — Runtime des Prototyps, für die Implementierung irrelevant.
- `assets/` — die Repo-Assets, die der Prototyp lädt.
Betroffene Repo-Dateien: `index.html` (CSS + Markup der Panels), `src/main.js`
(`banner`, `buildTops`, `buildSub`, `buildTrain`, `refreshSplash`), `src/config.js`
(`MENU`-Gruppen, `cupFixture.line`, ggf. `MODES.sub`), `src/render.js` (`modalRows`,
`modalLayout`), `src/beats.js` (die `rules`-Payloads).
## Vor dem Commit
`node test.js` muss grün sein (`CLAUDE.md`, Punkt 2) — die Fixture-Deskriptor-Tests hängen an
`cupFixture`, also die `line`-Kürzung dort mit anpassen. `main.js?v=N` bumpen.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 714 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

File diff suppressed because it is too large. Load diff