PhaserMetadata export

Sprite Sheet Generator for Phaser 3

Export a JSON atlas Phaser loads with one line, or a plain grid PNG for load.spritesheet. Both paths, no build step, no TexturePacker licence.

A sprite sheet exported as a JSON atlas, next to the settings it needs in Phaser 3
What you export

Format menu

Phaser / PixiJS

JSON atlas (TexturePacker format)

The Phaser export writes a TexturePacker-format JSON atlas: every frame keyed by name with its frame rect, source size, and trim data. Phaser reads it natively through load.atlas, so frame positions never depend on you retyping a grid. If you prefer the grid path, the same PNG also works with load.spritesheet.

Step by step

Getting the sheet into Phaser

  1. 1

    Export the PNG and the JSON

    Export the sheet as PNG, then use Format > Phaser / PixiJS for the atlas JSON. Keep both file name stems the same.

  2. 2

    Load the atlas

    In preload(), call this.load.atlas with the texture key, the PNG path, and the JSON path.

  3. 3

    Build the animation

    Frames are named frame_000, frame_001, and so on. Use generateFrameNames with a zero-padded prefix, or generateFrameNumbers if you loaded the grid instead.

  4. 4

    Turn on pixelArt

    Set pixelArt: true in the game config so the renderer uses nearest-neighbour sampling globally.

JavaScript
// Atlas path (recommended)
function preload() {
  this.load.atlas('hero', 'hero.png', 'hero.json');
}

function create() {
  this.anims.create({
    key: 'walk',
    frames: this.anims.generateFrameNames('hero', {
      prefix: 'frame_',
      start: 0,
      end: 7,
      zeroPad: 3,
    }),
    frameRate: 12,
    repeat: -1,
  });

  this.add.sprite(100, 100, 'hero').play('walk');
}

// Grid path, if you exported the PNG only
this.load.spritesheet('hero', 'hero.png', {
  frameWidth: 32,
  frameHeight: 32,
  spacing: 2, // your gutter
});
Cheat sheet
SettingPhaser value
Atlas loaderthis.load.atlas(key, png, json)
Grid loaderthis.load.spritesheet(key, png, config)
Frame namesframe_000, zeroPad: 3
Gutterspacing in the loader config
Crisp pixelspixelArt: true in the game config
Built for the workflow

TexturePacker-compatible

The same JSON shape Phaser has read for years, so every atlas tutorial and plugin still applies.

Trim data included

Trimmed frames carry spriteSourceSize and sourceSize, so Phaser re-inflates them to their original footprint.

No build step

Two static files next to your other assets. No CLI, no watcher, no licence key.

Grid path too

Prefer load.spritesheet? Export the uniform PNG and pass frameWidth, frameHeight, and spacing.

Troubleshooting

When the sheet fights Phaser

The console reports a 404 for the texture while loading the atlas

Cause
load.atlas takes the image path as an argument, and the JSON also names the image internally. A mismatch between the two, or a path relative to the wrong base, misses the file.
Fix
Pass both paths explicitly to load.atlas and keep the PNG and JSON in the same directory with the same stem. Check the network tab for the URL Phaser actually requested.

The animation plays once and freezes on the last frame

Cause
repeat defaults to 0, which means play the sequence a single time.
Fix
Set repeat to -1 for an endless loop, or to a positive count for a fixed number of cycles. For a one-shot that should rest on a pose, keep repeat at 0 and set the idle animation in the animationcomplete handler.

Frames drawn through load.spritesheet include a strip of the neighbour

Cause
The grid loader assumes no gaps unless you tell it otherwise, so an exported gutter shifts every frame after the first.
Fix
Pass spacing, and margin if the sheet has an outer border, in the loader config. Or switch to the atlas path, where the rects are explicit and spacing is irrelevant.

Sprites look soft even with pixelArt enabled

Cause
pixelArt sets nearest sampling but does nothing about sprites landing on fractional coordinates, which is what a moving camera produces.
Fix
Add roundPixels: true to the game config alongside pixelArt: true. For a camera that follows a body, roundPixels on the camera keeps the whole scene on whole pixels.

The animation speed does not match what you previewed

Cause
frameRate and duration are two ways to say the same thing, and setting duration overrides frameRate silently.
Fix
Set frameRate to the number you previewed at and leave duration undefined. If a designer wants a total length instead, set duration alone and let Phaser derive the rate.

Trimmed frames appear to bob up and down

Cause
The atlas restores the original footprint, but the origin is applied to that footprint, so an inconsistent origin across animations reads as vertical drift.
Fix
Call setOrigin once with the same values for every animation of a character, typically 0.5 and 1 for something standing on the ground, and let the trim data handle the rest.

Switching animations restarts the sprite from a jarring pose

Cause
play interrupts the current animation immediately, so a run that cuts to an idle mid-stride jumps rather than settles.
Fix
Use playAfterRepeat or playAfterDelay when the current cycle should finish first, and keep the first frame of each animation close in silhouette to the last frame of the animation that usually precedes it.
Versions & compatibility

What changes between Phaser versions

Phaser 3
load.atlas has read this JSON shape since Phaser 3.0. Every atlas tutorial written for Phaser 3 applies unchanged, including generateFrameNames, play, and the animationcomplete event.
Phaser 4
The loader signature and the TexturePacker JSON format carry over. Code that loads and animates the atlas needs no change; only unrelated parts of the framework moved.
Phaser 2 and CE
The old versions read a TexturePacker JSON Hash or Array too, through load.atlasJSONHash. The file works, but the animation API is different, so follow a Phaser 2 tutorial for the play calls.
Bundlers and static hosting
The output is two static files. With Vite or webpack, put them in the public directory rather than importing them, so the runtime paths stay predictable and the JSON is not inlined into the bundle.
Scale manager and pixel art
The scale manager can put the canvas on a fractional zoom, which softens sprites no matter what the renderer settings say. Pick an integer zoom, or Scale.FIT with a resolution that divides your design size cleanly.
Phaser FAQ

Want the long version? Read the engine import guide, or see every export format.

Other engines

Export for Phaser

Pack your frames in the browser. What you walk away with: JSON atlas (TexturePacker format), ready for Phaser.