Scroll-Linked Image Mask Reveal
An image whose circular clip-path mask grows and shrinks in lockstep with scroll.
- Category
- Sections
- Added
- 2026-08-24
- Deps
- 1
- Updated
- 2026-09-01
Props
This entry takes no configurable props.
"use client";
import { useRef } from "react";
import { motion, useScroll, useTransform } from "framer-motion";
export function ScrollLinkedImageMaskReveal({ src, alt = "" }: { src: string; alt?: string }) {
const targetRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({
target: targetRef,
offset: ["start end", "end start"],
});
const clipPercent = useTransform(scrollYProgress, [0, 1], [0, 75]);
const clipPath = useTransform(clipPercent, (v) => `circle(${v}% at 50% 50%)`);
const scale = useTransform(scrollYProgress, [0, 1], [1.3, 1]);
return (
<div ref={targetRef} className="relative flex h-[70vh] items-center justify-center overflow-hidden">
<motion.img src={src} alt={alt} style={{ clipPath, scale }} className="h-full w-full object-cover" />
</div>
);
}
About this section
Most reveal-on-scroll components fire once when an element crosses some threshold and then sit in their finished state, which is fine until someone scrolls back up and the reveal stays frozen, disconnected from where they actually are on the page. This one does not fire in that sense at all: a circular clip-path radius is derived directly from scrollYProgress via useTransform, so the mask grows and shrinks continuously and bidirectionally as the container passes through the viewport, tracked with useScroll's target and offset pair rather than a one-shot useInView check. Because clip-path and scale are motion values rather than React state, they update every scroll frame without triggering a re-render, which is what keeps this smooth even stacked several to a page. Reach for the sibling component, Scroll Reveal Wipe, instead when the reveal should commit once and stay revealed; that one is a useInView, single-fire animation, and mixing the two mental models, continuous versus one-shot, on the same page can look inconsistent if you are not deliberate about which effect is doing which job.
Curator’s note
Unlike Scroll Reveal Wipe (a once-triggered useInView animation), this mask is driven directly by a continuous scrollYProgress motion value via useTransform — it tracks scroll bidirectionally in real time rather than firing once and staying in its end state.
Pairs well with
Matched on shared tags and category — the entries most likely to be used alongside this one.
Vertical Timeline Reveal
sectionsA scroll-triggered vertical timeline whose dots and cards reveal in sequence.
Line Mask Reveal
animationsReveals text one line at a time, each sliding up from behind its own clipping mask.
Stagger Reveal Group
animationsA wrapper that reveals its children one after another as the group scrolls into view.