Skip to content

video-compressor: animated WebP output option - #351

Merged
simonw merged 1 commit into
mainfrom
claude/video-compressor-animated-webp
Oct 1, 2026
Merged

simonw merged 1 commit into
mainfrom
claude/video-compressor-animated-webp

Conversation

@simonw

@simonw simonw commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Add animated webp as an option to the video-compressor tool (alternative to mp4)

Claude Opus 5.5

A Format switch above the versions table picks MP4 video or animated WebP.

In WebP mode:

  • Each version has a WebP quality from 0 to 100 (defaults 80/75/60/65/55) instead of CRF. The audio column and the MP4-only options (H.264 profile, no audio, strip metadata, limit to 30 fps) are hidden.
  • Encoder speed sets libwebp's -compression_level: 0, 2, 4 (the default) or 6. In testing, 6 took about 10× as long as 4 for files only 1–2% smaller.
  • Max frame rate defaults to 15 fps and never goes above the source's. File size grows almost in step with frame rate.
  • Files are encoded with libwebp_anim, which stores only the parts of each frame that changed. They use -loop 0 because ffmpeg's WebP output plays only once by default. They have no audio, and the WebP muxer writes no metadata.
  • Results preview as an <img> and download as .webp. "Encode full version" keeps the format.
  • The embed snippet becomes '&lt;img src="…webp" width height alt="" loading="lazy"&gt;', and the note above it says to fill in the alt text.
  • libwebp_anim hands its output to ffmpeg only at the very end, so ffmpeg's progress time stays at zero. The progress bar counts the frame= log lines instead.

Results in both formats can sit side by side: switch format and generate again, and they're sorted by size. The poster frame is now extracted only before the first MP4 job, so a WebP-only run skips it.

Also adds a [hidden] { display: none !important } rule, so hidden elements with a CSS display value really hide. The poster row was showing while it was empty.

Animated WebP is much larger than MP4. The 3-second, 128 KB test clip came out at about 290–350 KB as WebP, and the UI says so.

Tests

Two new Playwright tests in tests/test_video_compressor.py:

  • test_webp_format_switches_settings runs offline. It covers the controls, quality header, filename hint, the <img> embed snippet (including the XHTML variant), and that each version keeps its WebP quality and CRF separately.
  • test_animated_webp_encode encodes a 1-second sample and then the full clip. It parses the RIFF chunks to check each file is animated, loops forever, is 640×360, has the right total length and has no EXIF/XMP/ICCP chunks. It also checks the command line, filenames and progress reporting, then encodes an MP4 alongside it.

pytest tests/test_video_compressor.py -k "not jsquash": 8 passed. test_poster_webp_falls_back_to_jsquash_without_native_support fails in the sandbox where this was written, on main as well: it fetches @jsquash/webp from jsDelivr inside the browser, and that browser had no network access.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EGZFbqVeWgoceoCSNFnfvY

> Add animated webp as an option to the video-compressor tool (alternative to mp4)

A Format switch above the versions table picks MP4 or animated WebP. WebP
versions are encoded with libwebp_anim, loop forever (-loop 0; the webp muxer
defaults to playing once), have no audio, and get their own per-version
quality (0-100) plus encoder speed and max frame rate settings (15 fps by
default). Results preview as <img>, download as .webp, and the embed snippet
becomes an <img loading="lazy"> tag. The poster frame is now only extracted
before the first MP4 job.

Also adds a [hidden] { display: none !important } rule so hidden elements
with a display style (like the poster row) really hide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGZFbqVeWgoceoCSNFnfvY
@claude

claude Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

@simonw

simonw commented Oct 1, 2026

Copy link
Copy Markdown
Owner Author

WebP end up being a lot bigger than MP4, I'm going to land it anyway because it's an interesting demo of that fact.

@simonw
simonw merged commit d4c5041 into main Oct 1, 2026
1 of 4 checks passed
simonw pushed a commit that referenced this pull request Oct 1, 2026
test_webp_format_switches_settings, added in #351, has the same
assumption as the <video> snippet test: newer Playwright Chromium reads
the source size up front, so the <img> snippet carries width/height.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0139NfxSqowttMWdKwMQ7hYM
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.

2 participants