Getting started with generative art and Hydra

Getting started with generative art and Hydra

Hydra is a JavaScript library for creating interactive visual art by Olivia Jack. The API was designed to function like an analog video synthesizer, where the output of one process is fed into the next one.

Image: Sandin Image Processor, exhibited at School of the Art Institute of Chicago (SAIC), photographed by Rosa Menkman, https://commons.wikimedia.org/wiki/File:Sandin_Image_Processor.jpg

Hydra takes the resulting output and constructs a fragment shader that is rendered into a <canvas/> element.

This article will go over the three primary elements needed to make a hydra sketch: sources, modifiers, and outputs.

Getting Started

To follow along with the code examples, you can use the hydra editor at https://hydra.ojack.xyz/.

Sources

A source is a starting input for any hydra sketch. There are some predefined fragment shaders that are provided by hydra. We'll start by looking at osc.

An oscillator takes the x coordinate of the screen and passes it through a sine wave, essentially moving continuously between black (vec3(0.0,0.0,0.0)) and white (vec3(1.0,1.0,1.0)).

hydra-2022-4-15-0.5.42.png

To render the oscillator, we attach the out function to our source function.

osc().out()

The osc function takes three parameters: frequency, speed, and offset.

  • frequency affects how long a full cycle takes for the sine wave or essentially, how many bands appear on the screen (default: 60)

  • speed affects how quickly the oscillator moves to the left (default: 1.0)

  • offset affects the distance between and red, green, and blue channels (default: 0)

hydra-2022-4-15-0.21.20.png

osc(10, 0.1, 0.3).out()

Try seeing what happens if you use: gradient, noise, shape, solid, or voronoi

Modifiers

Modifiers take the pixel data from a previous process, manipulates it, and returns a new function that you can either pass to another modifier, or an output channel.

For example, we could take our oscillator and rotate it 90 degrees. Since we're working with WebGL, we'll need to convert degrees into radians.

hydra-2022-4-15-0.26.31.png

An easy way to set this up is to use <DEGREES> * Math.PI / 180

osc(10, 0.1, 0.3).rotate(90 * Math.PI / 180).out()
// or
osc(10, 0.1, 0.3).rotate(Math.PI * 0.5).out()

Any parameter can be defined as a function or array, so we could change our rotation over time.

osc(10, 0.1, 0.3)
.rotate((args) => {
   const d = args.time * 0.1
   return Math.PI * d
})
.out()
const r1 = Math.PI * 0.5
const r2 = Math.PI * 0.25

osc(10, 0.1, 0.3)
.rotate([ r1, r2 ])
.out()

We can also increase the color saturation of our shader with saturate

hydra-2022-4-15-0.37.37.png

osc(10, 0.1, 0.3).rotate(Math.PI * 0.5).saturate(5).out()

We can also use operators like add, blend, mult to mix layers together.

hydra-2022-4-15-0.43.30.png

const triangle = shape(3, 0.4).scrollY(0.07).rotate(Math.PI)

osc(10, 0.1, 0.3)
.rotate(Math.PI * 0.5)
.saturate(5)
.mult(triangle)
.out()

Output

Hydra has four possible output buffers. By default out send the shader to the first buffer or o0. We can observe all four buffers by using the render function without any parameters

hydra-2022-4-15-0.40.23.png

osc().out(o0)
noise().out(o1)
shape().out(o2)
voronoi().out(o3)

render()

You can switch to displaying a single buffer by passing in the buffer name as a parameter.

render(o2)

Experiment!

Now that you're familiar with hydra's syntax including sources, modifiers, and output buffers, you can start exploring with chaining functions together in different ways to make some fun visuals!

Additional Resources: