Code gen for Aseprite animations.
anitomata
Haskell code generation for Aseprite animations.
anitomata-aseprite
Synopsis
anitomata-aseprite
provides a preprocessor - aseprite2haskell
- that converts an Aseprite texture atlas JSON file into anitomata
Haskell code.
Usage
Imagine this fragment of directory structure for a game:
my-game
├── my-game.cabal
└── library
└── MyGame
└── Codegen
├── Atlas.hs
└── Atlas.json
Atlas.json
contains the JSON texture atlas exported using the Aseprite CLI. Atlas.hs
contains just this line:
{-# OPTIONS_GHC -F -pgmF aseprite2haskell #-}
This makes GHC invoke the aseprite2haskell
preprocessor so that the MyGame.Codegen.Atlas
module will contain AnimSlice
and AnimBuilder
values for all tags in the Aseprite texture atlas JSON. You will have one AnimSlice
per each Aseprite-tagged sequence of frames and one AnimBuilder
wrapping that AnimSlice
. The generated code will look something like this:
-- Auto-generated - do not manually modify!
{-# LANGUAGE ImportQualifiedPost #-}
module Atlas where
import Prelude
import Anitomata
import Data.Vector.Unboxed qualified as U
owlet_walk :: AnimBuilder
owlet_walk = fromAnimSlice owlet_walk_slice
owlet_walk_slice :: AnimSlice
owlet_walk_slice =
AnimSlice
{ animSliceDir = AnimDirForward
, animSliceFrameDurs = U.slice 0 6 durations
, animSliceFrames = U.slice 0 6 frames
}
owlet_run :: AnimBuilder
owlet_run = fromAnimSlice owlet_run_slice
owlet_run_slice :: AnimSlice
owlet_run_slice =
AnimSlice
{ animSliceDir = AnimDirForward
, animSliceFrameDurs = U.slice 6 6 durations
, animSliceFrames = U.slice 6 6 frames
}
-- ... more builders and slices ...
frames :: U.Vector AnimFrame
frames = -- ... vector of frames ...
durations :: U.Vector Double
durations = -- ... vector of durations ...
Be sure to include your texture atlas JSON file in your package description's extra-source-files
. Note that if you rewrite your JSON file via re-exporting from the Aseprite CLI (or just change the JSON file in general), you might need to clean your game project for the updates to be picked up in your game.
Texture atlas format
Currently, the preprocessor is not very flexible in regards to the JSON format exported out of Aseprite. You must export your texture atlas using these flags at a minimum:
path/to/aseprite \
--batch \
--list-tags \
--filename-format '{title}|{tag}|{frame}' \
--tagname-format '{title}|{tag}' \
--sheet-pack \
--format 'json-array' \
--sheet "path/to/atlas.png" \
--data "path/to/Atlas.json" \
path/to/spritesheets/*.aseprite
--list-tags
, --filename-format
, --tagname-format
, and --format
are critical. If you do not use these flags as shown above, aseprite2haskell
will not be able to parse your JSON.
Also note that you must tag every frame in your Aseprite file. The tags map to AnimSlice
values in anitomata
, so be sure to tag every minimal sequence of frames comprising a logical chunk of animation (e.g. the frames for a "walk" animation could have a tag named "walk"). This restriction may be lifted in the future, but for now, all frames must be tagged. Tagging in Aseprite is also how you control the AnimDirection
of your AnimSlice
values and the repeat count of your AnimBuilder
values.
Here's an example of a spritesheet appropriately tagged for use with aseprite2haskell
:
Goals
Defining animation slices is tedious and error prone. The main goal of anitomata-aseprite
is to automate away that pain. Currently, only the preprocessor is provided. This is great for rapidly integrating animations into a game, but some games may require dynamic loading of animations rather than using generated code. anitomata-aseprite
has a secondary goal of providing an aeson
parser to read animations in at runtime, but this code hasn't been written yet. If you need this functionality, please consider contributing!