Screen helpers · interface

LockableSurface

The surface a clip is recorded from: a fixed-size frame, composited and paced.

Explained in Recording and clips.

interface LockableSurface
import type { LockableSurface } from '@driftengine/core';

In depth

Three things it fixes, all of which were visible in the first export:

Aspect is rendered, not cropped. The scene is drawn at the export's own pixel size, so a vertical clip is framed vertically. Cropping a 16:9 view to 9:16 throws away 44% of the width, and the subject is exactly what falls outside — the shot was composed for the other rectangle.

The frame is composited. The scene canvas is copied into a target of exactly the requested size and the mark is stamped on top, so branding is inside the video rather than in DOM that the capture never sees.

Frames are paced. captureStream(0) records nothing until asked, so every frame in the file is one the renderer actually finished. Capturing at a rate the renderer cannot hold samples some frames twice and misses the next, which is what uneven duplication looks like: judder.

The honest limit. MediaRecorder timestamps by wall clock, so an export runs in real time and no amount of pacing changes that. There is no in-browser way to render slower than real time and still have the audio line up, short of shipping a muxer — which is a dependency, and the standing rule says no. What pacing can do is make every frame in the file the same distance from the last, by counting animation frames rather than milliseconds — see FramePacer. A device that cannot hold the requested rate then records a slower clip rather than a juddering one, and the measurement in pacing says which it was.

Methods

lockDrawingBuffer

lockDrawingBuffer(width: number, height: number): void

Pin the drawing buffer to an exact pixel size, ignoring CSS and DPR.

ParameterTypeDescription
widthnumber
heightnumber

unlockDrawingBuffer

unlockDrawingBuffer(): void