Halloween only 🎃 Get Wensity Pro for 31% less with

Scrubbable Video Reveal

An Apple-style image sequence scrubbed frame by frame on canvas, following your hand as you scroll in either direction.

cinematic interactionsscrubbablevideorevealframer motion
Scrubbable Video Reveal component preview

Overview

Scrubbable Video Reveal is a React and Tailwind CSS scroll scrubbed image sequence, the apple.com product video effect, in Next.js or any React app, built on Framer Motion. It skips the video tag, since compressed video scrubs badly backward, and preloads every frame, maps scroll progress to a frame index, and draws it to a canvas sized for retina screens. It can pin, sit in a device frame, and carry overlays as children. Reduced motion loads only the last frame and shows it still. Keep to 100 to 200 compressed WebP frames, since eager preload fetches them all.

Installation

Run the following command

~/your-project
pnpm dlx wensity@latest add scrubbable-video-reveal

Usage

Import ScrubbableVideoReveal from @/components/wensity/scrubbable-video-reveal and render it anywhere in your React or Next.js app. The source lands in your own repo, so every prop, class and animation below is yours to edit.

app/example.tsx
"use client";
import { ScrubbableVideoReveal } from "@/components/wensity/scrubbable-video-reveal";
const frames = Array.from({ length: 180 }, (_, i) =>
`/sequence/frame-${String(i).padStart(4, "0")}.webp`
);
export function ScrubbableVideoRevealDemo() {
return (
<ScrubbableVideoReveal
frames={frames}
aspect="16 / 10"
travel={3}
framed
/>
);
}

Props

PropTypeDefaultDescription
framesstring[]-Image sequence URLs in order. Prefer 100–200 compressed WebP / JPEG frames.
aspectstring"16 / 10"Aspect ratio for the canvas wrapper.
travelnumber3Scroll travel multiplier. Total inner height is travel × 100vh.
framedbooleantrueRender the surrounding device frame.
stickybooleantruePin the canvas via position sticky while the user scrolls.
childrenReact.ReactNode-Optional content rendered above the canvas as overlays.
useWindowbooleanfalseUse window scroll instead of an inner scrollable container.
preload"eager" | "lazy""eager"Loading strategy for image preload.
heightstring"640px"Scroll container height when useWindow is false.
  • Dynamic Island Toast component preview

    Dynamic Island Toast

    A pixel-faithful Apple Dynamic Island that morphs, splits, and breathes while it hosts live activities inside your app.

  • Infinite Marquee component preview

    Infinite Marquee

    A seamless, GPU-only logo strip that never stutters or snaps at the loop point.

  • Apple-Style Sticky Scroll component preview

    Apple-Style Sticky Scroll

    A pinned cinematic section that morphs in lock-step with scroll, staying perfectly in sync whichever way you travel.

  • Morphing Shape Background component preview

    Morphing Shape Background

    Lava lamp background for React heroes: soft gradient shapes that drift and melt.