Minimum viable instructions
Can a set of simple automatic entities behave in complex ways?
How simple, and how complex, are we talking?
These questions were on my mind when, earlier this year, I was asked to create an eye-catching animation for the Web. I was working at Tinybird, and we were implementing a new company marketing site.
The design aimed to evoke the digital realm, you know? It aimed to imply sophisticated algorithmic processes. It aimed to capture the majesty of data in motion. It aimed, let's not forget, to stir the hearts of all our site visitors with the excitement of B2B SaaS.
The assignment
Our most talented designer crafted this concept artwork, and sent it to me one cold morning in February:
And along with it, he sent me this reference animation he found somewhere:
TODO: Find out where he found it and give credit.
Cool. I thought: looks like a vector field representation of fluid flow, or perhaps even simpler: a grid of rectangles perturbed by procedural noise.
I sat on this for a few days (we had higher priority tasks to accomplish for this new marketing site anyways), and one evening I had an idea for how to set my visualization apart.
Seeking a bit more originality
My idea was this: instead of the rectangles representing undulations in some abstract medium beneath, what if, what if, they represented the motion of BIRDS IN FLIGHT!? After all, birds are ON BRAND for a company like Tinybird. And do you know what's also on-brand? Algorithms. (Tinybird is a analytics and data software company.) And do you know what is a classic of animation algorithms? Boids. BOIDS! Little triangles ("bird-oids", as the original author Craig Reynolds deemed them) that fly around your computer screen and influence each other and mingle and group and swoop and... flock.
A chance to visit known territory for myself
Just as many a mountain climber longs to climb a classic mountain peak, I had longed to experiment with simulated bird flocking.
It wasn't that I wanted to study an existing implementation of Boids. Nor did I want to merely play with, or put to use, an existing implementation of Boids. No. I wanted to try myself to come up with my very own version. I wanted to D.I.Y. To go out into that classic territory there on my own two feet (my own ten fingers) and find my own way up the mountain (simulation).
Sometimes, when out in the wilderness, it's more fun to ignore (or to throw away) the map. To find your own route, navigating and discovering for yourself. I thought: I've animated things in motion before, I have a notion of how to simulate birds flocking together. Let me take this as a challenge. Can I come up with a viable approach myself? Can I come up with my own take somehow, or perhaps reinvent the existing, canonical implementation? Or would I end up merely making the dullest virtual birds imaginable? Even that does sound somewhat exciting.
Bringing along a camera and microphone (and screen recorder)
I thought there was a chance this little challenge would turn out interesting, for myself of course, but possibly for others. So I decided to do a recorded coding session focusing on the bird flocking programming part. Here it is if you'd like to watch some:
Bye bye birdies
The next part was this: hide the birds, but keep on simulating them, keep on tracking their invisible motions. Then use this "movement data" to power some kind of systematic animation.
The situation was, the marketing site for Tinybird had no need for flocky birds. What it had was a need for was some kind of intriguing data visualization. Prospective Tinybird users don't necessarily care about virtual creatures, no, what prospective Tinybird customers care about is data (and data tools) in the abstract.
So, the birds were not to remain visible. The animation was to be abstract.
Avian aggregation
I'm sure there are biologists out there tracking the migratory movements of birds and wrangling their data, and creating plots and visualizations to show what the birds are doing. You can imagine a stream of data coming in, needing to be processed, needing to be transformed, stored and then loaded etc. This is Tinybird's cup of tea.
How to visualize this bird motion data? How about some kind of spatial historgram? That's how I interpreted the "grid of rectangles" concept from our designer. An "event" occurs, say a bird moves through a certain region, and we increment a counter for that region. The bird moves through a different region. Increment a counter. We are keeping tallies. Another bird moves through that first region, we increment it again. We are aggregating our events. We are in Tinybird's happy place.
The rectangles in the grid serve as "indicators", they represent the evolving counts of birds which pass through a given region of space. For baseline, at-rest, values, the indicator rectangles are think vertical bars (which you might say evoke the pipe character "|", which is a nice computery association). The rectangles thicken as "bird transit" events accumulate, and furthermore, they tilt according to the dominant direction of the flight of those birds. Then, to keep the animation always fresh, there's a decay behavior, so the rectangles return to baseline. Essentially, what the visualization shows are recent bird transit events on a grid.
Regrettably, I didn't end up doing a recorded coding session for this. But you can play with the final result at ./demo.html.
And here's a screen recording if you prefer:
Birds-eye view
Everybody wants to be able to do a lot with a little, right? And every simulation programmer wants to be able to make something rich and sophisticated with just a few essential instructions, right?
Who among us can resist that talk of "elegance", that idea of "emergence", of flowering complexity spontaneously coming into being from a simple set of rules? Consider Conway's Game of Life. Consider the Three-body problem. (In the case of the three-body problem I guess it's often treated as a nuisance, but, even so, you have to admit it is a magnificent nuisance.) Anyway...
Consider the act of covering vast spaces of possibility in only a few ordinary operations. Consider the challenge of becoming master of a universe that you yourself create. (And doing it all in just one or two evenings.)
To me, sounds like a good time. To me, sounds like:
...the three great virtues of a programmer: laziness, impatience, and hubris
Larry Wall, Programming Perl.
About this Larry Wall quote: