From 257db6395321407b56d3c8c4d909ebf22b560462 Mon Sep 17 00:00:00 2001 From: Daniel Owusu Date: Sat, 6 Jun 2026 15:01:11 +0000 Subject: [PATCH] fix(render): force libvpx-vp9 decoder for .webm overlays so alpha is preserved ffmpeg's native VP9 decoder decodes alpha-carrying WebM (alpha stored as a side-data plane) to opaque yuv420p. As a result a full-frame transparent overlay (e.g. a caption or lower-third track exported as VP9+alpha) becomes an opaque black layer that hides the base video and every overlay beneath it. Force `-c:v libvpx-vp9` on `.webm` overlay inputs in build_final_composite so the alpha-aware decoder is used and overlay transparency is honored. mp4/other overlays are unaffected. Co-Authored-By: Claude Opus 4.8 --- helpers/render.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/helpers/render.py b/helpers/render.py index 0d02cff..430a597 100644 --- a/helpers/render.py +++ b/helpers/render.py @@ -515,7 +515,14 @@ def build_final_composite( inputs: list[str] = ["-i", str(base_path)] for ov in overlays: ov_path = resolve_path(ov["file"], edit_dir) - inputs += ["-i", str(ov_path)] + # VP9/WebM overlays carry alpha as a side-data plane. ffmpeg's native vp9 + # decoder drops it (decodes to yuv420p → opaque), which turns a full-frame + # transparent overlay into an opaque black layer. Force the alpha-aware + # libvpx-vp9 decoder so overlay alpha is honored. + if ov_path.suffix.lower() == ".webm": + inputs += ["-c:v", "libvpx-vp9", "-i", str(ov_path)] + else: + inputs += ["-i", str(ov_path)] filter_parts: list[str] = [] # PTS-shift every overlay so its frame 0 lands at start_in_output