Someone asked us for the code of the visuals. The bulk of it is P5, the height map is inspired by Shiffman’s tutorial. The height values of the terrain are then multiplied by a factor of the distance from the center (hence the flat part in the middle). Square movement is two sine functions, one for their y positions and the other for their rotation. The sun is the shader in the class tutorial.
Hydra is used for feedback and coloring and the final transition. The transition is a Voronoi-modulated oscillator.
Inspiration for the composition of the visual was drawn from this video.
Here’s the full code. Steps:
- run shader
- run p5
- run for loop
- run draw()
- run o1
- run o3
- run render(o3)
- tinker with o3 as commented
// glow circle setFunction({ name: 'glowCircle', type: 'src', inputs: [{ type: 'float', name: 'locX', default: 0., }, { type: 'float', name: 'locY', default: 0., }, { type: 'float', name: 'glowAmount', default: 50., }, { type: 'float', name: 'r', default: 0.6, }, { type: 'float', name: 'g', default: 0.3, }, { type: 'float', name: 'b', default: 0.5, }, ], glsl: ` vec2 loc = vec2(locX,locY); // loc is in screen spaces, but _st is in normalized space float dist = glowAmount/distance(_st*resolution, loc); return vec4(r*dist,g*dist,b*dist,0.1); ` }) p5 = new P5({width: window.innerWidth, height:window.innerHeight, mode: 'WEBGL'}) s0.init({src: p5.canvas}) src(s0).out(0) p5.hide(); scl = 50; w = 4200; h = 3000; //set m as 300 m = 100; cols = w / scl; rows = h / scl flying = 0 terrain = [] spikes = [] toggle = 0 toggle2 = 0 size = 3; pink = p5.color(255, 34, 240); blue = p5.color(23, 200, 255); neon = p5.color(10, 220, 255); prv = [0,0,0]; ctr = [0,0,0]; p5.remove() //make electro sound go up with the other one for (var x = 0; x < cols; x++) { terrain[x] = []; spikes[x] = []; for (var y = 0; y < rows; y++) { terrain[x][y] = 0; //specify a default value for now spikes[x][y] = 0; } } p5.draw = ()=> { blue = p5.color(1, 6, 40); m = 100; size = p5.random(2,5); fade = 0.8; //p5.lights(); p5.background(blue); p5.translate(0, 300, -100); p5.rotateX(42*p5.PI/72); //p5.rotateZ(time*p5.PI / 3); //p5.fill(255*p5.noise(1), 190*p5.noise(1), 150 + 200*p5.noise(1), 255); p5.translate(-w/2, -h/2); p5.noStroke(); //p5.stroke(255, 34, 240); //GRID for (var i = 0; i < cols; i++) { p5.line(i*scl, 0, i*scl, h); } for (var i = 0; i < rows; i++) { p5.line(0, i*scl, w, i*scl); } //p5.noStroke(); flying -= 0.03; var yoff = flying; for (var y = 0; y < rows; y++) { var xoff = 0; for (var x = 0; x < cols; x++) { terrain[x][y] = p5.map(p5.noise(xoff, yoff), 0, 1, 0, m) + spikes[x][y]; spikes[x][y] *= fade; // xoff += 0.03; } yoff += 0.04; } //big blocks let cn = 12; if (cc[cn] != toggle){ toggle = cc[cn]; x = p5.int(p5.random(0.4, 0.6)*cols); y = p5.int(p5.random(1)*rows); x = p5.constrain(x, 1, cols-size-2); y = p5.constrain(y, 1, rows-size-2); //spike it up for(let i = 1; i < size; i++) { for(let j =1; j< size; j++) { spikes[x+i][y] = ccActual[cn]*55; spikes[x+i][y] = ccActual[cn]*55; spikes[x+i][y+j] = ccActual[cn]*55; spikes[x][y+j] = ccActual[cn]*55; } } } //sharp spikes let cn2 = 10; if (cc[cn2] != toggle2){ toggle2 = cc[cn2]; x = p5.int(p5.random(0.4, 0.6)*cols); y = p5.int(p5.random(1)*rows); //spike it up spikes[x][y] = 105*ccActual[cn2]; } //terrain for (var y = 0; y < rows - 1; y++) { //left side p5.fill(blue); //p5.noFill(); //p5.stroke(pink); p5.noStroke(); p5.beginShape(p5.TRIANGLE_STRIP); for (var x = 0; x < cols-1; x++) { let dist = p5.pow(x-cols/2,2)/20; p5.vertex(x * scl, y * scl, terrain[x][y]*dist); p5.vertex(x * scl, (y + 1) * scl, terrain[x][y + 1]*dist); } p5.endShape(); for (var x = 0; x < cols-1; x++) { p5.strokeWeight(10); p5.stroke(pink); if (x%10==0) { p5.stroke(neon); } let dist = p5.pow(x-cols/2,2)/20; p5.line(x*scl, y*scl, terrain[x][y]*dist, x*scl, (y+1)*scl, terrain[x][y+1]*dist); //p5.line(x*scl, y*scl, terrain[x][y]*dist, (x+1)*scl, (y)*scl, terrain[x+1][y]*dist); } } //translate p5.strokeWeight(5); p5.stroke(neon); p5.fill(pink); //central box p5.push(); p5.translate(w/2,2300, 70 + 40*p5.cos(flying*7-3)); p5.rotateX(-flying*3); p5.box(50 + ccActual[13]*0); prv[0]=cc[12]; p5.pop(); //box left p5.push(); p5.strokeWeight(7); p5.translate(w/2-100,1700, 100 + 60*p5.cos(flying*7-1)); p5.rotateX(-flying*3 - 1); p5.box(50 + ccActual[13]*0); prv[1]=cc[11]; p5.pop(); //box right p5.strokeWeight(10); p5.push(); p5.translate(w/2-60,100, 80 + 60*p5.cos(flying*7 - 6)); p5.rotateX(-flying*3); p5.box(50 + ccActual[13]*0); p5.pop(); //box left2 //box center } //o0 src(s0).out(o0) //MY GPU CANTTT osc(1,2,0).color(10, 10,10).brightness(-100).modulate(noise()).mask(src(o0).sub(osc(0.9, 0.4).modulate(voronoi(20,10), 0.9))).add(src(o0)).invert().out(o1) //final output [MAIN VISUAL] //option1: modulate by o0, become crystalline/transparent: v pretty //option2: blend multiple times o3 //option3: switch source to o1, this is the main function then blend with o3. src(o0).layer(glowCircle(31*p5.width/70, 7*p5.height/24, ()=> ccActual[13]*100+2500, ()=>0.3, 0.1 ,0.06)).blend(o3).out(o3) render(o3) //black screen //track 1 => automatically switches //build up => bring the sun out || sun moves //drop the beat => sun automatically detects that //on drop => o1 //modulate o(0) blend o3 //o1 source then hush hush()