pub tag buymeacoffee sponsor patreon discord instagram license


Summary

Render SMIL-animated SVGs in Flutter with programmatic pause / resume / speed / colour control — no native plugins, no platform channels, no external rasteriser.

spinner pulse color wave bounce

(GitHub and pub.dev both stream the SVGs above with their SMIL animations intact — so the strip above plays live, no GIF/MP4 needed.)

Two widgets ship in the box:

Widget What it does
SvgFrame Leaf renderer. Draws one frame of an SVG at a given position (0..1). No ticker, no animation controller. Drop one in for a static SVG, or wrap one in an AnimatedBuilder to drive position yourself.
AnimatedSvg Self-playing. Owns an internal AnimationController and plays the SVG's natural cycle (or a custom duration). Adds curve, repeat, stopAt, position (freeze), and tween shortcuts for color, transform, and opacity.

Built-in AnimatedSvgFilters: grayscale, sepia, invert, tint, colorize.

Supported SVG subset: <g>, <path>, <rect>, <circle>, <ellipse>, <line>, <polygon>, <polyline>, <animate>, <animateTransform> (translate, rotate, scale, skewX, skewY, matrix). calcMode="linear|spline|discrete" with keyTimes and keySplines. From/to/by shorthands. Indefinite and finite repeatCount. No gradients, no <use>, no <text>, no <image>, no <animateMotion>, no CSS filter effects.

Installation

flutter pub add smil_animated_svg

Usage

import 'package:smil_animated_svg/smil_animated_svg.dart';
import 'package:flutter/material.dart';

class Loader extends StatelessWidget {
  const Loader({super.key});

  @override
  Widget build(BuildContext context) {
    return AnimatedSvg.asset(
      'assets/spinner.svg',
      width: 64,
      height: 64,
      // Override the SVG's intrinsic cycle.
      duration: const Duration(seconds: 1),
      // Tint to match the active theme without re-authoring the SVG.
      color: Theme.of(context).colorScheme.primary,
      colorBlendMode: BlendMode.srcIn,
    );
  }
}

Other source constructors

SvgFrame.string(svgXml, position: 0.4);
SvgFrame.network('https://example.com/icon.svg');
AnimatedSvg.parsed(parseSvg(svgXml));   // pre-parsed, zero load cost

Frame-stepping a static SvgFrame

AnimatedBuilder(
  animation: myController,
  builder: (context, _) => SvgFrame.asset(
    'assets/pulse.svg',
    position: myController.value,
  ),
);

Tweens that ride the playback timeline

AnimatedSvg.asset(
  'assets/icon.svg',
  colorTween: ColorTween(begin: Colors.red, end: Colors.blue),
  transformTween: Matrix4Tween(
    begin: Matrix4.identity(),
    end: Matrix4.diagonal3Values(1.2, 1.2, 1.0),
  ),
);

Tween values are evaluated at the curved controller value during playback, or at the frozen position when one is supplied.

Error and placeholder builders

SvgFrame.network(
  'https://example.com/icon.svg',
  placeholderBuilder: (context) => const CircularProgressIndicator(),
  errorBuilder: (context, error, stack) => const Icon(Icons.broken_image),
);

The signatures match Image.errorBuilder / Image.frameBuilder conventions. With no errorBuilder, a failed load collapses to an empty SizedBox instead of throwing — bad SVGs never take a frame down.

Parse cache

Repeated mounts of the same assetPath or url reuse a parsed SvgRoot (32-entry LRU, hot-reload-aware). Call SvgFrame.clearCache() to drop it — useful in tests.


🔍 For more information, refer to the API reference.


💬 Contributing and Discussions

This is an open-source project, and we warmly welcome contributions from everyone, regardless of experience level. Whether you're a seasoned developer or just starting out, contributing to this project is a fantastic way to learn, share your knowledge, and make a meaningful impact on the community.

☝️ Ways you can contribute

  • Find us on Discord: Feel free to ask questions and engage with the community here: https://discord.gg/gEQ8y2nfyX.
  • Share your ideas: Every perspective matters, and your ideas can spark innovation.
  • Help others: Engage with other users by offering advice, solutions, or troubleshooting assistance.
  • Report bugs: Help us identify and fix issues to make the project more robust.
  • Suggest improvements or new features: Your ideas can help shape the future of the project.
  • Help clarify documentation: Good documentation is key to accessibility. You can make it easier for others to get started by improving or expanding our documentation.
  • Write articles: Share your knowledge by writing tutorials, guides, or blog posts about your experiences with the project. It's a great way to contribute and help others learn.

No matter how you choose to contribute, your involvement is greatly appreciated and valued!

☕ We drink a lot of coffee...

If you're enjoying this package and find it valuable, consider showing your appreciation with a small donation. Every bit helps in supporting future development. You can donate here: https://www.buymeacoffee.com/dev_cetera

LICENSE

This project is released under the MIT License. See LICENSE for more information.

Libraries

smil_animated_svg
Render SMIL-animated SVGs in Flutter.