In this tutorial, participants will learn to build generative art tools using Observable JavaScript notebooks. In doing so, they will build interfaces that control the inputs to art rendering functions. As a starting point, consider the work of Vera Molnár. Her algorithmic renderings of simple geometric shapes in many ways set the groundwork for contemporary generative artists.
The generative aspect of the above work is the randomness or noise in the rendering of the shapes (quadrilaterals). While a computer generates the randomness, there are a variety of design decisions made by the artist, such as:In this tutorial, participants will learn how to identify the pertinent inputs to generative art systems, and build user-interfaces for controlling those parameters.
As you can see, exposing design decisions as function parameters allows you to easily experiment with different designs. You may similarly want to experiment with augmenting how much randomness the computational system injects into your work:
The code underlying such systems is rather straightforward, though requires an understanding of how
<path>
elements are drawn in <svg>
elements:
// Render a single shape, given four corners
function renderQuad(corners = [{ x: 0, y: 0 }, { x: 100, y: 0 }, { x: 100, y: 100 }, { x: 0, y: 100 }]) {
const [c1, c2, c3, c4] = corners; // create four variables for more expressive code
// Return an element (this syntax is how Observable allows rendering of an SVG element)
return svg`<path style="fill:none; stroke: black; strokeWidth: 1px;"
d = "M" + c1.x + " " + c1.y + // move to top left corner
" L" + c2.x + " " + c2.y + // line to top right corner
" L" + c3.x + " " + c3.y + // line to bottom right corner
" L" + c4.x + " " + c4.y + // line to bottom left corner
" Z" // close the path
/>`;
}
The randomness comes from a fairly straightforward function that can easiliy be expanded upon:
// Compute corners of a quad
function getCorners(edgeLength, distortion) {
// A helper function to get *different* random distortions for each edge
const getOffset = d => (Math.random() - 1) * d;
let c1 = { x: getOffset(distortion), y: getOffset(distortion) }; // top left
let c2 = { x: c1.x + len + getOffset(distortion), y: c1.y + getOffset(distortion) }; // top right
let c3 = { x: c2.x + getOffset(distortion), y: c2.y + len + getOffset(distortion) }; // bottom right
let c4 = { x: c3.x - len - getOffset(distortion), y: c3.y + getOffset(distortion) }; // bottom left
return [c1, c2, c3, c4];
}
To see more options, see this notebook. And to learn more, attend the tutorial!