Laying out celled sprites & Photoshop automation
by Mark McCoy · 11/01/2006 (2:56 pm) · 14 comments
Lately I've been making sprites from 3d renders. The brutal bottleneck in this process has been getting my directory full of rendered files all laid out into a sheet of celled sprites.
So last night I did some tinkering with Photoshop's javascript interface.
The idea was to take a Photoshop file that has all the sprite cells as layers and convert it into a sprite sheet. Like so:

The initial layered file can be easily made using ImageReady's "Import folder as frames" menu option. Move back into PS (crop the file if needed) run the script and you have yourself a celled animated sprite.
Set the number of columns at the top of the script with the 'cols' variable. (Currently set to 5.) The script figures out the rest (based on the current size of the canvas). Bonus points to anyone who wants to script a little UI to allow user input.
Install it in on your machine in C:\Program Files\Adobe\Photoshop\Presets\Scripts\layersToSprite.js
In Photoshop run it by going to File > Automate > Scripts: layersToSprite.js
This script assumes that the only layers you have in the file are sprites, and that all sprites will be the same size. Also I assume that the bottom layer is the first cell and the top layer is the last cell.
It's not the most robust tool in the world but it'll save me some time, so I thought I'd share. For those who just want a zip file, it can be found here: layersToSpirte.zip
Will work with CS, may work with 7 if you have the scripting plugin installed.
Feel free to modify, expand and share any improvements (or alternative tools).
So last night I did some tinkering with Photoshop's javascript interface.
The idea was to take a Photoshop file that has all the sprite cells as layers and convert it into a sprite sheet. Like so:
The initial layered file can be easily made using ImageReady's "Import folder as frames" menu option. Move back into PS (crop the file if needed) run the script and you have yourself a celled animated sprite.
Set the number of columns at the top of the script with the 'cols' variable. (Currently set to 5.) The script figures out the rest (based on the current size of the canvas). Bonus points to anyone who wants to script a little UI to allow user input.
Install it in on your machine in C:\Program Files\Adobe\Photoshop\Presets\Scripts\layersToSprite.js
In Photoshop run it by going to File > Automate > Scripts: layersToSprite.js
// Put this file in Program Files\Adobe\Photoshop\Presets\Scripts\layersToSprite.js
// Run in PhotoShop: File > Automate > Scripts: layersToSprite.js
// Arrange layers into a sprite sheet.
if (documents.length > 0)
{
var cols = 5;
// --------------------------
docRef = activeDocument;
var activeLayer = docRef.activeLayer;
numLayers = docRef.artLayers.length;
var rows = Math.ceil(numLayers/cols);
var spriteX = docRef.width;
var spriteY = docRef.height;
// put things in order
app.preferences.rulerUnits = Units.PIXELS;
// resize the canvas
newX = spriteX * cols;
newY = spriteY * rows;
docRef.resizeCanvas( newX, newY, AnchorPosition.TOPLEFT );
// move the layers around
var rowi = 0;
var coli = 0;
for (i=(numLayers - 1); i >= 0; i--)
{
docRef.artLayers[i].visible = 1;
var movX = spriteX*coli;
var movY = spriteY*rowi;
docRef.artLayers[i].translate(movX, movY);
coli++;
if (coli > (cols - 1))
{
rowi++;
coli = 0;
}
}
}This script assumes that the only layers you have in the file are sprites, and that all sprites will be the same size. Also I assume that the bottom layer is the first cell and the top layer is the last cell.
It's not the most robust tool in the world but it'll save me some time, so I thought I'd share. For those who just want a zip file, it can be found here: layersToSpirte.zip
Will work with CS, may work with 7 if you have the scripting plugin installed.
Feel free to modify, expand and share any improvements (or alternative tools).
#3
What other tools is google holding out on me?
@Eric: You can make forum posts from the afterlife? Wow.
11/01/2006 (3:34 pm)
@Tom: Thanks! That is the kind of tool I was looking for yesterday on Google. Nice. (Note to self: When looking for tools, skip google, hack together a script that sort of does what you need and blog about it. Then wait for others to link to the tools someone else already made. Easy as pie.) What other tools is google holding out on me?
@Eric: You can make forum posts from the afterlife? Wow.
#4
11/01/2006 (6:08 pm)
Upon additional work flow testing, I'm finding the Photoshop workflow to still be useful, since it allows me to batch crop my renders as well...
#5
11/02/2006 (7:44 am)
This is VERY useful!
#6
Download the "Import Folder As Layers" script here:
user.fundy.net/morris/?photoshop28.shtml
It will magically convert a directory of files into a Layered PSD.
I commented out lines 111 and 112 to preserve the transparency of my files.
11/02/2006 (8:47 pm)
I found another script that allows you to skip the ImageReady step. Download the "Import Folder As Layers" script here:
user.fundy.net/morris/?photoshop28.shtml
It will magically convert a directory of files into a Layered PSD.
I commented out lines 111 and 112 to preserve the transparency of my files.
//docRef.flatten();
//docRef.changeMode(ChangeMode.RGB);
#7
The "Import Folder as Layers" script you referenced -- when I point it to a directory full of 512x512 images, the resulting PSD with multiple layers winds up being 504x490 ...
My images have transparencies, so I commented out the same lines -- but none of the graphics in these images touch the borders of the image itself -- so I'm thinking there's some extra code in there that makes the resulting PSD file as large as the "used pixel area" (or however you want to refer to it as).
Just a heads up to anyone else who may find themselves having this same issue -- perhaps i'll find a fix for it after looking through the code ...
11/04/2006 (10:40 pm)
Hrm -- strange. The "Import Folder as Layers" script you referenced -- when I point it to a directory full of 512x512 images, the resulting PSD with multiple layers winds up being 504x490 ...
My images have transparencies, so I commented out the same lines -- but none of the graphics in these images touch the borders of the image itself -- so I'm thinking there's some extra code in there that makes the resulting PSD file as large as the "used pixel area" (or however you want to refer to it as).
Just a heads up to anyone else who may find themselves having this same issue -- perhaps i'll find a fix for it after looking through the code ...
#8
11/06/2006 (6:11 am)
This can also be done using ImageMagick (free for those w/o photoshop). It's command line, and it took me about an hour to figure out. If you really want to know how it's done, send me an email to remind me.
#9
Not this time!
Although it didn't work exactly as I needed, I had my wife (custom code tech support girl at her dayjob, multimedia scripting advisor when she gets home) change a few things around and blammo! What used to take seemingly forever is now nearly instantaneous. Now my only concern is trying to avoid bogging down the game engine. Ha!
I can confirm that it works in PS CS 3 and I use it in conjunction with the Load Files Into Stack script.
Again, thank you.
J.
12/19/2007 (10:42 am)
Mark. Dude. Nay...I say "God." Thank you! I'm a 3D Illustrator/Animator, etc and every couple of years I do the artwork for a game or two. And every time one of these games shows up, I go out looking for a plug-in or something that will streamline this sprite card thing but wind up failing miserably and go back to doing it manually. What tools that do exist seem to be win only and I don't swing that way. If such tools do exist for Macsters, they are extremely adept at eluding my search tactics.Not this time!
Although it didn't work exactly as I needed, I had my wife (custom code tech support girl at her dayjob, multimedia scripting advisor when she gets home) change a few things around and blammo! What used to take seemingly forever is now nearly instantaneous. Now my only concern is trying to avoid bogging down the game engine. Ha!
I can confirm that it works in PS CS 3 and I use it in conjunction with the Load Files Into Stack script.
Again, thank you.
J.
#10
Here it is.
var title = "Spritesheet to Layers";
// Set up UI.
var dlg = new Window('dialog', title, [100,100,320,155]);
dlg.scTxt = dlg.add('statictext',[10,17,45,35],"Cells X");
dlg.CellX = dlg.add('edittext',[55,15,77,35],'3');
dlg.scTxt = dlg.add('statictext',[80,17,115,35],"Cells Y");
dlg.CellY = dlg.add('edittext',[125,15,147,35],'4');
dlg.okayBtn = dlg.add('button', [155,17,215,35],'Okay', {name:'ok'});
dlg.show();
var cellintx = parseInt(dlg.CellX.text);
var cellinty = parseInt(dlg.CellY.text);
var nextrow = parseInt(dlg.CellX.text);
var cellsizew = activeDocument.width/cellintx;
var cellsizeh =activeDocument.height/cellinty;
// Make Duplicate layers because Photoshop doesn't have paste over function.LOL
var dups = cellintx * cellinty;
for(var i = 1; i < dups; i++)
{
activeDocument.artLayers[0].duplicate();
};
// Rename layers
var lyrCount = activeDocument.layers.length
for(var i = lyrCount-1; i>=0;i--)
{
activeDocument.artLayers[i].name = 'Frame '+(lyrCount-i-1);
};
// Begin shifting the layers working from the top layer down. It moves the images so that the lower left cell becomes the top layer
// and the upper left cell becomes the bottom layer (frame 0). The outer loop determins the row and the inner loop determins the column
var cellmovex = cellintx -1;
var cellmovey = cellinty -1;
var columncount =0;
var columnshift = -cellsizew*cellmovex;
var rowshift = -cellsizeh*cellmovey;
for(var i=0; i<=cellinty-1; i++)
{
for(var subi =columncount ; subi <=nextrow-1; subi++)
{
activeDocument.artLayers[subi].translate(columnshift, rowshift);
columnshift = columnshift + cellsizew;
};
columncount += cellintx;
nextrow += cellintx;
columnshift = -cellsizew*cellmovex;
rowshift = rowshift +cellsizeh;
};
// Crop final image once all the layers are in place.
activeDocument.crop (new Array(0,0,cellsizew,cellsizeh));
08/27/2008 (2:53 pm)
I ran across Mark McCoy's post and thought "Hey I need that!" and then I thought I need to do it in reverse too. So I decided to write one. Here is the code. Forgive me if it is sloppy or not propper format for javascript but I didn't have any experience in JS for Photoshop until this morning. I didn't even know PS did this. lol I have tested it best I can and it works for me. I have PS CS3. Save it where ever and run it as a script in PS. Enter the number of Cells X and Y click the okay button and it will do the rest. It will give you a cropped layer version of you spritesheet. With the last frame on top and the first frame on the bottom.Here it is.
var title = "Spritesheet to Layers";
// Set up UI.
var dlg = new Window('dialog', title, [100,100,320,155]);
dlg.scTxt = dlg.add('statictext',[10,17,45,35],"Cells X");
dlg.CellX = dlg.add('edittext',[55,15,77,35],'3');
dlg.scTxt = dlg.add('statictext',[80,17,115,35],"Cells Y");
dlg.CellY = dlg.add('edittext',[125,15,147,35],'4');
dlg.okayBtn = dlg.add('button', [155,17,215,35],'Okay', {name:'ok'});
dlg.show();
var cellintx = parseInt(dlg.CellX.text);
var cellinty = parseInt(dlg.CellY.text);
var nextrow = parseInt(dlg.CellX.text);
var cellsizew = activeDocument.width/cellintx;
var cellsizeh =activeDocument.height/cellinty;
// Make Duplicate layers because Photoshop doesn't have paste over function.LOL
var dups = cellintx * cellinty;
for(var i = 1; i < dups; i++)
{
activeDocument.artLayers[0].duplicate();
};
// Rename layers
var lyrCount = activeDocument.layers.length
for(var i = lyrCount-1; i>=0;i--)
{
activeDocument.artLayers[i].name = 'Frame '+(lyrCount-i-1);
};
// Begin shifting the layers working from the top layer down. It moves the images so that the lower left cell becomes the top layer
// and the upper left cell becomes the bottom layer (frame 0). The outer loop determins the row and the inner loop determins the column
var cellmovex = cellintx -1;
var cellmovey = cellinty -1;
var columncount =0;
var columnshift = -cellsizew*cellmovex;
var rowshift = -cellsizeh*cellmovey;
for(var i=0; i<=cellinty-1; i++)
{
for(var subi =columncount ; subi <=nextrow-1; subi++)
{
activeDocument.artLayers[subi].translate(columnshift, rowshift);
columnshift = columnshift + cellsizew;
};
columncount += cellintx;
nextrow += cellintx;
columnshift = -cellsizew*cellmovex;
rowshift = rowshift +cellsizeh;
};
// Crop final image once all the layers are in place.
activeDocument.crop (new Array(0,0,cellsizew,cellsizeh));
#11
01/13/2009 (2:24 am)
Never too late to say thank you for this script! Thanks!
#12
06/21/2009 (9:26 pm)
Thank you very very much! This is very nice.
#13
11/27/2010 (11:11 pm)
I just signed up specifically to say thanks so much for the awesome script. It's my first time making a game and I honestly have no idea how to make the spritesheets from hundreds and hundreds of frames any easier than this. You really saved me a lot of time. Thank you thank you thank you! :)
#14
03/28/2018 (12:23 am)
I'm a 3D Illustrator/Animator, and so forth and each couple of years I do the work of art for a diversion or two. What's more, every time one of these recreations shows up. ipad Customer Service Number also gives information about your site. 
Associate Eric Elwell
Mark McCoy's Animated Sprite Shader!!