function drawRibbon(bass, mid) {
let spacing = 15;
let numLines = 8;
for (let i = 0; i < numLines; i++) {
let offset = (i - numLines / 2) * spacing;
beginShape();
for (let x = -width / 2; x < width / 2; x += 5) {
// Additive synthesis: fundamental + harmonics
let y = 0;
let baseFreq = 0.01;
let baseAmp = map(bass, 0, 255, 30, 100);
// Fundamental frequency
y += sin(x * baseFreq + time + i * 0.3) * baseAmp;
// 2nd harmonic (octave)
y += sin(x * baseFreq * 2 + time + i * 0.3) * (baseAmp * 0.5);
// 3rd harmonic
y += sin(x * baseFreq * 3 + time * 1.2 + i * 0.3) * (baseAmp * 0.33);
// 4th harmonic (with mid frequency)
y += sin(x * baseFreq * 4 - time * 0.7) * map(mid, 0, 255, 10, 30);
// 5th harmonic (subtle)
y += sin(x * baseFreq * 5 + time * 1.5) * (baseAmp * 0.2);
y += offset;
vertex(x, y);
}
endShape();
}
}
function draw() {
// Get audio analysis
let bass = fft.getEnergy("bass");
let mid = fft.getEnergy("mid");
let treble = fft.getEnergy("treble");
// Map audio to visual parameters
let bassNorm = map(bass, 0, 255, 0, 1);
let midNorm = map(mid, 0, 255, 0, 1);
let trebleNorm = map(treble, 0, 255, 0, 1);
// Keep colors between blue (240°) and pink (320°)
let hueRange = 80; // 320 - 240 = 80 degrees
let baseHue = 240; // Starting from blue
let hue = baseHue + (frameCount * 0.2 + bassNorm * 20) % hueRange;
colorMode(HSB, 310, 180, 100);
// Dark base background - use specific color
colorMode(RGB, 255);
background("#03272eff");
colorMode(HSB, 310, 180, 100);
push();
// Draw concentric circles pattern (Kusama's infinity nets style)
noFill();
for (let tile of tiles) {
let tileHue = (hue + tile.x * 0.05 + tile.y * 0.05) % 360;
push();
translate(tile.x + tileSize / 2, tile.y + tileSize / 2);
// Stroke weight responds to mid frequencies
strokeWeight(2 + midNorm * 3);
// Truchet quarter circles creating organic flow
stroke(tileHue, 90, 70, 0.3 + trebleNorm * 0.4);
// Arc size pulses with bass
let arcScale = 1.5 + bassNorm * 0.3;
switch (tile.type) {
case 0:
// Quarter circle top-left
arc(-tileSize / 2, -tileSize / 2, tileSize * arcScale, tileSize * arcScale, 0, 90);
break;
case 1:
// Quarter circle top-right
arc(tileSize / 2, -tileSize / 2, tileSize * arcScale, tileSize * arcScale, 90, 180);
break;
case 2:
// Quarter circle bottom-right
arc(tileSize / 2, tileSize / 2, tileSize * arcScale, tileSize * arcScale, 180, 270);
break;
case 3:
// Quarter circle bottom-left
arc(-tileSize / 2, tileSize / 2, tileSize * arcScale, tileSize * arcScale, 270, 360);
break;
}
// Polka dots in each tile - size responds to treble
randomSeed(tile.x * 1000 + tile.y);
let numDots = 2;
for (let i = 0; i < numDots; i++) {
let dotX = random(-tileSize / 2, tileSize / 2);
let dotY = random(-tileSize / 2, tileSize / 2);
let dotSize = random(8, 15);
// Pulse with music
dotSize += bassNorm * 5 + trebleNorm * 3;
noStroke();
// Keep dot hue within blue-to-pink range (240° to 320°)
let dotHue = baseHue + ((tileHue - baseHue + 60) % hueRange);
fill(dotHue, 100, 90, 0.7 + midNorm * 0.2);
circle(dotX, dotY, dotSize);
}
randomSeed();
pop();
}
pop();
}
function draw() {
noFill()
// Only bass influences the bezier control points
if (bass >= limit) {
x1 = noise(offset + 5) * width;
y1 = noise(offset + 10) * height;
x2 = noise(offset + 15) * width;
y2 = noise(offset + 20) * height;
x3 = noise(offset + 25) * width;
y3 = noise(offset + 30) * height;
x4 = noise(offset + 35) * width;
y4 = noise(offset + 40) * height;
bezier(x1, y1, x2, y2, x3, y3, x4, y4);
offset += 0.01; // Slower, fixed animation speed
}
}
function draw() {
const kickDrum = fft.getEnergy(80,100)
const kickEnergy = map(kickDrum, 0, 255, 0, 100);
flying -= 0.01;
var yoff = flying;
let terrainHeight = map(kickEnergy, 0, 100, 80, 200);
for (var y = 0; y < rowsTerrain; y++) {
var xoff = 0;
for (var x = 0; x < colsTerrain; x++) {
terrain[x][y] = map(noise(xoff, yoff), 0, 1, -terrainHeight, terrainHeight);
xoff += 0.2;
}
yoff += 0.2;
}
push()
stroke(255);
strokeWeight(0.5);
fill(200, 200, 200, 150);
rotateX(PI / 3);
for (var y = 0; y < rowsTerrain - 1; y++) {
beginShape(QUAD_STRIP);
const colorA = 160 //teal
const colorB = 240 //blue
let hue = map(y, 0, rowsTerrain - 1, colorA, colorB);
for (var x = 0; x < colsTerrain; x++) {
let sat = 100;
let brightness = 220;
fill(hue, sat, brightness, 150);
vertex(x * scl, y * scl, terrain[x][y]);
vertex(x * scl, (y + 1) * scl, terrain[x][y + 1]);
}
endShape();
}
pop()
}
function draw() {
const bass = fft.getEnergy("bass");
const treble = fft.getEnergy(80, 180);
const mid = fft.getEnergy("mid");
const lowMid = fft.getEnergy("highMid");
const mapBass = map(bass, 0, 255, 20, 170);
const mapTreble = map(treble, 0, 255, 10, 190);
const mapMid = map(mid, 0, 255, 20, 210);
const mapLowMid = map(lowMid, 0, 255, 90, 150);
// Draw all blobs with irregular positions
for (let blob of blobs) {
// Select audio value based on blob's type
let audioValue;
switch (blob.audioType) {
case 0: audioValue = mapBass; break;
case 1: audioValue = mapTreble; break;
case 2: audioValue = mapMid; break;
case 3: audioValue = mapLowMid; break;
}
drawBlob(blob, audioValue);
}
}
function drawBlob(blob, audioInfluence) {
noFill();
// Map audio influence to stroke weight (thickness)
const strokeThickness = map(audioInfluence, 0, 255, 0.2, 5);
strokeWeight(strokeThickness);
beginShape();
for (let i = 0; i < blob.numPoints; i++) {
const angle = map(i, 0, blob.numPoints, 0, TWO_PI) + frameCount * blob.rotationSpeed;
// Add MORE irregularity with noise for asymmetric shapes
const noiseVal = noise(
blob.noiseOffsetX + cos(angle) * 0.5,
blob.noiseOffsetY + sin(angle) * 0.5,
frameCount * 0.008
);
const irregularity = map(noiseVal, 0, 1, 0.5, 1.5); // Much more variation
// Radius influenced by audio
const audioMod = map(audioInfluence, 0, 255, 0.7, 1.4);
const r = blob.baseSize * irregularity * audioMod;
const px = blob.x + cos(angle) * r;
const py = blob.y + sin(angle) * r;
vertex(px, py);
}
endShape(CLOSE);
}
function draw() {
const bass = fft.getEnergy("bass");
const treble = fft.getEnergy(100, 150);
const mid = fft.getEnergy("mid");
const mapBass = map(bass, 0, 255, 20, 50);
const mapTreble = map(treble, 0, 255, 10, 70);
const mapMid = map(mid, 0, 255, 20, 80);
blendMode(BLEND)
background("#002b36");
blendMode(SCREEN)
drawWaveWithBackground(waves[0], colorPalette[1], 0, mapBass);
drawWaveWithBackground(waves[3], colorPalette[3], 0, mapTreble);
drawWaveDotted(waves[1], colorPalette[2], 1, mapTreble);
drawWaveStripes(waves[2], colorPalette[0], 5, mapMid);
stroke('white');
strokeWeight(2);
line(0, height / 2, width, height / 2)
noStroke();
}
function drawWaveStripes(waves, color, size, amp) {
stroke(color)
for (let x = 0; x < width; x += 5) {
let y = 0;
for (let wave of waves) {
y += wave.evaluate(x, amp);
}
ellipse(x, y + height / 2, 2);
line(x, height / 2, x, y + height / 2)
}
for (let wave of waves) {
wave.update();
}
}
function drawWaveDotted(waves, color, size, amp) {
stroke(color)
for (let x = 0; x < width; x += 8) {
let y = 0;
for (let wave of waves) {
y += wave.evaluate(x, amp);
}
ellipse(x, y + height / 2, 2);
}
for (let wave of waves) {
wave.update();
}
}
function drawWaveWithBackground(waves, color, size, amp) {
fill(color);
beginShape();
vertex(0, yAxis);
let previousY = 0;
for (let x = 0; x < width; x += 1) {
let y = 0;
for (let wave of waves) {
y += wave.evaluate(x, amp);
}
y += height / 2;
// crossed y-axis, ending and beginning a new shape
if ((y > yAxis && previousY < yAxis) || (y < yAxis && previousY > yAxis)) {
vertex(x, yAxis);
endShape();
beginShape();
vertex(x, yAxis);
}
// continuing the shape
else {
vertex(x, y);
}
previousY = y;
}
vertex(width, yAxis);
endShape();
for (let wave of waves) {
wave.update();
}
}
function draw() {
const bass = fft.getEnergy("bass");
const treble = fft.getEnergy(80, 180);
const mid = fft.getEnergy("mid");
const lowMid = fft.getEnergy("highMid");
const mapBass = map(bass, 0, 255, 20, 170);
const mapTreble = map(treble, 0, 255, 10, 190);
const mapMid = map(mid, 0, 255, 20, 210);
const mapLowMid = map(lowMid, 0, 255, 40, 180);
// Draw center reference circle
noFill();
ellipse(centerX, centerY, baseRadius * 2, baseRadius * 2);
// Position each wave group at different locations
drawCircle({
color: colorPalette[0],
size: 5,
lineLength: 190,
baseRadius: 50,
randomVal: 0,
amp: mapMid,
x: width * 0.5,
y: height * 0.55,
shouldRotate: true
});
drawCircle({
color: colorPalette[2],
size: 7,
lineLength: 35,
baseRadius: 35,
randomVal: 0,
amp: mapLowMid,
x: width * 0.38,
y: height * 0.21,
shouldRotate: false
});
drawCircle({
color: colorPalette[1],
size: 3,
lineLength: 30,
baseRadius: 30,
randomVal: 3,
amp: mapTreble,
x: width / 2 + sin(oscillationAngle) * 15, // Oscillate horizontally
y: height * 0.18 + cos(oscillationAngle) * 10, // Oscillate vertically
shouldRotate: false
});
drawCircle({
color: color[3],
size: 2,
lineLength: 32,
baseRadius: 20,
randomVal: 2,
amp: mapBass,
x: width * 0.30,
y: height * 0.7,
shouldRotate: false
});
// Increment rotation angle for next frame
rotationAngle += 0.01;
// Increment oscillation angle for smooth movement
oscillationAngle += 0.02;
}
function drawCircle(config) {
const {
color: colorStr,
size,
lineLength,
baseRadius,
randomVal,
amp,
x: posX,
y: posY,
shouldRotate = false
} = config;
strokeWeight(size / 4);
// Draw center circle with radial gradient
noStroke();
push(); // Save current color mode
fill(col);
ellipse(posX, posY, r * 2, r * 2);
// Draw lines with fixed length and same alpha based on amp
// Map amp to alpha (0-255) - all lines will have this same alpha
let alpha = map(amp, 10, 80, 10, 255);
push();
colorMode(RGB);
let col = color(colorStr);
col.setAlpha(alpha);
stroke(col);
let noiseOffset = 0;
// Add rotation offset if shouldRotate is true
let angleOffset = shouldRotate ? rotationAngle : 0;
for (let angle = 0; angle < TWO_PI; angle += 0.05) {
// Apply rotation offset to the angle
let rotatedAngle = angle + angleOffset;
let x = posX + cos(rotatedAngle) * baseRadius;
let y = posY + sin(rotatedAngle) * baseRadius;
line(posX + cos(rotatedAngle) * baseRadius, posY + sin(rotatedAngle) * baseRadius, x, y);
}
pop();
}
function draw() {
var treble = fft.getEnergy("treble");
// Add gentle time-based variation
time += 0.01;
var trebleFreq = treble + sin(time * 30) * 0.5;
// Use hue based on treble, but in the coral/red range like #D86072
let hue = map(smoothedTreble, 0, 255, 340, 20); // Range around the coral color hue
stroke(hue, 80, 88);
SphericalLissajous(trebleFreq);
}
function SphericalLissajous(freq) {
let step = 1.0;
beginShape();
noFill();
for (let theta = 0; theta < 720; theta += step) {
let x = r * cos(theta * freq);
let y = r * sin(theta * freq) * sin(theta * 2);
let z = r * sin(theta * freq) * cos(theta * 2);
vertex(x, y, z);
}
endShape();
}