A while back, I got an ominous and semi-threatening email from... my sprite packing tool. They had "detected" that I was using a Single User license on a machine also running Jenkins, a Continuous Integration (CI) tool. Indeed, I bought another license for this tool and set it up on my living room PC to build my game as I push new commits. I ignored this threatening email because the CI was broken anyway. Until yesterday, when I tried to revive the CI setup, and I saw that the stupid sprite packing tool broke the whole fucking build pipeline! π‘
If you look on the website for TexturePacker CI licenses, it will cheerfully inform you that you can buy a "TexturePacker Floating License Subscription" for β¬120/year (with tax). Every year! This price point is ridiculous if you're a bootstrapped indie like me. I could buy at least two sprites for that kinda money. But if you're working for a big corp (also me), that price point is way too low! The amount of paperwork involved in getting a purchase approved is the same whether the license is β¬120/year or in the low five figures.
But the problem this package solves is really not that complicated. It grabs images from a folder and puzzles them into larger images. Sure, bin-packing is an NP-hard problem, but there are plenty of algorithms that are "good enough." That's the difference between Computer Science and Computer Plumbing, after all. So I looked for an open-source alternative and found Free Texture Packer. Hilarious.
Feature-wise, Free Texture Packer is almost exactly what I need. It outputs a JSON file with the same keys and values as the other tool. The difference is that it can only output PNG images and not WebP, but that's not a huge loss because I can always hook up another step to the asset-building pipeline. π¨
One wrinkle is that it stores folders and images as absolute paths in the project files:
{
"meta": {
"version": "0.6.7"
},
"savePath": "D:\\Projects\\SSSG\\intermediate\\resources\\sprites",
"images": [],
"folders": [
"D:/Projects/SSSG/resources/sprites/actors/bobby",
"D:/Projects/SSSG/resources/sprites/actors/chichi",
"D:/Projects/SSSG/resources/sprites/actors/riya"
],
"packOptions": {
...
}
}
I tried using relative paths anyway, but the package just chokes on that. I should really submit a patch, but in the meantime, I resolved this issue by creating a temporary project file with a bit of Python code that has the absolute paths set up correctly:
def fixProjectFile(self, project_path):
self.log.info(f'Fixing project file "{project_path}"')
with open(project_path, 'r') as input:
project = json.loads(input.read())
parent = str(Path(project_path).parent)
new_images = []
for it in project['images']:
stripped = str.replace(it, self.project_root, '')
it = str.replace(parent + stripped, '\\', '/')
self.log.debug(f'image "{it}"')
new_images.append(it)
project['images'] = new_images
new_folders = []
for it in project['folders']:
stripped = str.replace(it, self.project_root, '')
it = str.replace(parent + stripped, '\\', '/')
self.log.debug(f'folder "{it}"')
new_folders.append(it)
project['folders'] = new_folders
self.log.debug(str(project))
with tempfile.NamedTemporaryFile('w', encoding='utf-8', delete=False) as temp:
json.dump(project, temp, indent='\t', sort_keys=True)
temp.flush()
return temp.name
Conclusion
TexturePacker fucked me over for a measly β¬120/year. As a result, I looked for a free alternative, and I would be hard-pressed to recommend the tool now.

