A Canvas 2D camera iris in front of a full-bleed photograph: machined blades in brushed dark metal, each catching the light at its own angle, with crisp overlapping seams, soft cast shadows, lit edges and fine grain, set in a turned metal ring on a matte lens body. As it opens the blades turn and retract, then the ring grows past the frame so the photo stands alone. Progress can be driven from scroll (a number or a MotionValue, read every frame without re-renders) or left to a slow open, hold and close loop. The light on the metal and the photo drift with the cursor. Blade count, colors, rotation, twist, pace and grain are props; it pauses offscreen and holds a still frame for reduced motion.
The import and the props worth knowing about, in one place.
import { ApertureReveal } from "@/components/beste/component/aperture-reveal";
<ApertureReveal className="h-[32rem] w-full" />
// Driven by scroll: pass a number from 0 (closed) to 1 (open), or a framer-motion MotionValue
const { scrollYProgress } = useScroll({ target: ref, offset: ["start start", "end end"] });
<ApertureReveal
className="absolute inset-0"
imageSrc="/photos/night-sky.jpg"
imageAlt="Snowy peaks under the Milky Way"
progress={scrollYProgress}
blades={11} // 5 to 16
bladeColor="#23201c" // any CSS color
highlightColor="#ffe9c7"
twist={0.8} // blades turn further while opening
/>Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
imageSrc | string | — | Photograph behind the iris. |
imageAlt | string | — | Alt text for the photograph. |
blades | number | — | Number of iris blades. |
bladeColor | string | — | Color of the blades and the machined ring. Any CSS color. |
highlightColor | string | — | Color of the light caught by blade edges and the ring. |
bodyColor | string | — | Color of the lens body around the ring. |
rotation | number | — | Starting angle of the blades, in degrees. |
twist | number | — | How far the blades turn while opening, 0 to 1. |
progress | number | { get: () => number } | — | 0 closed, 1 open with the ring gone past the frame. Leave unset to let autoplay run. |
autoplay | boolean | — | Open, hold and close on a slow loop. Defaults to on when no progress is given; when on, it wins over progress. |
speed | number | — | Autoplay pace, 1 is the default. |
grain | number | — | Fine grain on the metal, 0 to 1. |
interactive | boolean | — | Light on the metal and the photo follow the cursor. |
paused | boolean | — | Hold the autoplay where it is. |
className | string | — | |
children | ReactNode | — |