Skip to content

feat(frontend): add browser GIF export#124

Open
KyleTryon wants to merge 2 commits into
mainfrom
feat/frontend/gif-export
Open

feat(frontend): add browser GIF export#124
KyleTryon wants to merge 2 commits into
mainfrom
feat/frontend/gif-export

Conversation

@KyleTryon
Copy link
Copy Markdown
Contributor

@KyleTryon KyleTryon commented Jun 1, 2026

Release Notes

  • Add first-time browser GIF export to the editor.
  • Encode GIFs with ImageOptim/gifski WASM in the browser; no server conversion and no ffmpeg.wasm.
  • Add GIF presets:
    • Compact: 360p max, 10 fps, quality 65, fast encode.
    • Balanced: 480p max, 12 fps, quality 85. This is the default.
    • Sharp: 720p max, 15 fps, quality 100.
  • Keep GIF exports video-only, capped at 15 seconds, and presented as a legacy compatibility format with WebM recommended when supported.
  • Add immediate approximate export-size estimates for MP4, WebM, MOV, MKV, and GIF in the export summary.
  • Improve estimates with local source size/duration, Plex/Jellyfin source bitrate metadata, and HLS manifest bandwidth when available.
  • Log estimate basis, estimated bytes, actual output bytes, delta, and ratio after export so estimates can be calibrated from real output.
  • Rework the export dialog to show GIF-only controls only when GIF is selected, keep helper text slots stable, and reduce layout shift.

Implementation Notes

  • exportClip keeps Mediabunny Conversion for MP4, WebM, MOV, and MKV, and routes GIF through a dedicated path.
  • GIF export builds a Mediabunny input and CanvasSink, samples preset-timed frames, applies canvas resize and subtitle burn-in, then transfers RGBA buffers to a module Worker.
  • The Worker dynamically imports /vendor/gifski-wasm/gifski.js, initializes the generated WASM module/thread pool, feeds frames with timestamps, and returns an image/gif buffer.
  • GIF readiness blocks unsupported browsers: Web Worker support, SharedArrayBuffer, and cross-origin isolation are required.
  • GIF readiness also blocks exports that would exceed the 512 MiB raw RGBA frame budget before encoding starts.
  • The gifski WASM artifact is generated from pinned ImageOptim/gifski 1.34.0 source plus a local WASM patch using Docker Buildx.
  • Generated apps/frontend/public/vendor/gifski-wasm/ files are ignored build products, not committed source.
  • Root dev/build, frontend dev/build, Docker image builds, and CI all ensure the gifski artifact exists before building the frontend.
  • Vite dev now sends COOP/COEP headers so the local browser environment can satisfy the GIF worker requirements.
  • Plex, Jellyfin, shared provider types, and local editor sessions now carry export-estimate metadata used by the frontend estimator.

Release / Merge Gate

  • ImageOptim/gifski is AGPL-3.0-or-later. Keep this blocked until AGPL compatibility or a commercial gifski/pngquant license path is confirmed for Cliparr.

Validation

  • pnpm build:gifski-wasm
  • pnpm --filter @cliparr/frontend test
  • pnpm --filter @cliparr/frontend build
  • pnpm preflight

Adds browser-side GIF presets, universal size estimates, HLS/provider estimate metadata, and export estimate logging.

Validation: pnpm --filter @cliparr/frontend test; pnpm --filter @cliparr/frontend build; pnpm preflight
@cloudflare-workers-and-pages
Copy link
Copy Markdown
Contributor

cloudflare-workers-and-pages Bot commented Jun 1, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
cliparr-web 23c48e7 Commit Preview URL

Branch Preview URL
Jun 02 2026, 03:05 AM

@KyleTryon KyleTryon marked this pull request as ready for review June 1, 2026 23:30
@KyleTryon KyleTryon force-pushed the feat/frontend/gif-export branch from 13da411 to 23c48e7 Compare June 2, 2026 03:04
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