DEV Community

Alexandru Pavelescu
Alexandru Pavelescu

Posted on

Revealed: the Lando Norris website hero effect, as a 19 kB WebGL library

If you have seen the hero on landonorris.com, you know the effect: you drag the cursor across his face and a helmet appears where you pass, torn open along a wet ragged edge, then it heals back when you leave.

revealed is that effect as a library. Two images stacked in one box, the top one tears open where the visitor drags, the one underneath shows through, and it closes again behind the cursor.

A beige 1990s CRT monitor showing a 1997 website tears open along a carved edge to reveal a modern flat panel showing the same site redesigned, with a faint grey outline of the modern monitor visible over the CRT before it is uncovered

npm i revealed
Enter fullscreen mode Exit fullscreen mode
import { Revealed } from "revealed/react";

<Revealed front="/before.webp" back="/after.webp" />
Enter fullscreen mode Exit fullscreen mode

That is the whole setup. It renders one div, injects a canvas and the two image plates, takes the aspect ratio from the front image, and starts. No config, no refs, no effect hooks.

19.2 kB gzipped. Zero runtime dependencies. React is an optional peer, used only by the /react entry. There is a vanilla RevealField class and a CDN build too.

Why it does not look like a normal hover mask

I built this after failing to copy that hero. I assumed it was a brush trail: paint into a mask, decay the mask, threshold it, mix two images. Two things about theirs I could not reproduce that way. The reveal keeps spreading for about a second after you stop moving, and it has holes in it, islands of the original image standing inside an area that is otherwise uncovered.

Their bundles are on a public CDN, so I read the shader. It is not a brush trail. It is a fluid solver, and the cut thresholds the velocity field rather than a painted mask. It reveals where the fluid is moving, not where the pointer has been. That one decision is where both behaviours come from: the wave outliving the stroke is momentum, and the holes are what thresholding an incompressible field gives you, because a vortex core has no velocity at its centre while everything around it does.

revealed reproduces that character without shipping a fluid solver. The mask is RGBA8 and only the red channel holds the reveal, so the velocity lives in the two spare channels. No extra render target, no extra shader program, one extra texture fetch. WebGL1 throughout, no extensions, no float textures.

Measured on Intel integrated graphics: the leading edge travels 44px over 2.4s after the pointer stops, against a control that recedes 34px. At 1500x1192 the wave costs 11.4ms per frame versus 10.5ms without it, which is inside run-to-run noise.

Three layers, the third optional

The three layers side by side: the front plate, the back plate, and the skeleton line art

A front plate, a back plate, and an optional skeleton layer: line art of the hidden image, ghosted onto the front so people know there is something to find, and wiped exactly where the back plate is already uncovered. It can also be a real 3D wireframe, behind the revealed/mesh subpath so the core stays small.

One number, three names

<Revealed front="..." back="..." brush={{ persist: true }} />   // stays uncovered
<Revealed front="..." back="..." brush={{ spotlight: true }} /> // torch, no trail
<Revealed front="..." back="..." progress={scrollProgress} />   // no pointer at all
Enter fullscreen mode Exit fullscreen mode

persist is a heal rate of zero. spotlight is a heal rate of infinity. trail is everything in between. progress drives the same cut from scroll position, so the reveal wears the identical wet edge with no pointer involved.

The spotlight mode: a torch following the cursor with no trail behind it

Six presets

Six presets rendered at the same stroke position: liquid, dissolve, ink, shatter, clean and plain

<Revealed front="..." back="..." edge="ink" />
Enter fullscreen mode Exit fullscreen mode

liquid is the default. plain gives you a quiet, classic dissolve with no wave and no bubbles if the fluid character is not what you want.

It fails safely

The front plate is a real <img> in the DOM the whole time, so it is what you see when anything goes wrong: no WebGL, a software renderer, prefers-reduced-motion, a failed shader link, a 404 on a plate, or a lost context. A restored context brings the effect back on its own. Nothing ever renders a hole where your image should be.

It also pauses itself off screen and on hidden tabs, and it is SSR-safe: importing it on the server touches nothing, and revealed/react ships its own "use client", so no dynamic() wrapper.

Links

Other things I have made

topolines is the same idea applied to backgrounds: animated topographic contour fields for React, one component, zero dependencies, drawn on the GPU. It is what draws the contour lines behind the revealed docs site.

npm i topolines
Enter fullscreen mode Exit fullscreen mode

If you build something with either of them I would like to see it.

Top comments (1)

Collapse
 
idlecyrex profile image
Alexandru Pavelescu

A star on github would be really appreciated<3
github.com/idleCyrex/revealed