Making Generative Art

Tips, tools & resources plus my experience of entering the generative art space.

headshot of Nigel Fryatt wearing a grey shirt against a lime green background

Nigel Fryatt

25/08/23

Square crop of "TUNN3L 1969" - a sixties themed generative artwork

For a significant part of my life, I hadn't realised that programming could be used to create art. I suppose it had always seemed utilitarian to me.

That changed when I had a conversation with a creative technologist who profoundly reshaped my perception of coding. He passionately described the creative potential inherent in code and introduced me to the exciting field of generative art.

In my opinion, generative art stands as a fascinating mode of expression, combining an artist's imaginative visions with the limitless, iterable and autonomous possibilities of code. It is playful, anarchic, and employs chaos as a tool for creation across an array of different mediums.

The art form boasts a rich history dating back to the mid-twentieth century, and numerous contemporary artists continue to break boundaries today. In subsequent posts I will delve into key figures and innovators, but today i'm going to reflect on my journey as an emerging artist so far, alongside sharing the resources and tips I've found useful throughout my journey.

I don't claim expertise; there's still so much for me to grasp, but I hope that by telling my story I might encourage others to give it a go. As you'll see, my path certainly wasn't linear!

1. What is Generative Art?

Generative Art covers such a wide variety of mediums and approaches that there is no one-size-fits-all description, so I can only speak from my own experience. The term, I think, encompasses:

  • Art that’s made using programming languages or software that abstracts code into visual interfaces;
  • Using algorithms that are capable of adapting and operating without human intervention;
  • Art that is governed/influenced by rules and instructions defined by an artist;
  • Infused with randomness and collaboration... an artist sets a direction but often relinquishes an amount of creative control to algorithms too;
  • Art that might react to new inputs, represent data, or even create itself.

For a basic example, imagine the following experiment:

Stage One

I position an orange circle at the centre of my digital canvas. Surrounding it are ten other white circles. I then relinquish control to the computer, who moves the orange circle randomly through the space.

const stillCircles = [];
const stillCirclesAmount = 10;
const stillCirclesColour = [245, 245, 245];

const movingCircles = [];
const movingCirclesAmount = 1;
const movingCirclesColour = [255, 165, 0];

const circleSize = 50;

function setup() {
  createCanvas(800, 450);
  noStroke();

  for (let i = 0.5; i < stillCirclesAmount; i++) {
    stillCircles.push(
      new CoolCircle(
        (width / stillCirclesAmount) * i,
        random(circleSize, height - circleSize),
        circleSize,
        stillCirclesColour
      )
    );
  }

  for (let i = 0; i < movingCirclesAmount; i++) {
    movingCircles.push(
      new CoolMover(width / 2, height / 2, circleSize, movingCirclesColour)
    );
  }
}

function draw() {
  background(10);

  for (let c of stillCircles) {
    c.display();
  }

  for (let c of movingCircles) {
    c.move();
    c.display();
  }
}

class CoolCircle {
  constructor(x, y, size, colour) {
    this.pos = createVector(x, y);
    this.size = size;
    this.colour = colour;
  }

  display() {
    fill(...this.colour);
    circle(this.pos.x, this.pos.y, this.size);
  }
}

class CoolMover extends CoolCircle {
  constructor(x, y, size, colour) {
    super(x, y, size, colour);
    this.velocity = createVector(random(-10, 10), random(-10, 10));
    this.intersectColor = [
      [234, 123, 178],
      [45, 67, 10],
      [200, 234, 254],
    ];
  }

  move() {
    this.pos.add(this.velocity);
    this.velocity = createVector(random(-10, 10), random(-10, 10));
  }
}

Stage Two

Expanding the rules, I might stipulate that if the orange circle overlaps a white circle, its colour should change, with the computer randomly selecting from three choices that I’ve predefined.

const stillCircles = [];
const stillCirclesAmount = 10;
const stillCirclesColour = [245, 245, 245];

const movingCircles = [];
const movingCirclesAmount = 1;
const movingCirclesColour = [255, 165, 0];

const circleSize = 50;

function setup() {
  createCanvas(800, 450);
  noStroke();

  for (let i = 0.5; i < stillCirclesAmount; i++) {
    stillCircles.push(
      new CoolCircle(
        (width / stillCirclesAmount) * i,
        random(circleSize, height - circleSize),
        circleSize,
        stillCirclesColour
      )
    );
  }

  for (let i = 0; i < movingCirclesAmount; i++) {
    movingCircles.push(
      new CoolMover(width / 2, height / 2, circleSize, movingCirclesColour)
    );
  }
}

function draw() {
  background(10);

  for (let c of stillCircles) {
    c.display();
  }

  for (let c of movingCircles) {
    c.move();
    c.intersect();
    c.display();
  }
}

function keyPressed() {
  if (key === 's') {
    saveGif('mySketch', 10);
  }
}

class CoolCircle {
  constructor(x, y, size, colour) {
    this.pos = createVector(x, y);
    this.size = size;
    this.colour = colour;
  }

  display() {
    fill(...this.colour);
    circle(this.pos.x, this.pos.y, this.size);
  }
}

class CoolMover extends CoolCircle {
  constructor(x, y, size, colour) {
    super(x, y, size, colour);
    this.velocity = createVector(random(-10, 10), random(-10, 10));
    this.intersectColor = [
      [234, 123, 178],
      [45, 67, 10],
      [200, 234, 254],
    ];
  }

  move() {
    this.pos.add(this.velocity);
    this.velocity = createVector(random(-10, 10), random(-10, 10));
  }

  intersect() {
    for (let c of stillCircles) {
      const distance = dist(this.pos.x, this.pos.y, c.pos.x, c.pos.y);
      const radiusSum = (this.size + c.size) / 2;
      if (distance < radiusSum) {
        this.colour = random(this.intersectColor);
        return;
      } else {
        this.colour = movingCirclesColour;
      }
    }
  }
}

Stage Three

Let's see what happens if I increase the count of white circles to 1000 and that of moving circles to 100, while simultaneously reducing their size.

const stillCircles = [];
const stillCirclesAmount = 1000;
const stillCirclesColour = [245, 245, 245];

const movingCircles = [];
const movingCirclesAmount = 100;
const movingCirclesColour = [255, 165, 0];

const circleSize = 10;

function setup() {
  frameRate(5);
  createCanvas(800, 450);
  noStroke();

  for (let i = 0.5; i < stillCirclesAmount; i++) {
    stillCircles.push(
      new CoolCircle(
        (width / stillCirclesAmount) * i,
        random(circleSize, height - circleSize),
        circleSize,
        stillCirclesColour
      )
    );
  }

  for (let i = 0; i < movingCirclesAmount; i++) {
    movingCircles.push(
      new CoolMover(width / 2, height / 2, circleSize, movingCirclesColour)
    );
  }
}

function draw() {
  background(10);

  for (let c of stillCircles) {
    c.display();
  }

  for (let c of movingCircles) {
    c.move();
    c.intersect();
    c.display();
  }
}

class CoolCircle {
  constructor(x, y, size, colour) {
    this.pos = createVector(x, y);
    this.size = size;
    this.colour = colour;
  }

  display() {
    fill(...this.colour);
    circle(this.pos.x, this.pos.y, this.size);
  }
}

class CoolMover extends CoolCircle {
  constructor(x, y, size, colour) {
    super(x, y, size, colour);
    this.velocity = createVector(random(-10, 10), random(-10, 10));
    this.intersectColor = [
      [234, 123, 178],
      [45, 67, 10],
      [200, 234, 254],
    ];
  }

  move() {
    this.pos.add(this.velocity);
    this.velocity = createVector(random(-10, 10), random(-10, 10));
  }

  intersect() {
    for (let c of stillCircles) {
      const distance = dist(this.pos.x, this.pos.y, c.pos.x, c.pos.y);
      const radiusSum = (this.size + c.size) / 2;
      if (distance < radiusSum) {
        this.colour = random(this.intersectColor);
        return;
      } else {
        this.colour = movingCirclesColour;
      }
    }
  }
}

Stage Four

Let's see what happens if I increase the size of all of the circles and slow everything down.

const stillCircles = [];
const stillCirclesAmount = 10;
const stillCirclesColour = [245, 245, 245];

const movingCircles = [];
const movingCirclesAmount = 50;
const movingCirclesColour = [255, 165, 0];

const circleSize = 500;

function setup() {
  frameRate(5);
  createCanvas(800, 450);
  noStroke();

  for (let i = 0.5; i < stillCirclesAmount; i++) {
    stillCircles.push(
      new CoolCircle(
        (width / stillCirclesAmount) * i,
        random(circleSize, height - circleSize),
        circleSize,
        stillCirclesColour
      )
    );
  }

  for (let i = 0; i < movingCirclesAmount; i++) {
    movingCircles.push(
      new CoolMover(width / 2, height / 2, circleSize, movingCirclesColour)
    );
  }
}

function draw() {
  background(10);

  for (let c of stillCircles) {
    c.display();
  }

  for (let c of movingCircles) {
    c.move();
    c.intersect();
    c.display();
  }
}

class CoolCircle {
  constructor(x, y, size, colour) {
    this.pos = createVector(x, y);
    this.size = size;
    this.colour = colour;
  }

  display() {
    fill(...this.colour);
    circle(this.pos.x, this.pos.y, this.size);
  }
}

class CoolMover extends CoolCircle {
  constructor(x, y, size, colour) {
    super(x, y, size, colour);
    this.velocity = createVector(random(-10, 10), random(-10, 10));
    this.intersectColor = [
      [234, 123, 178],
      [45, 67, 10],
      [200, 234, 254],
    ];
  }

  move() {
    this.pos.add(this.velocity);
    this.velocity = createVector(random(-10, 10), random(-10, 10));
  }

  intersect() {
    for (let c of stillCircles) {
      const distance = dist(this.pos.x, this.pos.y, c.pos.x, c.pos.y);
      const radiusSum = (this.size + c.size) / 2;
      if (distance < radiusSum) {
        this.colour = random(this.intersectColor);
        return;
      } else {
        this.colour = movingCirclesColour;
      }
    }
  }
}

My experimentation could continue indefinitely and rules could be modified or added in reaction to what I'm discovering step by step.

This serves as a basic example of what generative art is.

However, this is just one kind of approach. Artists also make work by exploring mathematical concepts like fractals, doodling in their notebook and then rebuilding in code, creating machine learning algorithms, recreating patterns observed in the natural world, building on top of work learnt in a tutorial, or just playfully experimenting.

The possibilities are endless and extend beyond creating visual animations. Similar approaches are used by artists across a wide array of mediums: audio, text, interactivity, data visualisation, digital sculpture, and more.

2. Examples of the Rules used by Generative Artists

Here are some examples of rules I consider in the early stages of making work:

  • How many visual components to incorporate (circles, spirals, fractals, dots, lines, geometric shapes, text, backgrounds, images, and more);
  • starting and evolving position of elements;
  • starting and changing colour of elements;
  • motion of elements throughout time;
  • elements can/can't intersect;
  • User input does/doesn't change the display of elements;

In addition to the above, I usually also consider:

  • Am I starting from the basis of a ruleset, exploring a mathematical concept or just experimenting?
  • Should the work explicitly communicate a particular feeling, message or emotion?

3. Learning the Basics

Six recommendations for laying the groundwork:

  • If you are new to programming, begin by honing your skills in the basics of JavaScript or Python before diving into creative coding libraries and other languages. If you already have programming experience, dive right in, the documentation is great;
  • Engage actively with the community, both online and offline. Connect with local creative technologists and participate in ongoing discussions on social media platforms.
  • Familiarise yourself with the p5.js and Processing libraries, and discover the people that are involved in those communities;
  • Watch Dan Shiffman's Coding Train tutorials.
  • Remove the urge to make your work the best. Art thrives without competition. Persist in creating, and you'll naturally refine your skills over time.

4. Tools

Here are some creative coding libraries spanning a variety of programming languages:

JavaScript: P5.js

Python: P5

Java: Processing

C++: openFrameworks

Node based: Touch Designer

5. My Early Encounters with Computing

I was born in 1991 and raised in a small rural town situated about 40 miles north of London. There wasn't much there to keep us occupied during my childhood, so I spent most of my time outside exploring the countryside. My generation didn't really start to use mobile phones until we were well into our teenage years, and we didn't come across technology that often, except for those sluggish computer workstations at school.

Then the situation changed.

My dad shifted into a technical role, and suddenly, computers and servers cluttered the house. There was this massive industrial unit he worked at, stacked to the brim with equipment from floor to ceiling. Sensing my curiosity, he started to introduce me to this new world.

I began using the internet as a tool for learning since I struggled with the rigidity of school. This quickly evolved into a desire to build my own websites.

When I was thirteen, I dabbled in Adobe Photoshop to design my first layout and splice it into HTML. A website was born! Admittedly, it was terrible, but back then, it felt like I was Einstein.

6. Freelancing as a Web Developer

Skipping ahead from leaving school at 16 for an apprenticeship, a stint in a corporate role, and a nagging feeling that I had committed to a career path prematurely, I left my job.

I was determined to explore the creative side of life and embarked on a journey to study the world of acting and performance at university. This was quite a shift, moving me away from a secure career route to one laden with risks and almost certain failure.

I wasn’t a good actor, but that didn't deter me. I found inspiration in the creative process, the creation of art, and the intricate interplay between human expression and the fields of philosophy, psychology, and politics.

Then came graduation, and with it, change. I strongly felt that my fascination with the subject didn't compensate for my lack of talent. I accepted the fact that pursuing a career as an actor wasn't on the cards for me, which led me to contemplate what would come next.

Throughout my studies, I had dabbled in freelance web design intermittently, and it felt logical to continue down that path for the time being.

In reality, I was clueless, but I persisted, taking each day as it came — perhaps that's all you can do at that point in life, if not indefinitely.

This onward push gradually rekindled my passion for programming. However, this time around, I possessed a creative spark in need of an outlet. I grew fascinated by design as much as programming, dedicating a large amount of my time to upskilling in both areas.

Presently, I find myself five years into a really enjoyable career as a freelance web developer, peppered with stretches of full-time roles as well. I love what I do, but it hasn’t always been easy.

7. Discovering the Creative Potential of Coding

During the Coronavirus Lockdowns, much of my freelance work dissipated, a story all too familiar for many.

I began to hear about how others were being affected, and became particularly concerned about the impact the pandemic was having on the careers of artists, performers, and creative practitioners. Despite having stepped away from the industry, I wanted to do something to help.

Following some socially distanced strolls with a close friend who shared my concerns, Niklas Aarre, an idea took shape. We decided to create a radio show that would shine a spotlight on local creatives, engaging in conversations about their artistic practices. And so, The Arts Show came to life.

During one of our earliest broadcasts, we were joined by Dave Webb, a local creative technologist who is known as Crispy Smoked Web.

This was the moment that I discovered the creative potential of code.

Dave is probably bored of me banging on about how he ignited my passion for generative art, but I firmly stand by the principle of celebrating those who inspire us.

During the show, Dave discussed his practice and spoke with passion about code as an avenue for creative expression. He introduced our listeners to creative technology and also reflected on the broader impacts of technology on society. He discussed programming in a way I’d never heard before... it was creative, philosophical and subversive.

Listen to the chat:

[recorded: 20/12/2020, Radio Bath]

When we started "The Arts Show," our intention was to help others. Little did I know that it would profoundly help me in return.

As the broadcast concluded, I headed home and immersed myself in the world of creative programming, beginning by watching Dan Shiffman's Coding Train tutorials.

8. First Exhibited Work

Learning p5.js very quickly tumbled into taking deep dives into adjacent areas. It didn't take long before I started to encounter geometry and physics, with the trigonometry I'd learned at school suddenly becoming very useful (I never thought i'd see the day to be honest).

After enjoying countless hours watching tutorials, I shifted to learning through building projects and experimenting. Eventually, I completed my first piece of work that I felt was ready to share.

alternate spirals (moon)

05/01/2023. 3240px x 3240px.

The artwork invites you to ponder your relationship with the moon and explore its mathematical intrigue.

First shown on the 13th October 2022 at the EMERGE Showcase 2022.

Learn more about alternate spirals (moon).

9. To Finish

Thanks for reading! The last year and a half has been an incredible journey.

Looking ahead, i'm particularly enthusiastic about understanding how to embed more of my personal perspectives about the world into the art I make. Lately, I've been exploring the intersection between art and data visualisation, which has led to a sharp increase in the time I spend on my laptop (in a good way).

Having relocated to Bristol just three months ago, I'm starting to discover the local creative coding communities around the area, seeking to engage and contribute to the space.

Finally, remember Dave, the creative technologist I mentioned earlier? Well, we're mulling over an imaginative project involving cardboard boxes, robot costumes, and insightful conversations about artificial intelligence. Stay tuned for updates... and robots?!

10. Connect

If you're interested in chatting about creative programming or collaborating on a prioject you can reach me here:

Instagram

X