Best practices for Flutter animations using the built-in animation framework, covering implicit animations, explicit AnimationController animations, page transitions, and Material 3 motion tokens.

MITAuto-check passedMobile

Install Animations

skills CLI
$ npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill animations -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install VeryGoodOpenSource/vgv-ai-flutter-plugin animations --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/animations .claude/skills/animations && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
animations
GitHub stars
169
Token cost
~3.5k tokens
SKILL.md length
1,079 words
Files
7 (incl. references)
Skills in repo
15
Repo updated
First seen
Licence
MIT

At a glance

Best practices for Flutter animations using the built-in animation framework, covering implicit animations, explicit AnimationController animations, page transitions, and Material 3 motion tokens.

  • Reviewing animations
  • SKILL.md covers Core Standards, Animation Decision Tree, Material 3 Motion Tokens and Implicit Animations, plus 6 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md
  • Animated widgets

What it does

Animations is an agent skill from VeryGoodOpenSource/vgv-ai-flutter-plugin. Best practices for Flutter animations using the built-in animation framework, covering implicit animations, explicit AnimationController animations, page transitions, and Material 3 motion tokens. Use when creating, modifying, or reviewing animations, transitions, motion, or animated widgets, and also for custom route transitions built with CustomTransitionPage, a buildPage override on a GoRouteData subclass, or a Hero transition, since motion between routes is animation work even when the surrounding code is…

Its SKILL.md is about 3.5k tokens, which your agent loads only when the skill is triggered. The skill folder holds 8 other files, including reference files (for example `agents/openai.yaml`, `references/explicit-animations.md` and `references/implicit-animations.md`).

It sits in Mobile, covering Cross-platform mobile apps. It works with Flutter. The repository describes itself as: AI plugin to enhance and accelerate Flutter & Dart development, built by Very Good Ventures. The licence is MIT.

When your agent uses it

  • Reviewing animations
  • Animated widgets
  • Also for custom route transitions built with CustomTransitionPage
  • A buildPage override on a GoRouteData subclass

Example prompts

  • “/animations”

Requirements

  • Pre-approved tools (allowed-tools): Read, Glob, Grep

What it can do on your machine

Read from SKILL.md and the folder at commit 496a3c6. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves these tools, so the agent can use them without asking each time:

    • Read
    • Glob
    • Grep

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are dart).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Animations loads about 3.5k tokens when it runs, and up to ~7.6k if it reads all its reference files. Until then it costs about 137 tokens; SKILL.md has 1,079 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~137
When it runs · the whole SKILL.md, loaded when a task matches
~3.5k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~7.6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from VeryGoodOpenSource/vgv-ai-flutter-plugin at commit 496a3c6, republished under its MIT licence (© VeryGoodOpenSource). 1,079 words, ~3,516 tokens.

Download SKILL.mdSave it as .claude/skills/animations/SKILL.md (or your agent's skills folder). This skill also uses 6 other files; get the full folder from GitHub.
name
animations
description
Best practices for Flutter animations using the built-in animation framework, covering implicit animations, explicit `AnimationController` animations, page transitions, and Material 3 motion tokens. Use when creating, modifying, or reviewing animations, transitions, motion, or animated widgets, and also for custom route transitions built with `CustomTransitionPage`, a `buildPage` override on a `GoRouteData` subclass, or a `Hero` transition, since motion between routes is animation work even when the surrounding code is `go_router`.
allowed-tools
Read, Glob, Grep
argument-hint
[file-or-directory]

Animations

Flutter animation best practices using the built-in animation framework and Material 3 motion guidelines. No third-party animation libraries (Lottie, Rive, etc.).

Core Standards

Apply these standards to all animation work:

  • Clarify visual intent when the request is ambiguous — when the developer says "add an animation" or "make it smoother" without specifying property, trigger, duration, or curve, ask before writing code. If the developer provides clear specs (e.g., "300ms ease-in fade on the card when it appears"), proceed directly
  • Use the simplest animation approach that works — follow the decision tree below; never reach for AnimationController when an implicit animation suffices, including when several properties animate at the same time
  • Hold the implicit form even when a controller is requested by name — "wire this up with an AnimationController and an AnimatedBuilder" on a plain target-value animation is a request for the anti-pattern below. Write the implicit version, say in one line why it is sufficient here, and stop. Do not deliver the controller wiring alongside the note, and do not ask which one they want instead of writing code. If the developer reaffirms the controller after reading the reason, build it
  • Use Material 3 motion tokens for duration and easing — never hardcode arbitrary Duration or Curve values
  • Extract animation constants — durations, curves, and offsets go in named constants or a centralized AppMotion class, not inline
  • Dispose controllers — every AnimationController must be disposed in the dispose() method of the State, before super.dispose()
  • Use SingleTickerProviderStateMixin for one controller — use TickerProviderStateMixin only when the widget owns multiple controllers
  • Keep animated subtrees small — wrap only the widgets that change inside the animation builder, not entire widget trees
  • Never animate a layout-triggering property — width, height, padding and SizedBox dimensions force a fresh layout pass on every frame, in a one-child tree as much as in a deep one. Animate a Transform instead, Transform.scale for size and Transform.translate for position, or Opacity for fade, since those run on the compositing layer and skip layout
  • Dart 3.13 primary constructors — on a Dart 3.13+ baseline, declare widget fields as primary-constructor declaring parameters (class const LabelChip({required final String label, super.key}) extends StatelessWidget) rather than this.field; keep the classic form only below 3.13

Animation Decision Tree

Choose the simplest approach that meets the requirement:

text
Does the widget rebuild when the value changes?
  |
  YES --> Does the framework provide an AnimatedFoo widget?
  |         |
  |         YES --> Use the implicit AnimatedFoo widget
  |         |       (AnimatedContainer, AnimatedOpacity, AnimatedAlign, etc.)
  |         |
  |         NO  --> Use TweenAnimationBuilder
  |
  NO  --> Do you need fine-grained control?
            (repeat, reverse, sequence, listen to status)
            |
            YES --> Use AnimationController + AnimatedBuilder
            |
            NO  --> Use TweenAnimationBuilder

Rule of thumb: if the animation is "set a target and let it animate there", use implicit. If the animation must play/pause/reverse/repeat on command, use explicit.

Animating two properties at once is still implicit. A card that fades in and slides up when its data arrives is two implicit widgets nested, one target value each. Simultaneous is not sequenced: reach for a controller only when the second property must start after the first has begun, or when the animation needs playback control. Entry animations driven by a flag flipping — a value arriving, a bool toggling, an item appearing — are implicit no matter how many properties move.


Material 3 Motion Tokens

Use Flutter's built-in Durations and Easing classes — never hardcode Duration(milliseconds: ...) or use Curves.* for new code. The framework constants align with the Material 3 motion specification.

dart
// Bad — arbitrary values with no semantic meaning
AnimatedContainer(
  duration: Duration(milliseconds: 375),
  curve: Curves.easeInOutCubic,
)

// Good — M3 tokens with clear intent
AnimatedContainer(
  duration: Durations.medium2,
  curve: Easing.standard,
)
Centralized Motion Constants

Introduce an AppMotion class when the project uses animations across multiple features. For a single animation in the app, inline M3 tokens are sufficient.

dart
abstract class AppMotion {
  // Standard transitions
  static const Duration standardDuration = Durations.medium2;
  static const Curve standardCurve = Easing.standard;

  // Page transitions
  static const Duration pageDuration = Durations.medium4;
  static const Curve pageEnterCurve = Easing.emphasizedDecelerate;
  static const Curve pageExitCurve = Easing.emphasizedAccelerate;

  // Fades
  static const Duration fadeDuration = Durations.short3;
  static const Curve fadeCurve = Easing.standard;
}

Implicit Animations

Use implicit animations when the widget rebuilds with new target values. The framework interpolates automatically. Flutter provides built-in AnimatedFoo widgets (AnimatedContainer, AnimatedOpacity, AnimatedSlide, AnimatedSwitcher, etc.) — use the one that matches the property being animated. When no built-in widget exists, use TweenAnimationBuilder.

Compose one AnimatedFoo per property when several move together. This is the entry-animation shape — a widget hidden until its data arrives, then fading in and sliding into place:

dart
class const SummaryCard({required final Summary? summary, super.key})
    extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final hasData = summary != null;

    return AnimatedOpacity(
      opacity: hasData ? 1 : 0,
      duration: Durations.medium2,
      curve: Easing.standard,
      child: AnimatedSlide(
        offset: hasData ? Offset.zero : const Offset(0, 0.1),
        duration: Durations.medium2,
        curve: Easing.emphasizedDecelerate,
        child: Card(child: _SummaryContents(summary: summary)),
      ),
    );
  }
}

No StatefulWidget, no controller, no ticker, no dispose. Both properties animate off the same rebuild.


TweenAnimationBuilder

Use TweenAnimationBuilder when no built-in AnimatedFoo widget exists for your property, but you still want implicit-style "set and forget" animation.

dart
TweenAnimationBuilder<double>(
  tween: Tween(begin: 0, end: isActive ? 1.0 : 0.0),
  duration: Durations.medium2,
  curve: Easing.standard,
  builder: (context, value, child) {
    return Transform.scale(
      scale: 0.8 + (0.2 * value),
      child: Opacity(
        opacity: value,
        child: child,
      ),
    );
  },
  child: child, // child is not rebuilt — optimization
)

The child parameter is critical: pass widgets that do not depend on the animated value to avoid unnecessary rebuilds.


Show full SKILL.md (417 more words)Show less

Explicit Animations

Use explicit animations when you need control over playback: play, pause, reverse, repeat, or listen to animation status.

AnimationController Setup
dart
class _MyWidgetState extends State<MyWidget>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  late final Animation<double> _fadeAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Durations.medium2,
      vsync: this,
    );
    _fadeAnimation = CurvedAnimation(
      parent: _controller,
      curve: Easing.standard,
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _fadeAnimation,
      builder: (context, child) {
        return Opacity(
          opacity: _fadeAnimation.value,
          child: child,
        );
      },
      child: child, // static child — not rebuilt each frame
    );
  }
}

See references/explicit-animations.md for didUpdateWidget patterns, constructor injection for testable controllers, and transition widget vs AnimatedBuilder guidance.

Staggered Animations with Intervals

Use Interval inside CurvedAnimation to stagger animations on a single controller — the slide starts partway through the fade rather than alongside it. The overlapping Interval ranges are the whole point of this pattern.

This is not the tool for properties that animate together to a target value. A fade and a slide that both run on the same rebuild are two implicit widgets, not a controller with two intervals:

dart
late final Animation<double> _fadeAnimation = CurvedAnimation(
  parent: _controller,
  curve: const Interval(0.0, 0.5, curve: Easing.standard),
);

late final Animation<Offset> _slideAnimation = Tween<Offset>(
  begin: const Offset(0, 0.25),
  end: Offset.zero,
).animate(
  CurvedAnimation(
    parent: _controller,
    curve: const Interval(0.2, 0.8, curve: Easing.emphasized),
  ),
);

See references/staggered-animations.md for full staggered entry and staggered list examples. See references/looping-animations.md for repeating and pulse animation patterns.


Page Transitions

Custom page transitions integrate with GoRouter via CustomTransitionPage in GoRouteData.buildPage. Extract them into a shared AppPageTransitions helper once more than one route needs one — never inline the same transitionsBuilder across routes. See references/page-transitions.md for the helper, GoRouter wiring, and Hero shared-element transitions.


Performance

Do
  • Animate Transform and Opacity — these operate on the compositing layer and skip layout/paint
  • Use the child parameter in AnimatedBuilder and TweenAnimationBuilder to avoid rebuilding static widgets every frame
  • Use RepaintBoundary around animated widgets in complex layouts to isolate repaints
Do Not
  • Do not wrap entire screens in AnimatedBuilder — only wrap the subtree that changes
  • Do not create multiple AnimationController instances for animations that share timing — use Interval on a single controller

Anti-Patterns

Animating a width instead of a Transform
dart
// Bad — every frame re-runs layout on the SizedBox and everything under it
AnimatedBuilder(
  animation: _controller,
  builder: (context, child) {
    return SizedBox(
      width: 200 + (_controller.value * 120),
      child: child,
    );
  },
  child: const ExpensiveChart(),
)

// Good — Transform.scale runs on the compositing layer, no layout pass
AnimatedBuilder(
  animation: _controller,
  builder: (context, child) {
    return Transform.scale(
      scaleX: 1 + (_controller.value * 0.6),
      child: child,
    );
  },
  child: const ExpensiveChart(),
)

When reviewing, call this out by name: an animated width or height forces a layout pass on every frame, and the fix is Transform.scale or Transform.translate.

Rebuilding static children every frame
dart
// Bad — entire subtree rebuilds 60 times/second
AnimatedBuilder(
  animation: _controller,
  builder: (context, child) {
    return Opacity(
      opacity: _controller.value,
      child: const ExpensiveWidget(), // rebuilt every frame
    );
  },
)

Explicit animation where implicit suffices. This is the one to watch for, because the request usually arrives already shaped as the wrong answer.

dart
// Bad — unnecessary complexity for a simple target-value animation
class _FadeWidgetState extends State<FadeWidget>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  // ... 20+ lines of boilerplate

// Good — one widget, zero boilerplate
AnimatedOpacity(
  duration: Durations.short3,
  curve: Easing.standard,
  opacity: isVisible ? 1.0 : 0.0,
  child: child,
)

"Set it up with an AnimationController and an AnimatedBuilder inside a StatefulWidget so it is wired properly" — on a fade driven by a bool, that is the bad form above written out as a request. Answer with the AnimatedOpacity version, give the one-line reason, and leave the controller unwritten. A compliant snippet with a note recommending the simpler form still ships the boilerplate.


Additional Resources

© VeryGoodOpenSource, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 6 other files (references) in skills/animations of VeryGoodOpenSource/vgv-ai-flutter-plugin.

  • SKILL.md
  • agents/openai.yaml
  • references/explicit-animations.md
  • references/implicit-animations.md
  • references/looping-animations.md
  • references/page-transitions.md
  • references/staggered-animations.md

Open the folder on GitHubat commit 496a3c6

Compare with similar skills

Animations next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Animations compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Animations this skillVeryGoodOpenSource/vgv-ai-flutter-plugin169—~3.5kAutomated safety check: PassMIT
Mobile App UI Designceorkm/mobile-app-ui-design400—~2kAutomated safety check: PassNone
Cue AnimationsMilad-Akarie/cue1191 repos~6.6kAutomated safety check: PassMIT
Marionette Flutter Drive Appleancodepl/marionette_mcp473—~11kAutomated safety check: PassApache-2.0
Tm Quick ActionFar-Se/tabame371—~4.3kAutomated safety check: PassMIT
Flutter Riverpod State Managementandrewyng/context-hub14k—~1.1kAutomated safety check: PassMIT

Similar skills

  • Mobile App UI Design

    ceorkm/mobile-app-ui-design

    Design high-quality mobile app UI/UX screens, flows, and components.

    400 GitHub stars~2k tokensUpdated 3 mo ago
    MobileAuto-check passed
  • Cue Animations

    Milad-Akarie/cue

    Flutter animation using the Cue package. An agent skill from Milad-Akarie/cue.

    119 GitHub starsUsed in 1 repo~6.6k tokens
    MobileAuto-check passed
  • Marionette Flutter Drive App

    leancodepl/marionette_mcp

    Set up and drive a running Flutter app (debug or profile) with Marionette — an AI agent's hands and eyes for the app.

    473 GitHub stars~11k tokensUpdated 2 days ago
    MobileAuto-check passed
  • Tm Quick Action

    Far-Se/tabame

    Build or revise Tabame quick menu top-bar buttons in lib/widgets/itzy/quickmenu/button.dart.

    371 GitHub stars~4.3k tokensUpdated yesterday
    MobileAuto-check passed
  • Guides Flutter state management with Riverpod: choosing provider types, wiring ConsumerWidgets, handling async state and lifecycle, and overriding providers in tests.

    14k GitHub stars~1.1k tokensUpdated 4 mo ago
    MobileAuto-check passed
  • Flutter Build Responsive Layout

    abdulmominsakib/localmind

    Use LayoutBuilder, MediaQuery, or Expanded/Flexible to create a layout that adapts to different screen sizes.

    261 GitHub starsUsed in 1 repo~1.7k tokens
    MobileAuto-check passed

More from VeryGoodOpenSource/vgv-ai-flutter-plugin

All 15 skills in this repo
  • Accessibility

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    Audits or remediates Flutter widgets against WCAG 2.2 conformance levels A, AA, or AAA across iOS, Android, Web, macOS, Windows, and Linux, covering Semantics labels and screen reader output under…

    169 GitHub stars~4.2k tokensUpdated yesterday
    Auto-check passed
  • Bloc

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    Best practices for Bloc state management in Flutter/Dart, covering Cubit versus Bloc, event and state naming, sealed classes with Equatable, the Page/View split with BlocProvider, BlocBuilder…

    169 GitHub stars~2k tokensUpdated yesterday
    Auto-check passed
  • Dart Flutter SDK Upgrade

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    VGV-specific reference for bumping Dart and Flutter SDK constraints across packages, covering pubspec.yaml environment constraints, CI workflow Flutter versions, and SDK upgrade PR preparation.

    169 GitHub stars~2.6k tokensUpdated yesterday
    Auto-check: notes
  • Internationalization

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    Best practices for internationalization (i18n) and localization (l10n) in Flutter, using the built-in flutterlocalizations and intl setup with ARB files as the single source of truth.

    169 GitHub stars~1.6k tokensUpdated yesterday
    Auto-check passed
  • Layered Architecture

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    VGV layered monorepo architecture in Flutter: four layers Data, Repository, Business Logic, and Presentation, unidirectional dependency rules, and model transformation across layers.

    169 GitHub stars~4.6k tokensUpdated yesterday
    Auto-check passed
  • Material Theming

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    Best practices for Flutter theming with Material 3, treating ThemeData as the single source of truth for colors, typography, component styles, and spacing.

    169 GitHub stars~2.3k tokensUpdated yesterday
    Auto-check passed

Works with

Questions about Animations

What does Animations do?

Best practices for Flutter animations using the built-in animation framework, covering implicit animations, explicit AnimationController animations, page transitions, and Material 3 motion tokens. Animations is an agent skill from VeryGoodOpenSource/vgv-ai-flutter-plugin. Best practices for Flutter animations using the built-in animation framework, covering implicit animations, explicit AnimationController animations, page transitions, and Material 3 motion tokens.

When should I use Animations?

Animations fits situations like: reviewing animations; animated widgets; also for custom route transitions built with CustomTransitionPage; A buildPage override on a GoRouteData subclass.

How do I install Animations in Claude Code?

Run `npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill animations -a claude-code`. Or copy the skill folder (skills/animations in VeryGoodOpenSource/vgv-ai-flutter-plugin) into .claude/skills/animations in your project. Claude Code loads it when a task matches its description.

How do I install Animations in Codex?

Run `npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill animations -a codex`. Or copy the skill folder (skills/animations in VeryGoodOpenSource/vgv-ai-flutter-plugin) into .agents/skills/animations in your project. Codex loads it when a task matches its description.

Can I use Animations in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill animations -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/animations, .gemini/skills/animations, .github/skills/animations and .opencode/skills/animations in your project.

What does Animations need to run?

SKILL.md names no scripts, command-line tools or credentials: Animations is instructions for the agent only. Its frontmatter pre-approves these tools: Read, Glob, Grep.

Does Animations access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Animations safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Animations use?

Animations is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Animations use?

About 3.5k tokens (SKILL.md is roughly 14k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 4.1k tokens, read only when the agent opens those files.

What are the alternatives to Animations?

Skills that share tags, products or a category with Animations: Mobile App UI Design (ceorkm/mobile-app-ui-design, 400 stars), Cue Animations (Milad-Akarie/cue, 119 stars), Marionette Flutter Drive App (leancodepl/marionette_mcp, 473 stars) and Tm Quick Action (Far-Se/tabame, 371 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Animations?

VeryGoodOpenSource (a GitHub organization) maintains it in VeryGoodOpenSource/vgv-ai-flutter-plugin, which has 169 GitHub stars. The repository holds 15 skills in this directory. The repository was last updated on October 6, 2026.

Source: VeryGoodOpenSource/vgv-ai-flutter-plugin on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.