let specks;
let n = 100;
let shadow;
let nReflections;
function setup() {
createCanvas(windowWidth * 0.9, windowHeight * 0.9);
specks = [];
for (let i = 0; i < n; i++) {
newSpeck(i);
}
nReflections = int(random(5, 20));
rectMode(CENTER);
shadow = { x: 0, y: 0 };
}
function draw() {
translate(width / 2, height / 2);
t = frameCount;
background(10, 30, 40, 255 - 255 * abs(sin(t / 500) * sin(t / 500)));
shadow.x = (width / 200) * sin(t / 1000);
shadow.y = (height / 200) * cos(t / 1000);
border();
push();
rotate(t / 500);
manifest();
stir();
pop();
}
function stir() {
for (let i = 0; i < specks.length; i++) {
if (
specks[i].x > width / 1.8 ||
specks[i] < -width / 1.8 ||
specks[i].y > height / 1.8 ||
specks[i].y < -height / 1.8
) {
specks.splice(i, 1);
newSpeck(specks.length);
} else {
specks[i].x +=
specks[i].vx * sin(t / 50) * cos(t / 100) +
(specks[i].x / 1000) * cos(t / 1000);
specks[i].y +=
specks[i].vy * cos(t / 50) * sin(t / 100) +
random(-0.05, 0.05) +
(specks[i].x / 1000) * cos(t / 1000);
}
}
}
function manifest() {
noStroke();
for (let i = 0; i < specks.length; i++) {
opacity = 240 - 60 * sqrt(specks[i].size);
for (let j = 0; j < 20; j += 4) {
d = dist(specks[i].x, specks[i].y, shadow.x, shadow.y);
fill(
100 + 120 * abs(sin(d / 20)),
240,
255,
70 - 4 * specks[i].size - j * 2 - d / 20
);
for (let k = 0; k < nReflections; k++) {
push();
rotate((k * TWO_PI) / nReflections);
circle(
specks[i].x,
specks[i].y,
specks[i].size - j * (specks[i].size / 20)
);
pop();
}
}
}
}
function newSpeck(i) {
c = max(width, height);
specks[i] = {
x: randomGaussian(0, c / 10),
y: randomGaussian(0, c / 10),
vx: randomGaussian(0.2, 0.5),
vy: randomGaussian(0.2, 0.5),
size: random(1, 20)
};
}
function border() {
noFill();
stroke(20, 50, 60);
strokeWeight(4);
rect(0, 0, width - 20, height - 20);
}
function mousePressed() {
frameCount = 0;
setup();
draw();
}
function windowResized() {
resizeCanvas(windowWidth * 0.9, windowHeight * 0.9);
}