Skip to content
Sample of GAN Watercolor (Helena Sarin — Neural Bricolage / #latentDoodles)

ml_artists · SarinWatercolor

GAN Watercolor (Helena Sarin — Neural Bricolage / #latentDoodles)

Inspired by Helena Sarin's Neural Bricolage practice (#latentDoodles, GAN Weaver, The Book of veGAN): she trains GANs on her own watercolor paintings and sketches, then curates the output back into analog paintings. We replicate the kernel: a small Sarin-style palette of 5-7 colours; per step, paint a few curved strokes whose colour is sampled (with mild jitter) from the palette; each stroke is composited with low alpha for true watercolor translucency; after each batch a 1D vertical Gaussian 'bleed' simulates pigment diffusion through paper; the whole canvas slowly fades toward paper-white so older strokes become ghostly underlayers. The output is a layered Sarin-flavoured watercolor, not a photoreal GAN image — the algorithmic structure is the same.

Original: https://www.artnome.com/news/2018/11/14/helena-sarin-why-bigger-isnt-always-better-with-gans-and-ai-art

▶ 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
ml_artists
Source
ml artists
Evolution
particle
Render
watercolor_layers
Complexity
medium
Agents
4
Year
2018
Author
Helena Sarin (concept)

Math essence

Stroke is a densely-sampled curved path through 3-5 control points; rasterised as a Gaussian-thickness mask onto a float canvas; composited with alpha α. Vertical bleed = 1-D Gaussian convolution along y (kernel σ). Global fade: canvas ← canvas · γ + (1-γ)·paper. Palette is a K-row RGB table (3 fixed Sarin palettes or a low-frequency HSV random walk).

Parameters

Name Type Default Range Description
dim int 600 200–1500 Square canvas side length (px).
n_palette int 6 2–16 Number of palette colours K (Sarin: 5-7).
palette_seed int 20240601 0–2147483647 Seed for synthetic palette in 'random' mode.
strokes_per_step int 4 1–40 Strokes painted per step.
alpha float 0.06 0.001–0.5 Per-stroke opacity (low values = watercolor layering).
bleed_sigma float 1.4 0–8 Vertical bleed Gaussian sigma (0 disables).
fade float 0.997 0.9–1 Per-step multiplicative canvas fade.
palette_name str sarin_warm null–null sarin_warm|sarin_cool|sarin_folk|random.

Reference

First 60 lines of reference.py. Full source: library_external/ml_artists/SarinWatercolor/reference.py

"""SarinWatercolor — Helena Sarin "GAN + watercolor" kernel.

Helena Sarin works at the seam of GANs and analog watercolor: she
trains generative models on her own watercolor paintings and sketches
("#latentDoodles", *An Eternal Tangle of What Ifs*, *GAN Weaver*),
then curates the output back into physical paintings.  Her aesthetic
is a *low-frequency palette with watercolor bleed*: a small handful
of colours per piece, layered translucently, with the soft wet-blur
edges that come from pigment diffusion in paper.

We replicate the algorithmic kernel:
  1. Maintain a small fixed palette of K colours (Sarin-style: 5-7).
  2. At each step, pick a palette colour and stroke shape (a
     parametric cubic spline or short curve segment with a few
     control points).
  3. Paint the stroke into a float canvas with low alpha so layers
     accumulate translucently.
  4. Apply a vertical "wet bleed" — a 1D Gaussian blur along the
     y-axis — *after* each stroke, mimicking watercolor diffusion
     through paper grain.
  5. Slowly fade the whole canvas so newer strokes dominate while
     older ones remain as ghostly underlayers.

References:
- https://www.artnome.com/news/2018/11/14/helena-sarin-why-bigger-isnt-always-better-with-gans-and-ai-art
- https://www.nvidia.com/en-us/research/ai-art-gallery/artists/helena-sarin/
- https://aiartists.org/helena-sarin
"""
from __future__ import annotations

from typing import ClassVar

import numpy as np


class SarinWatercolor:
    """Layered watercolor strokes sampled from a small Sarin-style palette.

    Parameters
    ----------
    dim : int
        Square canvas side length (px).
    n_palette : int
        Number of palette colours K (Sarin typically uses 5-7).
    palette_seed : int
        Seed used to draw the synthetic palette from a low-frequency
        random walk.
    strokes_per_step : int
        Strokes drawn per ``step`` call.
    alpha : float
        Per-stroke opacity (kept low for true watercolor layering).
    bleed_sigma : float
        Vertical bleed Gaussian sigma (px).  0 disables bleed.
    fade : float
        Per-step multiplicative canvas fade (close to 1.0 keeps old
        strokes; lower lets newer ones dominate).
    palette_name : str
        ``"sarin_warm"``, ``"sarin_cool"``, ``"sarin_folk"`` or
        ``"random"`` for a generated palette.
    """

Try running it locally

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

python library_external/ml_artists/SarinWatercolor/reference.py

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

More from ml artists

Sample of DeepDream Field (Mike Tyka — AI: DeepDream / Inceptionism)

DeepDream Field (Mike Tyka — AI: DeepDream / Inceptionism)

ml_artists · TykaDeepDreamField

Inspired by Mike Tyka's AI: DeepDream series (2015-) and his co-authorship of 'Inceptionism: Going Deeper into Neural Networks' with Mordvintsev and Olah.

View →
Sample of Glitch (Mario Klingemann — glitch-print aesthetic)

Glitch (Mario Klingemann — glitch-print aesthetic)

ml_artists · KlingemannGlitch

Klingemann's practice amplifies the visible failure modes of digital pipelines — distorted faces mid-decode, colour-shifted artefacts, rectangular datamosh tears — into the subject matter itself.

View →
Sample of Memories of Passersby (Mario Klingemann — Memories of Passersby I)

Memories of Passersby (Mario Klingemann — Memories of Passersby I)

ml_artists · KlingemannMemorex

Inspired by Mario Klingemann's Memories of Passersby I (2018, Sotheby's) — a custom GAN trained on 17th–19th-century portraits that runs forever, never repeats an output, and 'observes itself' in a feedback loop.

View →
Sample of Neural Biodiversity (Sofia Crespo — Neural Zoo / Artificial Natural History)

Neural Biodiversity (Sofia Crespo — Neural Zoo / Artificial Natural History)

ml_artists · CrespoNeuralBiodiversity

Inspired by Sofia Crespo's Neural Zoo (2018-), Artificial Natural History (2019-), and Beneath the Neural Waves (2021): she uses 3D GANs, CNN-based texture synthesis and 3D style transfer to fabricate a 'natural history book that never was' — chimerical creatures whose anatomies recombine fragments of real species.

View →
Sample of Style Transfer Field (Gene Kogan — ml4a)

Style Transfer Field (Gene Kogan — ml4a)

ml_artists · KoganStyleTransferField

Inspired by Gene Kogan's Experiments with Style Transfer and the ml4a curriculum: neural style transfer iteratively updates an image so its Gram-matrix feature statistics match a style reference — the gradient of the style loss with respect to pixels defines a vector field.

View →

See all ml_artists artworks →