Serve bounce sprite switches exactly at the ball's apex

Hand-raised frame while the ball rises, pat-down frame from the apex on —
synced to the ball's direction instead of a height threshold. Includes
Oliver's hand-tuned ball offset.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-07-11 15:18:32 +02:00
1 parent 7069723042
commit 0bf6937121
1 file changed
+6 -3
+6 -3
View File
@@ -638,8 +638,11 @@ function drawChar(ch) {
// pick sprite
const pre = ch.side === 'P' ? 'p_' : 'o_';
let name = pre + (Math.floor(idleT * 1.6) % 2 ? 'idle1' : 'idle2'); // idle weight shift
if (phase === 'pretoss' && ch.side === score.server && ch.pose === 'idle')
name = pre + (Math.abs(Math.sin(idleT * 3.6)) > 0.55 ? 'bounce2' : 'bounce'); // hand rises as the ball comes up
if (phase === 'pretoss' && ch.side === score.server && ch.pose === 'idle') {
const w = idleT * 3.6; // same phase as the bouncing ball
const rising = Math.sin(w) * Math.cos(w) > 0;
name = pre + (rising ? 'bounce2' : 'bounce'); // hand up while the ball rises, pat down exactly at the apex
}
if (ch.pose === 'run') name = pre + (Math.floor(ch.runT * 9) % 2 ? 'run1' : 'run2');
if (receiverWaiting) name = pre + (sway > 0 ? 'run1' : 'run2'); // split-step shuffle
if (ch.pose === 'swing') name = pre + (ch.poseT < 0.15 ? 'swing1' : 'swing2');
@@ -736,7 +739,7 @@ function render() {
// server idly bouncing the ball while waiting
if (phase === 'pretoss') {
const sv = score.server === 'P' ? P : O;
const bx = sv.x - 0.32 * (sv.side === 'P' ? 1 : -1), by = Math.abs(Math.sin(idleT * 3.6)) * 0.78; // floor to the reaching hand
const bx = sv.x - 0.5 * (sv.side === 'P' ? 1 : -1), by = Math.abs(Math.sin(idleT * 3.6)) * 0.7; // floor to the reaching hand
const sh = proj(bx, 0, sv.z);
ctx.fillStyle = 'rgba(0,0,0,0.3)';
ctx.beginPath(); ctx.ellipse(sh.x, sh.y, Math.max(1.5, sh.s * 0.08), Math.max(1, sh.s * 0.035), 0, 0, 7); ctx.fill();