Why you cannot just scrub a video element
The first thing most people try is setting the video's time from the scroll position:
const video = document.querySelector("video");
addEventListener("scroll", () => {
const max = document.documentElement.scrollHeight - innerHeight;
video.currentTime = (scrollY / max) * video.duration;
});It works on a short, specially encoded clip on a fast laptop, and stutters almost everywhere else. Web video is compressed so most frames are stored as differences from an earlier full frame (a keyframe). To show an arbitrary moment, the browser has to find the keyframe before it and decode forward. Scrolling asks for a new moment dozens of times a second, so the browser is always seeking, and the picture lags or jumps. Re-encoding with a keyframe on every frame helps but makes the file several times larger, and mobile browsers still treat video seeking differently from desktop ones.
What works: turn the video into frames
The reliable approach is the one behind Apple-style product pages. Take still images out of the video at even intervals, load them all, and draw the right one to a canvas as the visitor scrolls. Picking an image that is already in memory takes no seeking and no decoding, so the page keeps up however fast someone scrolls. The full technique, with a code sketch, is in how to make an Apple-style scroll animation.
Doing that by hand usually means running ffmpeg, picking a frame rate, resizing, naming files and writing the scroll code. ScrollCraft does it in the browser instead.
Turn a video into a scroll website with ScrollCraft
- Open the builder. Go to the builder, choose any style on the first screen (your video will replace it) and press Next.
- Set the frame count. The slider runs from 60 to 200 and starts at 120. More frames scrub more smoothly and make a heavier site.
- Decide about phones. Turn on portrait frames if many visitors will be on phones. A second set at 720 by 1280 is cut from the centre of your footage.
- Drop in your video. Drag the file onto the upload box or click to choose it. Frames are sampled evenly across the clip, scaled so the long edge is at most 1280 pixels, and saved as JPEGs in your browser. A progress bar shows how far it has got.
- Write the page. The editor opens with your footage as the background. Add sections, headings, text and a button, and scroll the preview to see the words move over the video.
- Export. The ZIP has
index.htmland aframesfolder (plusframes-mobileif you made a portrait set), ready to drag onto Netlify or push to GitHub Pages. The HTML export guide walks through hosting.
If you would rather not write the words, describe your business and the AI writer drafts the whole site, then swap in your own video in the editor.
Footage that scrolls well
Not every clip makes a good scroll background. What tends to work:
- One slow, continuous move. An orbit around a product, a push in through a doorway, a slow pan across a landscape. Scrolling stretches and compresses time, so smooth motion stays smooth and jerky motion gets worse.
- No cuts. A hard cut becomes a single-frame jump in the middle of a scroll. If you need two shots, a dissolve between them scrubs better.
- Short clips. With 120 frames, a 10 second clip gives 12 frames per second of footage; a 60 second clip gives 2, and the motion between frames starts to show. Ten to thirty seconds is a good range.
- A steady camera. Handheld shake turns into flicker when the visitor scrolls slowly. Use a stabilised shot, a gimbal or a tripod.
- Room for text. Your headings sit on top of the footage. Darker or less busy areas of the frame keep them readable.
- Subject in the centre. Phones crop the sides of landscape footage, so keep what matters near the middle.
Keeping the site light
Every frame is a JPEG the visitor downloads, so frame count, frame size and content all matter. Busy, detailed footage compresses worse than smooth gradients. If the exported frames folder feels heavy, go back and pick a lower frame count before you trim anything else. The exported page loads every fifth frame first so the whole scroll is roughly covered early, then fills in the rest. The netlify.toml and vercel.json in the ZIP tell those hosts to cache the frames for a year, so returning visitors do not download them twice.