A Start recording right after Play composition still began with
empty frames. The composition's clock waited for its video, but the
recording went on and took every frame while the video loaded. A
clip that starts later in the video also slipped through, because
its player already had one picture while it still sought to the
clip's start.
- The view now counts every video sprite it leaves out as missing,
not only one without any first picture.
- GameRecorder takes no frame while the game view misses a video,
for at most VIDEO_WAIT_MS (3 s) at a time. The recorded time
stands and the sound of that time is dropped, so it stays in sync.
- RecordingClock.start forgets a hold from before the first frame.
Without that, the first real frames all got the time 0.
- A followed player starts at 1x until the first speed reading.
Before, it paused and sought every frame for about 100 ms, so the
first pictures after a wait stuck and then jumped. A step faster
than 4x and a time running backwards do not count as a start.
- Test hooks: __gm.gameVideo(id) reads the game view's own player,
TakeInfo.lastFrameAt shows when the last frame was taken.
Tests:
- Unit recording (clock after an early hold), video-follow (2 new,
1 adapted): 449 green in tests/core/recording, tests/viewport and
tests/core/composition*
- e2e 68e (a clip from 0.8 s shows that picture first and then
plays), 68f (a recording that already runs takes no frame while
the composition's video loads)
- 68e is red without the start at 1x, 68f without the hold
- README: 2038 editor checks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>