A gesture is read in a pause, not in a point

The flick lesson rode the incoming ball, over the player's shoulder — the one
moment he has no attention to spare for reading anything. It moves into the
room this game already keeps for teaching gestures: the serve stance, standing
still, mimed on the apron by the very demo the slingshot lesson plays. Same
clock, same hand, same words slot — one teacher, three lessons, and nothing new
drawn over a live rally.

The words carry both halves now, SWIPE AS YOU HIT TO AIM: WHEN alone teaches
nothing, and WHAT FOR alone gets tried at the wrong moment and read as a
gesture that does not work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-17 08:45:23 +02:00
1 parent 67cb0b74d7
commit 553b765846
3 files changed
+35 -31

No files matched your search

+7 -2
View File
@@ -91,8 +91,13 @@ communicating its own rules. Model A only works if the player can see they are b
only way in.
6. ~~**Teaching**~~ **DONE** (2026-08-17). The ghost-hand lesson for the PLACEMENT FLICK, in the
same register as PULL DOWN and TAP AS IT ARRIVES: a dotted track out of the player, the hand
riding it, SWIPE AS YOU HIT, mimed both ways in turn so it never teaches one corner.
same register as PULL DOWN and SWIPE TO DODGE — because it is now literally the same demo: the
apron mime, played in the SERVE STANCE after a beat of standing still, mimed both ways in turn so
it never teaches one corner. **A gesture is read in a pause, not in a point** (Oliver: "it is
displayed mid-play.. please rather show it in one of the pauses"): the first cut rode the
incoming ball, over the shoulder, at the moment the player has the least attention to spare.
The words carry both halves — SWIPE AS YOU HIT TO AIM — because WHEN alone teaches nothing and
WHAT FOR alone gets tried at the wrong moment and read as broken.
It rides the failure it answers — `G.flatStreak`, returns that left with no aim on them
(`flatCount`, reset by the first aimed one) — and only after `TUNE.flickHintAfter` of them,
because hitting flat is a legal shot and not a mistake. **One lesson at a time:** the tap hint
+1 -1
View File
@@ -659,6 +659,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one') {
</div>
</div>
</div>
<script type="module" src="src/main.js?v=279"></script>
<script type="module" src="src/main.js?v=280"></script>
</body>
</html>
+27 -28
View File
@@ -2140,26 +2140,22 @@ function drawHitHint() {
// goes, and wrong-footing the body across the net is how points are actually won. It was taught
// nowhere on touch: the placement ring shows the result of a flick, which is a receipt, not a
// lesson — if you never happen to swipe you never get one, so you never learn there was anything
// to learn. Same ghost hand as every other gesture in this game, over the same shoulder, riding
// the same failure it answers (a run of returns hit flat — doHit resets flatStreak the moment one
// leaves with an aim on it). It mimes BOTH ways in turn or it teaches one corner.
// to learn.
// IT IS TAUGHT IN THE PAUSE, NOT IN THE POINT. It first rode the incoming ball, over the player's
// shoulder — which is the moment he has the least attention to spare for reading anything: "it is
// displayed mid-play.. please rather show it in one of the pauses" (Oliver, 2026-08-17). So it
// moved into the room this game already keeps for teaching gestures: standing still in the serve
// stance, on the apron, in the very demo the slingshot lesson plays. Same clock, same mime, same
// words slot — one teacher, three lessons, and nothing new drawn over live play.
// Both ways in turn, or it teaches one corner, and away from whichever edge he is standing against.
function drawFlickHint() {
const cyc = 1.4, t = G.idleT % cyc;
const dir = (((G.idleT / cyc) | 0) % 2) ? -1 : 1;
const slide = Math.min(1, t / 0.8), gone = t > 0.95; // stroke, held a beat, lifted, repeat
if (gone) return;
const p0 = proj(P.x, 0, P.z);
const hx = Math.round(p0.x), hy = Math.round(p0.y) - 52;
ctx.save(); ctx.globalAlpha = 0.9;
ctx.fillStyle = UI.dim; // the track the thumb travels
for (let d = 10; d <= 38; d += 7) ctx.fillRect(hx + dir * d - 1, hy, 2, 2);
drawGhostHand(hx + dir * (10 + 28 * slide), hy, 1); // starts clear of his own sprite
ctx.font = F(10); ctx.textAlign = 'center'; ctx.textBaseline = 'top';
// ...and the words sit ABOVE the stroke and OPPOSITE it: below is the player's own feet and the
// BASELINE, and 10px type across a bright white line is the one place on this court it cannot be
// read. Clamped off the screen edges too — this rides the player and he stands in the corners.
shadowText('SWIPE AS YOU HIT', Math.max(52, Math.min(W - 52, hx - dir * 22)), hy - 26, UI.warm);
ctx.restore();
const n = ((G.idleHintT - TUNE.pullHintAfter) / 1.9) | 0;
const px = proj(P.x, 0, P.z).x;
// ...and the words carry BOTH halves, because either one alone is useless: WHEN (as you hit —
// a swipe at any other moment does nothing, and a player who tries one and sees nothing concludes
// the gesture is not there) and WHAT FOR (it aims). One line, the same imperative as PULL DOWN
// and TAP AS IT ARRIVES.
demoSwipe(px < W * 0.3 ? 1 : px > W * 0.7 ? -1 : (n % 2 ? -1 : 1), 0, 'SWIPE AS YOU HIT TO AIM');
}
// The modal: drawn LAST, over everything, and the world behind it is frozen (gameplay.update
@@ -2729,19 +2725,22 @@ export function render() {
if (txt) shadowText(txt, W / 2, METER_Y(), UI.warm); // same slot the draw meter uses
if (demo) drawPullHint(); // show the gesture instead of only naming it
}
// the tennis struggle hints: both ride the exact failure they answer, and only one at a time —
// teaching the flick to someone who cannot get a racket on the ball is the wrong lesson, so the
// tap always wins.
// THE FLICK LESSON BELONGS TO THE RALLY MODES, which is what rallyFeel() already means: CLASSIC
// and ZOMBIE TENNIS. Not the gore mode, and not gore's OPENER either — that tennis is a prologue
// you play for one game before the court turns, and placement is not the skill it is asking for.
// the tennis struggle hints, each riding the exact failure it answers.
// The TAP lesson stays on the incoming ball: it is about a moment, and a moment can only be
// taught while it is happening. The FLICK lesson is about a gesture, and a gesture is read in a
// PAUSE — so it waits for the serve stance and mimes itself on the apron there, exactly like the
// slingshot's. Nothing new is drawn over a live rally.
// It belongs to the RALLY MODES, which is what rallyFeel() already means: CLASSIC and ZOMBIE
// TENNIS. Not the gore mode, and not gore's OPENER either — that tennis is a prologue you play
// for one game before the court turns, and placement is not the skill it is asking for.
// (`G.mode === 'tennis'` covered classic AND that prologue, which is exactly the wrong seam; the
// match itself is not mode 'tennis' at all, it plays under splatter's permanent interlude.)
// Touch only: on a keyboard the aim is held keys and 'SWIPE' would name a gesture that does not
// exist there.
const inRally = G.phase === 'rally' && ball.active && ball.lastHit === 'O';
if (G.mode === 'tennis' && inRally && G.passStreak >= 2) drawHitHint();
else if (IS_TOUCH && inRally && rallyFeel() && G.flatStreak >= TUNE.flickHintAfter)
if (G.mode === 'tennis' && G.phase === 'rally' && G.passStreak >= 2 && ball.active && ball.lastHit === 'O')
drawHitHint();
else if (IS_TOUCH && rallyFeel() && G.phase === 'pretoss' && G.idleHintT > TUNE.pullHintAfter
&& G.flatStreak >= TUNE.flickHintAfter)
drawFlickHint();
// The free-floating register: no panel, one fixed slot, shouted. PERFECT, GAME N, DOUBLE KILL,
// RETURNED, CHANGEOVER, weapon labels — everything that used to be plain white 12px text sitting