Skip to main content

Convert Photoshop PSD files to Spine 2D skeletons (JSON + atlas + page PNG).

Project description

pspine

Convert Photoshop PSD files to Spine 2D skeletons (.json + .atlas + .png) — without opening Spine.

A reverse-engineered re-implementation of Spine's PSD importer. Verified against Spine 4.2.43 ground truth: byte-identical skeleton JSON (modulo hash) and pixel-identical per-layer regions; atlas page layout is structurally equivalent (different shelf-packer geometry — Spine doesn't care).

Quick start

uvx pspine my-symbol.psd

Writes my-symbol.json, my-symbol.atlas, my-symbol.png next to the input.

Usage

pspine [OPTIONS] PSD_FILES...

Options

Flag Effect
-o, --output DIR Write outputs to DIR instead of next to each PSD.
-n, --name NAME Base filename (no extension) for outputs. Single input only.
-q, --quiet Suppress progress; errors still print to stderr.
-v, --verbose Print extra detail per step (canvas size, every layer name, atlas shape).
--no-color Disable ANSI colors.
-h, --help Show help.
--version Show version.

Output is colorful by default and downgrades automatically when stdout isn't a TTY.

Examples

# Same folder as PSD (default)
pspine input.psd

# Specific output folder
pspine input.psd -o build/spine/

# Multiple PSDs into one folder
pspine assets/*.psd -o build/spine/

# Custom base name
pspine input.psd -n symbols-blue

# Verbose run
pspine input.psd -v

# Pipeline-friendly (no colors, no progress)
pspine input.psd --quiet --no-color

Layer name conventions

pspine mirrors Spine's PSD importer rules:

  • Each visible leaf pixel layer becomes one slot + one attachment with the layer's literal name.
  • Layer names containing [ignore] are skipped.
  • All slot names within the skeleton must be unique. Duplicates after the first are skipped with a yellow warning.

Group structure is currently flattened (no [skin] / [bone] / [slot] group-tag handling). If your PSD has duplicate leaf names across groups (a common pattern in slot-machine sheets), either rename the duplicates or [ignore] the noise layers. Multi-skin support is on the roadmap; see docs/reverse-engineering.md for the full Spine importer spec.

Output

For an input named foo.psd:

File Contents
foo.json Spine skeleton: one root bone, one slot per layer, one default skin. Spine version 4.2.43.
foo.atlas libgdx atlas: pma:true, filter:Linear,Linear, one region per slot.
foo.png Packed atlas page (RGBA, premultiplied).

Each region carries 1 px transparent edge padding so bilinear filtering can't sample neighbours.

Library use

from pspine import convert

result = convert("input.psd", out_dir="build/spine", base_name="symbols")
print(result.json_path, result.atlas_path, result.page_path)
print(f"{len(result.skeleton.slots)} slots")

A progress callback exposes the same events the CLI prints:

def on_event(event: str, payload: dict) -> None:
    print(event, payload)

convert("input.psd", on_progress=on_event)

Install

# One-shot run (no install)
uvx pspine ...

# Install globally as a tool
uv tool install pspine
# or
pipx install pspine

# As a library dependency
uv add pspine
# or
pip install pspine

Development

git clone https://github.com/USER/pspine
cd pspine
uv sync
uv run pspine --help

Publishing

The package is published to PyPI with a token. From a clean checkout:

uv build                               # produces dist/*.whl and dist/*.tar.gz
UV_PUBLISH_TOKEN=pypi-... uv publish   # uploads dist/*

To bump the version, edit __version__ in src/pspine/__init__.py; pyproject.toml reads it dynamically.

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pspine-0.1.0.tar.gz (12.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pspine-0.1.0-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file pspine-0.1.0.tar.gz.

File metadata

  • Download URL: pspine-0.1.0.tar.gz
  • Upload date:
  • Size: 12.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pspine-0.1.0.tar.gz
Algorithm Hash digest
SHA256 67dbff39e42b34815e4659cc667ae9188cf97108cc6ea9ea8695ed9f56caf52d
MD5 e763111f353e266a0c30dacff02f8173
BLAKE2b-256 0d402585182573c2f26b7101d820b4098049faae621f374afce85fa63ea94b11

See more details on using hashes here.

File details

Details for the file pspine-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pspine-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pspine-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 369b7e30889f95ea4648ed753683abd62c8bb99d1fdc5c1156586fdd4b8ea3f6
MD5 ac0b063dde1f57c91a7ffb89cce33182
BLAKE2b-256 a97d02c08c98c4cf1f243f432b4cf8f01b4b7b266f3ac51a26b152d300eb9f10

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page