How it works
Each card is a plane in its own <View>; UVs are displaced in the fragment shader by distance to the (smoothed) hover point, gated by an animated uHover.
WebGL image planes that wave, ripple or split RGB channels under the cursor.
Each card is a plane in its own <View>; UVs are displaced in the fragment shader by distance to the (smoothed) hover point, gated by an animated uHover.
Renders through the single shared <Canvas> via drei <View> — no extra WebGL context, and the render loop only runs while a view is mounted. Textures are loaded once via useTexture and shared.
Real <img> alt text sits underneath for screen readers; reduced mode keeps the image static.
// uMode: "wave" uniform float uStrength; // 0.5 uniform float uFrequency; // 10 uniform float uRadius; // 0.35