Skip to content

Media: Show determinate GIF conversion progress in the upload snackbar - #80329

Open
adamsilverstein wants to merge 12 commits into
trunkfrom
add/gif-conversion-progress
Open

Media: Show determinate GIF conversion progress in the upload snackbar#80329
adamsilverstein wants to merge 12 commits into
trunkfrom
add/gif-conversion-progress

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented Jul 15, 2026

Copy link
Copy Markdown
Member

What?

Fixes #80325.

Shows determinate progress in the editor's upload progress snackbar while an animated GIF is being converted to a video: the snackbar's spinner is replaced with a determinate ProgressBar and the label switches from "Uploading" to "Processing". The block canvas is untouched - the image keeps its existing fade treatment.

Follows the direction in this review comment: an earlier iteration overlaid the progress bar on the Image block itself, which doesn't scale to small images and puts per-item processing UI on the block rather than in the shared upload surface.

Why?

Converting a long animated GIF to a video (#76942, #80072) can take tens of seconds: every frame is decoded and re-encoded via WebCodecs. #80260 fixed the outright hang, but during a legitimately long conversion the author only sees an indeterminate spinner with no indication of how far along the conversion is or whether it is making progress at all.

Exact progress is available for free: the conversion loop reads the total frame count up front (ImageDecoder track.frameCount) and processes frames one at a time, so framesDone / frameCount is precise. Encoder backpressure happens inside the same loop, so the frame index tracks wall-clock progress closely.

How?

Data layer:

  • convertGifToVideo() in @wordpress/video-conversion accepts an optional onProgress callback reporting a 0–1 fraction. It is throttled to whole-percent increments so a thousand-frame GIF doesn't flood the worker message channel. The worker RPC layer (comctx) proxies top-level function arguments across the worker boundary, so the callback passes straight through.
  • transcodeGifItem() in @wordpress/upload-media dispatches the previously dormant updateItemProgress() action from that callback. (QueueItem.progress, the UPDATE_PROGRESS reducer case, and getItemProgress() already existed with no producers or consumers.) Dispatches are additionally time-gated to one per 250ms: without this, a fast conversion emits ~100 reports in a couple of seconds and each dispatch synchronously re-renders every upload-store consumer in the editor, saturating the main thread so the browser never paints the bar. The final report always goes through.
  • Progress is readable straight off the queue items returned by the existing getItems() selector; no new store API is added.

UI:

  • UploadProgressSnackbar looks for a queue item reporting progress below 100 (the conversion runs on a sideload companion item, so the full queue is scanned rather than just the originals it counts). While one exists, the notice icon slot renders a determinate ProgressBar (from @wordpress/components) instead of the Spinner, and the label reads "Processing — file.gif" (with the usual "x of y" form for batches).
  • The bar is styled for the snackbar's dark surface (white indicator via the --wp-components-color-foreground custom property, 4px tall, 48px wide) and the notice text is indented to clear the wider icon slot.
  • Once conversion reaches 100% the snackbar falls back to the regular indeterminate "Uploading" state while the resulting video file uploads.

Out of scope: network upload progress for the resulting video file (apiFetch doesn't expose upload progress; for long GIFs the conversion phase dominates).

Testing Instructions

Test in WordPress Playground

  1. Ensure client-side media processing is active (it is on by default in the plugin).
  2. In a Chromium-based browser, create a new post and upload a long animated GIF (a few hundred frames) to an Image block.
  3. While the GIF is being converted, observe the upload snackbar switch from "Uploading — file.gif" (spinner) to "Processing — file.gif" with a determinate progress bar advancing in place of the spinner, then back to the regular flow ("Upload complete").
  4. Short GIFs and regular images still show the spinner throughout (no progress is reported).

The states can also be reviewed in Storybook: Editor/UploadProgressSnackbar.

Unit tests:

npm run test:unit -- packages/editor/src/components/upload-progress-snackbar packages/video-conversion packages/upload-media

Note: there is no e2e assertion for the transient Processing state because conversion of the small e2e GIF fixtures completes in well under a second, which would make the assertion flaky. The data flow (worker progress reports, throttling, snackbar states) is covered by unit tests.

Screenshots

(Updated screenshot of the snackbar's Processing state incoming.)

The conversion loop knows the exact frame count up front, so per-frame
progress is precise. Add an onProgress callback to convertGifToVideo(),
throttled to whole-percent increments, and dispatch the previously
unused updateItemProgress action from transcodeGifItem. A new
getProgressById selector resolves progress for an attachment, matching
sideload companions via additionalData.post.

See #80325.
Replace the indeterminate spinner overlay with a determinate
ProgressBar while a long-running client-side operation reports
progress for the block's attachment, so authors converting long
animated GIFs can see how far along the conversion is.

See #80325.
Fast conversions can emit ~100 whole-percent reports in a couple of
seconds. Each dispatch synchronously re-renders every upload-store
consumer in the editor, which saturates the main thread and starves
painting - the progress bar was in the DOM but never drawn. Allow at
most one dispatch per 250ms (the final report always goes through).

Verified in the editor: the bar now paints and advances visibly during
conversion.

See #80325.
@adamsilverstein adamsilverstein added [Type] Enhancement A suggestion for improvement. [Feature] Media Anything that impacts the experience of managing media labels Jul 15, 2026
@github-actions github-actions Bot added the [Package] Block library /packages/block-library label Jul 15, 2026
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Size Change: +504 B (+0.01%)

Total Size: 7.75 MB

📦 View Changed
Filename Size Change
build/modules/video-conversion/worker.min.js 83.8 kB +83 B (+0.1%)
build/scripts/editor/index.min.js 500 kB +108 B (+0.02%)
build/scripts/upload-media/index.min.js 15.6 kB +81 B (+0.52%)
build/styles/editor/style-rtl.css 31.3 kB +57 B (+0.18%)
build/styles/editor/style-rtl.min.css 26.6 kB +59 B (+0.22%)
build/styles/editor/style.css 31.4 kB +60 B (+0.19%)
build/styles/editor/style.min.css 26.6 kB +56 B (+0.21%)

compressed-size-action

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: adamsilverstein <adamsilverstein@git.wordpress.org>
Co-authored-by: jasmussen <joen@git.wordpress.org>
Co-authored-by: andrewserong <andrewserong@git.wordpress.org>
Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Flaky tests detected in 2970d39.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/29788532163
📝 Reported issues:

adamsilverstein and others added 3 commits July 16, 2026 14:34
The default ProgressBar is a 1.5px hairline in theme foreground color,
nearly invisible over noisy GIF frames or dark video posters. Thicken it
and give it media-relative contrast: white indicator on a dark
translucent track, with a light outline and drop shadow so the track
extent stays visible over dark media.
…rogress

# Conflicts:
#	packages/upload-media/src/store/private-actions.ts
#	packages/upload-media/src/store/test/private-actions.js
#	packages/upload-media/src/store/utils/video-conversion.ts
#	packages/video-conversion/CHANGELOG.md
#	packages/video-conversion/README.md
#	packages/video-conversion/src/index.ts
#	packages/video-conversion/src/video-conversion-worker.ts
@jasmussen

Copy link
Copy Markdown
Contributor

Thanks for the PR, and the tireless work. I responded on something related on the upload hang discussion, which is to say: we are entering some complexity territory with some of this work that may be worth visioning out before going too far into details. The details are critical, but they need to all connect, somehow. For me in this case, the topic is less showing progress while converting GIFs, but rather: how do we show process for processing media in general, and how do we do that in a way that scales not only from the block, but eventually, to the media library itself—because presumably you should be able to upload and process a GIF there too.

I share that mostly as apprehension with going too fast on this area too soon. I know @fcoveram has had a lot of thoughts around the media library, and those thoughts should likely extend here as well. For example I outline a loose idea of showing an "upload tray" that can both surface retry options and give status information for enqueued processing actions that are bulk-added. My instinct would go the same way with this. That means I'd also show any progressbars inside such a tray, rather than on the block itself. E.g. what would it look like if you uploaded dancing-megaman, a 26x26px piece of pixel art? The progressbar would not be visible. For that reason, I'd keep the image must fading in and out, if possible with a blurred version of itself as a backdrop, and have the actual progressbar happen in the aforementioned tray.

But that's a vague vision that needs a bit more clarity before committing. So looking at the issue which is valid: can we still use UploadProgressSnackbar, but make it determinate? If we have to, we can replace the Spinner inside with ProgressBar, which should be possible to make determinate. What do you think?

@adamsilverstein

adamsilverstein commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

But that's a vague vision that needs a bit more clarity before committing. So looking at the issue which is valid: can we still use UploadProgressSnackbar, but make it determinate? If we have to, we can replace the Spinner inside with ProgressBar, which should be possible to make determinate. What do you think?

Generally I like this direction, maybe even show "Processing" or some similar verb instead of uploading during this phase.

to the media library itself—because presumably you should be able to upload and process a GIF there too.

I've been experimenting with leveraging the client side media code in the classic media screen (including GIF -> Video support):

… block

Per review feedback, keep the block canvas treatment as-is (a progress
bar overlaid on the block would be invisible on small images) and make
the upload progress snackbar determinate instead: while the GIF-to-video
conversion reports progress, the spinner is replaced with a ProgressBar
and the label switches from Uploading to Processing.

Remove the now-unused getProgressById selector; consumers read per-item
progress directly off the queue items returned by getItems().
@github-actions github-actions Bot added [Package] Editor /packages/editor and removed [Package] Block library /packages/block-library labels Jul 20, 2026
@adamsilverstein adamsilverstein changed the title Media: Show determinate progress while converting animated GIFs to video Media: Show determinate GIF conversion progress in the upload snackbar Jul 20, 2026
@adamsilverstein

adamsilverstein commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

@jasmussen - I tried moving the progress indicator to the snackbar in 2970d39: the block canvas is untouched now (the image keeps its existing fade), and UploadProgressSnackbar is determinate instead. While the conversion reports progress, the Spinner in the icon slot is swapped for a determinate ProgressBar and the label switches to "Processing — file.gif". Once conversion reaches 100% it falls back to the regular "Uploading" state while the resulting video file uploads.

Since progress now lives on the upload queue item itself (readable via getItems()), a future upload tray - or the media library - can render the same data; I removed the by-attachment selector the block overlay needed. The updated states are in Storybook under Editor/UploadProgressSnackbar.

Screenshots

snackbar-processing-02-27pct snackbar-processing-04-27pct

@jasmussen

Copy link
Copy Markdown
Contributor

Honestly that looks pretty good at a glance! Did you make the actual progressbar hairline thicker? It's intentionally 1.5px which is small but visible and elegant. If it's unchanged, IMO, this could work. I still think there's a larger vision we can unpack at a later time.

@adamsilverstein

Copy link
Copy Markdown
Member Author

Honestly that looks pretty good at a glance! Did you make the actual progressbar hairline thicker? It's intentionally 1.5px which is small but visible and elegant. If it's unchanged, IMO, this could work. I still think there's a larger vision we can unpack at a later time.

The height is set explicitly in https://github.com/WordPress/gutenberg/pull/80329/changes#diff-96ffb1246440442d4d45343faaa6ee39c03d36f5757ee78124ad42a94e2abe51R28, I will try removing that height style to capture a screenshot of what it looks like without that.

@adamsilverstein

Copy link
Copy Markdown
Member Author

Height removed:

converting

I think thats about 2px vs 4 px?

now
snackbar-hairline-demo

previously
snackbar-zoom-05-56pct

How does that look @jasmussen?

The 1.5px hairline is an intentional part of the component's design and
reads fine on the snackbar, so drop the 4px height override and keep only
the width and foreground-color adjustments.
@jasmussen

Copy link
Copy Markdown
Contributor

That looks perfect. In general for all our reused componentry, the less CSS we can add on top of it, the better, so it all looks the same across every instance! Nice.

@adamsilverstein
adamsilverstein requested a review from Mamaduka July 22, 2026 15:41
@adamsilverstein

Copy link
Copy Markdown
Member Author

Thanks for the reviews and approval @jasmussen. I'll leave this open a bit longer to get a code review as well, and I think we can land this before the next Beta.

@andrewserong

Copy link
Copy Markdown
Contributor

I like the idea of a progress bar and when it displays I quite like the look of it, too. The main issue I've run into in testing is just that for the majority of smaller GIFs I upload the conversion stage is so quick it effectively looks like a flicker, rather than a good bit of visual feedback. I.e. in the following, the progress bar only shows for a frame or two:

2026-07-23.14.17.24.mp4

This is probably more of a design question, but if I'm wondering if we should stick with either the spinner or the progress bar, and not switch from spinner to progress bar to spinner?

I imagine the blocker to using a progress bar overall is that we then sort of need to bake in the overall progress across the entire upload sequence rather than just the GIF processing stage?

@ramonjd

ramonjd commented Jul 23, 2026

Copy link
Copy Markdown
Member

The main issue I've run into in testing is just that for the majority of smaller GIFs I upload the conversion stage is so quick it effectively looks like a flicker

Came to do some manual testing and I can't see the progress bar at all. I think I'm doing something wrong.

I understand there's an upper limit, but I tried:

  • 35MB
  • 25MB
  • 21MB
  • 15MB
  • 6MB

GIFs, and all only show the upload snackbar, no progress indicator.

Kapture.2026-07-23.at.14.31.58.mp4

To confirm, I'm using latest Chrome running this branch freshly built. (also checked playground)

Here's one of the GIFs I'm using (5.7MB)

2026-07-23 14 26 01

@adamsilverstein

Copy link
Copy Markdown
Member Author

I like the idea of a progress bar and when it displays I quite like the look of it, too. The main issue I've run into in testing is just that for the majority of smaller GIFs I upload the conversion stage is so quick it effectively looks like a flicker, rather than a good bit of visual feedback. I.e. in the following, the progress bar only shows for a frame or two:

Ha its too fast now!

Came to do some manual testing and I can't see the progress bar at all. I think I'm doing something wrong.

@ramonjd Can you confirm the companion video is generated for you (you can watch for it sideloading in the network panel, check your uploads folder or check if you have an option to transform the gif to a video). Note that videos with transparency are not converted.

@andrewserong can you also confirm you are getting the conversion working?

@andrewserong

Copy link
Copy Markdown
Contributor

@andrewserong can you also confirm you are getting the conversion working?

Yep, the videos are being converted to video for me, it's just that the processing stage for some of these test GIFs is so quick. As such, I'd probably suggest we take a look at this PR for 7.2 rather than 7.1 and see if we can have the progress bar contain the whole upload progress between conversion + file uploads etc, rather than switching between spinner + progress bar and back again.

One nuance there is that the server-side / non-client-side path will probably never be able to have an accurate progress bar since we don't have the same level of insights into what the real progress will be, so I imagine there'll still be a case where we want to sometimes show progress bar and sometimes a spinner.

What do you reckon? Does this change feel like a must have for 7.1?

@ramonjd

ramonjd commented Jul 24, 2026

Copy link
Copy Markdown
Member

Can you confirm the companion video is generated for you

Thanks for the help. I used a different gif from https://commons.wikimedia.org/wiki/Category:Animated_GIF_files_between_50_MP_and_100_MP and now I can reproduce what @andrewserong is experience. mp4 is being generated fine 👍🏻

This is a 15MB GIF:

Kapture.2026-07-24.at.13.02.49.mp4

@adamsilverstein

adamsilverstein commented Jul 24, 2026

Copy link
Copy Markdown
Member Author

What do you reckon? Does this change feel like a must have for 7.1?

Nope. For sure lets punt to 7.2.

I'm curious if you throttle your CPU (in the performance tab) can you get the progress bar to display? I think the optimization PRs just made it really efficient so maybe we don't even need this.

@adamsilverstein

Copy link
Copy Markdown
Member Author

If we decide to enable Animated GIF sub-sizes, the processing time increases dramatically so we may want to show progress... but the indicator may be more of a "processing image X of Y" string vs a bar.

@andrewserong

Copy link
Copy Markdown
Contributor

I'm curious if you throttle your CPU (in the performance tab) can you get the progress bar to display? I think the optimization PRs just made it really efficient so maybe we don't even need this.

Yeah, funnily enough CPU throttling (even by 20x) doesn't make much of a difference to the duration of when the progress bar is showing for me 🤷

If we decide to enable Animated GIF sub-sizes, the processing time increases dramatically so we may want to show progress... but the indicator may be more of a "processing image X of Y" string vs a bar.

Gotcha, yeah, sounds like a good thing to review all together when we pick up that work for 7.2 👍

@adamsilverstein

Copy link
Copy Markdown
Member Author

Yeah, funnily enough CPU throttling (even by 20x) doesn't make much of a difference to the duration of when the progress bar is showing for me 🤷

Interesting... I'll give it another test!

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

Labels

[Feature] Media Anything that impacts the experience of managing media Needs Design Feedback Needs general design feedback. [Package] Editor /packages/editor [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show progress when converting animated GIFs to video

4 participants