JSFiddle - React, Tailwind, and code Playground

HTML

<div class="content">
  <img width="600" height="600"/>
  <button>Generate</button>
</div>

CSS

*, *::before, *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background: #234251;
  display: grid;
  place-items: center;
  min-height: 100vh;
}

.content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

.content img {
  border: 2px solid #2378ef;
  border-radius: 10px;
}

.content button {
  background: #5632de;
  color: azure;
  width: fit-content;
  padding: 1rem 3rem;
  font-family: monospace;
  font-size: .9rem;
  text-transform: uppercase;
  letter-spacing: .5rem;
  border: none;
  border-radius: 10px;
}

JavaScript

const img = document.querySelector("img");
const button = document.querySelector("button");

button.addEventListener("click", async () => img.src = await water_color(600, 600));

function paint(canvas, center, radius, color) {
  const context = canvas.getContext("2d");
  const brush = create_polygon({
      x: 0,
      y: 0,
    },
    radius,
    500
  );

  deform_polygon(brush, 100);

  context.globalCompositeOperation = "add";
  context.fillStyle = color;
  for (let i = 0; i < 150; i++) {
    context.translate(
      center.x + canvas.width * random(-0.2, 0.2),
      center.y + canvas.height * random(-0.2, 0.2)
    );
    context.rotate(Math.random());
    context.beginPath();
    for (let point of brush) context.lineTo(point.x, point.y);
    context.fill();
    context.setTransform(1, 0, 0, 1, 0, 0);
  }
}

function water_color(width, height) {
  const canvas = document.createElement("canvas");
  const colors = [];

  canvas.width = width;
  canvas.height = height;

  for (let i = 0; i < 3; i++)
    colors.push(
      `rgb(${~~random(100, 255)}, ${~~random(0, 255)}, ${~~random(150, 255)}, .03)`
    );

  for (let color of colors) {
    paint(
      canvas, {
        x: canvas.width / 2 + random(-200, 200),
        y: canvas.height / 2 + random(-200, 200),
      },
      10,
      color
    );
  }
  return new Promise((resolve) => resolve(canvas.toDataURL()));
}

function random(min, max) {
  return min + Math.random() * (max - min);
}

function create_polygon(center, radius, sides) {
  const inc = (Math.PI * 2) / sides;
  const points = [];

  for (let i = 0, a = 0; i < sides; i++, a += inc)
    points.push({
      x: radius * Math.cos(a) + center.x,
      y: radius * Math.sin(a) + center.y,
    });
  return points;
}

function deform_polygon(points, offset) {
  for (let point of points) {
    const xOff = offset * (1 - 2 * Math.random());
    const yOff = offset * (1 - 2 * Math.random());

    point.x += xOff;
    point.y += yOff;
  }
}