Skip to content

Format matrix: WebM fallback + transparent video (issue 06) - #9

Open
lenxism wants to merge 2 commits into
mainfrom
feat/format-matrix-webm-transparency
Open

Format matrix: WebM fallback + transparent video (issue 06)#9
lenxism wants to merge 2 commits into
mainfrom
feat/format-matrix-webm-transparency

Conversation

@lenxism

@lenxism lenxism commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • Probes encoder capabilities when the export dialog opens (scene/encoder-capabilities.ts, mediabunny canEncodeVideo, cached per session) and reduces them to plain data; every decision derived from the probe is a pure, Vitest-covered core rule (16 new tests, TDD red-first).
  • Format matrix per ADR-0024: MP4/H.264 default; WebM/VP9 fallback announced in the dialog ("WebM — this browser can't encode MP4"), never a silent switch; transparency forces WebM/VP9 + alpha: 'keep' and is only offered when the alpha probe passes AND the Stage background is transparent (mirroring the transparent-PNG rule), with the Safari/desktop-editors caveat surfaced.
  • Resolution presets become encoder-aware: presets whose resolved size exceeds the probed encoder maximum are hidden (e.g. 4K when the hardware encoder tops out lower).
  • Exporter: exhaustive muxer switch (Mp4/WebMOutputFormat), alpha-0 clear + per-frame scene.background re-assert for transparent captures (an animated stage colour would rebake it mid-encode), and per-frame encode-canvas clear so semi-transparent pixels don't accumulate prior frames.

Test plan

  • 400 Vitest tests green (16 new for selectVideoFormat, transparentVideoAvailable, availableVideoHeightPresets, resolveVideoEncode webm/alpha, .webm filename)
  • typecheck + lint + build green
  • Browser evidence (.scratch/animation-video-export/evidence/06/, system Chrome via Playwright): MP4 · H.264 default at dialog open; transparency check flips format to WebM · VP9 with caveat; exported transparent WebM decoded frame asserts corner alpha 0 / center 255 and composites correctly over an orange page background; opaque default downloads .mp4; transparency option absent for a gradient background
  • mp4Fallback dialog state not exercisable live in Chrome (it encodes H.264) — rule and label covered by Vitest/typecheck

Note

Medium Risk
Touches the multi-second video encode path and format/transparency gating; mistakes could cause failed encodes or silent wrong format, but logic is heavily unit-tested and avoids starting doomed exports.

Overview
Adds issue 06 video format matrix: MP4/H.264 stays default; browsers without H.264 get WebM/VP9 with an explicit “can't encode MP4” warning (mp4Fallback). Transparent video forces WebM + VP9 alpha: 'keep', only when the alpha encoder probe succeeds and the stage background is transparent (same idea as transparent PNG).

Core gains probed VideoEncoderCapabilities, pure helpers (selectVideoFormat, transparentVideoAvailable, encoderMaxDimension, availableVideoHeightPresets), transparent on VideoExportRequest, and resolveVideoEncode(format, transparent) with VP9 + alpha mode. Resolution presets are encoder-aware (e.g. 4K hidden when max dimension is too low; separate alpha VP9 ceiling).

Scene: new probeVideoEncoderCapabilities (mediabunny canEncodeVideo, session cache); Exporter muxes MP4 or WebM, applies alpha-0 clear / per-frame scene.background nulling and encode-canvas clearRect for transparent WebM.

Export panel probes on open, disables video until probe completes, shows format/fallback/transparent UI, and builds the updated video request.

Reviewed by Cursor Bugbot for commit 30d6ef8. Bugbot is set up for automated code reviews on this repo. Configure here.

Probe encoder capabilities at export-dialog open (mediabunny canEncodeVideo,
cached per session); every decision over the probed plain data is a pure core
rule: MP4/H.264 default, honest WebM/VP9 fallback ("this browser can't encode
MP4", never silent), transparency forces WebM + alpha 'keep' and is offered
only when the alpha probe passes and the Stage background is transparent, and
resolution presets respect the probed encoder maximums (4K hidden when the
hardware encoder tops out lower).
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mockstudio Ready Ready Preview, Comment Jul 9, 2026 7:04pm

Comment thread src/core/export.ts Outdated
Comment thread src/core/export.ts
The transparent branch of selectVideoFormat gated only on "alpha encodable"
while the ladder clamped against the opaque VP9 max — so a transparent choice
could pair with an empty preset list, and an offered preset could exceed what
alpha-preserving VP9 (a stricter encoder config) actually accepts. Replace the
vp9Alpha boolean with a probed vp9AlphaMaxDimension ceiling and key both the
format selection and the resolution clamp on it when the export is transparent.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 30d6ef8. Configure here.

Comment thread src/ui/ExportPanel.tsx
) : videoPresets.length === 0 ? (
<p className="text-[11px] leading-snug text-muted">
This browser can&apos;t encode video (no MP4 or WebM encoder).
</p>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty presets misreport encoder

Medium Severity

When capabilities are loaded and selectVideoFormat returns a valid choice but availableVideoHeightPresets filters out every height (e.g. a wide match-frame aspect with a modest encoder max), the resolution section still says the browser cannot encode MP4 or WebM, even though the format row may show MP4 or WebM as available.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 30d6ef8. Configure here.

Comment thread src/ui/ExportPanel.tsx
let cancelled = false
void probeVideoEncoderCapabilities().then((probed) => {
if (!cancelled) setCapabilities(probed)
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probe rejection stalls dialog

Medium Severity

The export panel only handles a fulfilled probeVideoEncoderCapabilities promise. If the probe rejects, capabilities never leave null, so video mode can show “Checking encoder support…” indefinitely and keep export disabled even after the probe has finished.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 30d6ef8. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant