Implementation Details
How it works
Built from scratch for this page — no library. A canvas rasterises the lens shape into a PNG whose red and green channels encode a per-pixel offset vector — how far the pixel there should bend, and in which direction — with the magnitude falling off from the rim inward along a signed-distance field, so the bevel stays an even width around the corners as well as the straight edges. That map drives feDisplacementMap three times over at slightly different strengths, once per colour channel, which is where the colour fringing at the rim comes from; the three are screen-blended back together and a specular pass is laid over the top.
Why the specular is on a separate canvas
The highlight rides on a second canvas rather than a spare channel of the first, because SVG filters work in premultiplied alpha and encoding it alongside the displacement crushes it to nothing exactly at the rim, where it matters most.
The trade-off
The whole chain is a plain filter: url(#…) on the content itself, which is the entire point: what bends is the live DOM, so CSS animations, video and a text selection dragged through the glass all refract with no special handling and nothing kept in sync. It is also the whole cost. The graph re-evaluates every frame the lens moves, on the main thread, at device pixel resolution — most of the work here has gone into making that cheap rather than making it prettier.
The WebKit quirk
The engines disagree in ways the spec does not settle: WebKit resolves the filter's user-space origin against the nearest transformed ancestor instead of the filtered element, so the lens has to establish a coordinate system of its own just to land in the right place.
The Chrome quirk
Chrome has one of its own: at the rim, where the map's channels sit near their extremes, Chrome measurably under-bends the refraction — worst at the corners, where two channels are extreme and opposite at once. The cause is colour management: Chromium's GPU filter path converts the displacement map into the display's colour profile before feDisplacementMap samples it, so the values the filter reads are not the ones the map encodes. Confirmed by forcing Chrome onto the sRGB profile, which brings it back in line with Safari and the spec. Not fixable from page code — the conversion is a channel-mixing matrix, not a constant, so no compensating scale cancels it.
For how this holds up against two published WebGL glass libraries over the same scene, see the follow-up comparison.