Hydra⚡Intro

by

and

d17e avatar
🐰

https://hydra.ojack.xyz

Hi!

This is a quick introduction to the basic Hydra APIs.

It was built by David Vandenbogaerde, aka d17e, for the Creative Coding Amsterdam Meetup on November 17th, 2024.

This is one long HTML page, so we built in an auto-scroller for you. You can press the space-bar to play/pause the scroller. Or click on the hidden button in the top-right of the screen to change its speed.

The original inspiration for this 'talk/site' was the live-coding 101 Workshop by Timo Hoogland and Saskia Freeke in June 2024.
In case you're interested in finding out more on live coding in general, you can find a list of resources at https://github.com/tmhglnd/live-coding-101
🐰

What is Hydra?

Hydra is an open-source project initiated by Olivia Jack.
It is a web-based live-coding environment that allows you to create visuals using JavaScript and WebGL. It is inspired by analog modular synthesizers and early video synthesis. Hydra allows you to create visuals collaboratively in a browser window, and stream them in real time.

shortcuts

  • CTRL-Enter: run a line of code
  • CTRL-Shift-Enter: run all code on screen
  • ALT-Enter: run a block
  • CTRL-Shift-H: hide or show code
  • CTRL-Shift-F: format code using Prettier
  • CTRL-Shift-S: Save screenshot and download as local file
  • CTRL-Shift-G: Share to twitter (if available). Shares to @hydra_patterns
This is Hydra!
solid(1, 1, 1) .out()
solid(1, 0, 1) .out()
solid(1, 0, 0) .out()
solid(0, 0, 0) .out()
Let's do a real demo?
from hydra-scrollable-webpage
shape(99) .scale(1, 1, ()=> window.innerWidth / window.innerHeight) .mult(osc(20, 0.1, 2)) .modulateScale( osc(1, 2).invert(), 0.5, 0.5) .out()
solid(0, 0, 0) .layer(src(o0) .scale(1.01).mask( shape(99) .scale(1.5, 1.5, () => window.innerWidth / window.innerHeight))) .blend( shape(99) .scale(1.5, 1.5, () => window.innerWidth / window.innerHeight) .mult(osc(20, 0.1, 2)) , 0.1) .out()
src(o0) .modulateHue( src(o0) .scale(1.01) , 1) .out()
src(o0) .scale(1.01) .out()
src(o0) .modulateRotate( src(o0) .scale(1.01) .hue(() => time/9) .brightness(-0.3), .01) .out()
src(o0) .modulatePixelate( src(o0) .hue(()=>time/9) .r() .contrast(2) .pixelate(32,32) , 1024 , 8) .out()
src(o0) .scale(0.99) .out()

👀👀👀

What just happened?

Well, I'm not exactly sure actually.

But I do know a few things that I want to share here, that should help you along at least a little bit...
src(o0) .mult(solid(), 0.01) .out()
solid() .out()
There are five main types of functions in hydra:
source, geometry, color, blend and modulate
Sources seem like a good place to start, no?

Sources

  • solid: solid colors
  • gradient: gradients
  • shape: basic shapes
  • osc: oscillators
  • noise: Perlin noise
  • voronoi: Voronoi diagrams
  • src: output of another layer
  • ...

solid

          solid( r, g, b, a = 1 )
        
solid(1, 0, 0).out()
solid(0, 1, 0).out()
solid(0, 0, 1).out()
solid(0, 0, 99999).out()

gradient

          gradient( speed )
        
gradient(0).out()
speed = 1; gradient(1).out()

speed

Changes the overall speed
speed = 10; gradient(1).out()
is the same as
speed = 1; gradient(10).out()

shape

          shape( 
            sides = 3, 
            radius = 0.3, 
            smoothing = 0.01 
          )
shape().out()
But who needs triangles when you have...
// hexagons shape(6).out() // and comments!
shape(6, 0.1, 1).out()
Now, Hydra also has some super powers
🦾🦾🦾
All number type parameters can also take an array of numbers
shape( [3, 6], [.6, .1, .2, .9] ).out()
What's even more, these arrays come packed with their own magic tricks!
🪄🪄🪄

array functions

fast( speed = 1 )
smooth( smooth = 1)
ease( ease = 'linear' )
offset( offset = 0.5 )
fit( low = 0, high = 1)
shape( [3, 6] .smooth(), [.6, .1, .2, .9] ).out()
shape( [3, 9] .smooth(), [.6, .1, .2, .9] .smooth() .fast(3) .ease('easeInOutCubic') ).out()
        🤯
      

noise

          noise( scale = 10, offset = 0.1 )
        
noise().out()
noise( [9, 99] .smooth() .fast(0.3) ) .out()
noise( 11, [0.1, 0.8].smooth() ) .out()

voronoi

          voronoi( 
            scale = 5, 
            speed = 0.3, 
            blending = 0.3)
voronoi().out()

osc

          osc(
            frequency = 60,
            sync = 0.1,
            offset)
osc().out()
offset?
osc(1, 1, 0) .out()
offset => color space
          0 .. Math.PI/2
        
osc(1, 1, Math.PI/2) .out()
osc(1, 1, [Math.PI/2, Math.PI*2].smooth() ) .out()
Can you guess what's next? 🧙
Right! Magic!

🪄🪄🪄

Each parameter can also be a function
// offset osc(1, 1, () => { console.info(Math.round(time)); return Math.sin(time / 99) * (Math.PI/2); }) .out()
        ⏱️
      
time is on our side!

Synth Settings

  • speed: change overall speed (R/W)
  • bpm: change overall bpm (R/W)
  • width: canvas width
  • height: canvas height
  • mouse: mouse coordinates ({x, y})
  • time: tick tock tick tock
  • ...
shape(99) .scroll( () => -mouse.x / width, () => -mouse.y / height) .out()
        💡
      
shape(99) .out();
Is it round?
shape(99) .scale(1, 1, window.innerWidth / window.innerHeight ) .out()
What about resizing?
shape(99) .scale(1, 1, () => window.innerWidth / window.innerHeight ) .out()

src

but what about
          .out()
        
?
osc().out(o0); shape().out(o1); voronoi().out(o2); gradient().out(o3); render();
          src( tex )
        
src(o0) .modulate(noise(3), 0.005) .blend(shape(4), 0.01) .out(o0)
        🔊🎸🔊🎸🔊
      
        😮
      

Geometry

operates on a texture:
rotate( angle = 10, speed )
scale( 
          amount = 1.5, 
          xMult = 1, 
          yMult = 1, 
          offsetX = 0.5, 
          offsetY = 0.5 
        )
pixelate( pixelX = 20, pixelY = 20)
kaleid( nSides = 4 )
...
noise() .pixelate(20, 20) .out()
noise() .kaleid(9) .out()

repeat

repeat( 
          repeatX = 3, 
          repeatY = 3, 
          offsetX, 
          offsetY )
repeatX( reps = 3, offset )
repeatY( reps = 3, offset )
shape() .repeat() .out()

scroll

scroll( 
          scrollX = 0.5, 
          scrollY = 0.5, 
          speedX, 
          speedY )
scrollX( scrollX = 0.5, speed )
scrollY( scrollY = 0.5, speed )
shape() .scroll(0.1, 0.1, 0.9, 0.3) .out()

Color

operates on a texture:
brightness( amount = 0.4 )
contrast( amount = 1.6 )
luma( threshold = 0.5, tolerance = 0.1 )
thresh( 
          threshold = 0.5, 
          tolerance = 0.04 )
...
voronoi(99) .out()
voronoi(99) .brightness([.3, .7].smooth()) .out()
voronoi(99) .contrast([.5, 3].smooth()) .out()
voronoi(99) .luma([.3, .7].smooth()) .out()
voronoi(99) .thresh([.3, .7].smooth()) .out()

Color Cont'd

operates on a texture:
color( r = 1, g = 1, b = 1, a = 1 )
saturate( amount = 2 )
hue( hue = 0.4 )
colorama( amount = 0.005 )
posterize( bins = 3, gamma = 0.6 )
...
voronoi(99) .color(3, .2, .9) .out()
voronoi(99) .color(3, .2, .9) .saturate([.3, 4].smooth().fast(.3)) .out()
voronoi(99) .color(3, .2, .9) .saturate([.3, 4].smooth().fast(.3)) .hue(() => (Math.sin(time) + 1) / 4) .out()
voronoi(99) .color(3, .2, .9) .saturate([.3, 4].smooth().fast(.3)) .hue(() => (Math.sin(time) + 1) / 4) .posterize(1) .out()
voronoi(99) .colorama( [0, Math.PI/2] .smooth() .fast(.1)) .out()

Color Cont'd

operates on a texture:
shift( r = 0.5, g, b, a )
invert( amount = 1 )
r( scale = 1, offset )
g( scale = 1, offset )
b( scale = 1, offset )
        🥱
      

Blend

operates on a texture, but also takes a texture as parameter:
add( texture, amount = 1 )
sub( texture, amount = 1 )
mult( texture, amount = 1 )
diff( texture )
...
// TOP LEFT osc().color(.6, .2, .1).out(o0); // TOP RIGHT osc().color(.2, .8, .7).rotate(-Math.PI/2).out(o2); src(o0).add(src(o2)).out(o1); src(o2).add(src(o0)).out(o3); render();
// TOP LEFT osc().color(.6, .2, .1).out(o0); // TOP RIGHT osc().color(.2, .8, .7).rotate(-Math.PI/2).out(o2); src(o0).mult(src(o2)).out(o1); src(o2).mult(src(o0)).out(o3); render();
// TOP LEFT osc().color(.6, .2, .1).out(o0); // TOP RIGHT osc().color(.2, .8, .7).rotate(-Math.PI/2).out(o2); src(o0).diff(src(o2)).out(o1); src(o2).diff(src(o0)).out(o3); render();

Blend Cont'd

operates on a texture, but also takes a texture as parameter:
blend( texture, amount = 0.5 )
layer( texture )
mask( texture )
// TOP LEFT osc().color(.6, .2, .1).out(o0); // TOP RIGHT osc().color(.2, .8, .7).rotate(-Math.PI/2).out(o2); src(o0).blend(src(o2)).out(o1); src(o2).blend(src(o0)).out(o3); render();
// TOP LEFT osc().color(.6, .2, .1).out(o0); // TOP RIGHT osc().color(.2, .8, .7).rotate(-Math.PI/2).out(o2); src(o0).layer(src(o2)).out(o1); src(o2).layer(src(o0)).out(o3); render();
// TOP LEFT osc().color(.6, .2, .1).out(o0); // TOP RIGHT osc().color(.2, .8, .7).rotate(-Math.PI/2).out(o2); src(o0).mask(src(o2)).out(o1); src(o2).mask(src(o0)).out(o3); render();
        🥁🥁🥁
      

Modulate

operates on a texture, but also takes a texture as parameter:
modulate( texture, amount = 0.1 )
voronoi().out(o0); osc().out(o2); src(o0).modulate(src(o2)).out(o1); src(o2).modulate(src(o0)).out(o3); render();
speed = .33; voronoi().out(o0); osc().out(o2); src(o0).modulate( src(o2), [0, 1].smooth()) .out(o1); src(o2).modulate( src(o0), [0, 1].smooth()) .out(o3); render();

Modulate

modulateHue( texture, amount = 1 )
modulateScale
          ( texture, multiple = 1, offset = 1 )
modulatePixelate
          ( texture, multiple = 10, offset = 3 )
modulateRotate
          ( texture, multiple = 1, offset )
// Example from Hydra Reference src(o0) .modulateHue( src(o0).scale(1.01), 1) .layer( osc(4,0.5,2).mask( shape(4,0.5,0.001))) .out(o0)

Modulate Cont'd

modulateRepeat( 
          texture, 
          repeatX = 3, 
          repeatY = 3, 
          offsetX = 0.5, 
          offsetY = 0.5 )
modulateRepeatX
          ( texture, reps = 3, offset = 0.5 )
        
modulateRepeatY
          ( texture, reps = 3, offset = 0.5 )
        
// Example from Hydra Reference // straight lines illusion shape(4,0.9) .mult(osc(4,0.25,1)) .modulateRepeatX( osc(10), 5.0, ({time}) => Math.sin(time) * 5) .scale(1,0.5,0.05) .out(o0)

Modulate Cont'd

modulateKaleid( texture, nSides = 4 )
modulateScrollX( texture, scrollX = 0.5, speed )
modulateScrollY( texture, scrollY = 0.5, speed )
// Example from Hydra Reference osc(10, 0.1, 2) .modulateKaleid( osc(16).kaleid(999), 1) .out(o0)
But there's even more to explore!

External Sources

initCam, initImage, initVideo, init, initStream, initScreen
And more!

Audio

fft, setSmooth, setCutOff, setBins, setScale, show, hide
But that's for another time...
s0.initImage('https://i.imgur.com/B2wV89r.png'); src(s0) .scale(.2, .8, .3) .modulatePixelate( osc(() => Math.sin(time)), 999) .color([.7, .3].smooth(), [.3, .7].smooth(),.4) .out()
        🙏
      
Thank you for your time!
s0.initImage('https://i.imgur.com/B2wV89r.png'); src(s0) .scale(.2, .8, .3) .modulatePixelate( osc(() => Math.sin(time)), 999) .color([.7, .3].smooth(), [.3, .7].smooth(),.4) .modulateKaleid(voronoi(), [2, 6].smooth().fast(.4)) .out()

Hydra⚡Intro

by

and

d17e avatar
🐰

https://hydra.ojack.xyz