A few weeks ago, while working on ReadShape, I was faced with a not very surprising issue. Some books don't have covers. Never did, never will.
How is this possible? Well, when you walk into a book store of course all the books will have covers, even if just to keep all the paper together. But we live in the digital age, where anyone can publish a book without a publisher and in some cases without using proper grammar. In such cases you will often times encounter books without a cover.
This creates a somewhat unique problem. Of course, you can go with a simple solution and just display a cover-not-found.jpeg, but that's not over-engineered enough.
This led me down the colorful & artsy path of generative art.
Essentially, generative art is art which was generated by a machine using an algorithm.
The cool thing about it is that it can output wildly different results each time it's ran.
This is some generative art from Tyler Hobbs titled "Fidenza". Each a different invocation of the same algorithm.
Here is a different algorithm from Kjetil Golid titled "Tilework".
As could be seen from the examples, there's a fair bit of variance in output that each algorithm can produce.
In many cases the algorithm needs to produce some amount of overall uniformity. The Fidenza output would not look nearly as good if each line would go in a new direction randomly.
To have this overall uniformity often times something called a "flow field" (also known as "vector field") is used. Essentially what it does is it creates a grid where each vector contains a direction.
It is more easy to understand with the following picture.
Now that each point sets you going in some direction you simply pick a point and follow the arrows for N steps.
Generating a flow field is something I won't go into, but if you're curious about learning more have a look at this post from Tyler Hobbs.
Now, back to why we're going down this rabbit hole in the first place — books.
Generative art seems to be just the thing I'm looking for. However, something that still has to be kept in mind is that for my use case, given the same inputs, I always want to return the same output. This is simply so that I could save on my S3 bill and generate these covers on the fly.
This means a few things — no random values, no unnecessary dependencies, and it has to be fast.
What I ended up doing was creating a murmur hash based on the input arguments, because murmur is fast and always returns a uint32 value. Perfect for doing probability-based decisions, creating rgb values, and good enough for creating a flow field.
If you're interested in viewing the source code, have a look here: https://github.com/ReadShape/covers
Here are is an example of the outcome
It's simple, fast, and contains a good amount of variety. You can play around with it here.
I hope you learned something new today, and hopefully you'll be able to see these covers in action soon on ReadShape.
You're also welcome to contribute to the GitHub repository.