var colors = ["#FFD50F","#FF4F00", "#FF6DA5","#581845", "#900C3F", "#C70039","#1EE1DE"];
song = loadSound('Ash - Daydream.mp3.mp3');
SIZE = min(windowWidth, windowHeight);
createCanvas(windowWidth, windowHeight);
var spectrum = fft.analyze();
var bass = fft.getEnergy("bass");
var treble = fft.getEnergy(100, 200);
var colorSpeed = map(bass, 0, 255, 0.5, 5) + map(treble, 0, 255, 0.5, 5);
const SEGMENTS = random(5, 10);
var screenPct = min(height, width) / 1000;
INNER_RADIUS = screenPct * 50;
RADIUS_VARIATION = screenPct * 800;
for (var i = 0; i < SEGMENTS; i++) {
iniVertices.push(pointForIndex(i / SEGMENTS, width / 2, height / 2));
const valX = iniVertices.map(d => d.x);
const valY = iniVertices.map(d => d.y);
const minX = Math.min(...valX);
const maxX = Math.max(...valX);
const minY = Math.min(...valY);
const maxY = Math.max(...valY);
const centerX = (maxX - minX) / 2 + minX;
const centerY = (maxY - minY) / 2 + minY;
randomFill(centerX, centerY, colorSpeed);
var hobbyPoints = createHobbyBezier(iniVertices, { tension: 1, cyclic: true });
vertex(iniVertices[0].x, iniVertices[0].y);
hobbyPoints.forEach(({ startControl, endControl, point }) => {
bezierVertex(startControl.x, startControl.y, endControl.x, endControl.y, point.x, point.y);
let polygon = createPolygon(iniVertices);
const area = sqrt(pow(polygon.maxX - polygon.minX, 2) + pow(polygon.maxY - polygon.minY, 2));
for (var i = 1; i <= 3; i++) {
drawingContext.fillStyle = "black";
randomFill(centerX, centerY, i % 2 == 0 ? -i : i);
const vertices = getPaddingVertices(polygon, area / 30);
hobbyPoints = createHobbyBezier(vertices, { tension: 1, cyclic: true });
vertex(vertices[0].x, vertices[0].y);
hobbyPoints.forEach(({ startControl, endControl, point }) => {
bezierVertex(startControl.x, startControl.y, endControl.x, endControl.y, point.x, point.y);
polygon = createPolygon(vertices);
function randomFill(x, y, vel) {
const ctx = drawingContext;
const gradient = ctx.createConicGradient(frameCount / 20 * vel, x, y);
const iniColor = random(colors);
const amount = floor(random(3, 6));
gradient.addColorStop(0, iniColor);
for (var i = 0; i < amount; i++) {
gradient.addColorStop(1 / (amount + 2) * (i + 1), random(colors));
gradient.addColorStop(1, iniColor);
ctx.fillStyle = gradient;
function mousePressed() {
function createPolygon(vertices) {
var polygon = { vertices: vertices };
var minX = (vertices.length > 0) ? vertices[0].x : undefined;
var minY = (vertices.length > 0) ? vertices[0].y : undefined;
for (var i = 0; i < polygon.vertices.length; i++) {
vertex2: vertices[(i + 1) % vertices.length],
edge.outwardNormal = outwardEdgeNormal(edge);
edge.inwardNormal = inwardEdgeNormal(edge);
minX = Math.min(x, minX);
minY = Math.min(y, minY);
maxX = Math.max(x, maxX);
maxY = Math.max(y, maxY);
function inwardEdgeNormal(edge) {
var dx = edge.vertex2.x - edge.vertex1.x;
var dy = edge.vertex2.y - edge.vertex1.y;
var edgeLength = Math.sqrt(dx * dx + dy * dy);
return { x: -dy / edgeLength, y: dx / edgeLength };
function outwardEdgeNormal(edge) {
var n = inwardEdgeNormal(edge);
return { x: -n.x, y: -n.y };
function getPaddingVertices(polygon, shapePadding) {
for (var i = 0; i < polygon.edges.length; i++) {
var edge = polygon.edges[i];
var dx = edge.inwardNormal.x * shapePadding;
var dy = edge.inwardNormal.y * shapePadding;
offsetEdges.push(createOffsetEdge(edge, dx, dy));
for (var i = 0; i < offsetEdges.length; i++) {
var thisEdge = offsetEdges[i];
var prevEdge = offsetEdges[(i + offsetEdges.length - 1) % offsetEdges.length];
var vertex = edgesIntersection(prevEdge, thisEdge);
x: (prevEdge.vertex2.x + thisEdge.vertex1.x) / 2,
y: (prevEdge.vertex2.y + thisEdge.vertex1.y) / 2
function createOffsetEdge(edge, dx, dy) {
vertex1: { x: edge.vertex1.x + dx, y: edge.vertex1.y + dy },
vertex2: { x: edge.vertex2.x + dx, y: edge.vertex2.y + dy }
function edgesIntersection(edgeA, edgeB) {
var den = (edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex2.x - edgeA.vertex1.x) - (edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex2.y - edgeA.vertex1.y);
var ua = ((edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) - (edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) / den;
var ub = ((edgeA.vertex2.x - edgeA.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) - (edgeA.vertex2.y - edgeA.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) / den;
if (ua < 0 || ub < 0 || ua > 1 || ub > 1)
return { x: edgeA.vertex1.x + ua * (edgeA.vertex2.x - edgeA.vertex1.x), y: edgeA.vertex1.y + ua * (edgeA.vertex2.y - edgeA.vertex1.y) };
function pointForIndex(pct, x, y) {
let angle = pct * TWO_PI;
let cosAngle = cos(angle);
let sinAngle = sin(angle);
let time = frameCount / 300;
let noiseValue = noise(NOISE_SCALE * cosAngle + NOISE_SCALE, NOISE_SCALE * sinAngle + NOISE_SCALE, time);
let radius = INNER_RADIUS + RADIUS_VARIATION * noiseValue;
x: radius * cosAngle + x,
function createHobbyBezier(vertices, { tension = 1, cyclic = false } = {}) {
const n = vertices.length;
for (let i = 0; i < n; i++) {
const p0 = vertices[(i - 1 + n) % n];
const p2 = vertices[(i + 1) % n];
const p3 = vertices[(i + 2) % n];
const d01 = dist(p0.x, p0.y, p1.x, p1.y);
const d12 = dist(p1.x, p1.y, p2.x, p2.y);
const d23 = dist(p2.x, p2.y, p3.x, p3.y);
const a = pow(d12, 2 * tension);
const b = pow(d01, 2 * tension);
const c = pow(d23, 2 * tension);
x: (1 - a1) * p1.x + a1 * p2.x,
y: (1 - a1) * p1.y + a1 * p2.y
x: (1 - a2) * p2.x + a2 * p1.x,
y: (1 - a2) * p2.y + a2 * p1.y
const p0 = vertices[n - 1];
const d01 = dist(p0.x, p0.y, p1.x, p1.y);
const d12 = dist(p1.x, p1.y, p2.x, p2.y);
const d23 = dist(p2.x, p2.y, p3.x, p3.y);
const a = pow(d12, 2 * tension);
const b = pow(d01, 2 * tension);
const c = pow(d23, 2 * tension);
x: (1 - a1) * p1.x + a1 * p2.x,
y: (1 - a1) * p1.y + a1 * p2.y
x: (1 - a2) * p2.x + a2 * p1.x,
y: (1 - a2) * p2.y + a2 * p1.y