A rough first attempt at recreating Tyler Hobbs' wonderful generative watercolour effect, this time in Javascript rather than Processing as in Tyler's original. Uses Rob Britton's randgen.js to generate the Gaussian random numbers required in the polygon deformation step.
Double-click anywhere in the canvas to “paint” a blotch of colour (currently set to use hues from blue-green to pink-purple, see line 108 of index.html).
xxxxxxxxxx
<html lang="">
<head>
<meta charset="utf-8">
<title>Canvas watercolour</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdn.jsdelivr.net/npm/d3@12.10.3/d3.min.js"></script>
<script src="https://unpkg.com/d3-selection-multi"></script>
<script src="randgen.js"></script>
<style>
canvas{border: 1px solid #aaaaaa;}
</style>
</head>
<body>
<canvas></canvas>
<script type='text/javascript'>
let width = 600,
height = 600,
PR = window.devicePixelRatio || 1,
scaledWidth = width*PR,
scaledHeight = height*PR;
const canvas = d3.select('canvas')
.attrs({
width: scaledWidth,
height: scaledHeight,
})
.styles({
width: `${width}px`,
height: `${height}px`
});
const context = d3.select('canvas').node().getContext("2d");
context.scale(PR, PR);
context.clearRect(0,0, scaledWidth, scaledHeight);
context.lineWidth = 1;
context.globalCompositeOperation = 'multiply;'
function makeShape(x, y, radius){
return [
[x, y-radius],
[x+(radius*.65), y-(radius*.65)],
[x+radius, y],
[x+(radius*.65), y+(radius*.65)],
[x, y+radius],
[x-(radius*.65), y+(radius*.65)],
[x-radius, y],
[x-(radius*.65), y-(radius*.65)],
]
}
function deform(points, factor){
let newPoints = [],
midX, midY, rangeX, rangeY;
for(let p=0; p<points.length; p++){
newPoints.push(points[p]);
if(p == points.length-1){
midX = d3.mean([points[p][0], points[0][0]]);
midY = d3.mean([points[p][1], points[0][1]]);
rangeX = Math.abs(points[p][0]-points[0][0]);
rangeY = Math.abs(points[p][1]-points[0][1]);
}else{
midX = d3.mean([points[p][0], points[p+1][0]]);
midY = d3.mean([points[p][1], points[p+1][1]]);
rangeX = Math.abs(points[p][0]-points[p+1][0]);
rangeY = Math.abs(points[p][1]-points[p+1][1]);
}
let newX = rnorm(midX, rangeX*factor),
newY = rnorm(midY, rangeY*factor);
newPoints.push([newX, newY]);
}
newPoints.push(points[0]);
return newPoints;
}
function draw(points){
context.beginPath();
context.moveTo(points[0][0], points[0][1]);
for(let v=1; v<points.length; v++){
context.lineTo(points[v][0], points[v][1]);
}
context.closePath();
context.fill();
}
function paint(shape, colour, deforms, layers){
context.fillStyle = colour;
for(let l=0; l<layers; l++){
let layer = shape;
for(let it=0; it<=deforms; it++){
layer = deform(layer, 0.8);
if(it == deforms){
draw(layer);
}
}
}
}
d3.select(window).on('dblclick', () => {
let trans = d3.mouse(canvas.node());
let shape = makeShape(trans[0], trans[1], 50),
maxIt = 1;
for(let it=0; it<=maxIt; it++){
shape = deform(shape, 0.5);
if(it == maxIt){
paint(shape, `hsla(${Math.random()*150+150},70%,50%,0.005)`, 8, 50);
}
}
});
</script>
</body>
</html>
Updated missing url https://unpkg.com/d3/build/d3.min.js to https://cdn.jsdelivr.net/npm/d3@12.10.3/d3.min.js
https://unpkg.com/d3/build/d3.min.js
https://unpkg.com/d3-selection-multi