← Back to list

Monsoon Resonance: Simulating the Fluid Dynamics of a Midnight Rainstorm

“Monsoon Resonance” is a generative media art piece that visualizes the quiet, meditative beauty of summer raindrops falling onto a dark…

asamiile in Kinomoto AI · 2026-06-26 03:06 · 0 claps · 3.8 min read paywalled
#claude-code #ai-agent #python #generative-art #mcp-server
Open on Medium ↗
Wiki topics: LLM · Large Language Models AGT · AI Agents 💄 · Beauty

Monsoon Resonance: Simulating the Fluid Dynamics of a Midnight Rainstorm

[embed]

“Monsoon Resonance” is a generative media art piece that visualizes the quiet, meditative beauty of summer raindrops falling onto a dark pond at midnight. Moving away from abstract geometry and high-energy collisions, this piece embraces a deep, organic naturalism. Silver and cyan ripples bloom into expanding concentric rings, gracefully interfering with one another to form a hypnotic, shimmering tapestry against a deep indigo background. Python and the py5 library provided the ideal foundation, leveraging NumPy’s vectorized operations to perform fluid dynamic physics calculations and directly manipulate raw pixel buffers at 60 frames per second.

Visual & Aesthetic Approach

The aesthetic of “Monsoon Resonance” is cinematic and grounded in physical realism. Instead of using complex 3D meshes to simulate water, the artwork relies on a 2D scalar wave field combined with a custom, shader-like coloring technique. The scene isolates the surface of the pond as a dark-field environment, illuminated only by a soft, diffuse moonlight and the faint, warm reflection of a distant amber lamp on the far shore.

The color palette is derived directly from the physical height of the simulated waves. The peaks of the ripples catch a brilliant Pearl and Cyan moonlight, while the troughs sink into a deep, near-black Indigo. By compressing the dynamic range and applying subtle specular highlights, the 2D data reads as a highly viscous, reflective 3D surface. The resulting animation perfectly captures the rhythmic, breathing cadence of a midnight monsoon.

Code & Technical Breakdown

The core of the simulation is a Finite-Difference Time-Domain (FDTD) implementation of the 2D wave equation. This algorithm calculates how wave energy propagates through a grid over time. This is handled entirely in NumPy within the step_wave() function.

# From step_wave()
def step_wave() -> None:
    """One FDTD step of the 2D wave equation."""
    global u, u_prev
    # 5-point Laplacian without boundary reflections (use zero padding)
    lap = np.zeros_like(u)
    lap[1:-1, 1:-1] = (
        u[:-2, 1:-1] + u[2:, 1:-1]
        + u[1:-1, :-2] + u[1:-1, 2:]
        - 4.0 * u[1:-1, 1:-1]
    )
    u_next = (2.0 * u - u_prev + WAVE_SPEED_SQ * lap) * DAMPING
    # Soft border absorber — fade values in margin zone
    u_next *= BORDER
    u_prev, u = u, u_next

Why this works: The wave equation requires knowing the current state (u), the previous state (u_prev), and the spatial curvature (the Laplacian) of the surface. By slicing the NumPy arrays (u[:-2, 1:-1], etc.), the code calculates a 5-point discrete Laplacian across the entire 480x270 grid instantly without a single Python for loop. The formula *2.0 u — u_prev represents the momentum of the wave, while the Laplacian acts as the restoring force of surface tension. Crucially, multiplying the grid by the BORDER** mask smoothly dampens the energy near the edges of the simulation, ensuring that the ripples gently fade out rather than violently reflecting off the invisible walls like a bathtub.

A realistic pond needs realistic raindrops. Simply adding a single spike of energy to the grid creates a single, unrealistic expanding ring. Instead, the simulation injects a “Mexican-hat” impulse.

# From add_drop()
def add_drop(cx: float, cy: float, strength: float, sigma: float) -> None:
    # ... boundary checks omitted for brevity ...
    yy, xx = np.ogrid[y0:y1, x0:x1]
    r2 = (xx - cx) ** 2 + (yy - cy) ** 2
    s2 = sigma * sigma

    # Mexican hat profile, normalized so peak ≈ strength
    profile = (1.0 - r2 / (2.0 * s2)) * np.exp(-r2 / (2.0 * s2))
    u[y0:y1, x0:x1] += (strength * profile).astype(np.float32)

Why this works: The Mexican-hat profile (technically the Laplacian of a Gaussian) defines a positive central peak surrounded by a shallow, negative annular trough. When injected into the physics grid, this specific shape perfectly seeds the generation of multiple, trailing concentric bands as the wave propagates outward. This perfectly mimics the physical displacement of water caused by a real raindrop breaking the surface tension.

Translating the raw physics grid into the final cinematic image requires a highly custom rendering pipeline.

# From render_to_rgb()
# Signed deflection — positive = crest, negative = trough
pos = np.clip(u, 0.0, None)
neg = np.clip(-u, 0.0, None)

# Compress dynamic range so faint ripples register without saturating
crest = np.tanh(pos * 4.0)
trough = np.tanh(neg * 4.0)

# Sharp specular: only the very highest peaks reflect bright pearl
sharp = np.clip(pos * 6.0 - 0.55, 0.0, None) ** 1.6
sharp = np.clip(sharp, 0.0, 1.6)

# ... blending logic ...

Why this works: This function acts as a software shader. It splits the simulation grid (u) into positive crests and negative troughs. By passing these values through a hyperbolic tangent function (np.tanh()), the code compresses the dynamic range, allowing faint, distant ripples to remain visible without the central, high-energy impact zones blowing out to pure white. The sharp array acts as a harsh specular threshold, ensuring that only the absolute highest peaks of the waves catch the brilliant Pearl moonlight. This multi-layered approach gives the final image a profound sense of depth, liquidity, and realism.

Conclusion

“Monsoon Resonance” stands as a testament to the power of simulating underlying physical realities rather than attempting to fake them with noise or textures. By implementing a true FDTD wave equation and pairing it with a carefully tuned, physically inspired rendering pipeline, the artwork achieves a breathtaking level of naturalism. Implementing this in py5 and NumPy proves that Python is not just a language for data science, but a robust environment for creating deeply emotive, high-performance generative art.

GitHub (this work): https://github.com/asamiile/py5-media-art/tree/main/sketch/monsoon_resonance

YouTube: Generative Art Playlist

Portfolio: asami.tokyo

Purchase assets: Adobe Stock

Support this project: Buy Me a Coffee


메타데이터
post_id
faebd18d3f9b
slug
monsoon-resonance-simulating-the-fluid-dynamics-of-a-midnight-rainstorm-faebd18d3f9b
url
https://medium.com/kinomoto-mag/monsoon-resonance-simulating-the-fluid-dynamics-of-a-midnight-rainstorm-faebd18d3f9b
canonical_url
https://medium.com/kinomoto-mag/monsoon-resonance-simulating-the-fluid-dynamics-of-a-midnight-rainstorm-faebd18d3f9b
author_url
https://medium.com/@asamiile
status
ok
fetched_at
2026-07-09 13:13:48