Recipe: Exporting to Phaser
Take a sprite with named animations + slices for hitboxes, export it as a sprite sheet + JSON, and load it into a Phaser 3 project. The editor's exporter is Aseprite-compatible, which Phaser's loader.atlas consumes directly.
![Screenshot: the Motestack export dialog on the Sprite Sheet tab with the Aseprite JSON output and a Phaser scene side-by-side showing the hitbox rectangle drawn from the slice — placeholder]
Goal
Hand a single PNG + JSON pair to Phaser and call sprite.play('walk'), sprite.body.setSize(...) reading from a slice — no glue code, no manual frame-by-frame definitions.
What ships in the JSON
The editor emits a fully Aseprite-compatible Hash layout. Phaser's Phaser.Loader.Atlas understands this layout natively — same JSON shape Aseprite uses.
Important fields:
{
"frames": {
"frame0.png": { "frame": { "x": 0, "y": 0, "w": 32, "h": 32 }, "duration": 100, ... },
...
},
"meta": {
"app": "motestack",
"version": "0.10.x",
"frameTags": [
{ "name": "idle", "from": 0, "to": 3, "direction": "forward" },
{ "name": "walk", "from": 4, "to": 11, "direction": "pingpong" }
],
"slices": [
{
"name": "hitbox",
"color": "#ff0000",
"keys": [
{ "frame": 0, "bounds": { "x": 8, "y": 4, "w": 16, "h": 24 } },
{ "frame": 4, "bounds": { "x": 6, "y": 4, "w": 20, "h": 24 } }
]
}
]
}
}Steps in Motestack
1. Tag your animations
In the Frames timeline, click + Tag over the frames you want to name. Set name = "walk", direction = "pingpong", etc. Repeat for idle, attack, death, …
2. Author slices for hitboxes / hurtboxes
Y activates the Slice tool. Drag a rectangle on the canvas to create the slice. In the Slices panel:
- Name:
hitbox(orhurtbox,pickup,feet-anchor). - Color: any colour — for visual identification only, doesn't affect export.
- Per-frame keys: drag the slice on different frames to give it different bounds per frame. The exporter remaps frame indices to the local sprite-sheet positions.
3. Export the sprite sheet
Ctrl+K → "Export sprite sheet". In the dialog:
- Source: pick the sprite or animation you want to export.
- Layout:
gridis fine for most cases. - Padding: 0 unless your engine needs gutters.
- Scale: 1 — upscale at engine load time if you want, don't bake it in.
Save both files. You get myhero.png + myhero.json.
Steps in Phaser
1. Load the atlas
preload() {
this.load.atlas(
'hero',
'assets/myhero.png',
'assets/myhero.json',
)
}2. Create the sprite
create() {
const hero = this.add.sprite(100, 100, 'hero', 'frame0.png')
// Phaser auto-creates animations from the `meta.frameTags` array in
// the JSON (Phaser ≥ 3.50 with `loader.aseprite` is even simpler;
// `loader.atlas` requires you to define them once):
this.anims.createFromAseprite('hero')
hero.play({ key: 'walk', repeat: -1 })
}(For older Phaser versions, iterate meta.frameTags manually and call this.anims.create({ key, frames, ... }).)
3. Read slices for hitboxes
Slices live under meta.slices. Phaser doesn't auto-bind them to physics bodies — read the JSON yourself:
const json = this.cache.json.get("hero");
const hitbox = json.meta.slices.find((s) => s.name === "hitbox");
// Per-frame keys: pick the most recent key with frame ≤ current frame
function resolveSlice(slice, frameIdx) {
let active = null;
for (const k of slice.keys) {
if (k.frame <= frameIdx) active = k;
else break;
}
return active?.bounds;
}
hero.on(Phaser.Animations.Events.ANIMATION_UPDATE, (_anim, frame) => {
const bounds = resolveSlice(hitbox, frame.index);
if (bounds)
hero.body.setSize(bounds.w, bounds.h, false).setOffset(bounds.x, bounds.y);
});You now have a hitbox that resizes with each frame of the animation, driven entirely by the metadata you authored in Motestack.
Tips
- Pivots (slice → pivot point) are also in the JSON:
slice.keys[i].pivot = { x, y }. Use them to attach effects (muzzle flash, footstep dust) at sprite-relative anchors. - Onion-skin tints don't export — they're a workspace overlay only. The PNG is the clean composed output.
- Color cycles don't bake. If your project uses indexed mode + cycles, the sprite sheet exports static colours. To animate cycles in Phaser, ship the sprite sheet plus a
cyclesJSON and rotate slots at runtime via a custom material. - Frame durations ride in the JSON (
frames[].duration). Phaser uses them by default when constructing animations from frameTags.
See also
- Export formats — full options for the export dialog.
- Slices — authoring the per-frame regions.
- Frame tags — naming time ranges.