Watch a held body for a time, not for a count of frames
game-maker / gate (push) Successful in 2m52s
game-maker / suite (push) Successful in 14m21s

The suite to 46c620a (#294) was red by one check: e2e 41, "a body
dragged while playing hangs where the pointer holds it and is let
go at rest". The body hung where it should, on -3490 in every
frame, and fell from rest. The check failed on its own bound of 30
frames while held: that run drew 21 in the second of holding, the
green runs of the day drew 37 to 54.

- The bound is now the time the hold was watched: 800 ms between
  the first and the last sample before the release, and five
  samples at least.
- The detail of the check names that time next to the frames.
- Nothing in src/ changes.

This is not the wobble of 9cff528 and 543b052 (#282) once more.
Those were about when the samples are taken, this one about how
many a runner manages. Why that run was so slow is not known.

Tests:
- e2e 41 on melektaus-atx: 21 checks, all pass, 66 frames in 1114
  ms while held.
- No counter-probe: a run as slow as the red one was not
  reproduced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-02 20:33:21 +02:00
1 parent e933fad446
commit e066613583
1 file changed
+8 -3
+8 -3
View File
@@ -328,7 +328,11 @@ export async function physics(t) {
const letGo = await evaluate('window.__dragLetGo'); const letGo = await evaluate('window.__dragLetGo');
const log = (await json('__gm.world()'))?.log ?? []; const log = (await json('__gm.world()'))?.log ?? [];
await stop(); await stop();
const held = dragSamples.filter((s) => s.t < letGo).map((s) => s.y); const heldSamples = dragSamples.filter((s) => s.t < letGo);
const held = heldSamples.map((s) => s.y);
// How long the hold was watched, not how many frames that took: a busy runner drew 21 frames
// in the second a quiet one draws 50 in, and a count of 30 called that a failure.
const heldFor = held.length > 1 ? heldSamples.at(-1).t - heldSamples[0].t : 0;
const released = dragSamples.filter((s) => s.t >= letGo); const released = dragSamples.filter((s) => s.t >= letGo);
// 200 ms of free fall from rest is about 25 below the hold, a body let go at speed is not. // 200 ms of free fall from rest is about 25 below the hold, a body let go at speed is not.
const falling = released.filter((s) => s.t - letGo <= 200).map((s) => s.y); const falling = released.filter((s) => s.t - letGo <= 200).map((s) => s.y);
@@ -336,7 +340,8 @@ export async function physics(t) {
check( check(
'a body dragged while playing hangs where the pointer holds it and is let go at rest', 'a body dragged while playing hangs where the pointer holds it and is let go at rest',
arrived && arrived &&
held.length >= 30 && held.length >= 5 &&
heldFor >= 800 &&
held.every((y) => Math.abs(y - target) < 1.5) && held.every((y) => Math.abs(y - target) < 1.5) &&
// Let go it only falls: no jump above the hold, no kick up. How far the first frame after // Let go it only falls: no jump above the hold, no kick up. How far the first frame after
// the release has already fallen follows the frame time, so that is not a bound here. // the release has already fallen follows the frame time, so that is not a bound here.
@@ -347,7 +352,7 @@ export async function physics(t) {
JSON.stringify({ JSON.stringify({
target, target,
arrived, arrived,
held: { frames: held.length, first: held[0], last: held.at(-1) }, held: { frames: held.length, ms: Math.round(heldFor), first: held[0], last: held.at(-1) },
stamped: typeof letGo === 'number', stamped: typeof letGo === 'number',
released: released.slice(0, 3).map((s) => [Math.round(s.t - letGo), s.y]), released: released.slice(0, 3).map((s) => [Math.round(s.t - letGo), s.y]),
fell, fell,