diff --git a/HANDOFF.md b/HANDOFF.md
index 98d80bc..a081050 100644
--- a/HANDOFF.md
+++ b/HANDOFF.md
@@ -385,10 +385,31 @@ them missed would hand out free ammo. The soak asserts `gunId` is never set with
`mx || mz || assist`, and finger-steering zeroes `mx`/`mz` — so a player sliding left and right under
auto-fire still counted as standing still and never ran. `mgMoving` is in that expression now.
-**The oval on his back was the mg racket.** `drawMgRacket` put its head at `(P.x, 0.95, P.z - 1.35)`,
+**The mg racket is GONE.** It was a procedural racket drawn over a sprite that already holds one:
+straight up-court it projected onto the player's back as a floating oval, and offset to the side it
+just stuck out. Oliver: "can we please just hide it?" The pellets streaming up-court are the
+feedback. `drawMgRacket` is deleted, not commented out.
+
+**(Previously) the oval on his back was the mg racket.** `drawMgRacket` put its head at `(P.x, 0.95, P.z - 1.35)`,
which at this camera projects almost exactly onto the player sprite. Offset by `P.facing` it reads as
a racket held out beside him.
+**A third array had the empties-under-the-iterator bug.** A rocket blast can bank the last kill of a
+game, and the beat that follows (a duel, a chapter boss) does `pellets.length = 0` — so the pellet
+loop's next index read undefined and the frame threw. `shots`, `pellets`, `extras` and the body loop
+all carry the same `if (!x) continue` guard now. **Any array iterated in `updateZombies` that can
+contain something whose death advances the game needs it.**
+
+**A gradient that ends at alpha 0 hides the thing you are aligning.** The laser's far corners were
+pinned correctly from the first attempt, but each wedge layer faded to fully transparent along its
+length — so the beam became invisible before it reached the pinned edge, the VISIBLE end sat well
+short of it, and moving the geometry appeared to do nothing twice in a row. The far stop is lit
+(0.62 of the layer's alpha) now, so the visible edge and the pinned edge are the same line.
+
+**The beam falls off with distance** — brightest at the strings, thinning down the court, because
+that is what a beam travelling away from you does. The far stop is 0.32 of the layer's alpha: enough
+depth to read, never zero, so the visible end stays the pinned end.
+
**The laser's far edge is pinned in SCREEN space.** Running out to `beamLen` on the ground landed it
on the ads' TOP line; it should die at their middle. `c3.y = c4.y = proj(0,0,-6).y - AD_H / 2` — the
x's keep their perspective, the y is pinned. That holds in both orientations and leaves `beamLen`
@@ -420,6 +441,12 @@ Drive the game deterministically via `window.T` with `javascript_tool`. The Brow
context reports `document.visibilityState === 'hidden'`, so RAF is paused; halt it anyway with
`window.requestAnimationFrame = () => 0` and step with `T.step(1/60)`. `T.press('Space')` = tap.
Clear the intro first: `document.getElementById('intro')?.remove()`.
+- **Two consecutive `render()` calls do NOT produce the same frame**, so "draw it, change one thing,
+ draw again, diff the pixels" silently measures nothing. `render()` mutates camera state as a side
+ effect (`aimCam += ((G.aim ? 1 : 0) - aimCam) * 0.15`), so the whole scene shifts slightly between
+ grabs and the diff lights up everywhere — it reported a laser beam extending 16 px above where its
+ own geometry could possibly reach. To check WHERE something lands, recompute the projection
+ directly (`T.proj(...)`) and compare numbers; keep pixel-diffing for "did anything at all change".
- **The module-refresh list MUST include the VERSIONED entry point.** `index.html` loads
`main.js?v=N`, and `fetch('main.js', {cache:'reload'})` does not bust that URL — so main.js alone
stays stale through a reload while every other module is fresh. Read the src off the page:
diff --git a/index.html b/index.html
index 260ac12..eef9520 100644
--- a/index.html
+++ b/index.html
@@ -179,6 +179,6 @@
-
+