Wait for driven videos before a run starts so no sprite flashes (#404)
game-maker / gate (push) Successful in 4m28s
game-maker / suite (push) Failing after 16m24s

The game view opens a player for each driven video only when it draws,
and it draws only while its tab is visible. Without a detour over the
Game tab the players came up with the click on Play. Until a video had
loaded, its sprite showed its base colour, white in the user's cut.
Sharing the players of the scene view would not have helped. From the
Animations tab those are discarded after two to four seconds.

- Play holds the run at second 0 until every driven video in the game
  view has its first picture, at most 3 s. The status line says
  "Loading the videos… · Esc stops".
- The game clock stands while it waits. Behaviors and sounds start
  only after it, so picture and sound stay together.
- Load scene in a running game waits the same way.
- A driven video without a picture is not drawn at all instead of
  white. That holds everywhere, also on a switch to the Game tab
  without Play and at a cut whose video is not ready.
- The exported player waits the same way.
- __gm.playInfo() reports waiting for the e2e check.

Tests:
- e2e 66p puts the sprite in front of the camera and waits 4.5 s so
  the game view has no player left. Then it reads every frame of the
  run: 14 frames of waiting on #22252c at time 0, then blue, no white.
- Against the old code 66p fails: 14 frames #ffffff, then blue.
- Unit video-library: 7 passed, 1 new for loading().
- e2e 66 on melektaus-atx: ALL PASSED, 27 checks.
- Gate on melektaus-atx: exit 0, 297 files, 4558 tests.
- tsc, eslint, Prettier clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-11 17:07:53 +02:00
1 parent 843b110bcb
commit dd60a795e1
8 files changed
+143 -7

No files matched your search

+35
View File
@@ -455,6 +455,41 @@ export async function video(t) {
JSON.stringify(inRun),
);
// 66p. Play opened the Game tab's players only then: unless that tab had been shown just before,
// a driven sprite showed its plain white for the first frames of a run. Now the run waits
// for their first pictures, the clock held, and a sprite without one is not drawn. LATE goes
// in front of the camera (and of what earlier steps left there); every frame of the run is
// read in the page. 4.5 s first, so the players 66n opened are let go.
await mutate(`
const scene = __gm.state.activeScene;
const cam = scene.objects.find((o) => o.id === 'o3').position;
Object.assign(scene.objects.find((o) => o.id === '${LATE}').position, { x: cam.x + 120, y: cam.y + 80, z: 1000 });`);
await sleep(4500);
await t.evaluate(`window.__vd66p = [];
(function read() {
const info = __gm.playInfo();
const rect = info.playing && __gm.gameRect('${LATE}');
if (rect) window.__vd66p.push({ color: __gm.pixelAt(Math.round(rect.x), Math.round(rect.y)), waiting: info.waiting, time: info.time });
if (window.__vd66p.length < 90) requestAnimationFrame(read);
})();`);
await play();
await sleep(1500);
await stop();
const runFrames = await json('window.__vd66p.splice(0)');
const waited = runFrames.filter((f) => f.waiting);
check(
'a run waits for the pictures of its driven videos and never shows a driven sprite white',
runFrames.length >= 20 &&
waited.length > 0 &&
waited.every((f) => f.time === 0) &&
runFrames.every((f) => f.color !== COLORS.white) &&
runFrames.at(-1).color === COLORS.blue,
JSON.stringify({
waited: waited.length,
frames: runFrames.map((f) => `${f.color}${f.waiting ? '*' : ''}`),
}),
);
await mutate(`
const p = __gm.state.project;
const gone = ['${OBJECT}', '${EARLY}', '${LATE}'];