Keep the praise word on screen, and take the cliff out of the groundstroke

Oliver on v371: the praise word is cut off on the left on the iPhone. It
is centred under the player's feet, so out wide it ran past the edge;
every pop is now clamped to the canvas by its measured width.

Step 4, measured first. The rally sim gets a human bot (taps on the timed
ring with a timing spread), a Climb mode and a lost-point breakdown. At
level 26 the ladder falls over six rungs and then goes flat: nearly every
lost point is the player's own early whiff, the CPU barely ever misses,
and the auto-run reaches everything, so no opponent dial decides points.
A quality ramp, a follow-through and CPU put-aways were each measured
and reverted; the options go to Oliver in PROJECT.md.

Shipped: in the rally modes q no longer drops from 1 to 0.43 one ms past
PERFECT; it falls smoothly to the window's edge (TUNE.qSeamless). A tap
30 ms early is q 0.86 instead of 0.61. Same window, same whiff edge. v372.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5.5 committed 2026-10-14 18:01:24 +02:00
1 parent d561050af8
commit 5dd5d71c33
7 files changed
+170 -9

No files matched your search

+29
View File
@@ -1143,6 +1143,35 @@ test('a SHORT ball is an approach, a deep one keeps the baseliner back, and nobo
} finally { TUNE.matchFlub = flub; }
});
test('a groundstroke a little off PERFECT is a little worse, not a weak ball (no cliff past perfectMs)', () => {
// Step 4's measurement (2026-10-14): q was 1 inside perfectMs and 1 - off/half outside it, so a
// groundstroke (half-window ~80 ms) fell from 1 to 0.43 a millisecond past PERFECT, and a tap 30 ms
// before the ring's kiss came back at q ~0.6, ~45 ms at 0.32 (0.57 now). The rally modes now fall from 1 at the edge of
// PERFECT to the window's edge. The finger lands 3 frames EARLY of the kiss, every ball.
const assist = TUNE.autoAssist; TUNE.autoAssist = 1.15;
try {
startMatch(); G.interlude.introT = 0; G.match.opp = 6;
for (let i = 0; i < 2.2 * 60; i++) update(DT);
let armed = false, incoming = 0, returned = 0, sumQ = 0;
for (let i = 0; i < 90 * 60; i++) {
G.modal = null; G.modalQ.length = 0; G.hp = G.hpMax; G.match.opp = 6;
if (G.phase === 'pretoss' && !(G.interlude && G.interlude.introT > 0)) { if (i % 40 === 0) keyPressed('Space'); }
else if (G.phase === 'toss') { if (ball.vy < 0.4 && ball.y > 2.4) keyPressed('Space'); }
else if (G.phase === 'rally' && ball.active && ball.lastHit === 'O' && ball.vz > 0 && !armed) {
const c = ringCue();
if (c && c.eta - c.sweet <= 3 / 60 + 1e-6 && c.eta - c.sweet > 2 / 60) { armed = true; incoming++; keyPressed('Space'); }
}
const before = ball.lastHit;
update(DT);
if (armed && before === 'O' && ball.lastHit === 'P') { returned++; sumQ += ball.pow; armed = false; }
else if (armed && (!ball.active || G.phase !== 'rally')) armed = false;
}
assert.ok(incoming >= 20, 'a real sample: ' + incoming);
assert.ok(returned / incoming >= 0.9, `an early-ish tap still returns: ${returned}/${incoming}`);
assert.ok(sumQ / returned >= 0.45, 'and still returns a real ball (0.32 on the old curve): mean q ' + (sumQ / returned).toFixed(2));
} finally { TUNE.autoAssist = assist; }
});
test('a TAP is timed from touch-down: a normal 120 ms tap on the gold ring still returns cleanly', () => {
// Oliver, 2026-10-14: "manchmal scheine ich den Ball trotz gutem Timing nicht mehr zu bekommen".
// A tap only proves it is a tap when the finger LIFTS, so it swung ~100-150 ms late — inside the