Nicholai 75168f7678 init: agent event bus + state
structure:
  state/CURRENT.md — 2-4 line session state (rewritten each session)
  events/ — json event bus (pull-based, optional context)
  persistent/ — important decisions (one doc per decision)
  emit — helper script for emitting events
2026-01-24 03:27:11 -07:00

3.8 KiB

name description metadata
gif Displaying GIFs, APNG, AVIF and WebP in Remotion
tags
gif, animation, images, animated, apng, avif, webp

Using Animated images in Remotion

Basic usage

Use <AnimatedImage> to display a GIF, APNG, AVIF or WebP image synchronized with Remotion's timeline:

import {AnimatedImage, staticFile} from 'remotion';

export const MyComposition = () => {
  return <AnimatedImage src={staticFile('animation.gif')} width={500} height={500} />;
};

Remote URLs are also supported (must have CORS enabled):

<AnimatedImage src="https://example.com/animation.gif" width={500} height={500} />

Sizing and fit

Control how the image fills its container with the fit prop:

// Stretch to fill (default)
<AnimatedImage src={staticFile("animation.gif")} width={500} height={300} fit="fill" />

// Maintain aspect ratio, fit inside container
<AnimatedImage src={staticFile("animation.gif")} width={500} height={300} fit="contain" />

// Fill container, crop if needed
<AnimatedImage src={staticFile("animation.gif")} width={500} height={300} fit="cover" />

Playback speed

Use playbackRate to control the animation speed:

<AnimatedImage src={staticFile("animation.gif")} width={500} height={500} playbackRate={2} /> {/* 2x speed */}
<AnimatedImage src={staticFile("animation.gif")} width={500} height={500} playbackRate={0.5} /> {/* Half speed */}

Looping behavior

Control what happens when the animation finishes:

// Loop indefinitely (default)
<AnimatedImage src={staticFile("animation.gif")} width={500} height={500} loopBehavior="loop" />

// Play once, show final frame
<AnimatedImage src={staticFile("animation.gif")} width={500} height={500} loopBehavior="pause-after-finish" />

// Play once, then clear canvas
<AnimatedImage src={staticFile("animation.gif")} width={500} height={500} loopBehavior="clear-after-finish" />

Styling

Use the style prop for additional CSS (use width and height props for sizing):

<AnimatedImage
  src={staticFile('animation.gif')}
  width={500}
  height={500}
  style={{
    borderRadius: 20,
    position: 'absolute',
    top: 100,
    left: 50,
  }}
/>

Getting GIF duration

Use getGifDurationInSeconds() from @remotion/gif to get the duration of a GIF.

npx remotion add @remotion/gif # If project uses npm
bunx remotion add @remotion/gif # If project uses bun
yarn remotion add @remotion/gif # If project uses yarn
pnpm exec remotion add @remotion/gif # If project uses pnpm
import {getGifDurationInSeconds} from '@remotion/gif';
import {staticFile} from 'remotion';

const duration = await getGifDurationInSeconds(staticFile('animation.gif'));
console.log(duration); // e.g. 2.5

This is useful for setting the composition duration to match the GIF:

import {getGifDurationInSeconds} from '@remotion/gif';
import {staticFile, CalculateMetadataFunction} from 'remotion';

const calculateMetadata: CalculateMetadataFunction = async () => {
  const duration = await getGifDurationInSeconds(staticFile('animation.gif'));
  return {
    durationInFrames: Math.ceil(duration * 30),
  };
};

Alternative

If <AnimatedImage> does not work (only supported in Chrome and Firefox), you can use <Gif> from @remotion/gif instead.

npx remotion add @remotion/gif # If project uses npm
bunx remotion add @remotion/gif # If project uses bun
yarn remotion add @remotion/gif # If project uses yarn
pnpm exec remotion add @remotion/gif # If project uses pnpm
import {Gif} from '@remotion/gif';
import {staticFile} from 'remotion';

export const MyComposition = () => {
  return <Gif src={staticFile('animation.gif')} width={500} height={500} />;
};

The <Gif> component has the same props as <AnimatedImage> but only supports GIF files.