Skip to content
Sample of Smooth-Minimum SDF field

hodgin_iquilezles · SmoothMinSDF

Smooth-Minimum SDF field

Two animated 2D SDF primitives (a moving circle and a translating slab) are blended with Quilez's quadratic-polynomial smooth-minimum and rendered as a scalar field. The mix factor (the blend weight returned by Quilez's vec2 smin) tints the field with the colour of the dominant primitive; iso-contours are drawn as thin highlight bands. The result is a slow, organic metaball-blob visual that breathes.

Original: https://iquilezles.org/articles/smin/

▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.

Family
hodgin_iquilezles
Source
hodgin × iquilezles
Evolution
sdf
Render
scalar_field
Complexity
low
Agents
0
Year
2013
Author
Inigo Quilez

Math essence

smin_quadratic(a, b, k) = min(a, b) - h*h*k/4 with h = max(k - |a-b|, 0)/k. The blend weight m = h*h*0.5 linearly interpolates the two primitives' materials. Field shading uses 0.5 - smin/k to highlight the zero-isosurface, with iso-contours drawn at fixed step intervals to evoke Quilez's SDF debug visualisations.

Parameters

Name Type Default Range Description
dim int 360 120–800 Square output size in pixels.
radius_a float 60 10–140 Radius of the moving circle SDF.
radius_b float 50 8–140 Half-width of the moving slab SDF.
k float 35 1–120 Smooth-minimum blend thickness (px).
slab_halfwidth float 24 4–80 Half-thickness of the slab SDF.
color_a tuple 1,0.42,0.32 null–null RGB colour of primitive A (warm).
color_b tuple 0.3,0.62,1 null–null RGB colour of primitive B (cool).
background tuple 0.04,0.04,0.08 null–null Background RGB colour (used outside the field).
contour_step float 4 1–16 Iso-contour step size (in field units).

Reference

First 60 lines of reference.py. Full source: library_external/hodgin_iquilezles/SmoothMinSDF/reference.py

from __future__ import annotations

from typing import ClassVar

import numpy as np


def _smin_quadratic(a: np.ndarray, b: np.ndarray, k: float) -> np.ndarray:
    kk = k * 4.0
    h = np.maximum(kk - np.abs(a - b), 0.0) / kk
    return np.minimum(a, b) - h * h * kk * 0.25


class SmoothMinSDF:
    """Smooth-Minimum SDF field — Inigo Quilez (iquilezles.org).

    The "smooth-minimum" or "smooth-union" operator combines two signed
    distance fields into a single field whose iso-zero surface melts and
    blends the two primitives together (Quilez's *smin* article,
    https://iquilezles.org/articles/smin/).

    We render the *scalar field itself*: two animated 2D SDF metaballs —
    a circle and a horizontal slab — blended with the popular
    *quadratic-polynomial* smooth-minimum

        smin(a, b, k) = min(a, b) - h*h*k/4,  h = max(k-|a-b|, 0)/k.

    Pixels are shaded by the field value using the "mix factor" trick
    (the original Quilez vec2 smin that also returns the blend weight)
    so the two primitives are coloured in their own hues across the
    smooth transition.
    """

    family: ClassVar[str] = "hodgin_iquilezles"
    sketch: ClassVar[str] = "smoothminsdf"

    def __init__(
        self,
        dim: int = 360,
        radius_a: float = 60.0,
        radius_b: float = 50.0,
        k: float = 35.0,
        slab_halfwidth: float = 24.0,
        color_a: tuple[float, float, float] = (1.00, 0.42, 0.32),
        color_b: tuple[float, float, float] = (0.30, 0.62, 1.00),
        background: tuple[float, float, float] = (0.04, 0.04, 0.08),
        contour_step: float = 4.0,
        **_,
    ) -> None:
        self.dim = dim
        self.radius_a = float(radius_a)
        self.radius_b = float(radius_b)
        self.k = float(k)
        self.slab_halfwidth = float(slab_halfwidth)
        self.color_a = np.array(color_a, dtype=np.float32)
        self.color_b = np.array(color_b, dtype=np.float32)
        self.bg_color = np.array(background, dtype=np.float32)
        self.contour_step = float(contour_step)
        self.reset()

Try running it locally

The reference implementation is self-contained Python with numpy. Install the package and run:

python library_external/hodgin_iquilezles/SmoothMinSDF/reference.py

Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.

More from hodgin × iquilezles

Sample of Boids Flock (Hodgin Murmuration)

Boids Flock (Hodgin Murmuration)

hodgin_iquilezles · BoidsFlock

A 2D flock of boids steered by Craig Reynolds' three classic rules (separation, alignment, cohesion) over a coarse spatial-hash neighbor query.

View →
Sample of Fractional Brownian Motion noise

Fractional Brownian Motion noise

hodgin_iquilezles · FBMNoise

Quilez's canonical fBM: a 2D value-noise base summed over N octaves whose frequency doubles and amplitude is multiplied by G = exp2(-H) per octave.

View →
Sample of Magneto Particles (Hodgin Magnetosphere)

Magneto Particles (Hodgin Magnetosphere)

hodgin_iquilezles · MagnetoParticles

Particles pulled and pushed by N orbiting magnetic anchors whose charges flip sign over time.

View →
Sample of Mulberry32 PRNG (stratified scatter)

Mulberry32 PRNG (stratified scatter)

hodgin_iquilezles · Mulberry32RNG

Mulberry32 is a tiny 32-bit-state pseudo-random number generator popularised in the demoscene and used pervasively by Quilez and other graphics programmers as the RNG inside procedural sketches.

View →
Sample of Saturn Rings (orbital resonance)

Saturn Rings (orbital resonance)

hodgin_iquilezles · SaturnRings

Thousands of particles are initialized in an annulus between inner_radius and outer_radius around a central mass, with circular orbital velocities v = sqrt(M/r).

View →
Sample of Worley / Cellular Noise

Worley / Cellular Noise

hodgin_iquilezles · WorleyNoise

Quilez's classic 2D Worley noise: a unit grid of cells, each containing one pseudo-random feature point placed by a 2D integer hash.

View →

See all hodgin_iquilezles artworks →