Skip to content
Mobile
Skill

/animations

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

BOOST
From plugin
vgv-ai-flutter-plugin
17315 skills1 agent3 hooks2 MCP
Install
$ npx -y skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill animations --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/animations

Context preview

The summary Claude sees to decide when to auto-load this skill.

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

SKILL.md

animations.SKILL.md
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:

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.

// 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.

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` widget

Read more
Ships withvgv-ai-flutter-plugin

A Claude Code plugin that accelerates Flutter & Dart development with best-practices skills from Very Good Ventures. Developed with 💙 by Very Good Ventures 🦄

Get the whole plugin

Other skills on vgv-ai-flutter-plugin.