Every screen deals itself in, every time

The entrance is no longer a one-off on the boot: dealStage re-arms the class at
the funnel every stage change already passes, so the title screen flies its
plaque and buttons in whenever you arrive at it. The sub-menus join in — their
header, content and footer arrive one after the other instead of the panel
dropping in as one slab — and the poster wall deals its three rooms rather than
its list, since a moving child inside a moving parent starts at twice the
offset and reads as a stutter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-31 13:25:26 +02:00
1 parent aab83dacdc
commit 3324fe9cda
3 files changed
+67 -18

No files matched your search

+37 -13
View File
@@ -196,8 +196,32 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
#intro[data-stage="player"] #player,
#intro[data-stage="promo"] #promo,
#intro[data-stage="card"] #card,
#intro[data-stage="newbest"] #newbest { display: flex; flex-direction: column; flex: 1;
animation: drop 0.3s ease-out; }
#intro[data-stage="newbest"] #newbest { display: flex; flex-direction: column; flex: 1; }
/* ...and every screen DEALS ITS BANDS IN (2026-08-31, Oliver: "wäre natürlich auch toll für die
untermenüs"). The panel used to drop in as one slab; now its header, its content and its
footer arrive one after the other on the same overshoot the splash and the canvas modals use.
The children of the stage, not the stage itself — a slab that drops says "a screen appeared",
a deal says "the machine is laying this out for you". The splash keeps its own finer stagger
below (its two bands would otherwise fly as two lumps), hence the :not. */
#intro.deal > .card > div:not(#splash) > * {
animation: dealIn 0.28s cubic-bezier(0.34, 1.56, 0.64, 1) backwards; }
#intro.deal > .card > div:not(#splash) > *:nth-child(1) { animation-delay: 0.02s; }
#intro.deal > .card > div:not(#splash) > *:nth-child(2) { animation-delay: 0.09s; }
#intro.deal > .card > div:not(#splash) > *:nth-child(3) { animation-delay: 0.16s; }
#intro.deal > .card > div:not(#splash) > *:nth-child(4) { animation-delay: 0.23s; }
#intro.deal > .card > div:not(#splash) > *:nth-child(n+5) { animation-delay: 0.30s; }
/* the poster wall deals its ROOMS, not one lump: the list is the whole screen there, so letting
it arrive as a single band wastes the entrance. The list itself stops animating — a moving
child inside a moving parent starts at twice the offset and reads as a stutter. */
#intro.deal #stmode > #modeList { animation: none; }
#intro.deal #modeList > .mgroup {
animation: dealIn 0.28s cubic-bezier(0.34, 1.56, 0.64, 1) backwards; }
#intro.deal #modeList > .mgroup:nth-child(1) { animation-delay: 0.09s; }
#intro.deal #modeList > .mgroup:nth-child(2) { animation-delay: 0.17s; }
#intro.deal #modeList > .mgroup:nth-child(3) { animation-delay: 0.25s; }
@media (prefers-reduced-motion: reduce) {
#intro.deal > .card > div:not(#splash) > *,
#intro.deal #modeList > .mgroup { animation: none; } }
/* the overlay is HIDDEN during play, not removed: a restart puts it straight back, and the
display:grid above would otherwise win over the hidden attribute */
#intro[hidden] { display: none; }
@@ -522,26 +546,26 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
/* THE DEAL-IN (2026-08-31, Oliver: "es wäre toll, wenn sich die buttons nach dem laden aufbauen
würden — arcade style"). The canvas modals have always arrived on an easeOutBack overshoot
rather than decelerating politely into place; this is that same snap, in CSS, for the one
moment the menu has an entrance to make. It fires ONCE, on the boot: the rule hangs off
:not(.busy), so it triggers when main.js takes the loading state off and never again — coming
back from a run must not make you wait for a flourish you have already seen. */
moment the menu has an entrance to make. It plays on EVERY arrival at the title screen, not
just the boot (Oliver) — main.dealSplash re-arms the class, because an animation whose class
never left cannot restart itself. */
@keyframes dealIn {
from { opacity: 0; transform: translateX(-56px); }
60% { opacity: 1; }
to { opacity: 1; transform: translateX(0); }
}
#splash:not(.busy) #plaque,
#splash:not(.busy) .foot.bare > * {
#intro.deal #splash #plaque,
#intro.deal #splash .foot.bare > * {
animation: dealIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) backwards; }
#splash:not(.busy) #plaque { animation-delay: 0.02s; }
#splash:not(.busy) #mStart { animation-delay: 0.12s; }
#splash:not(.busy) #mOther { animation-delay: 0.19s; }
#intro.deal #splash #plaque { animation-delay: 0.02s; }
#intro.deal #splash #mStart { animation-delay: 0.12s; }
#intro.deal #splash #mOther { animation-delay: 0.19s; }
/* the pair of secondary buttons is a CLASS, so it needs the same weight as the shorthand above
to override its delay — the id selectors around it get there on their own */
#splash:not(.busy) .foot.bare > .two { animation-delay: 0.26s; }
#splash:not(.busy) #build { animation-delay: 0.33s; }
#intro.deal #splash .foot.bare > .two { animation-delay: 0.26s; }
#intro.deal #splash #build { animation-delay: 0.33s; }
@media (prefers-reduced-motion: reduce) {
#splash:not(.busy) #plaque, #splash:not(.busy) .foot.bare > * { animation: none; } }
#intro.deal #splash #plaque, #intro.deal #splash .foot.bare > * { animation: none; } }
/* the boot bar wears the stats screen's kill bar, doing duty as a loading bar. While #splash is
.busy it stands in the buttons' place — same band, same height, so nothing jumps when it goes. */
#boot { display: none; margin-bottom: 10px; }