diff --git a/.cspell.yaml b/.cspell.yaml
index 3211d4dd..6747f45c 100644
--- a/.cspell.yaml
+++ b/.cspell.yaml
@@ -89,10 +89,13 @@ words:
- shellenv
- shorebirdtech
- softwareupdate
+ - subclassing
- subosito
- tabler
- temurin
+ - tweens
- uiscene
+ - vsync
- vvago
- webkitallowfullscreen
- widgetbook
diff --git a/src/content/docs/flutter-concepts/animations.mdx b/src/content/docs/flutter-concepts/animations.mdx
new file mode 100644
index 00000000..a167e18d
--- /dev/null
+++ b/src/content/docs/flutter-concepts/animations.mdx
@@ -0,0 +1,194 @@
+---
+title: 'Flutter Animations'
+description:
+ Reference guide for implementing implicit, explicit, and physics-based
+ animations in Flutter.
+sidebar:
+ order: 6
+---
+
+The Flutter animation framework provides a layered architecture for controlling
+motion. At its core, the framework categorizes animations into implicit
+transitions, explicit controller-driven animations, and physics-based
+simulations.
+
+## Implicit animations
+
+Implicit animations automatically interpolate between a current value and a new
+target value over a specified duration. The framework calculates intermediate
+frames when a property changes and the widget rebuilds.
+
+`AnimatedContainer` is a versatile implicit widget that can animate changes to
+size, color, padding, and alignment simultaneously:
+
+```dart
+AnimatedContainer(
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ width: isExpanded ? 200 : 100,
+ decoration: BoxDecoration(
+ color: isExpanded ? Colors.blue : Colors.red,
+ borderRadius: BorderRadius.circular(isExpanded ? 16.0 : 8.0),
+ ),
+ child: const Text('Hello'),
+)
+```
+
+The underlying architecture relies on `ImplicitlyAnimatedWidget`. When the
+framework detects a change in the widget's configuration (via
+`didUpdateWidget`), it creates an internal `AnimationController` and begins a
+transition from the old values to the new values.
+
+### Non-linear interpolation (curves)
+
+By default, animations transition linearly. Applying a `Curve` modifies the
+interpolation rate. The framework provides standard curves via the `Curves`
+class, such as `Curves.easeIn`, `Curves.bounceOut`, and `Curves.elasticInOut`.
+You can also define custom mathematical curves by subclassing `Curve` and
+overriding the `transformInternal` method.
+
+## Explicit animations
+
+Explicit animations require manual lifecycle management using an
+`AnimationController`. This approach is necessary for looping animations,
+sequenced transitions, and animations triggered by gesture events.
+
+```mermaid
+graph TD
+ T["TickerProvider
(vsync)"] -->|Tick per frame| C["AnimationController
(0.0 to 1.0)"]
+ C -->|Linear Value| A["CurvedAnimation
(Non-linear timing)"]
+ A -->|Eased Value| TW["Tween
(Maps to target data type)"]
+ TW -->|Output Value| W["AnimatedBuilder
(Rebuilds UI)"]
+
+ style T fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px,color:#000
+ style C fill:#e8f5e9,stroke:#4caf50,stroke-width:2px,color:#000
+ style A fill:#fff3e0,stroke:#ff9800,stroke-width:2px,color:#000
+ style TW fill:#fce4ec,stroke:#e91e63,stroke-width:2px,color:#000
+ style W fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px,color:#000
+```
+
+### Animation controllers and vsync
+
+An `AnimationController` generates a new value whenever the hardware is ready
+for a new frame. To prevent off-screen computations and synchronize with the
+device refresh rate, the controller requires a `TickerProvider` (passed via the
+`vsync` argument).
+
+```dart
+class _MyWidgetState extends State with SingleTickerProviderStateMixin {
+ late final AnimationController _controller;
+
+ @override
+ void initState() {
+ super.initState();
+ _controller = AnimationController(
+ duration: const Duration(seconds: 2),
+ vsync: this,
+ );
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose(); // Prevent memory leaks
+ super.dispose();
+ }
+}
+```
+
+### Tweens and mapping
+
+A controller typically outputs values between `0.0` and `1.0`. A `Tween` maps
+this unit interval to a required data type (such as `Color`, `Offset`, or
+`double`).
+
+```dart
+final Animation sizeAnimation = Tween(
+ begin: 10.0,
+ end: 100.0,
+).animate(
+ CurvedAnimation(
+ parent: _controller,
+ curve: Curves.easeOut,
+ ),
+);
+```
+
+### Rebuilding the UI
+
+To apply the animation to the render tree, use an `AnimatedBuilder` or subclass
+`AnimatedWidget`. This localized rebuilding prevents the entire widget tree from
+refreshing on every frame.
+
+```dart
+AnimatedBuilder(
+ animation: sizeAnimation,
+ builder: (BuildContext context, Widget? child) {
+ return Container(
+ width: sizeAnimation.value,
+ height: sizeAnimation.value,
+ color: Colors.blue,
+ child: child, // The child is passed through to prevent rebuilding it
+ );
+ },
+ child: const FlutterLogo(),
+)
+```
+
+## Physics-based simulations
+
+For animations that must react naturally to user input (such as a scroll view
+snapping into place), use the physics simulation engine rather than
+fixed-duration controllers.
+
+The `AnimationController` can execute a `Simulation` using
+`controller.animateWith(Simulation)`. The framework provides several standard
+physics models:
+
+- `SpringSimulation`: Models tension and friction.
+- `GravitySimulation`: Models gravitational acceleration.
+- `FrictionSimulation`: Models gradual deceleration.
+
+```dart
+final SpringDescription spring = SpringDescription(
+ mass: 1.0,
+ stiffness: 100.0,
+ damping: 10.0,
+);
+
+final SpringSimulation simulation = SpringSimulation(
+ spring,
+ 0.0, // start position
+ 100.0, // end position
+ 0.0, // initial velocity
+);
+
+_controller.animateWith(simulation);
+```
+
+## Third-party vector animations
+
+For complex vector graphics and state-machine animations, use third-party
+formats rather than the built-in widget framework:
+
+- **[Lottie](https://lottiefiles.com/)**: Uses animations exported as JSON from
+ Adobe After Effects. Best for static, non-interactive visual assets.
+- **[Rive](https://rive.app/)**: Uses interactive state machines designed for
+ real-time manipulation. Best for dynamic assets requiring programmatic state
+ changes.
+
+## Performance considerations
+
+Modifying properties that affect layout (such as `width`, `height`, or
+`padding`) forces the framework to recalculate geometry on every frame, which
+can cause dropped frames.
+
+To optimize performance, animate properties that are composited directly on the
+GPU without altering layout constraints:
+
+- **Opacity**: Use `FadeTransition` or `AnimatedOpacity`.
+- **Transform**: Use `RotationTransition`, `ScaleTransition`, or
+ `SlideTransition`.
+
+When using `AnimatedBuilder`, always pass static child widgets via the `child`
+parameter. This prevents the framework from recreating the child subtree during
+every animation tick.