A perfect serve is a cut ball: it hooks from kill to kill

Slice is not a tin and not a rack slot. It is what a perfect serve DOES —
the toss ritual's 45 ms window, or a pull that stops inside perfectBand.
Every other weapon is handed to you; this one is a technique, and it hands
the plain ball a real route to the DOUBLE/TRIPLE KILL ladder that until now
only a bomb or a lucky line-up could reach. Banking your specials stops
meaning playing worse in the meantime.

Only a kill hooks, so a wound ends the chain and no brute, steward or boss
ever extends one. It is a crowd skill shot, which is the half of the arsenal
the tins do not cover.

The pull had to learn a third state to say this. Quality SATURATES at
pullFull, so an overpull and a perfect pull drew an identical band: the game
was asking you to hit a window it never showed you. The band now goes chalk
white inside it and the mark on the target grows a second ring — the fill
says where the ball lands, the ring says it will not stop there.

The chain path is deliberately NOT previewed. It is a scallop laid over the
exact patch of court you need to read, it solves the shot before you take
it, and the bodies walk — any chain drawn at pull time is a lie by the time
the ball arrives, which is the one thing the band exists not to be.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-09 13:44:17 +02:00
1 parent 655b86d27f
commit 99d84b2c9d
4 files changed
+91 -6

No files matched your search

+15 -2
View File
@@ -744,7 +744,12 @@ function drawShotBand(a, u0, flying) {
// of tapering, so the gesture SHOWS you the wedge before you commit to it. Oliver asked for the
// band itself to communicate the shape of the shot.
const beamW = WEAPONS[slotId(G.weapon)]?.beam ? 1 : 0;
// CHALK WHITE = this one is SLICED. The band has always had one threshold (kills / only staggers)
// and the perfect window sat inside the killing half, invisible: quality saturates at pullFull, so
// an overpull drew exactly the band a perfect pull did. White is the third state, and the only
// place white appears on the court — nothing else in the palette is near it.
const hex = beamW ? WEAPONS[slotId(G.weapon)].col
: a.pf ? '#f2f2e6'
: a.q >= TUNE.zSplatQ ? (a.zt ? UI.hot : UI.warm) : '#9db4d0';
// the slice of arc to draw: everything while aiming, a short streak behind the ball in flight
const lo = flying ? Math.max(0, u0 - TAIL) : 0;
@@ -965,7 +970,7 @@ function drawBeamCuts(dirX, dirZ, ox, oz, L) {
function drawAimMark(a, u0, flying) {
const left = 1 - u0;
if (left <= 0.01) return;
const col = a.q >= TUNE.zSplatQ ? (a.zt ? UI.hot : UI.warm) : '#9db4d0';
const col = a.pf ? '#f2f2e6' : a.q >= TUNE.zSplatQ ? (a.zt ? UI.hot : UI.warm) : '#9db4d0';
const onBody = !!a.zt;
const m = proj(a.tx, a.ty, a.tz); // a.ty is where the ball ARRIVES — mark and impact are one point
// NOTHING BEHIND THE CAMERA DRAWS. proj's scale is camF/(camZ - z), so a point at or past the
@@ -982,7 +987,15 @@ function drawAimMark(a, u0, flying) {
if (onBody) ctx.ellipse(m.x, m.y, m.s * 0.26, m.s * 0.38, 0, 0, 7); // upright, over the torso
else ctx.ellipse(m.x, m.y, m.s * 0.30, m.s * 0.12, 0, 0, 7); // flat, lying on the grass
ctx.fill();
ctx.globalAlpha = 1;
// ...and a SECOND ring outside it when the shot is sliced: the fill says where the ball lands,
// the ring says it will not stop there. Drawn on the mark rather than as a third HUD element
// because your eye is already on this body — that is what you are aiming at.
if (a.pf && onBody) {
ctx.globalAlpha = 0.75 * (flying ? left * left : 1);
ctx.strokeStyle = col; ctx.lineWidth = Math.max(1, m.s * 0.02);
ctx.beginPath(); ctx.ellipse(m.x, m.y, m.s * 0.36, m.s * 0.50, 0, 0, 7); ctx.stroke();
}
ctx.globalAlpha = 1; ctx.lineWidth = 1;
}
function drawRing(x, z, color, k = 1) { // k: radius scale — the landing ring contracts on time-to-touchdown