87b2ee9402351b02005a1ac1a1058de2324075dd
19
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
87b2ee9402 |
Record every frame with Real time off on Start recording (#423)
At 4K and 60 fps the user's computer reaches about 39 fps in real time.
Reading each frame back from the GPU takes longer than a frame, and
neither reading back later nor the canvas route helped. With Real time
off the run moves on by one frame of the recording at a time, however
long the computer takes, so the file has every frame.
- Start recording has a new check Real time, on by default. Only the
node records so, the editor recording stays in real time.
- SteadyPace in recording.ts is the pace as a pure class. A step is
1/fps once the frame before is taken and the sound up to it is made,
otherwise 0 and the run holds. A frame's time is its number.
- The sound is made apart, as decided in the issue. AudioSwitch routes
what the run plays to the live library, or to the offline library of
a SteadySound while such a recording lasts. That library has the same
mix, buses, FX and limiter and is rendered up to each next frame.
- A driven video holds at every picture asked for, and the frame waits
for it. Its sound is decoded from the MP4 and played in step through
its bus.
- Two Chrome quirks measured and worked around. A held video hands
over the picture of a seek before seeked, so the frame callback is
asked for when the seek begins. A seek right onto where a picture
begins shows that one or the one before, so such a seek lands half a
millisecond further. Together 30 s became 10.7 s for 2 s of video.
- The notice tells how far the recording has got, and the line at the
end how long it took.
Deviations and limits:
- Input is not ignored, it still reaches the game, which runs slower.
- At most ten minutes per recording. Chrome holds the whole buffer of
the OfflineAudioContext while rendering, 230 MB for ten minutes.
- A free video plays on in real time and does not fit. A sound playing
before the start stays at the speakers.
Found along the way:
- A check in e2e 60 was red since
|
||
|
|
4d0a696327 |
Keep composition sound in step and give compositions a bus of their own
A composition's sound ran on the audio clock while its picture ran on the frames. A frame counts at most 0.1 s, so after a hitch the sound stayed ahead of the picture until the next stop. Songs in a trailer drifted off the cut. The items of a composition also had no bus of their own, and a video sprite could not pick where its sound goes. - CompositionSound.follow compares the audio clock with the picture each frame. More than 40 ms apart, it starts the sound again where the picture is. This holds in the tab and in a run. - A time scale other than 1 now restarts the sound again and again. It stays in time but comes in pieces. - The sprite of a video item shows "Driven (by composition)" as a fixed Video clock row. Video time is hidden there, because the composition sets it every frame. - Every composition has a bus in the mix and a node in the master routing. A new one goes to the master unless other compositions are linked elsewhere, apart from where the sounds go. - Audio items pick From asset, To composition, Master or a bus. New items start with To composition. Items saved before keep From asset, so music already sent through a bus does not bypass it. - Video sprites have a new row Video bus: From asset by default, the master or a bus. In a composition the default is the composition's bus, also for video sprites inside a container item. - The chosen bus is part of the key of the video player, so a sprite with another bus gets a player of its own. Found along the way: - Six tests with full lists of sprite defaults expected the old rows and now list Video bus too. Tests: - tsc, eslint, Prettier clean - Unit: 971 green in the 28 files touched - npm run check on melektaus-atx: green, 309 files, 4804 tests - e2e 68 (melektaus-atx): 13 checks green, 68i new. The sound item and the video item go into mix:cp68-cut, which goes to the master. - e2e 69 (melektaus-atx): ALL PASSED, 23 checks, 69q and 69r new. After a hitch of 500 ms the sound restarted twice and then lay 0.5 to 5 ms off the playhead. - Counter-checks in unit tests: without the comparison the hitch test fails, without the bus in the preload the run test fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
875c76026a |
Silence a free video once its sprite is destroyed (#420)
A sprite whose Video clock is free played its video on after it was destroyed, heard in a game, until the player was let go 2 to 4 s later. A driven one was already held and quiet after 100 ms. - The library holds and quiets a free player nothing asked for in HUSH_MS, as it did a driven one. That covers Destroy, a scene load, the end of a run and a sprite switched off. - Asked for again before it is let go, it plays on from where it was held, heard only in a run. A hidden page leaves it alone, as the sweep does. - A sprite only out of view keeps its free video playing and heard. Whether a video is heard should not hang on the camera. Before, it ran 2 to 4 s and was then let go. Now it plays on, which opens its player even where it was never in view. Tests: - Unit: video-library 1 new. A free player losing its wearer is held and quiet 200 ms later, stays so through a new run, plays on heard when asked again with the same element, and runs on on a hidden page. - e2e 66 on melektaus-atx: ALL PASSED, 36 checks, 66g-ii new. Heard 31 frames before Destroy, held and muted in every frame read after. - Counter-probe without hushing free players: the unit test and only 66g-ii fail, the player plays on heard (paused false, muted false). - Gate on melektaus-atx: 309 files, 4797 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
acd12326dc |
Fade sounds and videos in and out on the items of a composition
A trailer needs its music and its clips to come in softly and leave
softly. Until now an item of a composition could only play at one
level, and a video item could not even be turned down on its own.
- Every item with sound gets a grip at its upper left and upper right
corner. Dragging one inwards fades the item in or out. Dragging it
back to the edge removes the fade. Lower down the same edge still
trims as before.
- The fade is drawn as its curve, with the part above it darkened.
The inspector shows Fade in and Fade out in seconds, each with the
curves sound clips already know.
- The model keeps fadeIn and fadeOut in frames plus curveIn and
curveOut on the item. Old projects load unchanged. An item shorter
than its fades plays them cut to its length but keeps the setting.
- Sound, pattern and song items ramp the gain of their own bus. The
scheduler plans the ramps on the audio clock next to the notes.
Starting in the middle of a fade picks it up from there.
- Video items set the new sprite property Video volume each frame.
It multiplies with the fade and is only shown for a driven video.
The player glides to each new level over 15 ms so it does not click
between frames.
Not covered: a container item that carries a video further down gets
no grips. Only a video on the item's own sprite counts.
Tests:
- tsc, eslint, Prettier clean.
- Unit tests for composition, music, song and sound (12 files): 269
passed, 7 of them new.
- e2e 69 on melektaus-atx: ALL PASSED, 21 checks. 69p drags a grip to
a fade in of 10 frames and hears the item bus rise from 0.127 over
0.229 and 0.339 to 1 within one second.
- Counter-checks as unit tests: without the audio ramps, and without
the level on the video sprite in the game, both go red.
- Gate on melektaus-atx: 309 files, 4796 tests passed, 8 more than
at
|
||
|
|
043c224cc3 |
Rename Game Maker to Feuerwerk and serve it at /feuerwerk/ (#422)
The editor gets a name of its own that fits beside Brandmauer, Glutspeicher and Feuerwehr. This is stage 1, 2 and 4 of #422: the name, the URL and the stored state in the browser. Repository, CI runners, containers and the GAME_MAKER_* variables follow in stage 3. - All paths come from SITE_PATH in src/core/site.ts: the API endpoint, the data folders, the play page and the base in vite.config.ts. A later move is one line instead of fifteen. - The window title, the sign-in screen, the playground and the README say Feuerwerk. The package, __feuerwerkPlay, the take worklet and the writing app in Ogg and Matroska follow. - The session cookie is now feuerwerk_session, so everyone signs in once more. - localStorage keys are now feuerwerk.*. moveOldStoredKeys copies the old game-maker.* keys over on the first start, so settings, panel sizes and save games survive. - tools/ci/serve.sh serves the build under /feuerwerk/. The variable GAME_MAKER_BASE_URL keeps its name until stage 3. Outside the repository, nockal.com/feuerwerk/ is a second symlink to the same tree. nginx sends the bare /game-maker/ folder there with a 301. Everything else under /game-maker/ is still served directly, so shared play links and the API keep working. Finding: when nginx redirects a path without a trailing slash or with a query, the Brandmauer answers with its own 307 to the same URL plus a slash, placed after the query. A play link would lose its token that way, which is why only the bare folder is redirected. Tests: - Gate on melektaus-atx: CHECK EXIT 0, 307 files, 4756 tests (4 new in site.test.ts). - Counter-check: when the migration misses the old prefix, 3 of the 4 new tests fail. - e2e 60 under /feuerwerk/: ALL PASSED, 20 checks. - From outside: /feuerwerk/ 200, /game-maker/ 301, an old play link 200. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
65d7bf6a1f |
Silence a composition video as soon as its item ends
A video in a composition plays on a driven player that the item tells where to stand every frame. When the item ended, its object was gone and stopped asking, but the player ran on with its sound until it was let go for being unused. That took 2 to 4 seconds, and in a pause it never happened at all. The same held for the composition preview. - A driven player nobody asked for in 100 ms is now paused and muted. When its wearer comes back it carries on where it should be, as before. It is still let go after 2 to 4 seconds. - A player still without its first picture keeps playing, without sound, because it only gets that picture by playing. - Leaving the animation or composition tab now silences their video preview at once instead of after 2 to 4 seconds. - Free videos (Video clock free) keep the old behaviour. A sprite destroyed by a behavior is still heard for 2 to 4 seconds. Tests: - Unit video-library: 10 green (1 new). Without the new timer the new test is red. - e2e 68: ALL PASSED, 11 checks (68g new). An item of 0.5 s with a 2 s video plays audibly while it is there, and the player is paused and muted in every frame from about 200 ms after it ends. - Gate on melektaus-atx: green, 305 files, 4737 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
93190e185c |
Route a video's sound through its own Master routing node
An editor recording had no sound while the video tab played a video. The tab played its <video> straight to the speakers, past the Web Audio graph, so the recording tap behind the limiter never heard it. Fixing only that would have left videos as the one sound source the Master routing cannot reach, so they get their own node, like sounds. - A video asset with sound has a routing node labelled "Video". One without sound has none, it would have nothing to send. - Its links take the sound after volume and FX. Several links or another level give the video its own bus, as with a sound. - A new video follows the bus most other videos use. With none linked yet it goes to the Master, not to where the sounds go. Songs and sounds no longer follow videos either. - Players only know their file, so videoBusesOf maps each file to the bus of its first asset. setMix takes that map and moves the gains of running videos at once when the routing changes. - In the game, played in the editor or released, a video's sound follows its links. The tabs (video, composition, animation preview) play straight into the Master, as the sound tabs have since #368. - The video tab's sound now goes through the Master, so its volume, FX and limiter apply there and the editor recording hears it. - The recording badge beside the menu is an HTML element over the canvas now. The second render that drew it on the desynchronized canvas let the screen show a frame without it, so it flickered. The element is never in the copy, and clicks go through it. Tests: - Unit master-routing and sound-library: 3 new, green. Red without video in the routing kinds, without moving the gains, and with the old rule for the links of a new video. - e2e 66e-iii: the tab plays a video linked to a bus, the level is 0.09 on the Master and 0 on the bus. 66g: in the game the bus has 0.09. Both red with the old ways. - e2e 67e reads the badge from a real screenshot, still green. - The README names 2043 e2e checks. - Gate on melektaus-atx: 304 files, 4694 tests green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
6e6b6a4d9a |
Wait for a composition's videos and copy and paste its items (#417)
A composition lost the first frames of a video item. Its clock ran while the player was still loading, in the tab and in the game. The game only waited for videos once, when it started. A composition that a behavior starts later spawned its items after that wait. - The view now records which video sprites it left out for lack of a first picture, one entry per object. - The composition tab holds its playhead while the preview misses a video, for at most VIDEO_WAIT_MS (3 s) like the game. - CompositionSystem holds a composition's clock while one of its live items misses its video. The rest of the game keeps running. - The editor play and the published game pass their view to the run as RunServices.pictures. - VIDEO_WAIT_MS moves to core/model/video.ts, because the runtime does not import from viewport/. - Videos loaded ahead for coming items do not hold the clock. Items can now be copied and pasted inside the composition tab. - Ctrl+C keeps the timing of the copied items next to the objects. - Ctrl+V pastes objects and items in one undo step. The earliest item lands at the frame under the pointer, on the track there. - Without the pointer over the tracks it lands at the playhead, on the selected track or on the top track of the selected items. - Several items keep their distances and tracks to each other. - The same copy pastes into a scene as plain objects. Objects copied from a scene do not paste into a composition, they have no timing. Tests: - Unit composition-edit, clipboard, composition-play: 3 new for pasting, 1 new for the clock waiting in the game - e2e 69i (play from the end waits for the video), 69j (paste under the pointer and at the playhead), 68d (a composition started from On start waits for its video) - each new check is red without its fix - README: 2036 editor checks 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> |
||
|
|
36ffd9a61a |
Land a driven video's seek without a frame so it is never empty (#404)
Since
|
||
|
|
b9fcf48097 |
Show a cut into the middle of a clip without its old picture (#404)
A switched-off driven video waits at the video time it has where it is, before its first key mostly the start value. Switched on at another spot, its player has to seek first. Until the seek is done the texture still holds the old picture, so the start of the clip flashed for a frame or two at the cut. - A view holds its last picture while a driven video that just came into sight is still seeking, for at most 0.3 s. At a cut the old clip stays one frame longer and the right picture of the new one follows. - A seek counts as done only when the browser hands in the next video frame (requestVideoFrameCallback), and the texture is uploaded right then. The seeked event alone was too early, one red frame was left. - A seek that takes longer than 0.3 s leaves the sprite out until its picture is there. The wrong picture does not show either way. Tests: - e2e 66q switches a sprite off at 0.2 s (red) and on at 1.2 s (blue) and reads every frame in the browser. No red may show, blue must stand at the end. - Against the old code 66q fails with 2 red frames before the blue. With only the seeked event it still fails with 1 red frame. - e2e 66 on melektaus-atx: ALL PASSED, 28 checks, run twice. - Unit video-library, video-follow: 19 passed. - Gate on melektaus-atx: CHECK EXIT 0, 297 files, 4562 tests. - tsc, eslint, Prettier clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3a1e420806 |
Read a driven video's speed on the frame clock so 1x stays 1x (#404)
A driven video measures how fast its wearer's time runs and sets its playbackRate from that. The time moves on with the ticker, but the reading took its clock from performance.now() while drawing. A frame that had more to do before the draw shifted that clock against the time, and a 1x animation read as up to 1.09. Outside 0.9 to 1.1 the video goes mute, so the sound could drop out for a moment. In CI this made e2e 66k red now and then. - VideoLibrary reads the speed with the timestamp of the frame (document.timeline.currentTime), the same clock the time runs on. It falls back to performance.now() where there is no document. - debugInfo() reports the measured speed of a driven player. - e2e 66k checks the measured speed and the correction of the rate apart. The rate alone may differ from 1 by up to 10 percent on purpose, so checking it at +-0.1 was too strict. Tests: - Unit video-library: 8 tests green, 1 new. With performance.now() back in place the new test is red and reads 1.089. - e2e 66 on melektaus-atx: all passed, 27 checks, speed 1.000 in all 5 readings. - Gate on melektaus-atx: CHECK EXIT 0, 297 files, 4562 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
dd60a795e1 |
Wait for driven videos before a run starts so no sprite flashes (#404)
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> |
||
|
|
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> |