843b110bcb5d6ffd3d96372585cdf0d52758f59b
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
843b110bcb |
Hold a driven video at the end of its file instead of restarting (#404)
A driven video plays on for about 100 ms after the last key, until the speed reading says it stands. With the key close to the end of the file, that runs the video past it. The browser then marks it ended, and follow() called play() on it in every frame. Per the HTML spec an ended video starts over from the beginning of its file on play(). The sprite flashed the first picture one to three times before it held. - An ended video now counts as standing at its end. follow() holds it and seeks to the wanted picture instead of playing it again. - The end of the file counts as an end too, not only the end of the clip. Tests: - e2e 66o plays an animation in once mode to 1.95 s of the 2 s test video and records the player time in every frame. It must never jump back, and the last picture must stand. - Against the old follow() 66o fails, the player jumps back to 0 once. A first version with the key at 1.9 s stayed green, the video never reached the end of the file. - e2e 66 on melektaus-atx: ALL PASSED, 26 checks. - Unit video-library, video-follow, video-clock: 31 passed. - tsc, eslint, Prettier clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
43fd22a763 |
Keep a driven video ready while its sprite is off (#404)
A cut between two videos flashed white: the sprite switched on had no picture yet, because its player only opened then or had been dropped meanwhile. A driven video now waits muted at its time while its sprite is off, in the editor and in a run. - A disabled sprite with Video clock Driven asks for its player without drawing it. A Free video still opens when shown. - A run's draw list keeps disabled driven sprites, marked as off. Before, collectWorldItems dropped every disabled object, so the game view never held a player for them. - VideoLibrary.wear() counts as asking. The sweeper dropped a held player after 2 to 4 s and it was loading again at the cut. - The speed of the asked time is read over a window that grows to 500 ms. Over 100 ms one 1/60 s step more or less read as 17 % off, the playback rate jumped and the sound dropped out. - A stream feeds every packet it has loaded to the decoder at once and waits once. One round trip per 20 ms packet let the decoder fall behind on a busy main thread, which made e2e 34 flaky in CI. Tests: - Unit streaming, video-library, video-follow: green, 4 new - e2e 34 + 66 (atx): ALL PASSED, stream skipped 0, 66m new - e2e 66 (atx), two runs: ALL PASSED, 25 checks, 66n new - Gate (atx): CHECK EXIT 0, 297 files, 4557 tests - Counter-checks: without the draw list fix 66n finds no player, without the wear() fix and with the old speed reading the new unit tests turn red Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c9e8a3f6ac |
Let an animation drive a sprite's video picture by picture (#404)
A video used to run on its own clock as soon as a sprite wore it. An animation could switch the sprite on and off, but never say which picture shows at which frame. Cutting a video in an animation needs the opposite: the animation sets the time and the video follows. - Sprites wearing a video or a clip get two rows, Video clock and Video time. They show only while the texture holds a video. - With Video clock on Driven the video does not play by itself. It shows the picture at Video time, counted from the clip's start. Past the end it goes round with Loop and holds the last picture without. - Video time is a number like any other, so keys, step, easing and curves give stills, slow motion and ramps. - A driven sprite gets a player of its own, keyed by the wearer's name. The same clip can run twice at different times. - Following has two ways (`videoFollow.ts`). Running forward at 0.25x to 4x the video plays at that rate and is nudged. A still, a scrub or a step backwards seeks, and only the newest seek counts. - Sound is heard only near 1x. The animation tab now plays it too, so a cut can follow the sound. Scrubbing is silent. - Scene, game view, the inspector's PREVIEW and the shader preview show the driven picture. In a running game Play animation sets it. Found on the way: - After a scrub the video in the animation tab kept running. The preview redrew only while the playhead moved, so nobody asked for the video once it stood. `AnimationEditor.tick` now redraws it every frame while it shows a video. - Every sprite has two more defaults (`videoClock: 'free'`, `videoTime: 0`). Eight tests in five files pinned the old list and are updated. Tests: - Unit: video-clock and video-follow new, 4 files with 42 tests green. - e2e 66 (melektaus-atx): ALL PASSED, 22 checks, 3 new. 66i: two sprites on one clip stand at 0.2 s red and 0.7 s green. 66j: a scrub to frames 2, 7, 12 and 3 shows red, green, blue, red, and each colour still stands 0.7 s later. 66k: playing runs 10-30 ms behind at rate 1.00-1.03 and is not muted. - Counterchecks: a seek that keeps the rate turns the seek test red. Not seeing Driven turns 66i, 66j and 66k red. - Gate (melektaus-atx): exit 0, 297 files, 4546 tests. - Not tested in the browser: Play animation in a running game. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c815d2c35f |
Keep a playing video when the window comes back to the front (#402)
Chrome draws no frames for a hidden page, so the scene stopped asking
for its videos. The sweeper of the VideoLibrary kept running and
dropped every player after 2 s. Back in the window, the video started
over, and Pixi warned that a texture source was destroyed while still
bound to a shader.
- The sweeper skips a hidden page. The time hidden does not count as
idle, the 2 s start once the page is shown again.
- A dropped player only unloads its video source instead of destroying
it. A shader that still holds the source no longer warns.
- CI serves videos through a new router for php -S. The built-in
server answers no Range requests, so Chrome could not seek. e2e 66
had 4 red checks in the suite job of
|
||
|
|
d48f174caf |
Play videos on sprites, converted on the server with clips (#402)
A video becomes an asset like a sound: uploaded once, converted to one format by a worker of its own, cut into clips in its tab, and worn by a sprite through its Texture row. Only Chrome is a target, without alpha. - Server: POST ?r=videos queues the upload under the hash of its bytes, so the MP4's name is known at once. The worker (VideoWorker over VideoFormat) writes H.264/AAC, yuv420p, constant frame rate, a keyframe every 15 frames, at most 1920x1080, with a poster and the details beside it. A failed job says why and is tried again on the next upload. - An upload may be up to 2 GB. It is streamed from the request to disk and hashed there, so php-fpm holds none of it in memory. The other routes keep their 256 MB. - The worker runs in the container game-maker-video on stein2, a compose project of its own (tools/video/), and in CI beside the PHP server. The CI image has ffmpeg for it. - Model: asset type video with size, length, frame rate and sound, and clips like a sound's. The clip helpers and commands serve both. - A sprite's Texture row offers videos and clips after the pictures. resolvePicture names a playing video by a key, and the texture library hands it to a VideoLibrary with one player per key. - The editor shows a placed video as a quiet preview. Play starts it over at its clip's start and lets it be heard through the master bus, a pause holds it, Esc makes it quiet again. - Video tab: the picture, a ruler, the clip strip and a track on the Sound tab's time axis. A drag spans a clip, a handle moves an edge, Play plays the picked clip. - The picker shows a video on its way with its progress and adopts an upload from it once it is ready. Dropping a video file does the same. Decided on my own: - Two sprites wearing the same clip share one player and show the same picture. Control per instance belongs to the follow-up with nodes. - A video plays in real time, the game's time scale does not slow it. - The container may use 3 of the 4 cores of stein2. Findings: - The first real upload (279 MB) got 413: the API's own ceiling of 256 MB for every request, not nginx or the Brandmauer. - Chrome has no picture of a video that never played, and a Pixi VideoSource drawn before the first frame stays empty for good. The texture is made in the first frame callback (openVideo). - A player nobody asks for in 2 s is let go. The inspector's PREVIEW asked only on an edit, so with the sprite not on screen its texture was destroyed under it and the batcher threw on every frame. The preview now redraws every frame while it shows a video, like a Time shader. A let-go texture keeps an empty source instead of none. - VideoSource.load() reloads the element and cuts off an earlier play(). Playing starts after loadeddata. Tests: - PHP videos.test.php: 68 checks, with the real ffmpeg - 300 MB upload through Brandmauer and nginx: 201 in 21 s, php-fpm at 13.7 MB RSS at most - Unit videos.test.ts: 20 tests - e2e 66 (stein2, atx was off): ALL PASSED, 18 checks; e2e 04 with the new asset count green - Gate (atx): 294 files, 4520 tests. serialize.test.ts used video as its example of an unknown type and now uses a made-up one. - Counter-checks: a keyframe gap of 30 fails the PHP check, a key that keeps the video's end fails 2 unit tests, a clip without its end fails "plays only its stretch" in e2e 66 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |