0

Skip to content

Art direction, ready for your AI.

Become a member

How to make a seamless video background for a website

Five steps to a hero loop with no visible cut, from the generation prompt to the final video tag.

Author
Nacho Seoane
Date
Reading time
6 min read
A strip of film closed into a loop, with a thin blue line at the splice

In short

A seamless video background comes from a locked camera, a measured seam and one encoded file per screen. Generate the clip with no camera movement, then compare its last frame with its first using SSIM in ffmpeg. We call a loop clean when that score reaches at least 95% of the score between two normal frames. Encode H.264 MP4 with no audio, which 97.49% of browsers support. Across the 31 loop files we measured, the median weighs 2.91 MB on desktop and 1.35 MB on phones, for clips of 4.6 to 7 seconds.

  • Ask for a static camera in so many words, and name what may move.
  • Treat a seam as clean at 95% of the normal frame-to-frame SSIM score.
  • Expect about 0.45 MB per second on desktop and 0.21 MB on phones.
  • Keep posters light, because a poster can set your Largest Contentful Paint.
  • Add a pause control, which WCAG 2.2.2 asks for beyond 5 seconds of movement.

Why background loops show a cut

A loop shows a cut when its last frame does not match its first. The jump is easiest to see on anything that should be continuous, like a slow camera drift, a horizon or light moving on a wall. That makes it a camera problem first, so the fix starts when you generate or shoot the clip.

The first video we made for our first hero asked for a fixed camera, and the generator panned anyway. Its last frame matched its first by only 64%, and it came out at 832×464. We regenerated it.

Step 1: Lock the camera and limit what moves

Ask for no camera movement in so many words, then name the few things allowed to move. This wording gave us a clean 5-second clip at 1280×720:

locked-off static camera, no camera movement, no zoom, no pan.
The woman stands perfectly still; only her hair and the hem of her dress move gently in the breeze.

Generators take motion words literally. In our tests with one video model, “calm” gave an almost frozen clip, while “clearly visible” invented gestures, clouds and ripples and left the ending different from the start. Ask for even movement of a concrete size, forbid the events you do not want in writing, and budget for 2 attempts.

If the tool has a loop option, use it. In Midjourney, typing --loop into the prompt was not enough for us, and the switch in the interface made the difference.

Step 2: Measure the seam instead of watching it

Score the last frame against the first with SSIM, and call the loop clean when that seam reaches at least 95% of the score between two normal frames. Your eye adapts after a few plays, and a number does not.

ffmpeg -i clip.mp4 -frames:v 1 first.png
ffmpeg -i clip.mp4 -vf "select=eq(n\,1)" -frames:v 1 second.png
ffmpeg -sseof -0.05 -i clip.mp4 -frames:v 1 last.png

# The seam, then the normal step. Read the "All:" value of each.
ffmpeg -i last.png -i first.png -lavfi ssim -f null -
ffmpeg -i first.png -i second.png -lavfi ssim -f null -

The comparison has to be relative. A grainy clip scores low on every pair of frames, so a fixed threshold would fail clips that loop perfectly. The clip above scored 0.868 at the seam against 0.850 between frames, which means the join is no bigger than any other step in the video.

Step 3: Repair a clip that fails

Most failures can be repaired without generating again, and the right repair depends on what went wrong.

Problem Repair Watch out for
Small difference, static camera Crossfade the last 1 s into the first With camera movement you get double images
The camera moves Play forward, then backward Reads as rewinding if anything has a direction, like smoke
Something drifts, like haze or a sliding subject Use a shorter window where start and end match The loop gets shorter
One-frame flashes Interpolate those frames Scan brightness across the clip: our first pass found 3 of 10
Same image given as first and last frame Still measure it We got a visible seam and needed a 1 s crossfade

Repairs we have used on our own loops, with what each one risks.

For very subtle clips, the standard 8-bit blends can leave a visible step in the middle of a crossfade. Mixing at 16 bits made the join look like any other frame in our case.

Step 4: Encode one file per screen

Encode H.264 MP4 with no audio track, once for desktop and once as a vertical crop for phones. The crop should be centred on the subject, because the desktop file scaled down leaves it too small on a phone.

# Desktop
ffmpeg -i clip.mp4 -an -c:v libx264 -preset slow -crf 19 -pix_fmt yuv420p -profile:v high -movflags +faststart hero.mp4

# Phone: 9:16 crop at 540×960
ffmpeg -i clip.mp4 -an -vf "crop=ih*9/16:ih,scale=540:960:flags=lanczos" -c:v libx264 -preset slow -crf 21 -pix_fmt yuv420p -profile:v high -movflags +faststart hero-mobile.mp4

# Poster: the first frame, so nothing jumps when the video starts
ffmpeg -i clip.mp4 -frames:v 1 -q:v 3 hero-poster.jpg

-an removes the audio track, and +faststart moves the file’s index to the front so playback can start before the download ends. The FFmpeg H.264 guide (opens in a new tab) notes that raising the CRF by 6 roughly halves the file, which makes it the first value to adjust. These are the sizes that came out across our catalogue.

File Files measured Smallest Median Largest Per second
Desktop, 1920 to 2560 px wide 17 1.09 MB 2.91 MB 4.84 MB 0.45 MB
Phone, 720×1280 14 0.45 MB 1.35 MB 3.74 MB 0.21 MB

Hero loops from our animated backgrounds and APSIS, 4.6 to 7 seconds long, measured on 4 November 2026.

Grain is expensive, because it changes on every frame. A 64-second recording with film grain weighed 70 MB at CRF 25. A light denoise (hqdn3d=4:3:12:12) and CRF 30 at 1280×800 brought it to 16 MB with the same average grain level. H.264 also has the widest reach of the common formats, as Can I use (opens in a new tab) shows.

Format Full support Partial support Our use
H.264 MP4 97.49% 0% Every loop
WebM 96.41% 0.84% None
AV1 79.04% 16.93% None
HEVC 19.99% 74.95% None

Global browser support according to Can I use, read on 4 November 2026.

If you’d rather start from a finished loop, our looping video backgrounds went through these same steps.

Step 5: Embed it so it always has something to show

Paint the poster first, start the video from script and handle a blocked autoplay. A visitor should see a finished image at every point, even if the video never plays.

<video id="hero" muted loop playsinline poster="/hero-poster.jpg" width="1920" height="1080"></video>

<script>
  const hero = document.getElementById("hero");
  const phone = matchMedia("(max-width: 767px)").matches;
  const still = matchMedia("(prefers-reduced-motion: reduce)").matches;
  if (!still) {
    hero.src = phone ? "/hero-mobile.mp4" : "/hero.mp4";
    hero.play().catch((error) => {
      if (error.name === "NotAllowedError") showPlayButton();
    });
  }
</script>

Four details matter here:

A video is one option among three, so read our comparison of video, WebGL and CSS for a hero background before you commit. The animated backgrounds in our catalogue went through these five steps.

Verdict. A clean loop is decided when the clip is generated. Lock the camera, because a fixed shot leaves the least to repair. Measure the seam, because your eye adapts. Encode one file per screen, which brings our median from 2.91 MB on desktop to 1.35 MB on phones.

Nacho SeoaneFounder of Orbital Supply

Directs the Orbital Supply catalogue of more than 60 websites. Since October 2026, every new prompt starts from a website that was built and reviewed first.

Questions

Short answers to what usually comes up next.

How long should a background video loop be?

Five to seven seconds is enough for most backgrounds. Our hero loops run from 4.6 to 7 seconds. Longer clips hide the repetition better, but they add weight at about 0.45 MB per second on desktop, so length is the first thing to trim if a file comes out too heavy for the page.

What file size should a background video be?

Aim for the smallest file that still looks clean, because no standard limit exists. Published guides range from a few hundred kilobytes to 5 MB. Our desktop loops weigh 1.09 to 4.84 MB, and our phone loops 0.45 to 3.74 MB. For scale, the median mobile home page weighed 2,362 KB in July 2025, according to the Web Almanac.

Should I use MP4 or WebM for a background video?

Use H.264 MP4 if you want one file. It has full support in 97.49% of browsers according to Can I use, against 96.41% for WebM. We ship H.264 only, so there is one file to maintain per screen. WebM can come out smaller, but it means one more encode and one more round of testing.

Does a background video slow the page down?

It can, and the first place to look is the poster. web.dev counts a video's poster or first frame, whichever comes earlier, as a candidate for Largest Contentful Paint, which should stay under 2.5 seconds. Several autoplaying videos also add up. On a 2× screen, ours dropped our catalogue from 60 to about 30 frames per second while scrolling.

Why does my background video not autoplay on iPhone?

The video usually lacks muted or playsinline, the attributes WebKit asks for before it plays a video inline without a gesture. If both are present, the browser or the operating system may still refuse playback. In that case play() rejects with a NotAllowedError, so keep the poster on screen and offer a play button.

Does a background video need a pause button?

Yes, if it starts by itself, moves for more than 5 seconds and sits beside other content, according to WCAG 2.2.2. A short clip on a loop counts, because the movement keeps going. Add a visible control styled like the rest of the site, and stop the video for visitors who prefer reduced motion.

Skip the blank page

Start from a finished website.

Each template is a tested prompt with its code, assets and motion.