A giant word cut out of a solid surface, used as a window onto a full-bleed photo. As progress runs from 0 to 1 the camera flies straight into one letter, the middle one by default: the whole word stays intact and simply grows around a point inside that letter's stroke, on an exponential curve, so the zoom reads as a steady flight with nothing sliding. The letter opens around the camera until the photo fills the frame. The photo moves toward the camera more slowly, for a sense of depth, and drifts gently with the pointer. The word is drawn as glyph outlines on a canvas at device resolution each frame, so it stays put and crisp at every scale. Follows any progress you give it (a pinned section's scroll, a slider) or loops on its own with autoplay. Reduced motion shows a still frame.
The import and the props worth knowing about, in one place.
import { TypeWindow } from "@/components/beste/component/type-window";
<TypeWindow
word="Horizon"
imageSrc="/photos/valley.jpg"
imageAlt="A mountain valley at first light"
className="h-[40rem]"
/>
// Drive it with a pinned section's scroll
const { scrollYProgress } = useScroll({ target: sectionRef, offset: ["start start", "end end"] });
<TypeWindow
word="North"
imageSrc="/photos/fjord.jpg"
progress={scrollYProgress} // a MotionValue or a number, 0 to 1
letter={1} // fly into the "o" instead of the middle letter
surface="foreground" // cut the word from the dark surface
fontWeight={900}
className="absolute inset-0"
/>Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
word | string | — | The word cut out of the surface; the photo shows through its letters |
imageSrc* | string | — | Photo seen through the word |
imageAlt | string | — | |
letter | number | — | Index of the letter the camera flies into; defaults to the middle letter of the word |
progress | ProgressSource | number | — | How far the camera has flown in, 0 to 1. A number or a MotionValue (for example a pinned section's scroll) |
autoplay | boolean | — | Fly in and back out on a loop by itself; a MotionValue `progress` always wins, a number applies when autoplay is off |
speed | number | — | Speed of the autoplay loop |
surface | "background" | "foreground" | — | Surface the word is cut from |
fontWeight | number | — | Weight of the word; heavier weights open wider windows |
tracking | number | — | Letter spacing of the word, in em |
fit | number | — | Share of the width the word fills at rest, 0 to 1 |
depth | number | — | How much the photo moves toward the camera as it flies in, 0 to 1 |
interactive | boolean | — | The photo drifts gently with the pointer |
paused | boolean | — | Stop the autoplay loop |
className | string | — | |
children | ReactNode | — |