Flutter Animations
madteacher/mad-agents-skillsThis skill focuses on creating smooth and efficient animations in Flutter, covering both implicit and explicit approaches to suit different needs, such as simple property changes or complex transition sequences. Key capabilities include implementing hero animations for shared element transitions, staggered animations for sequential effects, and physics-based animations for natural motion, making it ideal for developers aiming to enhance app interactivity and visual appeal. It also provides best practices, reusable widget patterns, and built-in transition options for a comprehensive understanding of Flutter animations.
Flutter Animations
Overview
Create smooth, performant animations in Flutter using the right approach for each use case. This skill covers complete animation workflow: from choosing between implicit/explicit approaches to implementing complex effects like hero transitions and staggered animations.
Animation Type Decision Tree
Choose the right animation type based on your requirements: Implicit Animations - Use when:
- Animating a single property (color, size, position)
- Animation is triggered by state change
- No need for fine-grained control Explicit Animations - Use when:
- Need full control over animation lifecycle
- Animating multiple properties simultaneously
- Need to react to animation state changes
- Creating custom animations or transitions Hero Animations - Use when:
- Sharing an element between two screens
- Creating shared element transitions
- User expects element to "fly" between routes Staggered Animations - Use when:
- Multiple animations should run sequentially or overlap
- Creating ripple effects or sequential reveals
- Animating list items in sequence Physics-Based Animations - Use when:
- Animations should feel natural/physical
- Spring-like behavior, scrolling gestures
- Draggable interactions
Implicit Animations
Implicit animations automatically handle the animation when properties change. No controller needed.
Common Implicit Widgets
AnimatedContainer - Animates multiple properties (size, color, decoration, padding):
AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: _expanded ? 200 : 100,
height: _expanded ? 200 : 100,
color: _expanded ? Colors.blue : Colors.red,
child: const FlutterLogo(),
)
AnimatedOpacity - Simple fade animation:
AnimatedOpacity(
opacity: _visible ? 1.0 : 0.0,
duration: const Duration(milliseconds: 300),
child: const Text('Hello'),
)
TweenAnimationBuilder - Custom tween animation without boilerplate:
TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0, end: 1),
duration: const Duration(seconds: 1),
builder: (context, value, child) {
return Opacity(
opacity: value,
child: Transform.scale(
scale: value,
child: child,
),
);
},
child: const FlutterLogo(),
)
Other implicit widgets:
AnimatedPadding- Padding animationAnimatedPositioned- Position animation (in Stack)AnimatedAlign- Alignment animationAnimatedContainer- Multiple propertiesAnimatedSwitcher- Cross-fade between widgetsAnimatedDefaultTextStyle- Text style animation
Best Practices
- Prefer implicit animations for simple cases
- Use appropriate curves for natural motion (see
Curvesclass) - Set
curveanddurationfor predictable behavior - Use
onEndcallback when needed - Avoid nested implicit animations for performance
Explicit Animations
Explicit animations provide full control with AnimationController.
Core Components
AnimationController - Drives the animation:
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Tween - Interpolates between begin and end values:
animation = Tween<double>(begin: 0, end: 300).animate(_controller);
CurvedAnimation - Applies a curve to the animation:
animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
);
AnimatedWidget Pattern
Best for reusable animated widgets:
class AnimatedLogo extends AnimatedWidget {
const AnimatedLogo({super.key, required Animation<double> animation})
: super(listenable: animation);
@override
Widget build(BuildContext context) {
final animation = listenable as Animation<double>;
return Center(
child: Container(
height: animation.value,
width: animation.value,
child: const FlutterLogo(),
),
);
}
}
AnimatedBuilder Pattern
Best for complex widgets with animations:
class GrowTransition extends StatelessWidget {
const GrowTransition({
required this.child,
required this.animation,
super.key,
});
final Widget child;
final Animation<double> animation;
@override
Widget build(BuildContext context) {
return Center(
child: AnimatedBuilder(
animation: animation,
builder: (context, child) {
return SizedBox(
height: animation.value,
width: animation.value,
child: child,
);
},
child: child,
),
);
}
}
Monitoring Animation State
animation.addStatusListener((status) {
switch (status) {
case AnimationStatus.completed:
_controller.reverse();
break;
case AnimationStatus.dismissed:
_controller.forward();
break;
default:
break;
}
});
Multiple Simultaneous Animations
class AnimatedLogo extends AnimatedWidget {
const AnimatedLogo({super.key, required Animation<double> animation})
: super(listenable: animation);
static final _opacityTween = Tween<double>(begin: 0.1, end: 1);
static final _sizeTween = Tween<double>(begin: 0, end: 300);
@override
Widget build(BuildContext context) {
final animation = listenable as Animation<double>;
return Center(
child: Opacity(
opacity: _opacityTween.evaluate(animation),
child: Container(
height: _sizeTween.evaluate(animation),
width: _sizeTween.evaluate(animation),
child: const FlutterLogo(),
),
),
);
}
}
Built-in Explicit Transitions
Flutter provides ready-to-use transitions:
FadeTransition- Fade animationScaleTransition- Scale animationSlideTransition- Slide animationSizeTransition- Size animationRotationTransition- Rotation animationPositionedTransition- Position animation (in Stack) Example:
FadeTransition(
opacity: _animation,
child: const FlutterLogo(),
)
Performance Tips
- Dispose controllers when widget is removed
- Use
AnimatedBuilderfor optimal rebuilds - Avoid
setState()in animation listeners (useAnimatedWidget/AnimatedBuilder) - Use
timeDilationto slow animations during debugging
Hero Animations
Hero animations create shared element transitions between screens.
Basic Hero Animation
Source screen:
Hero(
tag: 'hero-image',
child: Image.asset('images/logo.png'),
)
Destination screen:
Hero(
tag: 'hero-image', // Same tag!
child: Image.asset('images/logo.png'),
)
Complete Example
class PhotoHero extends StatelessWidget {
const PhotoHero({
super.key,
required this.photo,
this.onTap,
required this.width,
});
final String photo;
final VoidCallback? onTap;
final double width;
@override
Widget build(BuildContext context) {
return SizedBox(
width: width,
child: Hero(
tag: photo,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: Image.asset(photo, fit: BoxFit.contain),
),
),
),
);
}
}
Navigating between screens:
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) {
return Scaffold(
appBar: AppBar(title: const Text('Detail')),
body: Center(
child: PhotoHero(
photo: 'images/logo.png',
width: 300.0,
onTap: () => Navigator.of(context).pop(),
),
),
);
},
),
);
Radial Hero Animation
Transform from circle to rectangle during transition:
class RadialExpansion extends StatelessWidget {
const RadialExpansion({
super.key,
required this.maxRadius,
this.child,
}) : clipRectSize = 2.0 * (maxRadius / math.sqrt2);
final double maxRadius;
final double clipRectSize;
final Widget? child;
@override
Widget build(BuildContext context) {
return ClipOval(
child: Center(
child: SizedBox(
width: clipRectSize,
height: clipRectSize,
child: ClipRect(child: child),
),
),
);
}
}
Use with MaterialRectCenterArcTween for center-based interpolation:
static RectTween _createRectTween(Rect? begin, Rect? end) {
return MaterialRectCenterArcTween(begin: begin, end: end);
}
Hero Best Practices
- Use unique, consistent tags (often the data object itself)
- Keep hero widget trees similar between routes
- Wrap images in
Materialwith transparent color for "pop" effect - Use
timeDilationto debug transitions - Consider
HeroModeto disable hero animations when needed
Staggered Animations
Run multiple animations with different timing.
Basic Staggered Animation
All animations share one controller:
class StaggerAnimation extends StatelessWidget {
StaggerAnimation({super.key, required this.controller})
: opacity = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(0.0, 0.100, curve: Curves.ease),
),
),
width = Tween<double>(begin: 50.0, end: 150.0).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(0.125, 0.250, curve: Curves.ease),
),
);
final AnimationController controller;
final Animation<double> opacity;
final Animation<double> width;
Widget _buildAnimation(BuildContext context, Widget? child) {
return Container(
alignment: Alignment.bottomCenter,
child: Opacity(
opacity: opacity.value,
child: Container(
width: width.value,
height: 150,
color: Colors.blue,
),
),
);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: _buildAnimation,
);
}
}
Interval-Based Timing
Each animation has an Interval between 0.0 and 1.0:
animation = Tween<double>(begin: 0, end: 300).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(
0.25, // Start at 25% of controller duration
0.50, // End at 50% of controller duration
curve: Curves.ease,
),
),
);
Common Tweens
borderRadius = BorderRadiusTween(
begin: BorderRadius.circular(4),
end: BorderRadius.circular(75),
).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(0.375, 0.500, curve: Curves.ease),
),
);
Staggered Menu Animation
class _MenuState extends State<Menu> with SingleTickerProviderStateMixin {
static const _initialDelayTime = Duration(milliseconds: 50);
static const _itemSlideTime = Duration(milliseconds: 250);
static const _staggerTime = Duration(milliseconds: 50);
static const _buttonDelayTime = Duration(milliseconds: 150);
static const _buttonTime = Duration(milliseconds: 500);
final _animationDuration =
_initialDelayTime +
(_staggerTime * _menuTitles.length) +
_buttonDelayTime +
_buttonTime;
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: _animationDuration,
vsync: this,
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
Stagger Best Practices
- Use
Intervalto offset animations in time - Ensure controller duration covers all intervals
- Use curves for natural motion within intervals
- Consider
timeDilationto debug timing - Stagger menu items with increasing delay for ripple effect
Physics-Based Animations
Create natural-feeling animations using physics simulations.
Fling Animation
_controller.fling(
velocity: 2.0, // Units per second
);
Custom Physics Simulation
_controller.animateWith(
SpringSimulation(
spring: const SpringDescription(
mass: 1,
stiffness: 100,
damping: 10,
),
start: 0.0,
end: 1.0,
velocity: 0.0,
),
);
Common Physics Simulations
SpringSimulation- Spring physicsBouncingScrollSimulation- Scroll with bounceClampingScrollSimulation- Scroll without bounceGravitySimulation- Gravity-based
Best Practices
DO
- Dispose AnimationController in widget disposal
- Use
AnimatedBuilder/AnimatedWidgetinstead ofsetState()in listeners - Choose appropriate curves for natural motion
- Use
timeDilationfor debugging animations - Consider performance (avoid heavy widgets in animation builds)
- Test animations on various devices
- Support reverse animations for intuitive feel
DON'T
- Forget to dispose AnimationController (memory leak)
- Use
setState()in animation listeners whenAnimatedBuildersuffices - Assume animation completes instantly (handle
AnimationStatus) - Over-animate (animations can distract users)
- Create animations that feel "jerky" (use smooth curves)
- Ignore accessibility (respect
disableAnimationspreference)
Resources
references/
implicit.md - Complete reference for implicit animation widgets with examples and best practices. explicit.md - Deep dive into explicit animations, AnimationController, and patterns. hero.md - Hero animations guide with standard and radial transitions. staggered.md - Staggered animation patterns and timing strategies. physics.md - Physics-based animations and simulations. curves.md - Reference for Curves class and choosing appropriate curves.
assets/templates/
Template code for common animation patterns:
implicit_animation.dart- Implicit animation examplesexplicit_animation.dart- Explicit animation setuphero_transition.dart- Hero animation boilerplatestaggered_animation.dart- Staggered animation template
GitHub Owner
Owner: madteacher
SKILL.md
name: flutter-animations description: "Comprehensive guide for implementing animations in Flutter. Use when adding motion and visual effects to Flutter apps: implicit animations (AnimatedContainer, AnimatedOpacity, TweenAnimationBuilder), explicit animations (AnimationController, Tween, AnimatedWidget/AnimatedBuilder), hero animations (shared element transitions), staggered animations (sequential/overlapping), and physics-based animations. Includes workflow for choosing the right animation type, implementation patterns, and best practices for performance and user experience." metadata: author: Stanislav [MADTeacher] Chernyshev version: "1.0"
Flutter Animations
Overview
Create smooth, performant animations in Flutter using the right approach for each use case. This skill covers complete animation workflow: from choosing between implicit/explicit approaches to implementing complex effects like hero transitions and staggered animations.
Animation Type Decision Tree
Choose the right animation type based on your requirements: Implicit Animations - Use when:
- Animating a single property (color, size, position)
- Animation is triggered by state change
- No need for fine-grained control Explicit Animations - Use when:
- Need full control over animation lifecycle
- Animating multiple properties simultaneously
- Need to react to animation state changes
- Creating custom animations or transitions Hero Animations - Use when:
- Sharing an element between two screens
- Creating shared element transitions
- User expects element to "fly" between routes Staggered Animations - Use when:
- Multiple animations should run sequentially or overlap
- Creating ripple effects or sequential reveals
- Animating list items in sequence Physics-Based Animations - Use when:
- Animations should feel natural/physical
- Spring-like behavior, scrolling gestures
- Draggable interactions
Implicit Animations
Implicit animations automatically handle the animation when properties change. No controller needed.
Common Implicit Widgets
AnimatedContainer - Animates multiple properties (size, color, decoration, padding):
AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: _expanded ? 200 : 100,
height: _expanded ? 200 : 100,
color: _expanded ? Colors.blue : Colors.red,
child: const FlutterLogo(),
)
AnimatedOpacity - Simple fade animation:
AnimatedOpacity(
opacity: _visible ? 1.0 : 0.0,
duration: const Duration(milliseconds: 300),
child: const Text('Hello'),
)
TweenAnimationBuilder - Custom tween animation without boilerplate:
TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0, end: 1),
duration: const Duration(seconds: 1),
builder: (context, value, child) {
return Opacity(
opacity: value,
child: Transform.scale(
scale: value,
child: child,
),
);
},
child: const FlutterLogo(),
)
Other implicit widgets:
AnimatedPadding- Padding animationAnimatedPositioned- Position animation (in Stack)AnimatedAlign- Alignment animationAnimatedContainer- Multiple propertiesAnimatedSwitcher- Cross-fade between widgetsAnimatedDefaultTextStyle- Text style animation
Best Practices
- Prefer implicit animations for simple cases
- Use appropriate curves for natural motion (see
Curvesclass) - Set
curveanddurationfor predictable behavior - Use
onEndcallback when needed - Avoid nested implicit animations for performance
Explicit Animations
Explicit animations provide full control with AnimationController.
Core Components
AnimationController - Drives the animation:
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Tween - Interpolates between begin and end values:
animation = Tween<double>(begin: 0, end: 300).animate(_controller);
CurvedAnimation - Applies a curve to the animation:
animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
);
AnimatedWidget Pattern
Best for reusable animated widgets:
class AnimatedLogo extends AnimatedWidget {
const AnimatedLogo({super.key, required Animation<double> animation})
: super(listenable: animation);
@override
Widget build(BuildContext context) {
final animation = listenable as Animation<double>;
return Center(
child: Container(
height: animation.value,
width: animation.value,
child: const FlutterLogo(),
),
);
}
}
AnimatedBuilder Pattern
Best for complex widgets with animations:
class GrowTransition extends StatelessWidget {
const GrowTransition({
required this.child,
required this.animation,
super.key,
});
final Widget child;
final Animation<double> animation;
@override
Widget build(BuildContext context) {
return Center(
child: AnimatedBuilder(
animation: animation,
builder: (context, child) {
return SizedBox(
height: animation.value,
width: animation.value,
child: child,
);
},
child: child,
),
);
}
}
Monitoring Animation State
animation.addStatusListener((status) {
switch (status) {
case AnimationStatus.completed:
_controller.reverse();
break;
case AnimationStatus.dismissed:
_controller.forward();
break;
default:
break;
}
});
Multiple Simultaneous Animations
class AnimatedLogo extends AnimatedWidget {
const AnimatedLogo({super.key, required Animation<double> animation})
: super(listenable: animation);
static final _opacityTween = Tween<double>(begin: 0.1, end: 1);
static final _sizeTween = Tween<double>(begin: 0, end: 300);
@override
Widget build(BuildContext context) {
final animation = listenable as Animation<double>;
return Center(
child: Opacity(
opacity: _opacityTween.evaluate(animation),
child: Container(
height: _sizeTween.evaluate(animation),
width: _sizeTween.evaluate(animation),
child: const FlutterLogo(),
),
),
);
}
}
Built-in Explicit Transitions
Flutter provides ready-to-use transitions:
FadeTransition- Fade animationScaleTransition- Scale animationSlideTransition- Slide animationSizeTransition- Size animationRotationTransition- Rotation animationPositionedTransition- Position animation (in Stack) Example:
FadeTransition(
opacity: _animation,
child: const FlutterLogo(),
)
Performance Tips
- Dispose controllers when widget is removed
- Use
AnimatedBuilderfor optimal rebuilds - Avoid
setState()in animation listeners (useAnimatedWidget/AnimatedBuilder) - Use
timeDilationto slow animations during debugging
Hero Animations
Hero animations create shared element transitions between screens.
Basic Hero Animation
Source screen:
Hero(
tag: 'hero-image',
child: Image.asset('images/logo.png'),
)
Destination screen:
Hero(
tag: 'hero-image', // Same tag!
child: Image.asset('images/logo.png'),
)
Complete Example
class PhotoHero extends StatelessWidget {
const PhotoHero({
super.key,
required this.photo,
this.onTap,
required this.width,
});
final String photo;
final VoidCallback? onTap;
final double width;
@override
Widget build(BuildContext context) {
return SizedBox(
width: width,
child: Hero(
tag: photo,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: Image.asset(photo, fit: BoxFit.contain),
),
),
),
);
}
}
Navigating between screens:
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) {
return Scaffold(
appBar: AppBar(title: const Text('Detail')),
body: Center(
child: PhotoHero(
photo: 'images/logo.png',
width: 300.0,
onTap: () => Navigator.of(context).pop(),
),
),
);
},
),
);
Radial Hero Animation
Transform from circle to rectangle during transition:
class RadialExpansion extends StatelessWidget {
const RadialExpansion({
super.key,
required this.maxRadius,
this.child,
}) : clipRectSize = 2.0 * (maxRadius / math.sqrt2);
final double maxRadius;
final double clipRectSize;
final Widget? child;
@override
Widget build(BuildContext context) {
return ClipOval(
child: Center(
child: SizedBox(
width: clipRectSize,
height: clipRectSize,
child: ClipRect(child: child),
),
),
);
}
}
Use with MaterialRectCenterArcTween for center-based interpolation:
static RectTween _createRectTween(Rect? begin, Rect? end) {
return MaterialRectCenterArcTween(begin: begin, end: end);
}
Hero Best Practices
- Use unique, consistent tags (often the data object itself)
- Keep hero widget trees similar between routes
- Wrap images in
Materialwith transparent color for "pop" effect - Use
timeDilationto debug transitions - Consider
HeroModeto disable hero animations when needed
Staggered Animations
Run multiple animations with different timing.
Basic Staggered Animation
All animations share one controller:
class StaggerAnimation extends StatelessWidget {
StaggerAnimation({super.key, required this.controller})
: opacity = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(0.0, 0.100, curve: Curves.ease),
),
),
width = Tween<double>(begin: 50.0, end: 150.0).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(0.125, 0.250, curve: Curves.ease),
),
);
final AnimationController controller;
final Animation<double> opacity;
final Animation<double> width;
Widget _buildAnimation(BuildContext context, Widget? child) {
return Container(
alignment: Alignment.bottomCenter,
child: Opacity(
opacity: opacity.value,
child: Container(
width: width.value,
height: 150,
color: Colors.blue,
),
),
);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: _buildAnimation,
);
}
}
Interval-Based Timing
Each animation has an Interval between 0.0 and 1.0:
animation = Tween<double>(begin: 0, end: 300).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(
0.25, // Start at 25% of controller duration
0.50, // End at 50% of controller duration
curve: Curves.ease,
),
),
);
Common Tweens
borderRadius = BorderRadiusTween(
begin: BorderRadius.circular(4),
end: BorderRadius.circular(75),
).animate(
CurvedAnimation(
parent: controller,
curve: const Interval(0.375, 0.500, curve: Curves.ease),
),
);
Staggered Menu Animation
class _MenuState extends State<Menu> with SingleTickerProviderStateMixin {
static const _initialDelayTime = Duration(milliseconds: 50);
static const _itemSlideTime = Duration(milliseconds: 250);
static const _staggerTime = Duration(milliseconds: 50);
static const _buttonDelayTime = Duration(milliseconds: 150);
static const _buttonTime = Duration(milliseconds: 500);
final _animationDuration =
_initialDelayTime +
(_staggerTime * _menuTitles.length) +
_buttonDelayTime +
_buttonTime;
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: _animationDuration,
vsync: this,
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
Stagger Best Practices
- Use
Intervalto offset animations in time - Ensure controller duration covers all intervals
- Use curves for natural motion within intervals
- Consider
timeDilationto debug timing - Stagger menu items with increasing delay for ripple effect
Physics-Based Animations
Create natural-feeling animations using physics simulations.
Fling Animation
_controller.fling(
velocity: 2.0, // Units per second
);
Custom Physics Simulation
_controller.animateWith(
SpringSimulation(
spring: const SpringDescription(
mass: 1,
stiffness: 100,
damping: 10,
),
start: 0.0,
end: 1.0,
velocity: 0.0,
),
);
Common Physics Simulations
SpringSimulation- Spring physicsBouncingScrollSimulation- Scroll with bounceClampingScrollSimulation- Scroll without bounceGravitySimulation- Gravity-based
Best Practices
DO
- Dispose AnimationController in widget disposal
- Use
AnimatedBuilder/AnimatedWidgetinstead ofsetState()in listeners - Choose appropriate curves for natural motion
- Use
timeDilationfor debugging animations - Consider performance (avoid heavy widgets in animation builds)
- Test animations on various devices
- Support reverse animations for intuitive feel
DON'T
- Forget to dispose AnimationController (memory leak)
- Use
setState()in animation listeners whenAnimatedBuildersuffices - Assume animation completes instantly (handle
AnimationStatus) - Over-animate (animations can distract users)
- Create animations that feel "jerky" (use smooth curves)
- Ignore accessibility (respect
disableAnimationspreference)
Resources
references/
implicit.md - Complete reference for implicit animation widgets with examples and best practices. explicit.md - Deep dive into explicit animations, AnimationController, and patterns. hero.md - Hero animations guide with standard and radial transitions. staggered.md - Staggered animation patterns and timing strategies. physics.md - Physics-based animations and simulations. curves.md - Reference for Curves class and choosing appropriate curves.
assets/templates/
Template code for common animation patterns:
implicit_animation.dart- Implicit animation examplesexplicit_animation.dart- Explicit animation setuphero_transition.dart- Hero animation boilerplatestaggered_animation.dart- Staggered animation template