let initialStarNum = 200;
song = loadSound("Stellar Wind - Unicorn Heads.mp3");
let canvasSize = min(windowWidth, windowHeight);
createCanvas(canvasSize, canvasSize);
inColor = color("#333d9e");
outColor = color("#bbbeff");
for (let i = 0; i < initialBallNum; i++) {
ball.setPosGround(floor(random(0, 2)));
for (let j = 0; j < balls.length; j++) {
if (ball.getReflexionY() < balls[j].getReflexionY()) {
balls.splice(j + 1, 0, ball);
if (j == balls.length - 1) {
balls.splice(0, 0, ball);
for (let i = 0; i < initialStarNum; i++) {
for (let i = 0; i <= width / 2; i += 50) {
fill(3, 0, 24, map(i, 0, width / 2, 0, 255));
rect(width / 2, height / 2, width - i, height - i, 50);
for (let i = stars.length - 1; i >= 0; i--) {
rect(width / 2, height - 75, width, 150);
for (let i = 0; i <= width / 2; i += 10) {
fill(19, 0, 75, map(i, 0, width / 2, 0, 255));
rect(width / 2, height - ((150 - i) / 2), width - i, 150 - i, 50);
for (let i = 0; i <= width; i += 20) {
rect(i, height - 140, 8, 2, 50);
for (let i = balls.length - 1; i >= 0; i--) {
if (balls[i].getStartingY() == BACK) {
if (balls[i].getPositionY() <= -balls[i].size) {
ball.setPosGround(floor(random(0, 2)));
for (let j = balls.length - 1; j >= 0; j--) {
if (ball.getReflexionY() < balls[j].getReflexionY()) {
balls.splice(j + 1, 0, ball);
balls.splice(j, 0, ball);
let wave = fft.waveform();
if (pct[0] == undefined) {
for (let i = 0; i < wave.length; i++) {
for (let i = 0; i < pointNum; i++) {
let index = floor(map(i, 0, pointNum, 0, wave.length));
wavePos[index][0] = wavePos[index][1];
wavePos[index][1] = wave[index];
animPoint = lerp(wavePos[index][0], wavePos[index][1], pct[index]);
let h = constrain(animPoint * amplitude, 0, 150);
let a = cos(radians(map(i, 0, pointNum, 0, 360))) * h;
let o = sin(radians(map(i, 0, pointNum, 0, 360))) * h;
curveXPoints[i] = width / 2 + a + cos(radians(map(i, 0, pointNum, 0, 360))) * (circleSize/2);
curveYPoints[i] = height / 2 + o + sin(radians(map(i, 0, pointNum, 0, 360))) * (circleSize/2);
for (let i = 0; i < pointNum; i++) {
for (let j = 0; j < 1 - pointNum / 100; j += pointNum / 100) {
let x = curvePoint(curveXPoints[i % pointNum], curveXPoints[(i + 1) % pointNum], curveXPoints[(i + 2) % pointNum], curveXPoints[(i + 3) % pointNum], j);
let y = curvePoint(curveYPoints[i % pointNum], curveYPoints[(i + 1) % pointNum], curveYPoints[(i + 2) % pointNum], curveYPoints[(i + 3) % pointNum], j);
rotate(radians(125 + 360 / 100 * dotID));
fill(lerpColor(inColor, outColor, animPoint));
translate(width, height);
for (let i = 0; i < pointNum; i++) {
for (let j = 0; j < 1 - pointNum / 100; j += pointNum / 100) {
let x = curvePoint(curveXPoints[i % pointNum], curveXPoints[(i + 1) % pointNum], curveXPoints[(i + 2) % pointNum], curveXPoints[(i + 3) % pointNum], j);
let y = curvePoint(curveYPoints[i % pointNum], curveYPoints[(i + 1) % pointNum], curveYPoints[(i + 2) % pointNum], curveYPoints[(i + 3) % pointNum], j);
for (let i = 0; i < 10; i += 2) {
stroke(255, 10 + animPoint * 5);
strokeWeight(20 + i * 2);
circle(width / 2, height / 2, circleSize);
circle(width / 2, height / 2, circleSize);
for (let i = 0; i < 10; i += 2) {
fill(255, 0.5 + animPoint / 10);
ellipse(width / 2, height - 75, circleSize + i * 2, 60 + i * 2);
for (let i = balls.length - 1; i >= 0; i--) {
if (balls[i].getStartingY() == FRONT) {
if (balls[i].getPositionY() <= -balls[i].size) {
ball.setPosGround(floor(random(0, 2)));
for (let j = balls.length - 1; j >= 0; j--) {
if (ball.getReflexionY() < balls[j].getReflexionY()) {
balls.splice(j + 1, 0, ball);
balls.splice(j, 0, ball);
let spotPosition = sin(radians(lightTimer)) * 250;
spotPosition, height - (spotSize/2),
spotPosition - spotSize, height - (spotSize/2),
-10, height / 4 + spotSize);
arc(spotPosition - (spotSize/2), height - (spotSize/2), spotSize, 35, 0, PI);
arc(spotPosition - (spotSize/2), height - (spotSize/2), spotSize, 35, PI, TWO_PI);
for (let j = 0; j < balls[i].length; j++) {
} else if (balls[i].getPositionY() < balls[j].getPositionY()) {
balls.splice(j, 0, balls[i]);
balls.splice(j, 0, balls[i]);
if(key == 'm' || key == 'M'){