Automatically generate sprite sheet atlas files for your Phaser JS game with a Node.js script
Written in June 22, 2021 - 🕒 2 min. readIn one of my first game devlogs, I explained how to automate the sprite sheet generation for Phaser 3 using Webpack, but I think it would be more helpful if I had an external script to do that, so anyone can use it.
But why not simply use those websites that mesh together PNG
files into a sprite sheet? Well because Phaser not only needs the PNG
sprite sheet, but also an atlas JSON
file with all the sprite sheet details like frame name and dimensions.

For this I’m going to use the free-tex-packer-core package made by odrick. The basic usage in its documentation looks like the following:
const { packAsync } = require('free-tex-packer-core');
const images = [
{ path: "img1.png", contents: fs.readFileSync("./img1.png") },
{ path: "img2.png", contents: fs.readFileSync("./img2.png") },
{ path: "img3.png", contents: fs.readFileSync("./img3.png") }
];
const options = { allowRotation: false };
async function packImages() {
try {
const files = await packAsync(images, options);
for (let item of files) {
console.log(item.name, item.buffer);
}
} catch (error) {
console.log(error);
}
}
That by itself is already super helpful, but I want to take the extra step and be able to generate sprite sheets for all my sprites, and the way I have my files and folder is:
- original-files
- sprites
- hero
- hero_walking_1.png
- hero_walking_2.png
- hero_walking_3.png
- hero_jumping_1.png
- hero_jumping_2.png
- enemy
- enemy_walking_1.png
- enemy_walking_2.png
With a directories structure like the one above, I can have the following script that will loop through all directories in my sprite directory and get all the images inside each one of them:
const { packAsync } = require('free-tex-packer-core');
const path = require('path');
const { readFileSync, readdirSync, writeFileSync } = require('fs');
const SOURCE_SPRITES_PATH = path.resolve(__dirname, 'original-files', 'sprites');
const SPRITES_PATH = path.resolve(__dirname, 'assets', 'sprites');
async function generateAtlasFiles(assetName) {
let spritesFolders;
// use the parameter or get all folders from a directory
if (assetName) {
spritesFolders = [assetName];
} else {
spritesFolders = readdirSync(SOURCE_SPRITES_PATH);
}
for (const spritesFolder of spritesFolders) {
const spritesFiles = readdirSync(path.resolve(__dirname, SOURCE_SPRITES_PATH, spritesFolder));
const images = [];
spritesFiles.forEach((spritesFile) => {
images.push({
path: spritesFile,
contents: readFileSync(
path.resolve(__dirname, SOURCE_SPRITES_PATH, spritesFolder, spritesFile)
),
});
});
await packImages(images, spritesFolder);
}
}
async function packImages(images, spriteName) {
try {
const files = await packAsync(images, { allowRotation: false });
// let's save the png and json files
for (const item of files) {
// get the file extension
const fileExt = item.name.split('.').at(-1);
// save the file in the sprites directory
await writeFileSync(
path.resolve(__dirname, SPRITES_PATH, `${spriteName}.${fileExt}`),
item.buffer
);
}
} catch (error) {
console.log(error);
}
}
// process.argv[2] is the argument from the command when you run `node script.js arg`
generateAtlasFiles(process.argv[2]);
This script will create the files my-sprite.png
and my-sprite.json
for each of your sprites in your sprite folder when running node generate-sprites.js
, or node generate-sprites.js hero
to generate sprites sheets for only one sprite, in this case, the hero
sprite.
I hope this blog post was useful for you, have a good one!
Tags:
Related posts
Post a comment
Comments
mettli on 6/19/22
This is very helpful! Thank you a lot!