Files
splatter-tennis/design_handoff_menu_text_reduction
wuwiandClaude Fable 5 a331a1ae37 The menu text reduction: the design handoff, built
Sixty words on the wall became a dozen. The handoff's own summary of the rule:
Jersey 15 NAMES (screen titles, rooms, cards), Bangers CALLS exactly once per
screen (the fixture, the primary button, a modal headline), Silkscreen INFORMS
(numbers, labels, chips) — and a sentence survives only where it carries a
decision. Everything else moved into a bar, a pip or the modal that opens with
the mode.

  · Jersey 15 bundled subset (9 KB) and Bungee retired after one afternoon
  · SPLASH: the plaque is one row, the goal line is gone (the fixture button
    below said it already), the two doors carry a number each
  · PICK A GAME: rooms are one word, posters are their names, the fixture is a
    hero with the only second line — the whole wall fits one screen now
  · MATCH SETUP: unnumbered blocks, the meters' legend once instead of a
    description per court, no summary footer
  · DIFFICULTY: three pips instead of three sentences
  · TRAINING: the revanche is a full-width row, rungs are numbers, the list
    ends on the league that opens the rest of the ladder
  · VS: three paragraphs became YOU / HOST / JOIN
  · MODALS: one rule per row (the sub was the lead again in other words), the
    blood pool as pips on that same line, and the walk-on's two levels in ONE
    face at ONE size — a comparison drawn at two sizes is a headline with a
    footnote (Oliver)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 14:41:25 +02:00
..

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):
    @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.