let palette, circleA, circleB, particles, squareParticles;
createCanvas(windowWidth, windowHeight);
circleA = generateCircle();
circleB = generateCircle();
particles = generateParticles(width * height / 10800);
squareParticles = generateParticles(width * height / 13500);
strokeWeight(min(width, height) / 27);
function isPointInCircle(p, c) {
return p.dist(c.pos) < c.d / 2
function isPointOnCircle(p, c) {
return abs(p.dist(c.pos) ** 2 - (c.d / 2) ** 2) < c.d;
function fillIntersection(circleA, circleB) {
let xMin = max(circleA.pos.x - circleA.d / 2, circleB.pos.x - circleB.d / 2);
let xMax = min(circleA.pos.x + circleA.d / 2, circleB.pos.x + circleB.d / 2);
let yMin = max(circleA.pos.y - circleA.d / 2, circleB.pos.y - circleB.d / 2);
let yMax = min(circleA.pos.y + circleA.d / 2, circleB.pos.y + circleB.d / 2);
for (let y = yMin; y <= yMax; y++) {
for (let x = xMin; x <= xMax; x++) {
const p = createVector(x, y);
const inCircleA = isPointInCircle(p, circleA);
const inCircleB = isPointInCircle(p, circleB);
const onCircleA = isPointOnCircle(p, circleA);
const onCircleB = isPointOnCircle(p, circleB);
if ((onCircleA && inCircleB) || (onCircleB && inCircleA)) {
stroke(lerpColor(circleA.colour, circleB.colour, 0.5));
fill(c.colour.levels[0], c.colour.levels[1], c.colour.levels[2], 54);
circle(c.pos.x, c.pos.y, c.d);
function generateCircle() {
const c = random(palette);
palette.splice(palette.indexOf(c), 1);
const maxVel = min(width, height) / 72;
pos: createVector(random(width * 1 / 3, width * 2 / 3), random(height * 1 / 3, height * 2 / 3)),
d: min(width, height) / 3,
vel: createVector(random(-maxVel, maxVel), random(-maxVel, maxVel)),
if (c.pos.x - c.d / 2 < 0 || c.pos.x + c.d / 2 > width) {
if (c.pos.y - c.d / 2 < 0 || c.pos.y + c.d / 2 > height) {
function generateParticles(n) {
for (let i = 0; i < n; i++) {
pos: createVector(random(width), random(height)),
vel: createVector(random(-1, 1), random(-1, 1)),
function moveParticle(p) {
if (p.pos.x < 0 || p.pos.x > width) {
if (p.pos.y < 0 || p.pos.y > height) {
function drawParticle(p) {
stroke(p.colour.levels[0], p.colour.levels[1], p.colour.levels[2], 77);
function drawSquareParticle(p) {
stroke(p.colour.levels[0], p.colour.levels[1], p.colour.levels[2], 177);
square(p.pos.x, p.pos.y, 1)
particles.forEach(drawParticle);
squareParticles.forEach(drawSquareParticle);
fillIntersection(circleA, circleB);
particles.forEach(moveParticle);
squareParticles.forEach(moveParticle);
function mouseClicked() {