The fall drops fast, lies long, and never rises

Oliver, three refinements in one breath: the frame PROGRESSION quicker
(drop 0.06+0.25 -> 0.05+0.15 — against a live rolling ball the slower drop
read as mush), the prone hold KEEPS its bench-tuned 2 s ('the lying itself
can stay that long'), and the rise row is cut ('the opponent respawns
anyway') — done() re-marks the body in its wound skin regardless, so rising
first was a respawn with extra steps. The rise frames stay in the sheets
for the bench. Wound-beat test updated to the new contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-13 21:58:32 +02:00
1 parent f991f1ab10
commit 1e601ca33d
3 files changed
+15 -8

No files matched your search

+1 -1
View File
@@ -431,6 +431,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one') {
</div>
</div>
</div>
<script type="module" src="src/main.js?v=221"></script>
<script type="module" src="src/main.js?v=222"></script>
</body>
</html>
+8 -1
View File
@@ -396,7 +396,14 @@ function matchReady() {
// the collapse reads as one continuous movement decelerating into the ground; the 0.07 s fall2 it
// replaced gave the two drawn frames ~4 display frames each and read as a cut, and a 0.40 s one split
// them 0.80 against 0.56 m/s, which is a visible hitch between two poses of the same drop.
export const FALL = [['fall1', 0.06], ['fall2', 0.25], ['fall3', 2.0], ['rise', 0.45]];
// 2026-08-13, after the early-fall retiming: "the progression of frames in the fall must be
// quicker... we must remove the rise frame, the opponent respawns anyway... the lying itself can
// stay that long." So: the DROP tightened (0.06+0.25 -> 0.05+0.15 — the collapse now plays
// against a live rolling ball, and the slower drop tuned for a dead court read as mush next to
// it), the 2 s prone hold KEEPS its bench-tuned length, and the rise row is CUT: done() puts the
// body on its mark in its wound skin anyway, and rising just to be teleported read as a respawn
// with extra steps. The z_*rise frames stay in the sheets/preload — the bench can still show them.
export const FALL = [['fall1', 0.05], ['fall2', 0.15], ['fall3', 2.0]];
// Read LIVE by startFall, because a snapshot goes stale the moment the table is tuned and the match's
// 'over' beat would then expire mid-collapse — the exact bug the comment above is about.
export const fallLen = () => FALL.reduce((s, f) => s + f[1], 0);
+6 -6
View File
@@ -746,17 +746,17 @@ test('a wounding point knocks the body down and it gets up MINUS the limb', () =
update(DT);
assert.match(zb.showFrame, /fall1$/, 'first frame is the buckle');
assert.ok(!/w\d/.test(zb.showFrame), 'and it is the UNWOUNDED buckle');
// ...and it must LIE THERE a moment before it rises: a corpse that touches the ground and is
// instantly upright reads as a stumble, not as something the point did to it.
// ...and it must LIE THERE a moment: a corpse that touches the ground and is instantly upright
// reads as a stumble, not as something the point did to it. THE RISE ROW IS GONE (2026-08-13,
// Oliver: "remove the rise frame. the opponent respawns anyway") — the beat ends prone and the
// body takes its mark in the wound skin.
let downFrames = 0;
for (let i = 0; i < FALL_LEN * 60 && G.matchFall && !/rise$/.test(zb.showFrame || ''); i++) {
for (let i = 0; i < (FALL_LEN + 1) * 60 && G.matchFall; i++) {
update(DT); if (/fall3$/.test(zb.showFrame || '')) downFrames++;
}
assert.ok(downFrames > 0.3 * 60, 'it stays down for a beat: ' + (downFrames / 60).toFixed(2) + 's');
assert.match(zb.showFrame, /w1rise$/, 'it drags itself up as the one-armed body');
// ...and the point comes back only once it is standing
for (let i = 0; i < FALL_LEN * 60 && G.matchFall; i++) update(DT);
assert.equal(G.matchFall, null, 'the fall ends on its own clock');
assert.equal(racketStage(zb), 1, '...and it comes back as the one-armed body');
assert.equal(zb.showFrame, null, 'and hands the sprite back to drawZombie');
assert.equal(G.serveNum, 1, 'matchReady ran: the next point is armed');
});