Skip to content

Aseprite to Godot 4 — .aseprite to SpriteFrames, No Plugin

No Aseprite binary on the PATH, no editor plugin: drop the .aseprite file, check its tags, and export a bundle that Godot 4.7.2 loaded and drew frame by frame in the verification run.

An .aseprite file holds frames with their own durations in milliseconds, tags (named frame ranges with a direction and repeat count), layers and slices. Godot 4 cannot open it directly: it plays a SpriteFrames resource on an AnimatedSprite2D. Nerulio reads the file in your browser, turns every tag into a SpriteFrames animation with the same timing, packs the frames into one PNG and adds a ready scene. Copy the folder under res://, drop the .tscn into your scene, and the first tag plays with Nearest filtering. Godot 4 only (checked in 4.7.2).

Drop a sprite sheet, numbered frames, a GIF / APNG or an .aseprite file
Runs in your browser. Files are not uploaded.
Studio Sprite workspace: one frame with its pivot, a hit box and a hurt box, and the timeline with animation tags
The real Studio with a CC0 asset (OpenGameArt).
Exports to
  • Godot 4Verified· Godot 4.7.2
  • .asepriteVerified· Aseprite 1.3.18
  • 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
  • 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
  • GameMakerUNVERIFIED
  • CSS spritesVerified· Chromium
  • GIF / APNGDecoded· Pillow

What is in an .aseprite file, and what Godot needs

Aseprite saves a whole animation document. Every frame has its own duration in milliseconds. Tags group a range of frames into a named animation (walk = frames 4–9) and say how it plays: forward, reverse or ping-pong, forever or a set number of times. Layers keep parts of the drawing apart, and slices mark rectangles such as a pivot point or a hit box.

Godot 4 plays frame animation with an AnimatedSprite2D node that reads a SpriteFrames resource. Each animation in it has a name, a speed in frames per second, a loop flag and a list of frames; each frame is a texture plus a relative duration. Godot shows a frame for relative duration ÷ (FPS × speed scale) seconds, so milliseconds have to be converted, not copied.

Nerulio writes every tag at 10 FPS, so one tick is 100 ms (Aseprite's default frame length), and gives every frame a relative duration of its milliseconds ÷ 100. The playback time of every single frame therefore matches Aseprite, even when the durations differ inside one tag.

Tag
A named frame range in Aseprite with a direction (forward, reverse, ping-pong) and a repeat count.
SpriteFrames
The Godot resource that stores animations: name, speed (FPS), loop and frames.
AtlasTexture
A rectangle of a larger texture. Every exported frame is one, pointing into the packed PNG.
Relative duration
Godot's per-frame multiplier: 1.0 lasts one tick of the animation's FPS, 2.0 two ticks.

Example: a 32 × 32 hero with three tags

The .aseprite file has 16 frames and three tags. This is what the export writes into the SpriteFrames resource:

Aseprite                                  Godot 4 SpriteFrames
idle    frames 0–3    125 ms each   ∞     idle    10 FPS   1.25 × 4                      loop on
walk    frames 4–9    100 ms each   ∞     walk    10 FPS   1.0 × 6                       loop on
attack  frames 10–15  100,100,100,100,    attack  10 FPS   1.0, 1.0, 1.0, 1.0,            loop off
                      150, 250 ms   ×1                     1.5, 2.5

duration    = ms / (1000 / 10 FPS) = ms / 100      125 ms → 1.25    250 ms → 2.5
check       1.25 / 10 = 0.125 s    2.5 / 10 = 0.250 s   (same as Aseprite)

attack repeats once in Aseprite, so its loop flag is off: it plays once and stays on its last frame. In a script, play idle again from the node's animation_finished signal.

What survives the conversion

In AsepriteIn NerulioIn Godot 4
Frame pixels (visible layers)Composited frame, packed into one PNG pageAn AtlasTexture region of that PNG
Frame duration (ms)Kept per frameRelative duration = ms ÷ 100; the animation speed is 10 FPS
TagOne animation of the same nameA SpriteFrames animation of the same name
Direction reverse / ping-pongPlayback order written out (ping-pong: 0-1-2-3-2-1)Frames listed in that order
Repeat ∞Looploop = true
Repeat 1, 2, 3…Plays that many times in the previewloop = false: Godot plays it once (a repeat count is not stored)
No tags at allOne animation default with every frameAnimation default
Slice with a pivotFrame pivot (default without one: bottom centre)Node offset = −pivot of the first frame, centered = false
Slices named hit / hurt …Boxes per frameStored in the resource metadata nerulio, not as nodes
Layers, blend modes, opacityKept in the StudioFlattened: Godot receives the composited frame

Godot 4.7 also has a ping-pong loop mode of its own; the export does not depend on it because it writes the order frame by frame.

What it does

  • Reads .aseprite in the browser: layers, tags (direction, repeat), per-frame durations, slices → pivots, boxes and 9-slice.
  • SpriteFrames .tres with AtlasTexture regions, trim margins, relative durations and loop.
  • An AnimatedSprite2D .tscn with texture_filter = Nearest and the pivot offset.
  • A .png.import with lossless compression, no mipmaps and fix_alpha_border off, so faint pixels keep their colour.

How to do it

  1. Drop the .aseprite file.
  2. Check the tags and durations on the timeline (layers that compose exactly stay layers).
  3. Open Pack & Export and choose Godot 4.
  4. Unzip the bundle into your Godot project and open the scene.

Files you get

FileWhat it is for
hero.tresThe SpriteFrames resource: animations, FPS, loop flags, relative durations, AtlasTexture regions and trim margins; metadata nerulio with pivots, boxes and collision polygons.
hero.tscnA scene with one AnimatedSprite2D using the resource: Nearest filtering, autoplay of the first tag, the pivot as offset.
hero.pngThe packed frames (more pages when the frames do not fit on one).
hero.png.importImport settings Godot reads: lossless, no mipmaps, Fix Alpha Border off, so faint pixels keep their colour.
README-GODOT.mdThese steps for this bundle.

Import it into Godot 4

  1. Unzip the bundle and copy the whole folder anywhere under res://, for example res://characters/hero/. The .tres finds the PNG by a relative path, so keep the files together.
  2. Let the FileSystem dock finish importing. Godot uses the shipped hero.png.import, so the atlas is imported lossless and without mipmaps.
  3. Drag hero.tscn into your scene, or select your own AnimatedSprite2D and load hero.tres into its Sprite Frames property.
  4. Choose the animation in the node's Animation property or in the SpriteFrames panel; the shipped scene autoplays the first tag.
  5. From a script, switch with $Hero.play("walk"). For a tag that does not loop, connect animation_finished and play idle again.
  6. For your own nodes, set Project Settings › Rendering › Textures › Canvas Textures › Default Texture Filter to Nearest once, or set the node's Texture › Filter to Nearest.

Check the result

  • Run the scene: walk with six 100 ms frames should repeat every 0.6 s, the same as Aseprite's preview.
  • Open the SpriteFrames panel: every animation has the frame count of its tag (a ping-pong tag shows the written-out order).
  • Zoom the 2D viewport to 400 %: pixel edges stay square. Soft edges mean the node uses Linear filtering.
  • print($Hero.sprite_frames.get_meta("nerulio")) lists the pivot and boxes of every frame.

Troubleshooting

SymptomLikely causeHow to checkFix
The sprite looks blurryYour node inherits the project's default Linear filterZoom in; check the node's Texture › FilterSet Filter to Nearest on the node, or the project's Default Texture Filter to Nearest
Faint pixels (glow, smoke) change colourThe PNG was imported with Godot's default Fix Alpha Border instead of the shipped .png.importImport dock of the PNG: Fix Alpha Border is onKeep hero.png.import next to the PNG, or turn Fix Alpha Border off and click Reimport
A tag is missingThe file had no tags (everything became default), or the tag was renamed or removed before exportLook at the tag lanes on Nerulio's timeline before exportingAdd or fix the tag in Aseprite or on the timeline, then export again
A play-once tag loops, or a looping tag stopsRepeat ∞ becomes loop on; any repeat count becomes loop offSpriteFrames panel: the loop toggle of that animationChange the repeat in the tag, or toggle Loop in Godot; use animation_finished for play-once tags
The character jumps when the animation changesFrames have different pivots, but a node has one offset (the first frame's pivot)The export notes warn about differing pivots; every pivot is in metadata/nerulioUse one pivot slice for all frames, or align pivots in Nerulio (see the pivot editor) before export
Timing is faster or slower than in AsepriteThe node's Speed Scale or a play() custom speed is not 1Inspector: Speed ScaleSet Speed Scale to 1 and call play() without a custom speed
Godot 3 cannot open the .tresThe resource uses the Godot 4 format with per-frame durations—Use Godot 4, or export a plain PNG sprite sheet and build the frames by hand in Godot 3

Other ways to do it

OptionWhen it is the better choice
Export a PNG sheet from Aseprite (File › Export Sprite Sheet) and use Add Frames from Sprite Sheet in Godot's SpriteFrames panelOne or two animations with even timing: no extra files, but you set each animation's FPS by hand and per-frame durations are lost. See using a sprite sheet in Godot.
An .aseprite import plugin from the Godot Asset LibraryYou change the art often and want Godot to reimport on every save; such plugins call the Aseprite program, so it must be installed on every machine that imports.
The same file for another engineAseprite to Unity or Aseprite to Phaser.

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.

TargetFilesCheck
Godot 4.tres SpriteFrames · .tscn AnimatedSprite2D · .png.importVerified 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 · AnimationClipVerified Unity 6000.5.3f1Batch mode: sprite rects, pivots, pixels, clip keys and durations checked.
Phaser 3 / 4atlas JSON (multiatlas) · .anims.jsonVerified Phaser 3.90 + 4.2Frames and animations drawn by both versions.
PixiJS 8spritesheet JSON · animations · anchor · meta.scaleVerified PixiJS 8.21Rotated and multi-page atlases included.
Aseprite JSONhash / array · frameTags · slicesVerified Phaser load.aseprite · PixiJS 8.21Tags keep their direction and repeat count.
.asepritelayers · tags · durations · slicesVerified Aseprite 1.3.18Opened and rendered by the Aseprite command line.
Spine / libGDX.atlasVerified spine-canvas 4.2Every region drawn by the Spine runtime, rotated and trimmed; libGDX itself was not run.
Starling / Sparrow XMLXML per pageVerified 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ÖVELua quads · nerulio_atlas.lua · main.luaVerified LÖVE 11.5Every frame drawn and every animation stepped through the shipped helper.
Defold.atlas · .tilesourceBuilt Defold bob.jar 1.13.1Built by Defold's command-line builder; the built texture's UVs were read back.
GameMakerspr_<name>_stripN.png · gamemaker.jsonUNVERIFIEDNot loaded in GameMaker (no headless GameMaker). The strips are cut the way its strip importer cuts them.
CSS sprites.css · preview .htmlVerified ChromiumEvery class drawn from the shipped stylesheet.
GIF / APNGone file per animationDecoded PillowEvery frame and delay decoded again after export; APNG is exact.

Evidence

GIF decoder: 408 of 408 frames identical to Pillow on 29 real GIFs; APNG 132 of 132 on 16 files. .aseprite: 231 corpus files imported, re-written and reopened in Aseprite 1.3.18 with the same tags, durations and pixels (231/231). 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.

Limits

  • A repeat count above one is not stored: Godot plays such an animation once.
  • Layers arrive flattened; to animate parts separately in Godot, export them as separate files.
  • Hit and hurt boxes are data in the resource metadata; create the Area2D and CollisionShape2D nodes yourself.
  • A grid or island guess is a preview with a confidence; nothing is cut until you press Apply, and every choice has one-click alternatives.
  • .aseprite files whose layers do not compose exactly (e.g. group opacity) are imported flattened, and the Import panel says why.
  • Rotated frames in an imported atlas stay rotated; their export is UNVERIFIED.
  • Images up to 32,768 px per side (268 million pixels), subject to your browser's memory.

Versions and sources

Nerulio's bundle was loaded by Godot 4.7.2 in our verification runs: every animation's frame count, speed, loop and relative durations were read back and every frame was drawn at 1× and 4× and compared with the source. The .aseprite reader was checked on 231 real files that reopened in Aseprite 1.3.18 with the same tags, durations and pixels. What the steps above say about Godot follows the Godot 4.7 documentation.

Official documentation used

Questions

Do I need Aseprite installed?

No. The file is parsed in the browser. On a 231-file .aseprite corpus, 222 imported with layers and 9 flattened, each with the reason shown.

Why ship a .png.import?

Godot's default import recolours pixels under alpha 20 (fix_alpha_border). The bundle's import settings turn that off; with them, the FX sheet in the test passed in Godot.

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).