Caustic Light Pool
Water caustics computed from the real focusing condition, so the bright filaments land where the physics puts them.
- Category
- Backgrounds
- Added
- 2026-09-21
- Deps
- none
- Updated
- 2026-09-21
This is a viberdy Pro component
The live preview, the props panel and the write-up are open to everyone. The full source, the AI prompt and CLI install are part of Pro.
Props
"use client";
import { useEffect, useRef } from "react";
/**
* Water caustics, computed from the actual focusing condition.
*
* A caustic is not "the bright bit of a wave". It is where a bundle of
* refracted rays COLLAPSES — where the Jacobian of the map from the water
* surface to the pool floor goes to zero. For a height field h that determinant
* is (1 + d*hxx)(1 + d*hyy) - (d*hxy)^2, and because h here is a sum of sines,
* every second derivative is available analytically. No finite differences, no
* sampling error, and the bright filaments land exactly where the physics puts
* them rather than roughly where a |sin| happens to peak.
*/
function hexToRgb(hex: string): [number, number, number] {
const h = hex.replace("#", "");
const n = parseInt(h.length === 3 ? h.split("").map((c) => c + c).join("") : h, 16);
// ---------------------------------------------------------------
// Full source available with a viberdy Pro subscription.
// https://viberdy.dev/pricing
// ---------------------------------------------------------------
}About this background
Nearly every caustics effect on the web maps a wave height, or the absolute value of a sine, straight to brightness — which gives soft overlapping blobs and never quite reads as water. A caustic is a focusing phenomenon: it is where a bundle of refracted rays collapses onto the same patch of floor, which happens where the Jacobian of the surface-to-floor map goes to zero. Modelling the surface as a sum of sines makes that determinant analytic, because every second derivative of a sine is another sine, so the bright filaments land exactly where the physics puts them with no finite differences and no sampling error. Three choices around that carry the result. Brightness comes from a Lorentzian rather than the raw reciprocal of the determinant, because one over a quantity that reaches zero is unbounded and clips into blown-out speckle with banding at the edge of the clamp — the Lorentzian is a bounded smoothed delta whose width parameter is literally the filament thickness. The wave directions are spaced by the golden angle with non-integer frequency ratios, since evenly spaced angles or integer ratios make the sum periodic and a periodic caustic reads as a plaid. And the field is rendered into a quarter-scale buffer that the browser stretches, because per-pixel JavaScript at full resolution runs at single-figure frame rates while the upscale is invisible on something this low-frequency.
Curator’s note
Set optical depth to zero: the light goes flat. Everything you recognise as water is the determinant crossing zero.
Pairs well with
Matched on shared tags and category — the entries most likely to be used alongside this one.
Flow Field Drift
backgroundsParticles carried through a divergence-free curl-noise field, so the frame never drains into a few basins.
Topographic Contour Drift
backgroundsA survey map of terrain that never existed, traced live with marching squares and drifting underfoot.
Reaction Diffusion Plate
backgroundsA live Gray-Scott solver as a background plate — coral, mitosis and maze are the same two equations at different feed and kill rates.