Lessons in Avatar Generation
Making a generative profile picture collection isn't easy. But we're making it easy for ourselves.
This year, smol farm has released a few different profile picture-oriented collections: Dastardly Ducks, its spinoff Dastardly Moonducks, Yo Kitties, and, most recently, corg corg. For the Dastardly Ducks, I hastily assembled a hacked-together, purpose built generator, never planning on reusing the code again. When Cat Cora approached us about the Kitties, I knew I needed a cleaner solution. So I built one from scratch, designed to be the core code for our image generation going forward. That lasted mere months.
Today, we have a working prototype of yet a new NFT generation system. To test it out, we have loaded our previous projects into it and managed to generate expected results. However, we wanted to think bigger about functionality and flexibility. Prior attempts made assumptions about what an NFT collection and its assets would look like — and that was self-limiting.
Decouple Components from Layers
Every image generated in a smol farm profile picture project is assembled from a series of png layers. For our initial projects, it made sense to think of a layer as synonymous with a complete “piece” of the puzzle that made up a given duck, corgi, or kitty. However, when moving beyond basic, cartoony composition, this complicates things.
Consider profile-view collections like Azuki or, more recently, its derivative Mizuki. In such a composition, the head itself is sandwiched between two possible layers of hair — color and cut in the front should match what is visible behind their head. For short hairstyles, this may mean there is no “back” part of the hair, but it is an important consideration for hairstyles that need it.
To solve this, we now think of a “component” of the NFT as having anywhere from zero to infinity “layers.” Layer-less components enable them to still affect the NFT’s traits, such as giving the character astrology signs — as is popular in witch-themed collections. If it does have layers, each one has a z-index that determines what order it should render in the final image.
Separation of Concerns
Our second-generation system had one giant module that both handled configuration of the NFT collection — setting its layers, name, size, etc. — and all of the generation itself. While the code was cleanly written, it was still a rather large, complex file that relied too much on interconnected logic and various aspects being held in memory.
Instead, we now work from the assumption there are three distinct phases to generating a collection:
configuration - determining the parameters of a generation
generation - turning a configuration into a data set
rendering - creating the final media file from the data set
Now it will be easy to improve and upgrade these distinct modules — or even swap them out entirely. For instance, the current renderer is written in TypeScript. It is of no doubt native code could provide better performance and support for multithreading than going through node.
Extensibility Shouldn’t be an Afterthought
When making custom-built generation scripts, extensibility is of little issue. You know what you need and can write everything with that in mind. However, these assumptions quickly box in what your code is capable of doing. This even led us to always following patterns like “Collection Name #0123” for the names of the NFTs in these collections.
Now, everything has a default behavior that can be overridden. This reduces the complexity in cases where the additional functionality is not needed — but still lets us do cool stuff like how crypto coven and Galverse gave each witch a unique name. The default “namer” function just follows that classic pattern of the collection name and a serial number.
But now that can be overridden with something that can provide delightfully fantastic names. Same goes for the description too — enabling the generation of biographies for the characters.
Extensibility should also be easy. For instance, since a lot of collections add the three sets of zodiac signs — sun, moon, and rising — we want to be able to just drop in that as a feature without having to rewrite it every time.
Final Thoughts
This new generation system is still in its infancy and needs polishing and documentation before use outside of smol farm, but it now is capable of doing everything we have done thus far on a profile picture generation front. What is exciting is where we can go from here. Though we became known for our fairly simplistic cartoon animals — and we will continue to nurture that adorable world we have created — we want to make sophisticated generative art. As always, we deeply appreciate those coming along for the ride.
Thanks for Reading!
smol farm gazette is an independent publication by smol farm. All proceeds go to support independent lesbian creators. Most content is free, and the rest — along with the ability to comment — is just $5/mo.