Was excited to be asked to do visuals for Night School + Phillip Otterbach at the Crown <3

Documenting this was also my push to get hydra canvas rendering working in my toolchain (see below!), which is a lot easier to document than videos. However I learned that audio isn’t loading in examples (mb by design? I opened a PR), so I can’t show these demos with audio reactivity.

For Night School’s set, I wanted to play with these trios of soft blobs, and gradually overlay them with a moiré effect.

For Phillip’s set, I wanted to play with P5-specification of circle size. (This is one that is really hard to demonstrate the effect of without a working fft; additionally, p5 rendering isn’t really working for me in the newly-minted example canvas feature, so I’m just including code.)

Started minimal (showing responsivity), then layered on some sobel filtering and distortion at the end.

Tbh, I really wasn’t happy with how this went in terms of what I actually displayed (I was just getting over an illness and the set didn’t start how I wanted, and it took me about the first 1/3 to recover), but my pacing and restraint were, a lot of folks approached me after saying they really enjoyed the set.

I think my performer instincts kicked in and although I wasn’t producing exactly what I wanted, I built things gradually and let the music be the centerpiece, and paced extremely slowly.

(There’s something about ambient that makes you have to choose very deliberately where you make visual changes, or it will be extremely jarring. I spent a lot of time slowly blending things in and out while figuring out what I wanted to do. A lot of this was due to the fact I couldn’t see the buffers offscreen, so I needed to tease them in to make sure they were what I wanted. Kinda like mixing without headphones.)

sobel filter effect on audioreactive recording during dev

// otterbach set
p = new P5();

// setup 
cnv=p.createCanvas(400,400);
oldCnv=p.createGraphics(p.width,p.height);
p.noFill();

// reset
//p.remove()
p.background(0);
v0y=p.height/2;
v0y2=p.height/2;
p.imageMode(p.CENTER)  
p.angleMode(p.DEGREES)  

// step size and dir
xf=1.7
yf=1.7

p.draw = () => {  
  //p.background(0)
  oldCnv.image(cnv,0,0,p.width,p.height);  
  oldCnv.loadPixels();  
  p.push()  
  p.translate(p.width/2, p.height/2);  
  
  if(a.fft[0]>.6) yf*=-1
  if(a.fft[0]>.8) xf*=-1
  
  // the old image to give trailing
  p.image(oldCnv,
          xf*1*a.fft[0]*5,
          yf*p.sin(p.frameCount)/20,
          400,
          400); 
  p.pop()  
  p.stroke(0,255-a.fft[2]*255,255,200);
  
  di=1000
  p.strokeWeight(2)  
  p.ellipse(p.width/2-10,
          p.height/2+2+a.fft[2],
          di*a.fft[1]*10+50,
          di*a.fft[0]*20+2);  
  
  di=20
  //*Math.sin(time/100)
  p.stroke(Math.sin(time)*255,0,255,200);
  p.ellipse(p.width/2+10,
          p.height/2+10,di*a.fft[1]+0,
          di*a.fft[0]*20+0);  
  
  p.stroke(Math.sin(time)*255,255,255,200);
  p.ellipse(p.width/2+10,
          p.height/2-20,
          di*a.fft[2]*20,
          di*a.fft[1]*40);  
}

speed=.5

s0.init({src:p.canvas})
src(s0)
  .rotate([.2,.2,.4,.4,.9,.9,1.4,1.4]
          .smooth())
  .rotate(-1.4)
  .pixelate(100,10000)
  .out(o0)

render()

a.setCutoff(.1)
a.setSmooth(.2)
a.setBins(4)
a.show()

src(o0)  
  .scrollX(.05)  
  .blend(src(o0)
         .pixelate(1000,200)
         .modulate(src(o2).scale(.900)),
    ()=>a.fft[0]/4)
  .hue([0.32,.66]
       .smooth().fast(.1))
  //.mult(solid(1,0,0))
  .modulate(noise(.9))
  .modulateScale(
  src(o1).scrollX(.001)
  .scale(1.001))
  //.thresh(.1)
  .blend(src(o1),.1)
  .hue(()=>Math.sin(time/100))
  .add(solid(1,0,0).mask(shape(100)
                         .scrollX(.2)
                         .mult(gradient(.2))
                         .scale(4,
                                ()=>1+Math.sin(time/10))),.9)
  .out(o1)

src(o1)
    .sobely()
    .out(o3)

src(o3).diff(solid(1,0,1)).out(o2)

render()