What's happening in the background?

Normalizing Flows: the math behind the animation

The animated background on this website is a real-time visualization of a normalizing flow, a class of generative models from machine learning that learn to transform simple probability distributions into complex ones through a sequence of invertible transformations.

How it works

A normalizing flow starts with a base distribution, which in this case, a standard 2D Gaussian (the familiar bell curve in two dimensions). It then applies a chain of learned, invertible transformations to warp this simple distribution into something far more intricate.

The key insight is the change of variables formula: if \(z = f(x)\) is an invertible transformation, then the density of the transformed variable is:

\[p_x(x) = p_z\!\bigl(f(x)\bigr) \;\left|\det \frac{\partial f}{\partial x}\right|\]

By composing multiple simple transformations $f = f_K \circ f_{K-1} \circ \cdots \circ f_1$, the log-density becomes:

\[\log p_x(x) = \log p_z(z_0) + \sum_{k=1}^{K} \log \left|\det \frac{\partial f_k}{\partial z_{k-1}}\right|\]

The architecture: Real NVP

This visualization implements a Real NVP (Real-valued Non-Volume-Preserving) flow, introduced by Dinh et al. (2017). The model uses affine coupling layers, i.e., each layer splits the input into two halves and transforms one half conditioned on the other:

\[\begin{aligned} y_{1:d} &= x_{1:d} \\ y_{d+1:D} &= x_{d+1:D} \odot e^{s(x_{1:d})} + t(x_{1:d}) \end{aligned}\]

where $s$ and $t$ are scale and translation functions. The Jacobian determinant of each coupling layer is simply $e^{\sum s_i}$, making density evaluation efficient.

The animation alternates between x-coupling and y-coupling layers (6 total), interleaved with volume-preserving rotations, to build a rich, swirling density landscape.

What you’re seeing

  • Color intensity encodes the log-density $\log p(x)$ of the transformed distribution: brighter/more saturated regions represent higher probability
  • The grid overlaid on the flow shows how the transformation warps space: where the grid lines bunch together, probability mass has been concentrated
  • Mouse movement subtly shifts the flow parameters, letting you interactively perturb the density
  • Time evolution makes the coupling layer parameters oscillate sinusoidally, creating the hypnotic swirling patterns

The entire computation runs in a WebGL fragment shader on your GPU: every pixel independently evaluates the inverse flow, computes the change-of-variables log-determinant, and maps the resulting density to a color, all at 60 fps.


You found the easter egg! 🥚