Solandra

A simple, modern TypeScript-first Algorithmic Art Tool

Slideshow

Use Arrow keys or click to navigate

Principles

Opionated, agile (code is easy to change) framework for algorithmic art. See my essays for research/plans that went into this!

  • Sketches always have width 1, height depends on aspect ratio.
  • Angles in radians.
  • Points are [number, number].
  • Colours in hsl(a).
  • Leverage TypeScript: you shouldn't need to learn much, autocomplete and type checking should have your back.
  • Not for beginners.
  • Control flow at level of drawing (tiling, partitions etc).
  • Few dependencies/mostly from scratch.
  • Performance is not the goal.
  • Common algorthmic art things (e.g. randomness) should be easy.
  • Should feel fun/powerful.
  • Life is too short to compile things.
  • Rethink APIs e.g. standard bezier curve APIs make absolutely no sense
  • Declarative when possible (especially anything configuration-y), proceedural when pragmatic; make it easy to explore/change your mind.

Tutorial

Let's make the animated logo thing above to learn about how to use Solandra. Let's start with the background. The only way to do colours in Solandra is via HSL(A). Hue (0-360), Saturation (0-100) and Brightness (0-100). Oh and alpha (0-1). RGB is for computers not for you.

Every sketch is just a function on the main Solandra object (here called p). So we get friendly autocompletion.

p.background(220, 26, 14)

That's a bit boring. Let's draw something. First we set a fill colour. Then we use a fill call (to draw lines use draw instead). Solandra comes with loads of standard built in shapes, with clear, declarative APIs (you describe the shape).

p.setFillColour(220, 54, 50)
p.fill(new Rect({ at: [0.2, 0.2], w: 0.6, h: 0.4 }))

What did we learn? Points are always of the form: [x,y]. We use short names for common things (like width, w).

Let's draw many shapes. But we'll make the computer do the hard bit. What if we could just ask it to tile our canvas? We can.

p.forTiling(
  { n: 10, type: "square", margin: 0.1 },
  (at, [w, h], c, i) => {
    p.setFillColour(150 + i * 5, 54, 50)
    p.fill(new Rect({ at, w, h }))
  }
)

First we configure out tiling: 10 tiles across, square shape. Let's add a margin (that would be really tedious by hand).

Now let's use our tiling. That's a lot of arguments. But it doesn't matter. TypeScript keeps track of them. They are the position, tile size, tile centre and iteration count. We'll use the last one to pick a colour.

Let's draw polygons instead. Instead of tiling, let's move across our canvas. The API is basically the same. Configuration goes first (we can then easily tweak it).

p.forHorizontal({ n: 8, margin: 0.1 }, (at, [w, h], c, i) => {
  p.setFillColour(150 + i * 5, 54, 50)
  p.fill(new RegularPolygon({ at: c, r: w / 3, n: i + 3 }))
})

We need one more thing before we can finish our drawing: time. But it is really easy, usually just p.t gives the time in seconds. We throw in some trigonometric stuff to make look more organic and:

new RegularPolygon({
  at: [c[0], c[1] + Math.cos(p.t + (i * Math.PI) / 8) * 0.2],
  r: w / 3,
  n: i + 3,
})

Okay so let's put everything together and draw our animated logo.

(p: SCanvas) => {
  p.background(220, 26, 14)
  const { bottom, right, center } = p.meta
  const d = Math.min(bottom, right) / 2.8

  p.times(5, n => {
    const sides = 10 - n
    const r = d - n * 0.16 * d + (1 + Math.cos(p.t)) / 40
    p.setFillColour(220, 70, 10 + n * 12)
    p.fill(
      new RegularPolygon({
        at: center,
        n: sides,
        r,
      })
    )
  })
}

Examples

Now what? There are loads of examples with source code to learn from. You can also read the docs.

Solandra was made by James Porter.

Check out the GitHub page or install with npm i solandra

Read the Docs