Skip to content
Blog

Animating Games with Flame: Sprite Sheets, Effects, and Components

Flame 1.38.2 gives Flutter games first-class animation primitives: SpriteAnimation, SpriteAnimationComponent, and declarative Effects.

Published on • October 7, 2026

AI Assistant

Flutter is an excellent UI toolkit, but a game needs a game loop, a component tree, collision detection, and frame-based animation. Flame provides exactly that — a minimalist Flutter game engine that runs entirely in Dart, with no platform channels, inside a normal GameWidget.

The current stable release is flame 1.38.2 (with 2.0.0-dev.1 in preview), a Flutter Favorite with the #animations topic front and center in its pub.dev listing. Here’s how its animation system actually works.

Sprite Animations: Frames from a Sprite Sheet

The core primitive is SpriteAnimation — an ordered sequence of frames with a per-frame duration. The usual way to build one is from a sprite sheet using SpriteAnimationData.sequenced:

class EmberPlayer extends SpriteAnimationComponent
    with HasGameReference<EmberQuestGame> {
  EmberPlayer({required super.position})
      : super(size: Vector2.all(64), anchor: Anchor.center);

  @override
  void onLoad() {
    animation = SpriteAnimation.fromFrameData(
      game.images.fromCache('ember.png'),
      SpriteAnimationData.sequenced(
        amount: 4,           // number of frames
        textureSize: Vector2.all(16), // pixels per frame
        stepTime: 0.12,      // seconds per frame
      ),
    );
  }
}

Three constructors cover most cases:

  • SpriteAnimation.spriteList(...) — frames from separate images.
  • SpriteAnimation.fromFrameData(image, data) — the sprite-sheet path above.
  • SpriteAnimationData.sequenced(...) — the config object with amount, stepTime, textureSize.

Frames from individual files look like this:

final sprites = [0, 1, 2].map((i) => Sprite.load('player_$i.png'));
final animation = SpriteAnimation.spriteList(
  await Future.wait(sprites),
  stepTime: 0.01,
);
final player = SpriteAnimationComponent(
  animation: animation,
  size: Vector2.all(64.0),
);

Stateful Animation with SpriteAnimationGroupComponent

Characters rarely have one animation. SpriteAnimationGroupComponent<T> holds a map of animations keyed by a state enum, and you switch states by assigning current:

enum RobotState { idle, running, jumping }

class Robot extends SpriteAnimationGroupComponent<RobotState>
    with HasGameReference<RobotGame> {
  @override
  Future<void> onLoad() async {
    animations = {
      RobotState.idle: await loadSpriteAnimation(
        'robot_idle.png',
        SpriteAnimationData.sequenced(amount: 4, textureSize: Vector2.all(32), stepTime: 0.15),
      ),
      RobotState.running: await loadSpriteAnimation(
        'robot_run.png',
        SpriteAnimationData.sequenced(amount: 6, textureSize: Vector2.all(32), stepTime: 0.08),
      ),
      RobotState.jumping: await loadSpriteAnimation(
        'robot_jump.png',
        SpriteAnimationData.sequenced(amount: 2, textureSize: Vector2.all(32), stepTime: 0.1),
      ),
    };
    current = RobotState.idle;
  }
}

Under the hood, SpriteAnimationTicker ticks the animation and exposes an onFrame callback. Multiple components can share a single animation object, and resetOnRemove: true rewinds to frame 1 when the component leaves the tree.

Need animation outside the game canvas? SpriteAnimationWidget (from package:flame/widgets) renders a SpriteAnimation in the regular Flutter widget tree — handy for loading screens and HUD portraits.

Declarative Effects: Tween Without the Boilerplate

Sprite frames handle character animation; Effect handles everything else — movement, rotation, scale, opacity, color. Effects replace hand-written interpolation in update():

add(
  MoveToEffect(
    Vector2(300, 200),
    EffectController(duration: 0.8, curve: Curves.easeOutCubic),
  ),
);

add(
  SequenceEffect([
    ScaleEffect.by(Vector2.all(1.2), EffectController(duration: 0.15)),
    ScaleEffect.by(Vector2.all(1 / 1.2), EffectController(duration: 0.15)),
    RemoveEffect(),
  ]),
);

The built-in catalog includes MoveByEffect, MoveToEffect, MoveAlongPathEffect, RotateEffect.by/.to, ScaleEffect.by/.to, SizeEffect.by/.to, AnchorByEffect, AnchorToEffect, OpacityToEffect, OpacityByEffect, ColorEffect, SequenceEffect, CombinedEffect, RemoveEffect, and FunctionEffect.

Useful properties:

  • removeOnFinish (default true) — the effect detaches itself when done.
  • onComplete / completed — chain logic after an effect finishes.
  • pause() / resume() / reset() — runtime control.

Custom effects extend Effect (or ComponentEffect<T> for component-specific work) and implement apply(double progress), where progress runs 0→1.

class WobbleEffect extends Effect {
  WobbleEffect() : super(EffectController(duration: 0.5));

  @override
  void apply(double progress) {
    final angle = sin(progress * pi * 4) * 0.2;
    parent!.transform.rotation = angle;
  }
}

How It Fits Together

A typical animated entity wires up like this:

  1. Extend SpriteAnimationComponent (or PositionComponent for effects-only entities).
  2. In onLoad(), assign animation from a sprite sheet.
  3. Add Effects for transient motion — knockback, dash, fade-out.
  4. Swap animations on state change via SpriteAnimationGroupComponent.current.
  5. Mount the whole thing with runApp(GameWidget(game: MyGame())).

Note that Flame’s effects are independent of Flutter’s Tween/AnimationController — they run on the game clock, so they stay synchronized with your game loop even if frame rates vary. The old AnimationComponent name is gone; SpriteAnimationComponent is the modern replacement.

The Ecosystem Around Animation

Flame’s modular design means animation concerns plug in cleanly: flame_audio for sound synced to effects, flame_rive and flame_lottie for vector animations authored in external tools, flame_tiled for tilemap-driven scenes, and flame_forge2d for physics-based motion. Each is optional — the core flame package depends only on collection, meta, ordered_set, vector_math, and Flutter itself.

Getting Started

dependencies:
  flame: ^1.38.2

Then run the official codelab, Intro to Flame with Flutter (Brick Breaker), or explore runnable demos at examples.flame-engine.org. Full docs live at docs.flame-engine.org.

The animation API surface is deliberately small — sprite sheets for frames, groups for states, effects for motion. Learn those three, and most game animation problems decompose cleanly.