Aseprite to GameMaker — One Sprite Strip per Tag
GameMaker cuts an image whose name ends in _stripN into N frames on import and wants one sprite per animation. Drop the .aseprite file and export for GameMaker: each tag becomes its own strip with every cell aligned on the pivot, plus a gamemaker.json with origin, speed and milliseconds. UNVERIFIED in GameMaker: no headless GameMaker exists to load the files, so the strips were cut and compared with the source only.
GameMaker does not open .aseprite files; it imports images, and a PNG named …_stripN becomes a sprite of N frames. Drop the file into Nerulio, check the tags and export for GameMaker: every tag becomes its own strip (spr_hero_attack_strip4.png), with reverse and ping-pong written out, every frame placed on its pivot so one origin fits all, and gamemaker.json with the origin, the speed and each frame's milliseconds. A GameMaker sprite has one speed, so uneven timing is kept only as data. UNVERIFIED in GameMaker: the strips were decoded and compared with the source, never loaded in GameMaker.

- GameMakerUNVERIFIED
- Godot 4Verified· Godot 4.7.2
- Unity 6Verified· Unity 6000.5.3f1
- Phaser 3 / 4Verified· Phaser 3.90 + 4.2
- PixiJS 8Verified· PixiJS 8.21
- Aseprite JSONVerified· Phaser load.aseprite · PixiJS 8.21
- .asepriteVerified· Aseprite 1.3.18
- Spine / libGDXVerified· spine-canvas 4.2
- Starling / Sparrow XMLVerified· Phaser 4.2
- LÖVEVerified· LÖVE 11.5
- DefoldBuilt· Defold bob.jar 1.13.1
- CSS spritesVerified· Chromium
- GIF / APNGDecoded· Pillow
From tags with timing to sprites with one speed
Aseprite keeps a whole character in one file: frames with their own durations, tags for each action with a direction and a repeat count, layers, and slices that can hold a pivot. GameMaker keeps each action as a separate sprite asset with frames, one origin and one playback speed, and the manual's strip rule lets one PNG carry all frames of that sprite.
Nerulio composites the visible layers per frame and walks each tag in playback order: a reverse tag is written backwards and a ping-pong tag of 3 frames becomes 0-1-2-1, so N counts the steps of one cycle. All frames of a tag are drawn on one common cell with the pivot on the same pixel; that pixel is the origin. File names are lower-cased with anything but letters, digits and underscores turned into _.
Timing is where the formats differ most. If every frame of a tag lasts the same, the speed is exactly 1000 ÷ ms frames per second. If not, the strip gets the tag's rate (10 FPS for Studio tags), the export warns you, and the true milliseconds stay in durationsMs. The repeat count becomes a loop flag in the JSON; the strip itself carries no timing or loop setting.
- Tag
- A named frame range in Aseprite with a direction and a repeat count.
- Strip
- One horizontal PNG with all frames of a sprite, named
…_stripN. - Common cell
- The frame box shared by all frames of a strip, sized so every pivot lands on one point.
- durationsMs
- The exact milliseconds of every frame, kept in gamemaker.json.
Example: three tags of a 32 × 32 hero
idle 4 × 125 ms, ∞ → spr_hero_idle_strip4.png speed 1000 / 125 = 8, loop true
jump 3 × 80 ms, ping-pong → order 0-1-2-1 → spr_hero_jump_strip4.png speed 12.5
attack 100, 100, 150, 250 ms → spr_hero_attack_strip4.png speed 10 + warning, loop false
attack pivots on the 32 × 32 frames: x = 16, 16, 20, 12 (a lunge), y = 31
cell width = max left 20 + max right (32 − 12) 20 = 40
cell height = 31 + (32 − 31) = 32 origin x 20, y 31
strip = 4 × 40 = 160 × 32 pxThe attack cell is wider than the 32 px frame because the pivot moves inside the drawing; placing every pivot on x 20 is what keeps the body still while the arm lunges.
What survives the conversion
| In Aseprite | In Nerulio's GameMaker files | In GameMaker |
|---|---|---|
| Tag | One strip per tag, e.g. spr_hero_attack_strip4.png | One sprite, cut into N frames on import |
| Direction reverse / ping-pong | Frame order written out; N = steps of one cycle | N frames in that order |
| Equal frame durations | playbackSpeed = 1000 ÷ ms | Speed in Frames per second |
| Mixed frame durations | Tag rate + a warning; exact ms in durationsMs | One speed; per-frame time only through your code |
| Pivot slice or P pivot | Every frame on a common cell; xorigin, yorigin | Custom origin |
| Repeat ∞ / a count | loop: true / loop: false in the JSON | Not set by the import; stop play-once sprites in code |
| Visible layers | Composited; hidden layers left out | Flattened frames |
| Hit / hurt slices | Not written (use the Generic JSON export) | Collision mask set in GameMaker |
What it does
- One strip per tag named spr_<file>_<tag>_stripN.png, where N is the number of frames in playback order, reverse and ping-pong included.
- Every cell has the same size with the pivot on the same point, so the sprite origin is identical in every frame and nothing jumps.
- gamemaker.json per sprite: xorigin and yorigin, playbackSpeed in frames per second, loop, and durationsMs for every frame.
- Visible layers are composited into the strip; hidden layers stay out.
- A README with the import steps: Create Sprite › Import (or drag the PNG into the Asset Browser), then set Origin and Speed.
How to do it
- Drop the .aseprite file and check its tags on the Timeline.
- Set the pivot with P, or keep the pivot slice from the file; it becomes the origin.
- Open Pack & Export, choose GameMaker and export.
- In GameMaker, import each strip and enter the origin and speed from gamemaker.json or the README.
- For pixel art, turn off Interpolate colours between pixels in the Graphics section of your platform's Game Options.
Files you get
| File | What it is for |
|---|---|
spr_hero_attack_strip4.png | One strip per tag, cells of equal size with the pivot on one point. |
gamemaker.json | For each sprite: file, frame count, cell size, origin, speed in frames per second, loop, durationsMs, uniformTiming, verified: false. |
README-GAMEMAKER.md | Import steps and the origin and speed of every strip. |
Bring the strips into GameMaker (manual-based; not run here)
- Unzip the bundle: one PNG per tag. Import each one into its own sprite with the Sprite Editor's Import button, or drag it into the IDE, without renaming it.
- Name the sprite asset after the file without the suffix (
spr_hero_attack), so your code can refer to it. - Set the origin to the custom x and y from the README; for the attack above, x 20 and y 31.
- Set the speed to Frames per second with the README value: 8 for idle, 12.5 for jump, 10 for attack.
- For play-once tags (
loop: false), switch back to the idle sprite in your code after the last frame. - For pixel art, switch off Interpolate colours between pixels in your platform's Game Options › Graphics.
Check the result
spr_hero_jumphas 4 frames in the order 0-1-2-1 andspr_hero_attack4 frames of 40 × 32.- The origin cross stays on the feet through every frame of attack.
- Idle cycles in 4 × 125 = 500 ms, the same as Aseprite's preview.
From .aseprite to GameMaker files
| In the .aseprite | In the GameMaker export |
|---|---|
| Tag "run" with 8 frames | spr_hero_run_strip8.png |
| Frames with equal durations, e.g. 100 ms | playbackSpeed 10 frames per second |
| Frames with different durations | playbackSpeed = the tag's fps, exact ms in durationsMs, and a warning |
| Pivot slice or a pivot set with P | xorigin / yorigin, the same point in every cell |
| Repeat 0 (loop forever) | loop: true |
| Reverse or ping-pong direction | written out as the frame order of the strip |
| Hit and hurt slices | not written here (use the Generic JSON) |
| Verification | UNVERIFIED in GameMaker; strips decoded and compared with the source |
Troubleshooting
| Symptom | Likely cause | How to check | Fix |
|---|---|---|---|
| The attack plays faster than in Aseprite | Mixed durations: the sprite has one speed (10), so the 150 and 250 ms frames last 100 ms | uniformTiming: false and the export warning | Time the frames from durationsMs in code, or give the tag equal durations in Aseprite |
| A ping-pong sprite has more frames than the tag | The back-and-forth order is written into the strip (3 frames → 4) | Frame order 0-1-2-1 | Expected; play the sprite forwards and do not reverse it again |
| Idle and attack have different origins | Each strip has its own cell, so the numbers differ even when the anchor is the same point of the art | Compare the README values per strip | Enter each sprite's own origin; do not copy one origin to all |
| A layer is missing or a hidden one appears | Only the layers visible in the file are composited | Layer visibility in Aseprite | Show or hide the layer in Aseprite (or on Nerulio's timeline) and export again |
| The file name differs from the tag name | Names are lower-cased and spaces or symbols become _ ("Attack 2" → attack_2) | The README lists every file | Use the file name as written, or rename the tag in Aseprite |
| Something is off in GameMaker itself | This export was never loaded in GameMaker | — | Nerulio cannot check GameMaker behaviour; compare with the manual, and report the case so it can be fixed |
Other ways to do it
| Option | When it is the better choice |
|---|---|
Aseprite's File › Export Sprite Sheet as a horizontal strip per tag, renamed to _stripN | You already own Aseprite and a tag has one pivot and even timing; you set origin and speed by hand. |
| A sprite sheet you already have | GameMaker strips from a sprite sheet. |
| Another engine with per-frame timing | Aseprite to Godot keeps every frame's duration. |
Engine exports and how each was checked
"Verified" means the exported files were loaded by the real engine or tool on real CC0 assets and the result was compared with the source. Anything that was not loaded is labelled as such.
| Target | Files | Check |
|---|---|---|
| Godot 4 | .tres SpriteFrames · .tscn AnimatedSprite2D · .png.import | Verified Godot 4.7.2Loaded by Godot; every animation frame drawn and compared with the source file. The scene uses Nearest filtering; rotation is never used. |
| Unity 6 | .unity.json · Editor/NerulioSpriteImporter.cs · AnimationClip | Verified Unity 6000.5.3f1Batch mode: sprite rects, pivots, pixels, clip keys and durations checked. |
| Phaser 3 / 4 | atlas JSON (multiatlas) · .anims.json | Verified Phaser 3.90 + 4.2Frames and animations drawn by both versions. |
| PixiJS 8 | spritesheet JSON · animations · anchor · meta.scale | Verified PixiJS 8.21Rotated and multi-page atlases included. |
| Aseprite JSON | hash / array · frameTags · slices | Verified Phaser load.aseprite · PixiJS 8.21Tags keep their direction and repeat count. |
| .aseprite | layers · tags · durations · slices | Verified Aseprite 1.3.18Opened and rendered by the Aseprite command line. |
| Spine / libGDX | .atlas | Verified spine-canvas 4.2Every region drawn by the Spine runtime, rotated and trimmed; libGDX itself was not run. |
| Starling / Sparrow XML | XML per page | Verified Phaser 4.2Phaser 3.90 draws trimmed XML frames wrongly (its own bug); the "Sparrow XML (Phaser 3)" preset turns trim off and passes in 3.90 and 4.2. |
| LÖVE | Lua quads · nerulio_atlas.lua · main.lua | Verified LÖVE 11.5Every frame drawn and every animation stepped through the shipped helper. |
| Defold | .atlas · .tilesource | Built Defold bob.jar 1.13.1Built by Defold's command-line builder; the built texture's UVs were read back. |
| GameMaker | spr_<name>_stripN.png · gamemaker.json | UNVERIFIEDNot loaded in GameMaker (no headless GameMaker). The strips are cut the way its strip importer cuts them. |
| CSS sprites | .css · preview .html | Verified ChromiumEvery class drawn from the shipped stylesheet. |
| GIF / APNG | one file per animation | Decoded PillowEvery frame and delay decoded again after export; APNG is exact. |
Evidence
Exports: 49 runs in the real engines on real CC0 assets, 47 pass — the 2 failures are Phaser 3.90's trimmed-XML bug, which the Phaser 3 preset avoids. Packer head-to-head on 5 real frame sets (CodeAndWeb free web packer, GAPTools, free-tex-packer): smallest sheet on all 5 with rotation allowed, 4 of 5 without; every frame restored pixel-exact.
Limits
- UNVERIFIED in GameMaker: the strips were decoded and compared with the source frames only.
- One speed per sprite: uneven timing survives only in gamemaker.json.
- No hitboxes or collision shapes in the GameMaker files.
- Polygon (mesh) packing is not offered: none of the verified engines draws a mesh atlas from exported data.
- GameMaker strips are UNVERIFIED in GameMaker itself.
- Scale variants (@0.5x–@4x) use nearest-neighbour only.
- Trimmed Starling XML is drawn wrongly by Phaser 3.90; use the "Sparrow XML (Phaser 3)" preset there.
Versions and sources
Checked: the GameMaker strips decode with Pillow and every cell equals its source frame; the .aseprite reader reopened 231 real files in Aseprite 1.3.18 with the same tags, durations and pixels. Not checked: loading anything in GameMaker, which has no headless mode in the verification setup. The strip naming, import routes, origin, speed modes and the interpolation option follow the GameMaker manual.
Official documentation used
Questions
Has anyone opened these strips in GameMaker?
Not in our checks. GameMaker has no headless mode we could run, so the target is labelled UNVERIFIED. What was checked: the strips decode (Pillow) and every cell matches its source frame; the naming follows the GameMaker manual's sprite strip rule.
My tag has frames of different lengths. What does GameMaker get?
A GameMaker sprite has one playback speed. When a tag's durations differ, the strip uses the tag's fps and the export warns you; the exact milliseconds stay in durationsMs if you want to time frames in code.
Do hitboxes come along?
Not in the GameMaker files, which hold the image, origin and timing only. Boxes and collision polygons are in the Generic JSON export.
Is it free, and do I need an account?
Everything on these pages is free and works without an account. There is no watermark and no export that is held back.
Are my sprites uploaded?
No. The Studio decodes, packs and exports in this browser tab. Projects are autosaved in the browser (IndexedDB) and can be saved as a .nerulio file.
Does it need Aseprite or an engine plugin installed?
No. .aseprite files are read and written in the browser, and each engine bundle carries what that engine needs (for Godot, the import settings and scene; for Unity and the Godot TileSet, a small editor script).