diff --git a/HANDOFF.md b/HANDOFF.md index 6b92e6b..4fdf297 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -230,6 +230,20 @@ Oliver rejected the procedural fakes on sight. The rule this round: **animation expects; it's now ~62. Rack text is positioned proportionally (`g.h * 0.33` / `0.72`) so the tile height stays a free knob. +## Fifth feedback round (2026-07-27) +- **Crowd brightness**: both crowd sheets got an identical gamma-0.8 lift (means 30/14/39 → + 42/22/56) and the splatter tint dropped 0.5 → 0.26. **If you ever touch one crowd frame you must + apply the exact same curve to the other**, or the clap swap starts flashing brightness. + `assets/_sheet_crowd1.png` is the pre-lift original. +- **The splatter serve hint led with the tap** ("TAP TO SERVE · PULL BACK TO AIM") when pulling is + the entire gesture. Now "PULL BACK TO AIM · RELEASE TO FIRE", plus `drawPullHint()`: after + `TUNE.pullHintAfter` seconds of sitting in the serve stance untouched (`G.idleHintT`), a ghost + thumb slides back while chevrons grow up-court, on a loop. It teaches the inverse relationship + the text can't. +- **The mop boy has three sheets now**, not two: `x_boymop` is the push cycle used ONLY while + stopped and working, `x_boycarry` is him walking upright with the mop shouldered, `x_boyrun` is + the tennis-mode fetch. He was mopping the air the whole way to the stain. + ## Gotchas learned the hard way - Browser-pane verification: python http.server sends no cache headers, so edited ES modules often load STALE even after location.reload(). Reliable fix: preview_stop + diff --git a/assets/_sheet_boycarry.png b/assets/_sheet_boycarry.png new file mode 100644 index 0000000..59a2abe Binary files /dev/null and b/assets/_sheet_boycarry.png differ diff --git a/assets/_sheet_crowd1.png b/assets/_sheet_crowd1.png new file mode 100644 index 0000000..910b3e8 Binary files /dev/null and b/assets/_sheet_crowd1.png differ diff --git a/assets/x_boycarry1.png b/assets/x_boycarry1.png new file mode 100644 index 0000000..3716d8b Binary files /dev/null and b/assets/x_boycarry1.png differ diff --git a/assets/x_boycarry2.png b/assets/x_boycarry2.png new file mode 100644 index 0000000..4c9ad3c Binary files /dev/null and b/assets/x_boycarry2.png differ diff --git a/assets/x_boycarry3.png b/assets/x_boycarry3.png new file mode 100644 index 0000000..876950a Binary files /dev/null and b/assets/x_boycarry3.png differ diff --git a/assets/x_boycarry4.png b/assets/x_boycarry4.png new file mode 100644 index 0000000..0f1f4b1 Binary files /dev/null and b/assets/x_boycarry4.png differ diff --git a/assets/x_crowd.png b/assets/x_crowd.png index 910b3e8..92e386a 100644 Binary files a/assets/x_crowd.png and b/assets/x_crowd.png differ diff --git a/assets/x_crowd2.png b/assets/x_crowd2.png index 361df44..1428647 100644 Binary files a/assets/x_crowd2.png and b/assets/x_crowd2.png differ diff --git a/config.js b/config.js index 7a5a0da..a7c25a7 100644 --- a/config.js +++ b/config.js @@ -58,6 +58,7 @@ export const TUNE = { // mean something: at 0.45 the cone was ±10 m at the far baseline — the whole // court — so every downward pull picked the same body and the angle felt inert. // 0.10 gives ±2.9 m out there: you have to actually point at a lane. + pullHintAfter: 1.5, // s of doing nothing in the serve stance before the pull gesture demos itself aimTie: 0.12, // how much worse-aimed a NEARER body may be and still win the lane (0..1 of the // cone half-width). 0 = pure best-aligned wins; 1 = the old "nearest in the // lane always wins", which is what made the magnet grab the wrong shambler. diff --git a/gameplay.js b/gameplay.js index 1b540a3..1ca70aa 100644 --- a/gameplay.js +++ b/gameplay.js @@ -798,6 +798,8 @@ export function update(dt) { crowd.cheer = Math.max(0, crowd.cheer - dt); G.idleT += dt; const w = BOUNCE_IDLE.tempo; + // idle in the serve stance and not touching anything: after a beat, show the pull gesture + if (G.phase === 'pretoss' && !G.aim) G.idleHintT += dt; else G.idleHintT = 0; if (G.phase === 'pretoss' && Math.sin(G.idleT * w) * Math.sin((G.idleT - dt) * w) < 0) pock(0.12, 420); // ball bounce if (G.phase === 'toss') { const sv = score.server === 'P' ? P : O; sv.pose = 'serve'; sv.poseT = 0; } diff --git a/index.html b/index.html index 2713f0e..daf87d5 100644 --- a/index.html +++ b/index.html @@ -60,6 +60,6 @@
TAP TO START
- +