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;
}
}