# [anitomata-aseprite][] [![Version badge][]][version] ## 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: ```haskell {-# 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: ```haskell -- 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`: ![Aseprite tags](./images/aseprite-tags.png) ## 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! [anitomata-aseprite]: [Version badge]: [version]: