<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: hao jia</title>
    <description>The latest articles on DEV Community by hao jia (@iterandum).</description>
    <link>https://dev.to/iterandum</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4091913%2Fb40a7d0f-5ae5-45a5-99ab-68ae53a2cdb0.png</url>
      <title>DEV Community: hao jia</title>
      <link>https://dev.to/iterandum</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iterandum"/>
    <language>en</language>
    <item>
      <title>The WebP that was 92% smaller — because it only had one frame left</title>
      <dc:creator>hao jia</dc:creator>
      <pubDate>Tue, 01 Sep 2026 02:38:58 +0000</pubDate>
      <link>https://dev.to/iterandum/the-webp-that-was-92-smaller-because-it-only-had-one-frame-left-50fj</link>
      <guid>https://dev.to/iterandum/the-webp-that-was-92-smaller-because-it-only-had-one-frame-left-50fj</guid>
      <description>&lt;p&gt;&lt;strong&gt;It doesn't throw an error.&lt;/strong&gt; The conversion succeeds, the file downloads, the size looks fantastic.&lt;/p&gt;

&lt;p&gt;You find out three weeks later, when someone posts in the team channel: &lt;em&gt;"the animation in the docs isn't animating."&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Why this one is worth writing up
&lt;/h3&gt;

&lt;p&gt;The cost of this bug isn't the fix — the fix takes a minute. The cost is that &lt;strong&gt;you already used the wrong number as a conclusion&lt;/strong&gt;: it went into a format comparison, into a spec doc, into a message to your team, onto production.&lt;/p&gt;

&lt;p&gt;So the detection method goes first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two entry points, two very different reads
&lt;/h3&gt;

&lt;p&gt;I was standardising the animated assets on our docs site. The tool was ImgIng (imging.ai), which splits image work across separate panels — one for single images, one for animation. I fed the same 79.8 KB demo GIF (720×405, 36 frames, 2.88s) into both:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Entry point&lt;/th&gt;
&lt;th&gt;What the UI reported&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Animation workshop&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;36 frames · 2.88s total&lt;/strong&gt; / keep GIF · 64 colours · 36 frames&lt;/td&gt;
&lt;td&gt;21.3 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Convert panel → WebP&lt;/td&gt;
&lt;td&gt;detected icon/line art · defaulting to PNG-8 · 64 colours&lt;/td&gt;
&lt;td&gt;6.5 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Convert panel → AVIF&lt;/td&gt;
&lt;td&gt;detected icon/line art · defaulting to PNG-8 · 64 colours&lt;/td&gt;
&lt;td&gt;1.5 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The column that matters is the middle one, not the right one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The animation workshop read out a frame count and a duration, because it has to split frames to do its job. The convert panel classified the input as &lt;em&gt;icon/line art&lt;/em&gt; — a category that only exists for still images. Those bottom two rows went down the single-image path. The sizes are small because there was less content to encode.&lt;/p&gt;

&lt;p&gt;This isn't a bug. The convert panel is for still images; animation has its own entry point. But &lt;strong&gt;if you only watch the output size, you walk away believing AVIF compressed an animation to 1.5 KB&lt;/strong&gt; — and then you make decisions with that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three signals, cheapest first
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Signal 1: does the UI tell you the frame count?&lt;/strong&gt; Anything genuinely handling animation has to split frames, so it knows how many there are. No frame count on screen is a strong hint you're on the wrong path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signal 2: is the reduction outside the plausible range?&lt;/strong&gt; Format changes on animation typically buy you somewhere between a bit and a few times smaller. &lt;strong&gt;Dropping below a tenth should make you suspicious&lt;/strong&gt; — that looks a lot more like N frames becoming 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signal 3: play the exported file.&lt;/strong&gt; Crude and completely reliable. Trust no number; drag the file into a browser tab and see whether it moves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Picking a format by where it has to play
&lt;/h3&gt;

&lt;p&gt;Once you're actually on the animation path, the choice isn't about bytes. It's about &lt;strong&gt;where this file ends up playing&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;The constraint that matters&lt;/th&gt;
&lt;th&gt;Where it fits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GIF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;256 colours per frame, bulky&lt;/td&gt;
&lt;td&gt;Anywhere that must "just work": email bodies, older clients, chat forwarding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Animated WebP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;True colour, alpha, broadly supported in modern browsers&lt;/td&gt;
&lt;td&gt;The default for web and mobile — the balance point for most cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;APNG&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;True colour and full alpha, slightly larger than WebP&lt;/td&gt;
&lt;td&gt;High-fidelity stickers and short animations that need real transparency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Animated AVIF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Smallest, but older devices may not decode it; on the browser-side path there's no alpha and the loop is fixed to infinite&lt;/td&gt;
&lt;td&gt;Controlled, modern playback targets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(Positioning follows the vendor's published format table; the actual constraints are probed at runtime in the tool.)&lt;/p&gt;

&lt;h3&gt;
  
  
  The three things that actually block the migration
&lt;/h3&gt;

&lt;p&gt;Size is one axis, and rarely the one that stalls you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Email clients.&lt;/strong&gt; Support is all over the place and always has been. Animated content in marketing email is still GIF territory, and probably will be for a while.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. In-app browsers.&lt;/strong&gt; WeChat, LinkedIn, Instagram — the embedded webview doesn't necessarily decode what the system browser does. This needs a real-device pass before launch, not a caniuse check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. CDN and cache strategy.&lt;/strong&gt; New format means new URLs, cache re-warming, and a &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; fallback to write. &lt;strong&gt;This part is routinely bigger than the conversion work itself&lt;/strong&gt;, and it's the part that gets left out of estimates.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I ended up choosing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Internal docs and admin UIs:&lt;/strong&gt; animated WebP, no fallback. The browser population is known.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Public marketing site:&lt;/strong&gt; WebP with a GIF fallback in &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;. Storing a second copy costs less than handling the compatibility reports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anything users save and forward&lt;/strong&gt; — say, an operating walkthrough in a help centre that people screenshot and send to support: &lt;strong&gt;plain GIF.&lt;/strong&gt; The requirement that it opens in whatever software they have beats the byte count, every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limits
&lt;/h3&gt;

&lt;p&gt;The sizes above come from one flat-palette UI recording, deliberately chosen as easy-to-compress footage. &lt;strong&gt;On gradients or live action the relative ordering shifts&lt;/strong&gt; — GIF barely compresses that material at all, while WebP and AVIF pull further ahead. So use these numbers for the detection story, not to predict your own savings.&lt;/p&gt;

&lt;p&gt;One more constraint worth knowing before you pick animated AVIF on the browser-side path: &lt;strong&gt;no alpha, and the loop is fixed to infinite.&lt;/strong&gt; If either matters to you, that decision is already made.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>images</category>
    </item>
  </channel>
</rss>
