Curl Fields

Created July 3, 2025 (Today)Updated July 3, 2025 (Today)

What is "Curl"?

In vector calculus, curl measures the rotation or circulation of a vector field around a point. Imagine placing a pinwheel at a point, if the pinwheel rotates, then the curl is non-zero.

  • Think of curl as "how much the field wants to twist around a point"
  • In 2D, curl is a scalar:
    • Positive = counterclockwise spin
    • Negative = clockwise spin
    • Zero = no net spin

Curl is a numerical value that describes how a vector field "twists" at a given point.

2D vector field

function vectorField(x, y) {
    // return {
    //     x: -y,
    //     y: x,
    // }

    // const angle = Math.atan2(y, x)
    // return {
    //     x: -Math.cos(angle),
    //     y: -Math.sin(angle),
    // }

    return {
        x: Math.sin(y),
        y: Math.cos(x),
    }
}
Imagine dropping ping pong balls into this field

Computing Curl

For a 2D vector field, the curl is defined as:

×F=(FyxFxy)z^\nabla \times \vec{F} = \left( \frac{\partial F_y}{\partial x} - \frac{\partial F_x}{\partial y} \right) \hat{z}

(TODO: I don't know what this formula means or if its right)

∂Q/∂x  (Q(x + h, y) - Q(x - h, y)) / (2 * h)
∂P/∂y  (P(x, y + h) - P(x, y - h)) / (2 * h)

We can estimate the curl at a point by taking the difference between the vector field at a point and the vector field at a nearby point (finite difference method).

function curlAt(x, y, vectorFn, h = 0.001) {
    // Q = y-component
    const Q_forward = vectorFn(x + h, y).y
    const Q_backward = vectorFn(x - h, y).y
    const dQdx = (Q_forward - Q_backward) / (2 * h)

    // P = x-component
    const P_forward = vectorFn(x, y + h).x
    const P_backward = vectorFn(x, y - h).x
    const dPdy = (P_forward - P_backward) / (2 * h)

    return dQdx - dPdy
}
Curl field visualization

TODO: flow particles using curl field instead of vector field Explain how no sources and sinks makes for a better visualization

Further Research

  • Implement with Perlin noise fields