From flutter-skills
Implements animated effects, transitions, and motion in a Flutter app. Use when adding visual feedback, shared element transitions, or physics-based animations.
npx claudepluginhub gsmlg-dev/code-agent --plugin flutter-skillsThis skill uses the workspace's default tool permissions.
- [Core Concepts](#core-concepts)
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides MCP server integration in Claude Code plugins via .mcp.json or plugin.json configs for stdio, SSE, HTTP types, enabling external services as tools.
Manage Flutter animations using the core typed Animation system. Do not manually calculate frames; rely on the framework's ticker and interpolation classes.
Animation<T>: Treat this as an abstract representation of a value that changes over time. It holds state (completed, dismissed) and notifies listeners, but knows nothing about the UI.AnimationController: Instantiate this to drive the animation. It generates values (typically 0.0 to 1.0) tied to the screen refresh rate. Always provide a vsync (usually via SingleTickerProviderStateMixin) to prevent offscreen resource consumption. Always dispose() controllers to prevent memory leaks.Tween<T>: Define a stateless mapping from an input range (usually 0.0-1.0) to an output type (e.g., Color, Offset, double). Chain tweens with curves using .animate().Curve: Apply non-linear timing (e.g., Curves.easeIn, Curves.bounceOut) to an animation using a CurvedAnimation or CurveTween.Apply conditional logic to select the correct animation approach:
AnimatedContainer, AnimatedOpacity, TweenAnimationBuilder).AnimationController with AnimatedBuilder or AnimatedWidget).SpringSimulation).Tweens driven by a single AnimationController using Interval curves).Use this workflow for "fire-and-forget" state-driven animations.
Container) with its animated counterpart (e.g., AnimatedContainer).duration property.curve property for non-linear motion.setState() call.Use this workflow when you need granular control over the animation lifecycle.
SingleTickerProviderStateMixin (or TickerProviderStateMixin for multiple controllers) to the State class.AnimationController in initState(), providing vsync: this and a duration.Tween and chain it to the controller using .animate().AnimatedBuilder (preferred for complex trees) or subclass AnimatedWidget.Animation object to the AnimatedBuilder's animation property.controller.forward(), controller.reverse(), or controller.repeat().controller.dispose() in the dispose() method.dispose() is called.Use this workflow to fly a widget between two routes.
Hero widget.tag to the source Hero.Hero widget.tag to the destination Hero.Hero widgets are visually similar to prevent jarring jumps.Navigator.Use this workflow for gesture-driven, natural motion.
AnimationController (do not set a fixed duration).GestureDetector (e.g., onPanEnd providing DragEndDetails).SpringSimulation with mass, stiffness, damping, and the calculated velocity.controller.animateWith(simulation).class StaggeredAnimationDemo extends StatefulWidget {
@override
State<StaggeredAnimationDemo> createState() => _StaggeredAnimationDemoState();
}
class _StaggeredAnimationDemoState extends State<StaggeredAnimationDemo> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _widthAnimation;
late Animation<Color?> _colorAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
// Staggered width animation (0.0 to 0.5 interval)
_widthAnimation = Tween<double>(begin: 50.0, end: 200.0).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.0, 0.5, curve: Curves.easeIn),
),
);
// Staggered color animation (0.5 to 1.0 interval)
_colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.5, 1.0, curve: Curves.easeOut),
),
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose(); // CRITICAL: Prevent memory leaks
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Container(
width: _widthAnimation.value,
height: 50.0,
color: _colorAnimation.value,
);
},
);
}
}
Route createCustomRoute(Widget destination) {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => destination,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0); // Start from bottom
const end = Offset.zero;
const curve = Curves.easeOut;
final tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
final offsetAnimation = animation.drive(tween);
return SlideTransition(
position: offsetAnimation,
child: child,
);
},
);
}
// Usage: Navigator.of(context).push(createCustomRoute(const NextPage()));