florian marending

03 Dec 2022

A study of lines

Some schmuck tries his hands at generative art

After moving into a bigger apartment, I've found the walls of our office to be a bit naked. While I'm a hobby photographer and would like to get more into printing my work, for this space I have something else in mind.

It started with finding out about generative art via Tyler Hobbs' Fidenza. I found the look of this type of art very appealing. Maybe because I lack artistic talent, I like the idea of guiding randomness towards aestethic order, rather than create from scratch.

On this page I want to systematically explore techniques and patterns to generate interesting structures. To prevent myself from getting lost in the endless possibilities, I will restrict myself to straight lines.

How do I go about generating my lines?
Initially I had two programming languages in mind: Rust or Javascript. Rust being my favorite language was an obvious choice. However, the dynamic nature of JS lends itself to a problem like this. No sense in fighting Rusts borrow-checker for interactive code, and the upsides you get in turn don't really come into play here. What further seals the deal for me is that JS-based code can be natively embedded right here, on this page.

Next, I was exploring libraries that would make the whole ordeal easier. Top contenders include p5js, Pts.js and Paper.js. Ultimately, I came to the conclusion that I don't need the extensive feature sets of any of these libraries. Animation, physics and geometry utilities are nice-to-haves but unlikely to see any use in my use-case. Instead, all I really need is a way to programatically draw lines, ideally in a way that I can get a high-resolution image out of it somehow for print. And what better way to do this than with our good old friend, the SVG. So I just directly construct SVGs in my SolidJS components.

So without further ado, let's draw some lines!

Fig 1. Not a straight line

Wait, that's not a straight line! I just wanted to make sure you're paying attention. Many infinitesimally small straight lines can approximate a curve, you might say. That violates the spirit of the exercise, you silly goose, I would retort.

Fig 2. A straight line

Much better, we're checking all the boxes. Well, the one. If I was a famous artist already, I would hang this on the wall and have critics say clever sounding things about it. Alas, I need to try a bit harder. Let's try to bring some repetition into the mix, and while we're at it, some randomness.

Note that all the pieces on this page that contain randomness are uniquely generated for each page view. Consider yourself special!

Now we're getting somewhere! It's no masterpiece, but I don't hate it.

Excursion into wrong transforms

Before I arrived at the above piece, my makeshift SVG rendering blessed me with this abomination:

The problem here is the the origin of the rotational transform. You see, drawing a line that is not horizontal in an SVG could be accomplished by providing the start and endpoint (which do not have the same y coordinate) explicitly. When generating lots of randomly rotated lines of the same length, we have to do some trigonometry to figure out one of those points. And I for one don't have time to use my brain like that.

Instead, I want to draw my line horizontally, and then rotate it using the rotate transform that SVG provides.

<svg width="600" height="400" xmlns="http://www.w3.org/2000/svg"> <line x1={x} y1={y} x2={x + 50} y2={y} transform="rotate(rand())" stroke="black" /> </svg>

This way I don't have to do any math, just generate random numbers for the rotation. As it turns out, this doesn't work correctly as we have seen above. The lines are rotated about the (0, 0) origin instead of the center point of the line. To fix it, we either set the transform-origin property on the SVG correctly, or we get fancy:

<svg width="600" height="400" xmlns="http://www.w3.org/2000/svg"> <line x1="-25" y1="0" x2="25" y2="0" transform="rotate(rand()), translate(rand(), rand())" stroke="black" /> </svg>

We draw lines with center points on the origin and use the transform both for rotation and for translation. This way we don't have to set the origin of transformation. Note the order of the transforms: They are applied from right to left. If we first translated, we would have the wrong transform origin again.

While the above piece starts to look interesting, we have a bad case of untamed randomness. We might get more visually appealing structures by restricting e.g. the angle of the lines.

At this point I'm not sure if there is an optical illusion with all these specs-of-dust-looking things between the lines or my monitor is dirty. We will never know.

Adding more, smaller lines and rotating them around by 90 degrees makes this look a bit like rain. What if we try segmenting our piece into multiple regions with distinct handling of rotations? Let's say we keep all the angles at exactly 0 degrees, unless the midpoints of the lines are within a given distance of some random point. For these, we generate rotations between 80 and 100 degrees. We expect to see some area of disturbance around our chosen point.

That's quite nice! But that sharp transition between horizontal and vertical lines is almost screaming for a nicely feathered approach. What if we use the distance between the center point of a line and our epicenter to tune the rotation of the line? Say, the closer the line, the more upright, i.e. 90 degrees, the line is.

Fun fact: At this point in writing this note, the /notes/lines page you're currently viewing can be server-side rendered approximately 40 times per second. Compare that to 1000 times per second for the landing page! All that SVG generation already takes its toll on my little server. I think I'll have your browser do all the work instead and turn off server-side rendering for this page.

Alright, that turned out less interesting than expected. Maybe we're overdoing it with the randomness a bit. Currently there is nothing really of interest to see, everything is kind of the same, arbitrary. When we look at other works of generative art, we can often see artist driven macro features. Only the details are left to chance. They feel a lot more deliberate than what I've been pumping out here. So let's give that a shot instead.

Work in progress