# Seamless loop video: how to make one that never jumps

[Canonical HTML page](https://gradiently.design/guide/seamless-loop-video)

A loop that jumps once every ten seconds is worse than no motion at all. The fix is not a better editor; it is motion designed to come home.

## The short version

- A seamless loop is a video whose last frame leads straight into its first, so it can repeat without a visible jump.
- Generated motion loops cleanly when everything that moves completes a whole number of cycles in the length of the video.
- The most common stutter is a duplicated frame: the final frame should be the one just before the first frame, not a copy of it.
- Footage that wasn't designed to loop can be fixed by swapping its two halves and crossfading at the new join.
- Check a loop by playing it repeatedly at full size and comparing its last frame with its first.

A **seamless loop** is a video whose last frame leads straight into its first, so it can repeat forever without anyone seeing where it starts. The secret is that everything in the frame has to come home at exactly the right moment: every position, colour, light level and particle ends one step before where it began. Get that right and a ten-second clip can play all day.

This guide covers why loops jump, how to design motion that returns on its own, how to rescue footage that wasn't made to loop, and how to check the seam before you publish. For the look of the loop itself, see [animated gradient backgrounds](https://gradiently.design/guide/animated-gradient-background).

## Why most loops jump

A jump at the seam always has a specific cause, and each has a specific fix. It helps to name which one you are looking at.

| Cause | What you see | Fix |
| --- | --- | --- |
| End doesn't match start | Colour or position snaps back | Make motion periodic, or crossfade |
| Duplicated frame | A tiny stutter or pause at the join | Render the last frame one step before the first |
| Motion slows to a stop at the ends | A beat of stillness, then movement again | Keep speed continuous through the seam |
| Random noise or particles that don't repeat | Texture or specks jump | Loop the noise, or settle the particles first |
| Heavy compression | A soft pulse of blur at the join | Export at a higher quality |

The third cause is sneaky. If you animate from A to B and back with easing at both ends, the motion slows to a halt at the seam and the loop seems to hesitate. Easing belongs at the start and end of a one-off move, not at the join of a loop. [Easing](https://gradiently.design/guide/easing) explains the difference.

## Designing motion that loops on its own

The cleanest loops are made of periodic motion: movement that repeats by nature, like a point travelling round a circle or a light swelling and falling. If every moving thing completes a whole number of cycles in the length of the video, the final frame lines up with the first automatically. Circles, sine waves and full turns of hue are all periodic.

```js
const fps = 30
const seconds = 10
const frames = fps * seconds            // 300 frames, numbered 0 to 299

for (let i = 0; i < frames; i++) {
  const phase = i / frames              // 0 up to, but never reaching, 1
  const turn = phase * Math.PI * 2      // one full turn per loop

  const x = Math.cos(turn) * 40         // drift in a circle, 40 px across
  const y = Math.sin(turn) * 40
  const hue = 280 + Math.sin(turn * 2) * 20   // two gentle hue swings per loop
  const glow = 0.5 + 0.5 * Math.sin(turn)     // light breathes once per loop

  drawFrame(i, { x, y, hue, glow })     // your renderer
}
```

Periodic motion for a 10 second loop. Each value completes whole cycles, and because `phase` stops just short of 1, frame 300 (a copy of frame 0) is never drawn.

That last detail is what prevents the stutter. If your final frame is identical to your first, the player shows that picture twice in a row at every repeat. The final frame should be the one just before the first.

- Frame 298: `linear-gradient(150deg, #0f172a 0%, #1d4ed8 52%, #22d3ee 100%)`
- Frame 299: last: `linear-gradient(151deg, #0f172a 0%, #1d4ed8 51%, #22d3ee 100%)`
- Frame 0: first: `linear-gradient(152deg, #0f172a 0%, #1d4ed8 50%, #22d3ee 100%)`
- Frame 1: `linear-gradient(153deg, #0f172a 0%, #1d4ed8 49%, #22d3ee 100%)`

Across a good seam, each frame differs from the next by the same small step. There is no frame where the change is bigger, and no frame that repeats.

### Looping noise, grain and particles

Organic textures are often made from noise, which doesn't repeat by default. The standard trick is to move through the noise in a circle rather than a straight line, so after one loop you are back at the same point in it. Particle systems are different: each particle's position depends on the ones before. Running the simulation for a full loop before recording lets the particles settle into their rhythm, so the recorded end sits close to its start.

## How to loop footage that wasn't made to loop

Filmed clips, such as waves, smoke or clouds, rarely end where they begin. The classic fix works in any video editor: move the join into the middle of the clip, where the footage is already continuous, and hide the new cut with a crossfade.

1. **Split the clip in the middle** Cut the clip into two halves, A and B, at a moment with steady motion.
2. **Swap the halves** Place B first and A second. The end of A now flows into the start of B, because that was one continuous moment in the original, so the loop point is seamless.
3. **Crossfade the new middle** Where B meets A, overlap them by half a second to two seconds and fade one into the other. Soft, textural footage hides a crossfade best.
4. **Trim to a round length** Aim for a whole number of seconds, which makes the loop easy to time and to reuse.

> **Avoid obvious landmarks** A crossfade hides texture well but not objects. If a bird crosses the frame during the fade, people will see two ghosts. Choose a stretch of footage with nothing distinctive in it.

## Choosing a loop length

Longer loops feel less repetitive, but they are bigger files and need more periodic motion to stay interesting. Short loops repeat often, so their motion must be subtle enough not to become hypnotic. At 30 frames per second, a 10 second loop is 300 frames, which divides neatly into halves, thirds and quarters for your cycles.

| Where it plays | Suggested length | Why |
| --- | --- | --- |
| Stories and short posts | 5 to 10 seconds | Viewers move on quickly; small files |
| Reels and video backgrounds | 10 to 15 seconds | Room for a slower, calmer cycle |
| Website hero | 8 to 15 seconds | Short enough to keep the file light |
| Screens, displays, wallpapers | 15 to 30 seconds | People watch for longer, so repeats must be less noticeable |

Starting points, not rules. The file format matters too; see [GIF vs MP4](https://gradiently.design/guide/gif-vs-mp4).

## How to check the seam

Don't judge a loop by watching it once in an editor. Watch it the way people will meet it: repeating, at full size, for longer than feels necessary. Seams that hide in a small preview often show on a big screen.

```bash
# Play the loop four times in a row as one file, to watch the joins
ffmpeg -stream_loop 3 -i loop.mp4 -c copy loop-x4.mp4

# Save the first and last frames as images to compare side by side
ffmpeg -i loop.mp4 -vf "select=eq(n\,0)" -frames:v 1 first.png
ffmpeg -sseof -0.5 -i loop.mp4 -update 1 last.png
```

Two quick checks with ffmpeg. The last frame should differ from the first by exactly one normal step of motion.

- Watch the four-times file at full screen and look only at the join.
- Look at the edges and corners, where drift is most visible.
- Watch the grain and particles separately from the colour.
- If you see a soft pulse at the join, it is compression: export at a higher quality.

If you make loops in Gradiently, this is handled for you: every exported loop is built so the moving field completes whole cycles within the length you choose, from 5 to 30 seconds, and its end meets its start. It is the same approach you would take in code, applied to your Mark. Loops also make good [live wallpapers](https://gradiently.design/guide/live-wallpaper) and [website video backgrounds](https://gradiently.design/guide/video-background-website).

## FAQ

### What is a seamless loop?

It is a video or animation whose last frame leads directly into its first, so it can repeat continuously without a visible jump or pause.

### Why does my loop stutter at the end?

Usually because the last frame is a copy of the first, so the same picture shows twice. Make the final frame the one just before the first frame.

### How do I loop a video that wasn't filmed to loop?

Split it in the middle, swap the two halves and crossfade where they now meet. The original join becomes continuous, and the crossfade hides the new one.

### How long should a looping video be?

5 to 10 seconds for stories and posts, 10 to 15 for reels and web backgrounds, and 15 to 30 for screens and wallpapers people watch for longer.

### Why is there a blur at the loop point?

That is usually compression, not the animation. Exporting at a higher quality or bitrate removes it.
