Neon Topography: Tracing Contour Flows with Py5 and Noise Gradients

2026/8/31

Generative art often finds its most compelling aesthetics when modeling mathematical structures hidden in nature. My latest piece, a generative topographic map, visualizes an unseen terrain where 15,000 glowing particles continuously trace the contour lines of a slowly shifting 3D Perlin noise landscape.Imagine looking down at a dark void where electric purple and bright pink streams of light flow seamlessly, mapping out invisible mountains and valleys. The streams weave intricately alongside one another without intersecting, leaving glowing trails that gradually build up into complex, shifting topographical rings and fluid structures. It’s an exercise in visualizing vector fields with high density.Python and the py5 library proved to be the ideal tooling for this particular concept. Calculating vector gradients and updating physics for thousands of particles on a frame-by-frame basis requires robust math operations, which Python's NumPy handles gracefully. Py5 then provides the pristine canvas and additive blending operations needed to transform these raw coordinates into cinematic, glowing streaks of light.

Visual & Aesthetic Approach

The core technique behind this animation is the computation of a 2D gradient from a continuously evolving Perlin noise field. By finding the direction of the steepest ascent (the gradient) and rotating those vectors by 90 degrees, the particles flow perfectly perpendicular to the slope. This means they perpetually trace the contour lines of the noise terrain.To achieve the "Neon Topography" look, I employed py5's ADD blend mode alongside a semi-transparent black fade drawn over the canvas each frame. As particles move, their glowing trails overlap and accumulate brightness, simulating long-exposure photography. The palette revolves around electric purples and bright pinks, which dynamically shift depending on the underlying noise elevation, bringing a deep-sea luminescence and high-tech cinematic tone to the piece.

Code & Technical Breakdown

The heavy lifting happens within the draw loop, where we calculate the noise field, derive its gradients, and update our 15,000 particles. To keep performance manageable, a lower-resolution noise grid is precomputed and its gradients are extracted using NumPy.
# Precompute noise grid for fast gradient lookup
grid_res = 10
cols = py5.width // grid_res + 2
rows = py5.height // grid_res + 2

noise_grid = np.zeros((rows, cols), dtype=np.float32)
for r in range(rows):
    for c in range(cols):
        noise_grid[r, c] = py5.noise(c * grid_res * noise_scale, r * grid_res * noise_scale, time_val)
        
# Compute gradients of the grid
dy, dx = np.gradient(noise_grid)
By computing np.gradient, we immediately get the dx and dy matrices representing the slope across the entire canvas. Next, we map our particle coordinates to this grid and calculate their velocities:
# Map particle positions to grid indices
c_idx = (pos[:, 0] / grid_res).astype(np.int32)
r_idx = (pos[:, 1] / grid_res).astype(np.int32)

# Get gradient
grad_x = dx[r_idx, c_idx]
grad_y = dy[r_idx, c_idx]

# Vector perpendicular to gradient traces the contour line: (-grad_y, grad_x)
vx = -grad_y
vy = grad_x

# Normalize velocity
v_mag = np.sqrt(vx**2 + vy**2) + 0.0001
vx = (vx / v_mag) * dt
vy = (vy / v_mag) * dt
This simple 90-degree rotation (-grad_y, grad_x) is the mathematical heart of the sketch. It takes vectors pointing straight uphill and turns them sideways. The particles are thus locked into traversing the ridges and valleys of the noise space.Finally, we translate the abstract math into the neon aesthetic by tying particle color directly to the underlying noise field:
# Color shifts based on local noise value to highlight contours
local_noise = noise_grid[r_idx[i], c_idx[i]]
# 280 (purple) to 340 (pink) + noise mapping
hue = (hues[i] + local_noise * 100 + time_val * 20) % 360

# Additive drawing with low opacity
py5.stroke(hue, 80, 90, 40)
py5.line(pos[i, 0], pos[i, 1], new_x[i], new_y[i])
Py5’s HSB color mode allows us to smoothly shift hues. By adding the local_noise and an advancing time_val to the base hue, the topographical map gains an extra dimension of visual depth, smoothly rippling through the purple and pink spectrum as the landscape evolves.
kinetic math topological contour flow 2d p1

Conclusion

This work beautifully demonstrates how mathematical abstractions—specifically vector fields and gradients—can directly translate into organic, mesmerizing visuals. The combination of py5 and NumPy bridges the gap between data visualization and generative art, allowing us to render dense, complex particle systems that look and feel alive.