Refractive Gallery
An infinite draggable gallery viewed through a refractive lens, with chromatic aberration, refraction strength, zoom and damping all exposed. Ships a small keyframe stylesheet alongside the component.
Included with membership
Members install Refractive Gallery with one command and get the full source, the usage code and the Framer remix, licensed for client work. One membership covers the whole library and the CLI.
When to use it
A landing surface or an archive that is meant to be wandered rather than read — the grid has no beginning or end and the lens rewards moving the pointer around. It is a mood piece, not navigation: nothing about it tells a visitor where they are or how much there is.
- Ship a small copy of every image at <dir>/thumbs/<name>.webp. The grid tiles come from there, not from the paths you pass.
- Give the parent a real height — the gallery fills its container and an unsized parent collapses it to nothing.
- Pass a handful of images. They repeat to fill the grid, so more variety costs texture memory for little gain.
- Raise radius for a heavier, slower lens and lower it for a tight loupe.
Avoid:
- Do not pass paths without the thumbs copies in place. Every tile 404s, the grid renders black, and the lens still works — which makes it look like a shader bug rather than a missing file.
- Do not use it where someone needs to find a specific image. The grid wraps forever and there is no ordering to rely on.
- Do not put it inside a scrolling column; it captures the wheel to pan, and the page underneath stops scrolling.
Props
An endless grid of thumbnails with a glass lens following the cursor. Whatever passes under the lens is magnified and split into colour at its edges. The grid wraps in every direction, so there is no end to scroll to.
<RefractiveInfiniteGallery />
The grid and its lens. Fills its container, so give the parent a height.
| Prop | Type | Default | Description |
|---|---|---|---|
images* | string[] | — | Pictures to fill the grid. Required. They repeat to cover the full grid, so a handful is enough. Each one is drawn twice, at two sizes — see the note on the small copies below, because the grid renders black without them. |
zoom | number | 1.5 | How much the lens magnifies what is under it. |
radius | number | 260 | Size of the lens in pixels. |
damping | number | 0.30 | How quickly the lens follows the cursor. Lower makes it trail further behind; 1 pins it to the pointer. |
chromaticAberration | number | 0.014 | How far the colour channels separate at the lens edge. Small values read as real glass; large ones as an effect. |
refraction | number | 0.0 | How much the lens bends what is under it, on top of magnifying. Off by default — raise it for a rounder, heavier lens. |
itemSize | number | 50 | Size of one thumbnail in the grid. |
gap | number | 20 | Space between thumbnails. |
edgeFade | boolean | true | Fades the grid out toward the edges of the container so it does not stop abruptly. |
className | string | "" | Applied to the wrapper. |
mount | "auto" | "eager" | "eager" | When to build the lens. The default builds it on mount. Set "auto" to wait until the gallery is near the viewport and the page has frame headroom. Neither setting takes it off the shared frame loop or overrides the reduced-motion preference. A scene running its own loop would be invisible to the scheduler, so it could not be set aside under load, and it would slow every other animation on the page rather than only itself. |
thumbs folder and switching the extension to .webp. /gallery/car.png is read as /gallery/thumbs/car.webp. If that file is not there the tile request 404s and the tile stays fully transparent, which shows up as a black grid with a working lens — the single most common way to get this component wrong. Either ship the small copies alongside the originals, or pass paths that already sit in a thumbs folder, which are used as-is for both.