c0ba2673bacf8ddbe0cbdb88bc478380bcefa2d7
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c0ba2673ba |
Keep the video tab's picture following while scrubbing (#417)
Scrubbing in the video tab set currentTime on every pointer move. Each new seek aborts the running one. With a large video a seek takes longer than the gap between two moves, so none finished and the picture froze. The composition tab never had this, because its players run through the VideoLibrary, which only keeps the newest wish while a seek runs. - The pending-seek logic moves into a shared helper, src/viewport/videoSeek.ts. The VideoLibrary uses it unchanged. - The video tab seeks through the same helper and uploads the picture again after each finished seek. - Play drops a pending scrub wish. Otherwise the video would jump back right after it starts. - Scrubbing before the first picture no longer jumps back to the time the tab opened with. The video stays at the last chosen time. Tests: gate on melektaus-atx green, 303 files, 4681 tests (2 new in video-seek). e2e 66 ALL PASSED, 30 checks. Without the helper the new unit test is red ([0.1, 0.2, 0.3, 0.4, 0.5] instead of [0.1]). There is no browser check for the freeze itself, the test video seeks too fast to show it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
322fc39d16 |
Zoom the video tab's time smoothly like the other tabs (#377)
The video tab jumped on every wheel step and on Fit. The Sound, Pattern and Song tabs already ease the zoom since #377. The video tab now takes the same transition, so all tabs feel alike. - VideoCanvas runs wheel and Fit through `axisTween`. The duration comes from the General settings. Quick wheel steps add up, panning ends the transition, and the view that is stored is the one the transition lands on. - Opening a video still fits at once without a transition. Only the Fit button eases, as in the Sound tab. - `__gm.videoTab.zoom()` reports the zoom and whether a transition is on its way. Tests: - e2e 66 on melektaus-atx: ALL PASSED, 30 checks (1 new). The new check uses `sampleZoom` like the Sound tab. At 1000 ms the zoom is on its way two frames after the wheel (319 -> 321) and lands where the jump does (370.63). No counter-check against the old code. - Gate on melektaus-atx: CHECK EXIT 0, 299 files, 4586 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e191dc4b2e |
Record the game view from a behavior into a video asset (#405)
A game can now film itself. A behavior starts and stops a take, and the editor turns it into a video asset with the run's picture and the sound the player hears. The exported game hands the file over as a download, since there is no project to keep it in. - New action nodes `Start recording` (Name, Resolution, FPS) and `Stop recording`. An empty name becomes `Recording <timestamp>`. - Resolution is `Game view`, `720p` or `1080p`. For the fixed sizes the height is set and the width follows the camera. - The picture is the camera only, without hints, overlays or the letterbox. It is drawn into a render texture of the target size, so a smaller window still gives full 1080p. - `PictureReader` reads the texture back through pixel buffers with a fence. The editor never waits on the GPU, and a frame with all three buffers busy is dropped and counted. - Nothing of the take reaches the visible canvas. A first version drew tiles into it and copied them out, and with the low-latency canvas that midway state flickered on screen. - The sound is tapped behind the master limiter in the FX worklet and encoded as Opus. - H.264 is chosen when the browser has it, VP9 otherwise. A small own Matroska writer packs both tracks, no new dependency. It names the frame rate and BT.709 so ffmpeg keeps both. - A second `Start recording` is ignored with a warning in the log. A take goes on through `Load scene` and a restart, pauses with the editor and is saved when the run ends. It stops at 2 GB. - The editor uploads the take on the existing video route and makes the asset once the run is over. The video tab gets a Download button for the converted MP4. - `downloadBlob` in `src/ui` replaces the song editor's own copy. Findings: - `On start` runs before the game screen knows the world. A take therefore fixes its size on the first frame that has a camera. - Without a frame rate in the file, ffmpeg turned 30 fps into 59.94. - The worker's poster JPEG is off in colour for every upload (red 255 comes out as 229, BT.601). Not touched here. Tests: - Unit recording + matroska: 21 green, plus the node catalog cases. The Matroska test reads the file back with its own EBML reader. - e2e 67 (new) on melektaus-atx: ALL PASSED. 1080p30 from a 1280x800 window gives a 1920x1080 MP4 with sound and no dropped frame. Every 4th pixel is checked, a green quarter catches an upside-down picture. A take ended by Esc is saved with the timestamp name. - e2e 60j: the exported game downloads an `.mkv` with EBML magic. - The flicker is gone on the user's machine without `?vsync`. - Gate on melektaus-atx: CHECK EXIT 0, 299 files, 4586 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
ce933a4f32 |
Let a drag change only the picked clip in the Sound and Video tab (#403)
A drag with a clip picked could span a new clip in the strip or span the picked one anew over the wave. Both happened by accident while working on a clip. Now a drag only makes a new clip while none is picked. With one picked it moves its edges or the whole of it. - With no clip picked, a drag in the strip or over the wave (in the Video tab the track) spans a new clip, as before. - A click over the wave or in the track picks the clip at that point, as a click on its band does. Beside the clips it picks the sound or the video. The picked clip wins where clips lie over each other. - With a clip picked, its handles move its edges as before. A drag on its band in the strip moves the whole clip, its length kept and inside the file. Any other drag does nothing. - The rules live in waveView.ts (clipGrip, clipToPick, movedSpan) and both tabs use them. The cursor shows grab over the picked band. - The Video tab's track draws the clips not picked faint, as the wave does, so a click there has something to aim at. Tests: - Unit wave-view.test.ts: 16 tests (4 new) - Counter-check: a strip drag beside the picked clip spanning a new one again fails the picked-clip rule test - e2e 34 + 66 (atx): ALL PASSED, 162 checks, 1 new check in each - Gate (atx): 295 files, 4527 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
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> |