The existing exporter uses mediabunny, which delegates to the
WebCodecs VideoEncoder and AudioEncoder. On browsers where those
APIs are not exposed (the same environments that needed the decode
fallback in #794), export currently fails with
"AudioEncoder is not supported by this browser" before producing
any output.
This change adds a parallel fallback path in SceneExporter:
- New helpers \`isWebCodecsExportSupported()\` and
\`detectMediaRecorderSupport()\` live in a tiny dependency-free
module so they can be unit-tested without dragging in WASM.
- New \`exportWithMediaRecorder\` drives the existing CanvasRenderer
at real-time wall-clock, captures the output canvas with
\`HTMLCanvasElement.captureStream(fps)\`, mixes the project audio
buffer through a \`MediaStreamAudioDestinationNode\`, and records
the combined MediaStream with MediaRecorder, producing a WebM
blob the same browser can play back natively.
- \`SceneExporter.export()\` detects \`!isWebCodecsExportSupported()\`
at entry and delegates to the new path. The WebCodecs path is
unchanged for capable browsers.
Trade-offs of the fallback path:
- Output is always WebM (most browsers don't expose an MP4 muxer
via MediaRecorder). The user's requested format is honoured
best-effort.
- Rendering runs at real time, so a 60-second timeline takes
roughly 60 seconds to export. mediabunny's WebCodecs path
continues to render faster than real-time on capable browsers.
- Bitrate is mapped per quality preset to a numeric value
compatible with \`MediaRecorder.videoBitsPerSecond\`.
Unit tests cover the feature-detection helpers across the four
states of \`VideoEncoder\` / \`AudioEncoder\` / \`MediaRecorder\`
availability.