As I was poking around the Internet the other day, I ran across Jared S Tarbell's Gallery of Computation . I was really impressed with what he had done, especially since a few of his ideas were exactly where I was trying to go! I believe I had seen something about his Sand Stroke a few years back, and liked the effect. My Watercolor Stroke is the same basic idea, clearly borrowed from Sand Stroke! Now that I’ve found the site again, I’ll be studying his code closely!
This post is going to be more about Rust than about art. You have been warned! As I was working on moving the Hyphae code into TAHGA Lib , I found too much complexity and repetition in what I had done before. What I was doing to modularize it for the library was making matters worse. The problem was that I needed a structure to define a hypha, a single strand that grows over time until it dies. Then I needed a structure, to define a list of hyphae (for those of you who are confused by these terms: hyphae is the plural of hypha.) The Hyphae struct would not only hold the list of Hypha instances, but some housekeeping information as well. In particular, I wanted to set various parameters there which would affect how the hyphae would grow (for example, a initial growth speed, a maximum speed, etc.) So the Hyphae structure would provide a method to generate a new Hypha struct and add it to the list of hyphae.
Those of you who are paying close attention (all of you, I am sure…) may have noticed that things are getting just a bit unwieldy. Two recent posts, The Return of the Boids and Flying Triangles , both use the Boids algorithm. Likewise, two other posts, Watercolor Stroke and Revisiting the Watercolor Stroke , both rely on the Watercolor Stroke code. What’s more, the Watercolor Stroke is intended to be used in several future projects. This means all that code ends up being copied into a bunch of different programs. This is not very efficient! There must be a better way!!
I recently did a post about the watercolor stroke, a method to add a color wash along a line. I’ve extended this to use multiple colors. You can still pass it just one color as before, using the color() method. But now there is also a colors() method by which you can pass in any number of colors. Watercolor stroke will choose a color from the list at random, and will use that color until one of two things happens:
You may have noticed that, in my Nannou apps, I tend to use hsla colors. hsla is hsl plus an alpha channel, a, to control transparency. The hsl part defines the color. hsla stands for hue, saturation and lightness. In this color model, hue is the color itself. You can think if it as being chosen from a color wheel. In many implementations, this number is a number of degrees (0 to 360) or radians (0 to 2pi). In Nannou, it is a number from 0.0 to 1.0. Note that, because of the circular nature of the hue, 0.0 and 1.0 are the same color! Look at the image at the top of this post. It displays hues from 0.0 (along the bottom) to 1.0 (along the top). 0.0 is red. increasing it cycles through all the colors of the rainbow, and back to red at 1.0. If you were to keep going past 1.0, the colors would all repeat. For example, you would find that 1.1 is the same color as 0.1.
Recently, I had an idea about adding a color wash to a line. Suppose, in real life (not digitally,) I made a line of watercolor paint on some paper. Then suppose I took a very fine brush and smeared the paint at right angles to the line. I could go down the line and smear each part of it a different amount. This being watercolor, the darkness of the color in the smear would be greatest if I smeared it just a little, but if I smeared it a lot, the color would become quite light. I decided to try and do this digitally (so I don’t have to clean any paint brushes afterwords.)
I find myself, when I start a new project, spending a lot of time setting up a basic app before I get to the point where I can create something fun. I have to create a Rust application, set it up to use Nannou, create a basic Nannou app, test it to make sure it’s working (typos are inevitable, it seems). Then I have to add in any cool features I may have come up with from past apps I have done, which means remembering where I did it and copying in the code. The obvious fix for this is to make a template to use as a starting point for new projects. Unsurprisingly, that’s exactly what I did!
inconvergent has a great article about generative art, with many excellent examples of various techniques. While reading the section about Hyphae , I decided to give it a try and see what I could come up with along those lines. Hyphae (the plural of hypha) are long tendrils that grow from fungi. They grow from their tips, and will often branch new tendrils. My goal was to come up with a system to simulate their growth by following these rules:
Sol LeWitt was an artist who worked in many mediums. and was known for his association with the conceptual art and minimalism movements. As you know if you have been reading my posts here, I am interested in generative art. While Sol LeWitt was not a digital artist, he did do some interesting work in algorithmic art: his Wall Drawings . LeWitt believed that the idea behind a work of art, rather than the act of producing it, was the actual art work. He rejected the idea that who did the actual work was of primary importance. So he produced instructions (algorithms) for various pieces of art and had others draw them. Some, like Wall Drawing 46 , were very vague:
L-Systems can be used to draw plants! To make this work, we need to add some capabilities to our Turtle structure. Up until now turtles could either move ahead or turn. To draw plants, we need to be able to save a turtle state, do some drawing, and then move the turtle back to the saved state. This has the effect of magically teleporting the turtle to someplace it has already been, restoring its position, direction and color.
Let’s look at L-Systems ! Also known as Lindenmayer Systems, after their inventor, Aristid Lindenmayer , L-Systems are sets of rules for manipulating symbols. They consist of an alphabet of symbols that can be used to make strings, and a set of rules used to transform those strings. When fed a starting string, it will produce a sequence of new strings based on its rules. This was originally a way to formally describe the growth of fungi, algae, etc.
Turtle graphics are a form of vector graphics. In its most basic form, there is an object that moves around the canvas, leaving a trail as it goes. It’s called turtle graphics because you can think of the object as turtle with a pen strapped to her shell. The turtle can do two things: 1) move in a straight line for a certain distance, and 2) rotate to face a new direction. With a combination of move and rotate commands, the turtle can draw many kinds of objects.
Today, we’ll try to come up with something interesting based on the noise concepts we discussed in the last two posts. We’ll put some dots (which we’ll call particles) randomly on a canvas and have them move according to rules based on our noise functions. This will create streams of particles; we’ll be able to see their paths on the canvas. In a fit of not-very-creative naming, we’ll call our project Streams. This project is based on a similar project from the SARPEX blog and uses many of the concepts found there.
Last week we talked about noise, specifically Perlin noise, which lets you vary a value randomly but incrementally, leading to a slowly changing value. We used it to draw the outline of a mountain range, but it can be used anywhere you need a value that changes a tiny amount at a time. Conveniently, this also works in two dimensions. In 2-dimensional noise, the x and y axes each have their own noise, and (and this is important) they are not the same. So instead of asking the noise generator for a value at a position along a line, you have to pass it two values; you are asking for a value at a position on a plane.
Sometimes you just want to make some noise! In drawing terms, that means you don’t want a boring straight line; you want a straightish squiggly line which looks hand-drawn. Or you don’t want a flat surface, you want it to have some texture. You can generate these kinds of effects by adding some random noise, but how? There are a couple of ways to do this. We’ll cover some simple examples here.
Way back when I did my very first The Artist's Husband post , I used Javascript and p5.js to create a drunken lines drawing, a drawing where the direction of a line (as well as its color) is chosen by random. Doing this over and over again eventually fills the windows with a colorful image such as the one at the top of this post. Here is a Nannou app which does pretty much the same thing:
In my last post , we set up a basic sketch in Nannou. This week, we’ll look at a Nannou app. A Nannou app is like a Nannou sketch, but with more capabilities and tighter control of what is happening. They are very similar; in fact a sketch is just a shortcut for an app when you don’t need the features an app provides. This can save you some typing.
Now that you have Rust and Nannou installed , lets look at a basic Nannou sketch. A sketch in Nannou is a fast way to get a drawing displayed. Here is a simple one which just draws a rectangle and an ellipse on a colored background. use nannou::prelude::*; fn main() { nannou::sketch(view).run(); } fn view(app: &App, frame: Frame) { let draw = app.draw(); draw.background() .color(LIGHTBLUE); draw.rect() .color(ORANGE) .w(100.0) .h(200.0) .x_y(200.0, -100.0); draw.ellipse() .color(DARKGREEN) .w(200.0) .h(230.0) .x_y(100.0, -50.0); draw.to_frame(app, &frame).unwrap(); } So what is going on here? At the top level, the three important parts of this sketch are the use statement, which imports all the Nannou components we need, the main() function, and the view() function. This is, in itself, a complete Rust program as well as a Nannou sketch. In Rust, the main() function is where the program starts – it’s the code that is executed when the program is run. In this case, that is just one line: nannou::sketch(view).run();, but there’s a lot going on on that line!
In my last post , I mentioned Nannou , a generative art framework for the Rust programming language. While I am focusing mainly on drawing here, Nannou goes much further dealing with user interface, audio and video, and even lasers ! Its goal is to provide tools for artists building any kind of art installation. For drawing, it is similar to Processing in how it is used, and therefore similar to all the other frameworks I’ve discussed here, which are all based on, or at least inspired by, Processing.
This is my first real new post since 2020. All the ones posted at the end of 2023 were written back in 2020, and have been backlogged while we dealt with personal issues. New year, new posts! In my previous posts, I’ve explored some basic generative art in a variety computer languages and art frameworks. We tried Javascript with p5.js , Clojure with Quil , and Java and Processing . I don’t have any post to document it, but in the past few years, I also experimented with Kotlin and Go for artwork.