Early generative art

Pioneers of generative art

The computer may be potentially as valuable a tool to the arts as it has already proven itself to be in the sciences. Michael Noll

Once programmed with the right instructions, a single Jacquard loom could produce an unlimited number of copies of a given design without the need for human labor. Maniac - Benjamín Labatut

Generative art dates back at least to the rise of the computer in the 1950s. Immediately, early generative art pioneers realized that the computer may be potentially as valuable a tool to the arts as it was in the sciences. They used (now) archaic programming languages like Algol and Fortran. The corresponding code generated punched tapes that, when read by a computer, printed an output using some form of drawing machine, like the legendary Zuse Graphomat Z64. Indeed, at this time, computers had no screen on which the image could be visualized. Given the inherent limitations of this early creating process, the output was typically a single printed black-and-white piece of art.

We selected four pioneers of generative art, the so-called 3N computer art pioneers (Nees, Noll, and Nake) and Vera Molnár - one of the first women to use computers as an art practice:

  1. Georg Nees (1926 – 2016) was a German mathematician, computer scientist, and painter

  2. Michael Noll (1939-) is an American engineer

  3. Frieder Nake (1938-) is a German mathematician and computer scientist

  4. Vera Molnár (1924-2023) was a Hungarian media artist who studied aesthetics and art history

For each artist, we select and review one piece of art among their artistic portfolio and provide the code generating the work of art recoded in Processing language via a process of reverse engineering.

Schotter, Georg Nees, 1968

Georg Nees worked for Siemens as a software engineer. There, he was instrumental in that company purchasing a Zuse Graphomat, a drawing machine operated by computer-generated punched tape. The machine was capable of creating geometric patterns and, although the programming language that Nees used (ALGOL) was designed specifically for scientific computers, Nees used it to create aesthetic images.

Nees was interested in the relationship between order and disorder in picture composition. In one of his iconic artworks, Schotter (1968), he introduced random variables into the computer program, causing the orderly squares to descend into chaos.

/*
 Generative Art Recoded
 Schotter (Gravel)
 Georg Nees, 1968
 hex6c, 2020
 */

int margin = 60; // margin from border
int nrows = 21; // number of rows
int ncols = 12; // number of columns
float dx, dy; // position displacement
float angle; // rotation angle
float side; // side of the square
float distorsion; // distorsion factor

void setup() {
  size(496, 714);
  background(255);
  distorsion = 1.5;
  side = (width - margin * 2) / ncols;
  for (int x = 0; x < ncols; x++) { // move from left to right (on cols)
    for (int y = 0; y < nrows; y++) { // move from top to bottom (on rows)
      float noise = y * distorsion; // noise is proportional to vertical position
      dx = random(noise);
      dy = random(noise);
      angle = random(-noise, noise);
      tile(margin + x * side, margin / 3 + y * side, dx, dy, side, angle);
    }
  }
}

// draw a square at a given position
void tile(float x, float y, float dx, float dy, float side, float angle) {
  pushMatrix();
  translate(x + dx, y + dy);
  rotate(radians(angle));
  rect(0, 0, side, side);
  popMatrix();
}
Play - Tweak the code

Make a tweak of the p5.js code. If you like the result, fork the code on OpenProcessing and post your own version. Share the link on Discord.

Computer Composition With Lines, Michael Noll, 1964

In 1914 the Dutch painter Piet Mondrian (1872–1944) introduced a horizontal-vertical theme into his paintings which later culminated in the black-and-white painting Composition With Lines (1917). The painting consists of a scattering of vertical and horizontal bars which, at first glance, seem to be randomly scattered throughout the painting.

With further study, however, one realizes that Mondrian used considerable planning in placing each bar in proper relationship to all the others. Conceivably, Mondrian followed some scheme or program in producing the painting although the exact algorithm is unknown.

Michael Noll created a computer-generated version of Piet Mondrian’s painting to determine whether computers could mimic artistic creativity.

Interestingly, reproductions of both pictures were then presented to 100 subjects whose tasks were to identify the computer picture and to indicate which picture they preferred. Only 28% of the subjects were able to correctly identify the computer-generated picture, while 59% of the subjects pre­ferred the computer-generated picture. The study was published in The Psychological Record (1966).

/* 
 Generative Art Recoded
 Computer Composition With Lines 
 Michael Noll, 1964
 hex6c, 2020
 */

float min, max; // min and max lengths of bars
float radius; // radius of the ball
int cardinality = 400; // number of bars

void setup() {
  // a squared canvas
  size(600, 600);
  background(255);
  strokeWeight(6);
  strokeCap(SQUARE);
  // the ball is inscribed in the squared canvas
  radius = width / 2;
  max = radius / 8;
  min = 5;
  int count = 0;
  // draw all bars
  while (count < cardinality) {
    float x = random(width);
    float y = random(height);
    // is the point is inside the ball draw one bar
    if (dist(x, y, width/2, height/2) <= (radius - max)) {
      drawBar(x, y);
      count++;
    }
  }
}

// draw a bar either horizontally or vertically
void drawBar(float x, float y) {
  if (random(1) < 0.5) { // move horizontally
    if (random(1) < 0.5) {
      line(x, y, x + random(min, max), y); // move right
    } else {
      line(x, y, x - random(min, max), y); // move left
    }
  } else {
    if (random(1) < 0.5) { // move vertically
      line(x, y, x, y + random(min, max)); // move down
    } else {
      line(x, y, x, y - random(min, max)); // move up
    }
  }
}
Play - Tweak the code

Make a tweak of the p5.js code. If you like the result, fork the code on OpenProcessing and post your own version. Share the link on Discord.

Hommage à Paul Klee, Frieder Nake, 1965

Frieder Nake created Hommage à Paul Klee from a plotter drawing using a computer program written by himself. It is based on a painting by Paul Klee, entitled High Roads and Byroads, dated 1929.

Nake took Klee’s exploration of proportion and the relationship between the vertical and horizontal lines of the painting as the starting point for his algorithm. Nake then generated the drawing using a pen plotter. By deliberately writing random variables into the process, Nake also allowed the computer to make certain choices within a given number of options.

/*
 Generative Art Recoded
 Hommage à Paul Klee
 Frieder Nake, 1965
 hex6c, 2020
 */

int nrows = 10; // number of rows of the matrix
int ncols = 8; // number of colums of the matrix
// we need a grid of bidimentional points represented by two matrices Mx and My
float[][] Mx = new float[nrows][ncols]; // matrix of x coordinates of points
float[][] My = new float[nrows][ncols]; // matrix of y coordinates of points
int margin = 20; // canvas margin
int noise = 5; // noise factor

void setup() {
  size(600, 600);
  background(241, 237, 233);
  ellipseMode(RADIUS);
  noFill();
  float sidex = (width - 2 * margin) / (ncols - 1); // size of the x side of the rectangular
  float sidey = (height - 2 * margin) / (nrows - 1); // size of the y side of the rectangular
  // load a noisy grid of points
  for (int i = 0; i < nrows; i++) { // move from top to bottom (on rows)
    for (int j = 0; j < ncols; j++) { // move from left to right (on columns)
      // notice that column index j in a matrix correspond to x coordinate on the canvas
      Mx[i][j] = margin + sidex * j + random(-noise, noise); // add x coordinate of point
      // notice that row index i in a matrix correspond to y coordinate on the canvas
      My[i][j] = margin + sidey * i + random(-noise, noise); // add y coordinate of point
    }
  }
  strokeWeight(1);
  // draw horizontal segments
  for (int i = 0; i < nrows; i++) {
    for (int j = 0; j < ncols - 1; j++) {
      line(Mx[i][j], My[i][j], Mx[i][j+1], My[i][j+1]);
    }
  }

  // draw vertical segments from upper line to lower line
  for (int i = 0; i < nrows - 1; i++) {
    for (int j = 0; j < ncols - 1; j++) {
      if (random(1) < 0.5) drawSegments(i, j);
    }
  }

  for (int i = 1; i <= 5; i++) { // draw circles at random positions
    float radius = random(3, 40);
    float x = random(radius, width - radius);
    float y = random(radius, height - radius);
    ellipse(x, y, radius, radius);
  }
}

// draw vertical segments from upper line to lower line
void drawSegments(int i, int j) {
  float x1 = Mx[i][j], y1 = My[i][j], x2 = Mx[i][j+1], y2 = My[i][j+1]; // points on upper line
  float x3 = Mx[i+1][j], y3 = My[i+1][j], x4 = Mx[i+1][j+1], y4 = My[i+1][j+1]; // points on lower line
  int n = (int) random(5, 15); // random number of segments to draw
  boolean dice = (random(1) < 0.15); // probability of drawing a vertical segment
  strokeWeight(1);
  for (int k = 0; k < n; k++) { // draw segments
    // choose a random point (x,y) on the upper line (using the equation of the line passing through two points)
    float m1 = (y2 - y1) / (x2 - x1);
    float x = random(x1, x2);
    float y = m1 * (x - x1) + y1;
    // choose a random point (w,z) on the lower line (using the equation of the line passing through two points)
    float m2 = (y4 - y3) / (x4 - x3);
    float w;
    if (dice) // sometimes just draw a vertical segment
      w = x;
    else
      w = random(x3, x4);
    float z = m2 * (w - x3) + y3;
    line(x, y, w, z); // draw the segment from upper to lower lines
  }
}
Play - Tweak the code

Make a tweak of the p5.js code. If you like the result, fork the code on OpenProcessing and post your own version. Share the link on Discord.

(Dés)Ordres, Vera Molnár, 1974

Vera Molnár, one of the first women to use computers in her art practice, studied aesthetics and art history. Then she learned the early programming languages Fortran and Basic, and gained access to a computer at a research lab in Paris where she began to make computer graphic drawings on a plotter.

Disorder in the fault of a system has always evoked Molnár’s interest. She reflected on the influences that a minor implication of disorder had on regular systems and on the role of random in the process of creation.

/* 
 Generative Art Recoded
 (Dés)Ordres
 Vera Molnar, 1974 
 hex6c, 2020
*/

int margin = 20;
int rows = 17;
int cols = 17;
float side;

void setup() {
  size(700, 700);
  background(250, 245, 245);
  noFill();
  stroke(101, 87, 63);
  side = (width - margin * 2) / cols;
  for (int x = 0; x < cols; x++) { // move from left to right (on columns)
    for (int y = 0; y < rows; y++) { // move from top to bottom (on rows)
      drawQuad(margin + x * side, margin + y * side, side); // draw matrioska quads
    }
  }
}

// draw matrioska quads
void drawQuad(float x, float y, float side) {
  int nsquare = (int) random(5, 10); // number of quads to draw
  float x1, y1, x2, y2, x3, y3, x4, y4;
  int r = 1;
  float l = side / (2 * nsquare);
  pushMatrix();
  translate(x, y);
  for (int i = 0; i < nsquare; i++) {
    // compute four points for an increasingly smaller quad
    x1 = 0 + random(-r, r) + l*i;
    y1 = 0 + random(-r, r) + l*i;
    x2 = side + random(-r, r) - l*i;
    y2 = 0 + random(-r, r) + l*i;
    x3 = side + random(-r, r) - l*i;
    y3 = side + random(-r, r) - l*i;
    x4 = 0 + random(-r, r) + l*i;
    y4 = side + random(-r, r) - l*i;
    strokeWeight(1 * random(3));
    // draw a quad
    quad(x1, y1, x2, y2, x3, y3, x4, y4);
  }
  popMatrix();
}

Play - Tweak the code

Make a tweak of the p5.js code. If you like the result, fork the code on OpenProcessing and post your own version. Share the link on Discord.

Last updated