Skip to main content

PSD to JSON

This tool outputs layers of a psd as optimized assets with manifest

Note for Windows users : The generator has only been tested using WSL (Windows Subsystem for Linux). If you don't already use WSL you can learn more here.

Requirements

NOTE: pngquant is required for psd-to-json to run but is not part of the pip installation.

To install pngquant:

macOS users who use brew, can do the following:

brew install pngquant

Or, if you're using Linux or Windows/WSL:

sudo apt install pngquant -y

Configuration

psd-to-json will ook for a psd-to-json.config file in the directory where it is run. This is a JSON document that should have the following fields:

[{
  // output_dir : Where the generated files go.
  "output_dir": "path/to/output/", 
  // psd_files : An array of psd files to be processed each time you run the script.
  "psd_files": [ 
    "path/to/your.psd",
  ],
  // tile_slice_size : For layers in the "tiles" group, how big should the slices be?
  "tile_slice_size": 500, 

  // tile_scaled_versions : Resize tiles to any number of sizes.
  "tile_scaled_versions": [250], 

  // generateOnSave : Runs generator when any one of the PSDs is saved.
  "generateOnSave": true, 

  // pngQualityRange : Control PNG compression. (All PNGs are optimzied)
  "pngQualityRange": {  
    "low": 45,  // lowest possible quality.
    "high": 65  // highest possible quality
  },
  // jpgQuality : Quality of compressed JPG.
  "jpgQuality": 80 
}]

Running the script

Once you have everything as you like it, just run psd-to-json.

If you have generateOnSave set to true, the script will stay active, and saving any PSD in your psd_files array will trigger the script.

You can also run psd-to-json --watch to force generateOnSave to be true for that session.

Layer Naming

This entire tool revolves around layer naming. Layer names are used to determine how you want each layer to be processed. Layer names contain anywhere from two to four pieces of information. Each piece is divided with a pipe ("|") character, like so:

category | name | type | attributes

The number of pipes will determine how the layer name is parsed :

  • 0 Pipes : This layer or group should be ignored.
  • 1 Pipe : This layer contains a category and a name.
  • 2 Pipes : This layer contains a category, a name and attributes.
  • 3 Pipes : This layer contains a category, a name, a type and (potentially) attributes.

Let's go through each piece of information.

category (required)

Categories tell the processor how to treat the layer. There are five categories, which you pass in using the first character:

  • [G]roup : Groups are are just the category you give to groups that you'd like to be read as such. (If you wanted them to be read as a flattened image, you'd use S, see below.) Groups can be nested to any depth and be given attributes. (Even the magic ones, like lazyLoad.)

  • [P]oints : Point layers will be represented in the JSON as an XY point. Because you need to see them somehow, you'll probably want to have some visual representation of the point in your PSD, but take note : the point will register at the center of the layer content. This being the case, I've found that Xs make good point markers.

  • [Z]ones - Zone layers will be represented as a series of points that bound an area. For vector shapes, the bounding box as well as the points of a path will be recorded. For raster layers only the bounding box will be recorded. For example, a vector layer named Z | Boundary would output as a series of points with the name "Boundary".

  • [S]prites - Sprites are output as a PNG. Sprites that are partially off the canvas will be output in their entirity. Sprites can either be image layers or layer groups. In the latter case, they'll just be flattened and treated as image layers. There's a lot to say about sprites. The default behavior is to just output the image, but sprites can also have special types.

  • [T]iles - Tiles can be either groups or individual layers and will also output an image, but but tiles go a step further: they are diced up according to the tile_slice_size you set in config.json. You can also pass in an array of pixel-sizes in to tile_scaled_versions (if you'd like to support zooming, for example) which will generate versions of each tile at that size. Tiles support the jpg type and are generally designed to be lazyloaded, but that's up to you.

name (required)

The layer name can be whatever you want it to be, but be warned : layer names are used to create files, so if you have two layers with the same name they will only produce one file. This can actually be seen as a feature - it permits you to have multiple instances of the same sprite with different positions and attributes, but it could also confuse some folks. I also recommend avoiding special characters in layer names. Using camel case or underscores will make your life easier later on.

So, with those two requirements, here are a some valid layer names.

S | mySprite
P | myPoint
Z | myZone
G | myGroup
T | myTiles

But that's too easy ... let's complicate things a bit.

type (optional)

Types are simple strings that tell the generator how to process a layerGroup. In the resulting JSON, they are also saved as an attribute in that layer's object. See the available types in the types section.

attributes (optional)

For any layer you can pass in a list of custom attributes that are saved to the JSON alongside the rest of the information. See how they work in the attributes section.

Types

Sprites and tile categories support different types. Here's a quick breakdown of each.

Sprite Types

animation

Converts the layers in the group in to an animation spritesheet. No cropping occours so the elments of the animation are correctly placed relative to one another. The layers must all have integers for names (ie. 001, 002, 003). Child layer files are not saved and child attributes lost. This is how you'd name an animation:

S | groupName | animation |

atlas

Converts group in to a packed texture atlas. Child layer files are not saved, but the attributes and positions of children will be found in the "placement" array in the JSON.

S | groupName | atlas |

spritesheet

Convert group in to a simple spritesheet. Child layers are cropped and centered in a frame that is determined by the largest in the group. Child layer files are not saved, but the attributes and positions of children will be found in the "placement" array in the JSON.

S | groupName | spritesheet |

Note : Because the generate spritesheet is making frames of equal size, spritesheets composed of different sized sprites will shift when placed in Phaser. If placement position is important in a case like this, use atlas instead.

Tile Types

At the moment, tiles only support one type.

jpg

Tiles are by default transparent PNGs, but "jpg" tile groups will be exported as JPGs.

S | groupName | jpg |

Attributes

All layers regardless of type support attributes. They are passed in as a comma-separated list, like so:

S | layername | attribute1:value1, attribute2:value2

The attribute name cannot include spaces or special characters. The attribute value can be a string, integers, booleans or arrays.

Strings passed in without a colon are understood to be true booleans.

For example, if you have a layer with the following name :

P | enemy_spawn | level:5, isPrivate, style: "fancy", targets:["pandas", "dogs", "Bob"]

it should output the following JSON :

{
  "name": "enemy_spawn",
  "category" : "point",
  "x": 100,  // position of layer always stored
  "y": 200,  // ditto
  "attributes": {
      "level": 5,
      "isPrivate": true,
      "style": "fancy",
      "targets": [
        "pandas",
        "dogs",
        "Bob"
      ],
    }
  }

Credits

All PSD manipulation thanks to PSD Tools

Texture packing thanks to : https://github.com/Ezphares/TextureAtlas

Code (mostly) thanks to Claude Sonnet 3.5.

Metadata

Release files for psd-to-json 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for psd-to-json 0.0.1
File Interpreter ABI Platform
psd_to_json-0.0.1-py3-none-any.whl Python 3 none any Details

Release files / psd_to_json-0.0.1-py3-none-any.whl

Download URL psd_to_json-0.0.1-py3-none-any.whl
Size 28.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7d4c0ff3253236042b171ef2a589ae162f748e67739c9def4c97c0f1160fe56b
BLAKE2b-256 checksum
How to use checksums
a57df0f2f4e2256c67071bf70b01d77d8cbd535de7686de1e5d2059d62d5cf68
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 4, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.1 This release

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page