Screen helpers · interface
FrameRecorderOptions
Recording what is on a canvas — or on a prepared export target — to a file.
Explained in Recording and clips.
interface FrameRecorderOptionsimport type { FrameRecorderOptions } from '@driftengine/core';In depth
A convenience on top of the replay, not the feature. The replay itself is what makes a run worth posting; this saves the trouble of reaching for a screen recorder — and where the browser cannot do it, saying so plainly beats producing a file that will not play.
Deliberately not a server-side render. That is the "proper" answer and it is a backend, a queue, a storage bill and a moderation problem, for something the browser already does.
The honest limit, and it belongs here rather than in a commit message:
MediaRecorder timestamps every frame by wall clock, and that is measured
rather than assumed — a probe recording requested frames at gaps of 8.6 / 24.5 /
8.1 / 28.6 ms and ffprobe read the MP4's own timestamps back as 8.8 / 24.2 /
8.1 / 28.5 ms, avg_frame_rate=7110000/120161. Two things follow.
An export has to run in real time: there is no in-browser way to render a clip
slower than real time and have the audio line up, short of shipping our own
muxer, which is a dependency and the standing rule says no. So the export can be
paced (see ExportTarget) and measured, but it cannot be given more time.
And a constant-rate file is not on offer either. What is on offer is a file whose
frames are evenly spaced and hold moments the same distance apart, which is
what a viewer reads as smooth — so the schedule captures every n-th animation
frame and the content follows the wall clock. A device that cannot hold the
target rate then produces a slower clip rather than a juddering one, and the
measurement in pacing says which it was.
Properties
| Name | Type | Description |
|---|---|---|
canvasreadonlyoptional | HTMLCanvasElement | Record the canvas directly, at fps. Simple and appropriate for a debug
capture; for a clip anybody else will see, prefer stream from an
ExportTarget, which fixes the aspect, stamps the mark and paces the
frames. |
streamreadonlyoptional | MediaStream | A prepared video stream, e.g. ExportTarget.acquire(). Wins over canvas. |
audioreadonlyoptional | MediaStream | null | Mixed into the clip. Omit for a silent recording. |
fpsreadonlyoptional | number | Frames per second wanted — a floor, not a promise.MoreThe schedule counts animation frames (see |
videoBitsPerSecondreadonlyoptional | number | Bits per second for video. Defaults to a figure scaled from the frame's pixel count and rate — a constant is generous at one size and starved at another, and a starved encoder on high-motion footage looks like stutter. |
targetreadonlyoptional | { /** The canvas the scene is drawn into. */ readonly source: HTMLCanvasElement; /** Whoever owns that canvas's drawing-buffer size — normally the renderer. */ readonly surface: LockableSurface; readonly width: number; readonly height: number; readonly overlay?: FrameOverlay | ((width: number, height: number) => FrameOverlay); /** * Drawn live into every composed frame, after the scene and the baked mark. * * For anything that changes frame to frame — a speedometer, a clock — which the * baked `overlay` cannot express at all. See `ExportTargetOptions.drawFrame`. */ readonly drawFrame?: (ctx: CanvasRenderingContext2D, width: number, height: number) => void; /** * What the renderer is currently managing, frames per second. A device below * the target rate records at a smaller frame instead: a slightly softer clip * that holds its rate beats a full-size one that judders. Omit for no * measurement, which is treated as no evidence rather than as bad news. */ readonly measuredFps?: number; /** Forwarded to `ExportTargetOptions.presentedFrames`; see `duplicateFrame` below. */ readonly presentedFrames?: () => number; } | Record at a fixed frame size rather than at whatever the canvas happens to
be, compositing the scene and an optional mark into it.MoreThis is what makes an export a product rather than a screen capture: the frame is the requested shape whatever the window is, the mark is inside the video where a DOM overlay could never be, and frames are handed over one at a time so none is ever recorded twice. |