<?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: Ivan Chernoknizhnikov</title>
    <description>The latest articles on DEV Community by Ivan Chernoknizhnikov (@treamz).</description>
    <link>https://dev.to/treamz</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%2F4079883%2Fadb7b964-1de8-4926-84e3-bb733feb631b.jpg</url>
      <title>DEV Community: Ivan Chernoknizhnikov</title>
      <link>https://dev.to/treamz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/treamz"/>
    <language>en</language>
    <item>
      <title>How to play animated SVG in Flutter (flutter_svg won't)</title>
      <dc:creator>Ivan Chernoknizhnikov</dc:creator>
      <pubDate>Wed, 11 Nov 2026 20:32:14 +0000</pubDate>
      <link>https://dev.to/treamz/how-to-play-animated-svg-in-flutter-fluttersvg-wont-4m1p</link>
      <guid>https://dev.to/treamz/how-to-play-animated-svg-in-flutter-fluttersvg-wont-4m1p</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; flutter_svg doesn't play SVG animations: it skips SMIL&lt;br&gt;
elements like &lt;code&gt;&amp;lt;animate&amp;gt;&lt;/code&gt; and ignores &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;, so the file shows as a still&lt;br&gt;
picture. To play the animation that's already in the SVG, add&lt;br&gt;
&lt;a href="https://pub.dev/packages/svg_animate" rel="noopener noreferrer"&gt;svg_animate&lt;/a&gt; and use&lt;br&gt;
&lt;code&gt;AnimatedSvgPicture&lt;/code&gt; where you'd use &lt;code&gt;SvgPicture&lt;/code&gt;. It takes the same arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub add svg_animate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nc"&gt;AnimatedSvgPicture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'assets/spinner.svg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It plays SMIL, CSS &lt;code&gt;@keyframes&lt;/code&gt; and CSS motion paths, in pure Dart. The rest of&lt;br&gt;
this post is how it works, the three bugs real files exposed, and how it&lt;br&gt;
compares with Lottie, Rive and the other SVG packages.&lt;/p&gt;

&lt;p&gt;Our designer sent me a folder of animated SVGs. A spinner, a progress bar, a&lt;br&gt;
few icons. Nice stuff, all of it animated right there in the file with plain&lt;br&gt;
CSS and SMIL.&lt;/p&gt;

&lt;p&gt;I dropped them into flutter_svg and got static pictures.&lt;/p&gt;

&lt;p&gt;I spent an evening convinced I'd broken something. Wrong widget, wrong asset&lt;br&gt;
path, something dumb. Turns out no: flutter_svg just skips &lt;code&gt;&amp;lt;animate&amp;gt;&lt;/code&gt;. And it&lt;br&gt;
ignores &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; too, which is worse, because that means a stylesheet-driven&lt;br&gt;
SVG doesn't even render with the right colors, let alone move.&lt;/p&gt;

&lt;p&gt;The usual answer is "convert it to Lottie". I didn't want to go back to the&lt;br&gt;
designer and ask him to rebuild everything in After Effects when the animation&lt;br&gt;
was already sitting in the file he'd sent me. So I wrote svg_animate.&lt;/p&gt;
&lt;h2&gt;
  
  
  How svg_animate works: a flipbook of static SVGs
&lt;/h2&gt;

&lt;p&gt;flutter_svg draws SVGs by compiling them into a binary format with&lt;br&gt;
&lt;code&gt;vector_graphics_compiler&lt;/code&gt;, then replaying that. That compiler is good. I had no&lt;br&gt;
interest in writing a renderer.&lt;/p&gt;

&lt;p&gt;So: don't. Take the animated document, work out what every animated attribute&lt;br&gt;
is at time &lt;em&gt;t&lt;/em&gt;, write those values back into the markup, and hand the result to&lt;br&gt;
the existing compiler. Do that once per frame ahead of time, then flip through&lt;br&gt;
the compiled frames like a flipbook.&lt;/p&gt;

&lt;p&gt;A frame costs exactly what a static SVG costs to draw, because it &lt;em&gt;is&lt;/em&gt; a static&lt;br&gt;
SVG. You pay at load instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nc"&gt;AnimatedSvgPicture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'assets/spinner.svg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same arguments as &lt;code&gt;SvgPicture&lt;/code&gt;. Reuses flutter_svg's &lt;code&gt;SvgTheme&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;ColorMapper&lt;/code&gt; so nothing in an existing app breaks. If the file has no animation&lt;br&gt;
in it, it renders like a normal &lt;code&gt;SvgPicture&lt;/code&gt; and doesn't even start a ticker.&lt;/p&gt;

&lt;p&gt;Two evenings later the spinner was spinning. I felt great about myself for&lt;br&gt;
roughly a week.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bug 1: an SVGator banner that rendered blank
&lt;/h2&gt;

&lt;p&gt;A 450×450 promo banner exported from SVGator. Coins, sparkles, a train, a&lt;br&gt;
"BUY BONUS" badge. 90 KB of markup with five WebP images base64'd into it.&lt;/p&gt;

&lt;p&gt;It rendered as nothing at all. Not "wrong" — a blank box.&lt;/p&gt;

&lt;p&gt;Here's where I want to be honest about how I debugged it, because I got it wrong&lt;br&gt;
first. I built a minimal test case: a tiny SVG with one &lt;code&gt;&amp;lt;image&amp;gt;&lt;/code&gt; in it,&lt;br&gt;
referenced through &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt;. Nothing drew. I tried the same file through plain&lt;br&gt;
flutter_svg. Nothing drew there either. Great, I thought, images just don't work&lt;br&gt;
on this pipeline, not my problem.&lt;/p&gt;

&lt;p&gt;That conclusion was garbage. I'd hand-rolled the test PNG as a base64 string and&lt;br&gt;
it was truncated — zlib couldn't even decompress it. I'd proven nothing except&lt;br&gt;
that a broken PNG doesn't render.&lt;/p&gt;

&lt;p&gt;Generated a real one. Ran it again. Images render fine. &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; pointing at an&lt;br&gt;
image renders too, just at the wrong size.&lt;/p&gt;

&lt;p&gt;So back to the real file, this time properly: feed the raw SVG straight into&lt;br&gt;
&lt;code&gt;vector_graphics_compiler&lt;/code&gt;, no code of mine involved.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed assertion: 'width &amp;gt; 0 &amp;amp;&amp;amp; height &amp;gt; 0'  (writeDrawImage)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It dies in the compiler. Before any animation logic. &lt;code&gt;SvgPicture&lt;/code&gt; would have&lt;br&gt;
shown the same blank box.&lt;/p&gt;

&lt;p&gt;Bisecting the file by deleting things: strip the 19 &lt;code&gt;&amp;lt;use href="#img"&amp;gt;&lt;/code&gt;&lt;br&gt;
references and it compiles. The compiler loses an image's declared width and&lt;br&gt;
height when the image is reached through a reference, gets zero, and then&lt;br&gt;
refuses to draw something of zero size — killing the whole picture rather than&lt;br&gt;
that one element.&lt;/p&gt;

&lt;p&gt;Fix on my side: expand a &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; that points at an &lt;code&gt;&amp;lt;image&amp;gt;&lt;/code&gt; into the image&lt;br&gt;
itself before compiling. Only images — a &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; on a shape is fine, and&lt;br&gt;
copying those would just bloat the document.&lt;/p&gt;

&lt;p&gt;The banner rendered. Coins and all.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bug 2: slow frames and 27.5 MB of memory
&lt;/h2&gt;

&lt;p&gt;Every compiled frame carries the images inside it, because each frame is a&lt;br&gt;
self-contained picture. 82% of each 96 KB frame was image payload. At the&lt;br&gt;
default 60 fps that's 300 frames and &lt;strong&gt;27.5 MB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Worse than the memory: changing frame cost &lt;strong&gt;6.8 ms&lt;/strong&gt;. The frame budget at 60fps&lt;br&gt;
is 16.7 ms. That's 40% of it, just to decode, on an M-series Mac. On a mid-range&lt;br&gt;
phone it would have blown straight through.&lt;/p&gt;

&lt;p&gt;Two fixes, and I'm not proud of the first one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The image cache.&lt;/strong&gt; I went reading how vector_graphics decodes images and found&lt;br&gt;
this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FlutterVectorGraphicsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hashCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;_createImageKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;imageId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imageId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It keys Flutter's global image cache by the hash code of the loader you hand it.&lt;br&gt;
And mine was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;hashCode&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;identityHashCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frameIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;frameIndex&lt;/code&gt; in there. Every single frame opened its own namespace in the cache&lt;br&gt;
and re-decoded the same five bitmaps. I had disabled a cache that was sitting&lt;br&gt;
right there, with my own line of code, and then measured the result and blamed&lt;br&gt;
the architecture.&lt;/p&gt;

&lt;p&gt;Dropped &lt;code&gt;frameIndex&lt;/code&gt;. Frames are still unequal to each other — that's what &lt;code&gt;==&lt;/code&gt;&lt;br&gt;
is for — and two unequal objects sharing a hash code is perfectly legal Dart.&lt;br&gt;
Here it's the whole point. 6.8 ms → 1.4 ms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The duplicated bytes.&lt;/strong&gt; For memory I nearly went and wrote a parser for the&lt;br&gt;
binary format to find and hoist the image section. Then I realised I didn't need&lt;br&gt;
to understand the format at all: consecutive frames of one animation are the&lt;br&gt;
same document with a few numbers changed, and the encoder puts everything the&lt;br&gt;
picture embeds at the front. So just compare the frames byte by byte and find&lt;br&gt;
the longest run they all start with.&lt;/p&gt;

&lt;p&gt;On the banner that run is 78,772 bytes. The compiler reports 78,538 bytes of&lt;br&gt;
images. It found them, without knowing what it was looking at.&lt;/p&gt;

&lt;p&gt;Store that once, keep only the tails, glue a frame back together when it's&lt;br&gt;
asked for. 27.5 MB → 5.1 MB, and reassembling costs about 0.1 ms.&lt;/p&gt;

&lt;p&gt;I like this one because it doesn't depend on the encoder's layout. If the format&lt;br&gt;
ever stops front-loading resources, the shared run just gets shorter and nothing&lt;br&gt;
breaks.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bug 3: a CSS spinner with no 0% keyframe
&lt;/h2&gt;

&lt;p&gt;Last one, and it's the most embarrassing, because it's the most common CSS&lt;br&gt;
animation on earth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="nt"&gt;spin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;360deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;0%&lt;/code&gt;. My code filled the missing end from the element's own &lt;code&gt;transform&lt;/code&gt;&lt;br&gt;
attribute, and when the element didn't have one, it fell back to... the other&lt;br&gt;
keyframe. So both ends said 360 and the thing sat perfectly still while&lt;br&gt;
everything around it animated.&lt;/p&gt;

&lt;p&gt;The missing end has to come from the value the property has &lt;em&gt;outside&lt;/em&gt; the&lt;br&gt;
animation — no rotation for a transform, fully opaque for an opacity. With one&lt;br&gt;
wrinkle: you can't substitute an empty transform, because two transform lists&lt;br&gt;
only interpolate if they're built the same way. The stand-in has to keep the&lt;br&gt;
shape: &lt;code&gt;translate(0 0)&lt;/code&gt; against a translate, &lt;code&gt;scale(1)&lt;/code&gt; against a scale.&lt;/p&gt;
&lt;h2&gt;
  
  
  What svg_animate doesn't support
&lt;/h2&gt;

&lt;p&gt;Filters. At all. &lt;code&gt;vector_graphics&lt;/code&gt; drops &lt;code&gt;&amp;lt;filter&amp;gt;&lt;/code&gt; entirely, so drop shadows&lt;br&gt;
and glows just don't happen — the shapes draw, the effect doesn't. Same for&lt;br&gt;
&lt;code&gt;mix-blend-mode: plus-lighter&lt;/code&gt;, which is exactly what editors reach for to make&lt;br&gt;
something glow.&lt;/p&gt;

&lt;p&gt;Also no &lt;code&gt;d&lt;/code&gt; morphing, no &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, no &lt;code&gt;:hover&lt;/code&gt;, no event-based &lt;code&gt;begin&lt;/code&gt;. If you&lt;br&gt;
need any of that, &lt;a href="https://pub.dev/packages/full_svg_flutter" rel="noopener noreferrer"&gt;full_svg_flutter&lt;/a&gt;&lt;br&gt;
covers a lot more of the format. It's a good package. It also bundles a&lt;br&gt;
JavaScript runtime, which is a fair price for what it does and not one I wanted&lt;br&gt;
to pay for a spinner.&lt;/p&gt;

&lt;p&gt;Mine adds two pure-Dart packages, both already in flutter_svg's dependency tree.&lt;/p&gt;
&lt;h2&gt;
  
  
  svg_animate vs Lottie, Rive and other Flutter SVG packages
&lt;/h2&gt;

&lt;p&gt;"Animated SVG" means different things in different packages. Only some of them&lt;br&gt;
play the animation that's already written into the file:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;What it animates&lt;/th&gt;
&lt;th&gt;Plays the animation already in the SVG&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;svg_animate&lt;/td&gt;
&lt;td&gt;SMIL, CSS &lt;code&gt;@keyframes&lt;/code&gt;, CSS motion paths&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Pure Dart, on flutter_svg's own compiler; no filters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flutter_svg&lt;/td&gt;
&lt;td&gt;Nothing: draws a still picture&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Skips &lt;code&gt;&amp;lt;animate&amp;gt;&lt;/code&gt;, ignores &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lottie&lt;/td&gt;
&lt;td&gt;Lottie JSON files&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;The animation has to be rebuilt in After Effects and exported as Lottie&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rive&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.riv&lt;/code&gt; files from the Rive editor&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;The animation has to be rebuilt in Rive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;anim_svg&lt;/td&gt;
&lt;td&gt;SMIL and CSS &lt;code&gt;@keyframes&lt;/code&gt;, converted to Lottie at runtime&lt;/td&gt;
&lt;td&gt;Yes, except SVGator's script-driven exports&lt;/td&gt;
&lt;td&gt;Renders with the native thorvg engine through FFI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;full_svg_flutter&lt;/td&gt;
&lt;td&gt;Much more of SVG&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Bundles a JavaScript runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;animated_svg&lt;/td&gt;
&lt;td&gt;A transition between two SVG images, such as play to pause&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;For icon toggles, not animated files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;drawing_animation&lt;/td&gt;
&lt;td&gt;A line-drawing effect on &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; strokes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Draws paths progressively&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your designer already animated the file, in SVGator, by hand, or anywhere&lt;br&gt;
else that writes SMIL or CSS, use a package from the "Yes" rows. If you're&lt;br&gt;
starting from scratch and want a timeline editor, Lottie or Rive is the better&lt;br&gt;
tool.&lt;/p&gt;
&lt;h2&gt;
  
  
  Install svg_animate from pub.dev
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pub.dev/packages/svg_animate" rel="noopener noreferrer"&gt;pub.dev/packages/svg_animate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SMIL, CSS &lt;code&gt;@keyframes&lt;/code&gt;, CSS motion paths (which is how SVGator writes every&lt;br&gt;
movement, so its exports work), play/pause/seek through a controller. It's one&lt;br&gt;
of the &lt;a href="https://treamz.me/projects/#svg-animate" rel="noopener noreferrer"&gt;projects I maintain&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you've got an SVG that renders wrong, send it. Every single thing in this&lt;br&gt;
post came from someone's file not working.&lt;/p&gt;
&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Does flutter_svg support animated SVGs?
&lt;/h3&gt;

&lt;p&gt;No. flutter_svg draws an SVG as a still picture: SMIL elements such as&lt;br&gt;
&lt;code&gt;&amp;lt;animate&amp;gt;&lt;/code&gt; are skipped, and &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; blocks are ignored entirely, so CSS&lt;br&gt;
&lt;code&gt;@keyframes&lt;/code&gt; don't play and colours set in a stylesheet don't apply either.&lt;/p&gt;
&lt;h3&gt;
  
  
  How do I play an animated SVG in Flutter?
&lt;/h3&gt;

&lt;p&gt;Add svg_animate with &lt;code&gt;flutter pub add svg_animate&lt;/code&gt; and use&lt;br&gt;
&lt;code&gt;AnimatedSvgPicture&lt;/code&gt; where you would use &lt;code&gt;SvgPicture&lt;/code&gt;. It takes the same&lt;br&gt;
arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nc"&gt;AnimatedSvgPicture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'assets/spinner.svg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It plays the SMIL and CSS keyframe animations in the file, and an&lt;br&gt;
&lt;code&gt;AnimatedSvgController&lt;/code&gt; adds play, pause and seek. A file with no animation in&lt;br&gt;
it renders like a normal &lt;code&gt;SvgPicture&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need Lottie to animate an SVG in Flutter?
&lt;/h3&gt;

&lt;p&gt;Not when the animation is already in the SVG. Files written with SMIL or CSS&lt;br&gt;
&lt;code&gt;@keyframes&lt;/code&gt;, including exports from SVGator, play as they are with&lt;br&gt;
svg_animate, with no round trip through After Effects.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the difference between svg_animate and animated_svg?
&lt;/h3&gt;

&lt;p&gt;They solve different problems. svg_animate plays the animation inside an SVG&lt;br&gt;
file: SMIL elements and CSS &lt;code&gt;@keyframes&lt;/code&gt;. animated_svg doesn't read animation&lt;br&gt;
from the file; it transitions between two separate SVG images, such as a play&lt;br&gt;
icon turning into a pause icon.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does svg_animate work with SVGator exports?
&lt;/h3&gt;

&lt;p&gt;Yes, with SVGator's CSS export: SVGator writes movement as CSS motion paths,&lt;br&gt;
which svg_animate plays, and the image-heavy banner in this post is an SVGator&lt;br&gt;
export. SVGator's JavaScript export depends on an embedded script, and&lt;br&gt;
svg_animate doesn't run &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which SVG animation features does svg_animate support?
&lt;/h3&gt;

&lt;p&gt;SMIL (&lt;code&gt;&amp;lt;animate&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;animateTransform&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;animateMotion&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;set&amp;gt;&lt;/code&gt;), CSS&lt;br&gt;
&lt;code&gt;@keyframes&lt;/code&gt; and CSS motion paths. It interpolates numbers, colours, lengths&lt;br&gt;
and transform lists, and it loads SVGs from assets, the network, files, memory&lt;br&gt;
or a string.&lt;/p&gt;

&lt;h3&gt;
  
  
  What doesn't svg_animate support?
&lt;/h3&gt;

&lt;p&gt;SVG filters, so no drop shadows or glows; &lt;code&gt;mix-blend-mode: plus-lighter&lt;/code&gt;;&lt;br&gt;
morphing a path's &lt;code&gt;d&lt;/code&gt; attribute; &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;; &lt;code&gt;:hover&lt;/code&gt;; and event-based &lt;code&gt;begin&lt;/code&gt;.&lt;br&gt;
For those, &lt;a href="https://pub.dev/packages/full_svg_flutter" rel="noopener noreferrer"&gt;full_svg_flutter&lt;/a&gt; covers&lt;br&gt;
more of the format, at the cost of bundling a JavaScript runtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is svg_animate fast enough for production?
&lt;/h3&gt;

&lt;p&gt;Every frame is compiled ahead of time and costs the same to draw as a static&lt;br&gt;
SVG. On the image-heavy banner in this post, switching frames went from 6.8 ms&lt;br&gt;
to 1.4 ms once decoded images were cached, and memory went from 27.5 MB to&lt;br&gt;
5.1 MB once the bytes every frame shares were stored only once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which platforms does svg_animate run on?
&lt;/h3&gt;

&lt;p&gt;Android, iOS, macOS, Windows and Linux.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>svg</category>
      <category>opensource</category>
    </item>
    <item>
      <title>flutter_svg doesn’t animate. so I wrote the part that does.</title>
      <dc:creator>Ivan Chernoknizhnikov</dc:creator>
      <pubDate>Thu, 20 Aug 2026 15:47:52 +0000</pubDate>
      <link>https://dev.to/treamz/fluttersvg-doesnt-animate-so-i-wrote-the-part-that-does-3kjg</link>
      <guid>https://dev.to/treamz/fluttersvg-doesnt-animate-so-i-wrote-the-part-that-does-3kjg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fotb4yzfov2528lf3lwrq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fotb4yzfov2528lf3lwrq.gif" alt=" " width="300" height="300"&gt;&lt;/a&gt;&lt;br&gt;
Our designer sent me a folder of animated SVGs. A spinner, a progress bar, a&lt;br&gt;
few icons. Nice stuff, all of it animated right there in the file with plain&lt;br&gt;
CSS and SMIL.&lt;/p&gt;

&lt;p&gt;I dropped them into flutter_svg and got static pictures.&lt;/p&gt;

&lt;p&gt;I spent an evening convinced I'd broken something. Wrong widget, wrong asset&lt;br&gt;
path, something dumb. Turns out no: flutter_svg just skips &lt;code&gt;&amp;lt;animate&amp;gt;&lt;/code&gt;. And it&lt;br&gt;
ignores &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; too, which is worse, because that means a stylesheet-driven&lt;br&gt;
SVG doesn't even render with the right colors, let alone move.&lt;/p&gt;

&lt;p&gt;The usual answer is "convert it to Lottie". I didn't want to go back to the&lt;br&gt;
designer and ask him to rebuild everything in After Effects when the animation&lt;br&gt;
was already sitting in the file he'd sent me. So I wrote svg_animate.&lt;/p&gt;
&lt;h2&gt;
  
  
  the idea is embarrassingly simple
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F59hn734000rao3c513wj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F59hn734000rao3c513wj.webp" alt=" " width="800" height="231"&gt;&lt;/a&gt;&lt;br&gt;
flutter_svg draws SVGs by compiling them into a binary format with&lt;br&gt;
&lt;code&gt;vector_graphics_compiler&lt;/code&gt;, then replaying that. That compiler is good. I had no&lt;br&gt;
interest in writing a renderer.&lt;/p&gt;

&lt;p&gt;So: don't. Take the animated document, work out what every animated attribute&lt;br&gt;
is at time &lt;em&gt;t&lt;/em&gt;, write those values back into the markup, and hand the result to&lt;br&gt;
the existing compiler. Do that once per frame ahead of time, then flip through&lt;br&gt;
the compiled frames like a flipbook.&lt;/p&gt;

&lt;p&gt;A frame costs exactly what a static SVG costs to draw, because it &lt;em&gt;is&lt;/em&gt; a static&lt;br&gt;
SVG. You pay at load instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;AnimatedSvgPicture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'assets/spinner.svg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same arguments as &lt;code&gt;SvgPicture&lt;/code&gt;. Reuses flutter_svg's &lt;code&gt;SvgTheme&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;ColorMapper&lt;/code&gt; so nothing in an existing app breaks. If the file has no animation&lt;br&gt;
in it, it renders like a normal &lt;code&gt;SvgPicture&lt;/code&gt; and doesn't even start a ticker.&lt;/p&gt;

&lt;p&gt;Two evenings later the spinner was spinning. I felt great about myself for&lt;br&gt;
roughly a week.&lt;/p&gt;
&lt;h2&gt;
  
  
  then someone gave me a real file
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs9qjhhxz56mniq68bym5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs9qjhhxz56mniq68bym5.webp" alt=" " width="450" height="450"&gt;&lt;/a&gt;&lt;br&gt;
A 450×450 promo banner exported from SVGator. Coins, sparkles, a train, a&lt;br&gt;
"BUY BONUS" badge. 90 KB of markup with five WebP images base64'd into it.&lt;/p&gt;

&lt;p&gt;It rendered as nothing at all. Not "wrong" — a blank box.&lt;/p&gt;

&lt;p&gt;Here's where I want to be honest about how I debugged it, because I got it wrong&lt;br&gt;
first. I built a minimal test case: a tiny SVG with one &lt;code&gt;&amp;lt;image&amp;gt;&lt;/code&gt; in it,&lt;br&gt;
referenced through &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt;. Nothing drew. I tried the same file through plain&lt;br&gt;
flutter_svg. Nothing drew there either. Great, I thought, images just don't work&lt;br&gt;
on this pipeline, not my problem.&lt;/p&gt;

&lt;p&gt;That conclusion was garbage. I'd hand-rolled the test PNG as a base64 string and&lt;br&gt;
it was truncated — zlib couldn't even decompress it. I'd proven nothing except&lt;br&gt;
that a broken PNG doesn't render.&lt;/p&gt;

&lt;p&gt;Generated a real one. Ran it again. Images render fine. &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; pointing at an&lt;br&gt;
image renders too, just at the wrong size.&lt;/p&gt;

&lt;p&gt;So back to the real file, this time properly: feed the raw SVG straight into&lt;br&gt;
&lt;code&gt;vector_graphics_compiler&lt;/code&gt;, no code of mine involved.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed assertion: 'width &amp;gt; 0 &amp;amp;&amp;amp; height &amp;gt; 0'  (writeDrawImage)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It dies in the compiler. Before any animation logic. &lt;code&gt;SvgPicture&lt;/code&gt; would have&lt;br&gt;
shown the same blank box.&lt;/p&gt;

&lt;p&gt;Bisecting the file by deleting things: strip the 19 &lt;code&gt;&amp;lt;use href="#img"&amp;gt;&lt;/code&gt;&lt;br&gt;
references and it compiles. The compiler loses an image's declared width and&lt;br&gt;
height when the image is reached through a reference, gets zero, and then&lt;br&gt;
refuses to draw something of zero size — killing the whole picture rather than&lt;br&gt;
that one element.&lt;/p&gt;

&lt;p&gt;Fix on my side: expand a &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; that points at an &lt;code&gt;&amp;lt;image&amp;gt;&lt;/code&gt; into the image&lt;br&gt;
itself before compiling. Only images — a &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; on a shape is fine, and&lt;br&gt;
copying those would just bloat the document.&lt;/p&gt;

&lt;p&gt;The banner rendered. Coins and all.&lt;/p&gt;
&lt;h2&gt;
  
  
  and then it was slow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy2njaelynha3ihk47maq.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy2njaelynha3ihk47maq.webp" alt=" " width="800" height="293"&gt;&lt;/a&gt;&lt;br&gt;
Every compiled frame carries the images inside it, because each frame is a&lt;br&gt;
self-contained picture. 82% of each 96 KB frame was image payload. At the&lt;br&gt;
default 60 fps that's 300 frames and &lt;strong&gt;27.5 MB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Worse than the memory: changing frame cost &lt;strong&gt;6.8 ms&lt;/strong&gt;. The frame budget at 60fps&lt;br&gt;
is 16.7 ms. That's 40% of it, just to decode, on an M-series Mac. On a mid-range&lt;br&gt;
phone it would have blown straight through.&lt;/p&gt;

&lt;p&gt;Two fixes, and I'm not proud of the first one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The image cache.&lt;/strong&gt; I went reading how vector_graphics decodes images and found&lt;br&gt;
this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FlutterVectorGraphicsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;_createImageKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;imageId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imageId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It keys Flutter's global image cache by the hash code of the loader you hand it.&lt;br&gt;
And mine was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;hashCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;identityHashCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;frameIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;frameIndex&lt;/code&gt; in there. Every single frame opened its own namespace in the cache&lt;br&gt;
and re-decoded the same five bitmaps. I had disabled a cache that was sitting&lt;br&gt;
right there, with my own line of code, and then measured the result and blamed&lt;br&gt;
the architecture.&lt;/p&gt;

&lt;p&gt;Dropped &lt;code&gt;frameIndex&lt;/code&gt;. Frames are still unequal to each other — that's what &lt;code&gt;==&lt;/code&gt;&lt;br&gt;
is for — and two unequal objects sharing a hash code is perfectly legal Dart.&lt;br&gt;
Here it's the whole point. 6.8 ms → 1.4 ms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The duplicated bytes.&lt;/strong&gt; For memory I nearly went and wrote a parser for the&lt;br&gt;
binary format to find and hoist the image section. Then I realised I didn't need&lt;br&gt;
to understand the format at all: consecutive frames of one animation are the&lt;br&gt;
same document with a few numbers changed, and the encoder puts everything the&lt;br&gt;
picture embeds at the front. So just compare the frames byte by byte and find&lt;br&gt;
the longest run they all start with.&lt;/p&gt;

&lt;p&gt;On the banner that run is 78,772 bytes. The compiler reports 78,538 bytes of&lt;br&gt;
images. It found them, without knowing what it was looking at.&lt;/p&gt;

&lt;p&gt;Store that once, keep only the tails, glue a frame back together when it's&lt;br&gt;
asked for. 27.5 MB → 5.1 MB, and reassembling costs about 0.1 ms.&lt;/p&gt;

&lt;p&gt;I like this one because it doesn't depend on the encoder's layout. If the format&lt;br&gt;
ever stops front-loading resources, the shared run just gets shorter and nothing&lt;br&gt;
breaks.&lt;/p&gt;
&lt;h2&gt;
  
  
  the spinner that wouldn't spin
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdugn8qlkac0lzv19pmmm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdugn8qlkac0lzv19pmmm.gif" alt=" " width="480" height="240"&gt;&lt;/a&gt;&lt;br&gt;
Last one, and it's the most embarrassing, because it's the most common CSS&lt;br&gt;
animation on earth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;spin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;360deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;0%&lt;/code&gt;. My code filled the missing end from the element's own &lt;code&gt;transform&lt;/code&gt;&lt;br&gt;
attribute, and when the element didn't have one, it fell back to... the other&lt;br&gt;
keyframe. So both ends said 360 and the thing sat perfectly still while&lt;br&gt;
everything around it animated.&lt;/p&gt;

&lt;p&gt;The missing end has to come from the value the property has &lt;em&gt;outside&lt;/em&gt; the&lt;br&gt;
animation — no rotation for a transform, fully opaque for an opacity. With one&lt;br&gt;
wrinkle: you can't substitute an empty transform, because two transform lists&lt;br&gt;
only interpolate if they're built the same way. The stand-in has to keep the&lt;br&gt;
shape: &lt;code&gt;translate(0 0)&lt;/code&gt; against a translate, &lt;code&gt;scale(1)&lt;/code&gt; against a scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  what it doesn't do
&lt;/h2&gt;

&lt;p&gt;Filters. At all. &lt;code&gt;vector_graphics&lt;/code&gt; drops &lt;code&gt;&amp;lt;filter&amp;gt;&lt;/code&gt; entirely, so drop shadows&lt;br&gt;
and glows just don't happen — the shapes draw, the effect doesn't. Same for&lt;br&gt;
&lt;code&gt;mix-blend-mode: plus-lighter&lt;/code&gt;, which is exactly what editors reach for to make&lt;br&gt;
something glow.&lt;/p&gt;

&lt;p&gt;Also no &lt;code&gt;d&lt;/code&gt; morphing, no &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, no &lt;code&gt;:hover&lt;/code&gt;, no event-based &lt;code&gt;begin&lt;/code&gt;. If you&lt;br&gt;
need any of that, &lt;a href="https://pub.dev/packages/full_svg_flutter" rel="noopener noreferrer"&gt;full_svg_flutter&lt;/a&gt;&lt;br&gt;
covers a lot more of the format. It's a good package. It also bundles a&lt;br&gt;
JavaScript runtime, which is a fair price for what it does and not one I wanted&lt;br&gt;
to pay for a spinner.&lt;/p&gt;

&lt;p&gt;Mine adds two pure-Dart packages, both already in flutter_svg's dependency tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  it's on pub
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pub.dev/packages/svg_animate" rel="noopener noreferrer"&gt;pub.dev/packages/svg_animate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SMIL, CSS &lt;code&gt;@keyframes&lt;/code&gt;, CSS motion paths (which is how SVGator writes every&lt;br&gt;
movement, so its exports work), play/pause/seek through a controller.&lt;/p&gt;

&lt;p&gt;If you've got an SVG that renders wrong, send it. Every single thing in this&lt;br&gt;
post came from someone's file not working.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>fluttersvg</category>
      <category>animation</category>
    </item>
  </channel>
</rss>
