Disclaimer: I do not claim expertise in any of the tools/software mentioned. If you just want an explanation of the script, skip to the “Let’s Get to Scripting!" section.
Short backstory: It’s late Fall of 2021. I delved into the field of NFTs in the crypto space, and came across The Lizard Lab (@LizardLabNFT). Wanting to stick with one project and help grow a community, I began making memes and image edits. The lore-based nature of the project and the variety of traits piqued my interest, and I began exploring more methods of art generation, first by clipping images/assets via GIMP and assembling them in Sony Vegas, and then eventually I came across an open-source 2D animation tool: Synfig Studio.
Put simply, Synfig is animation software designed to allow creating animations without a need to draw frame-by-frame; one method is through asset/image manipulation - you select a start and endpoint over a given timeframe, and the software calculates how best to move the asset between the two points (rotation, scaling, etc.), filling the gaps. Not knowing how to draw, I saw this as an interesting way to create animations and tell small ‘stories’ in spite of my lack of skill - I had no art or animation experience prior to this, I saw it as a way to support a project I cared about.
I could position and manipulate assets however I wanted, come up with mini ‘storylines’ or looping ‘sequences’, and then generate them as GIFs to share with the community, promoting growth and engagement. A lot of this came from raw creative ideas - take an asset, come up with a sequence where it makes sense to move it, then use Synfig to position it accordingly. Lots of trial and error and moving multiple assets in tandem to come up with a cohesive animation.
I didn’t think too much of what I was doing - though the Lizard Lab team was extremely supportive and generously gave me access to all the project’s raw assets to do with as I pleased. At some point, though, I made an interesting discovery - the Synfig file format (.sif) is an “uncompressed human-readable XML file format” (per their website):
This meant certain parameters could be adjusted by directly modifying code instead of using the Synfig interface. Somehow(?) I made a mental connection to the Python programming language - hang on, what if you could programmatically edit, or even create animations with code this way? I’d dabbled in Python scripting for many years, and I knew it had built-in XML support to edit tags and values! With this knowledge, I pieced together an idea - I would animate every single trait of the Lizard Lab NFTs, and generate the animation files with Python!
I had every asset and trait at my disposal for each NFT, and I could crank out trait animations - how could I maximize efficiency with Python in such a manner?
My first thought was, generate a new raw .sif file using Python for each NFT, animate the assets in a ‘main file’, then copy and inject the animation data into each individual .sif file. This gave me an advantage of only needing to animate each unique trait once, and then I could apply it to every animation file that had that trait. This quickly proved too tedious - creating the individual .sif files purely by Python, while possible, required extensive planning to account for all possible tags, variables, and so on (this might be easier if all the traits were already animated, but as of this writing they are still in progress.)
It then struck me - the end .sif files weren’t the actual animations, they would need to be rendered separately anyway. What if I could just… compare each NFT’s trait list to the main file, and toggle on/off what I needed? I had all the assets in separate folders (one folder per NFT), I could probably go through them that way…
import os
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import ElementTree, Element
def asset_toggler(liz_num):
'''For a given lizard number,
iterate through the main animation file and check each layer -
if a layer matches an asset in the lizard's folder, toggle the layer view to "true"'''
tree = ET.parse(animation)
root = tree.getroot()
lizard_dir = base_dir + f"/{liz_num}"
# Reset all animation layers to "false"
for layer in root.iter('layer'):
if (layer.attrib['type'] == 'group') and (layer.attrib['desc'] in lizard_files):
layer.attrib['active'] = "false"
# Check if a lizard directory is valid first
if os.path.isdir(lizard_dir):
lizard_files = os.listdir(lizard_dir)
for layer in root.iter('layer'):
if (layer.attrib['type'] == 'group') and (layer.attrib['desc'] in lizard_files):
layer.attrib['active'] = "true"
# Write to animation file
tree.write(f'LIZARD_ANIM_{liz_num}.sif', encoding='UTF-8', xml_declaration='True')
This is not the whole code but it’s the basic concept - the full code is available on my GitHub, only 37 lines (while writing this I thought of some small optimizations, so it will be updated soon). To summarize:
This both allows for creating each animation only one time and then creating individual animation files for each NFT. For those wanting to animate entire collections, this process can save a lot of time/hassle - although if this is something artists/animators want to pursue, I would highly encourage projects to provide raw assets where possible to make this easier.
Thank you for reading! If you liked this article, feel free to explore any of the open-source projects I mentioned (GIMP, Synfig Studio, Python) - and consider donating to/supporting them! One of my end goals is to give back to them through my works. Depending on feedback, I might explore/explain my animation process in future articles.