@hackage anitomata-aseprite0.1.1.2

Code gen for Aseprite animations

anitomata-aseprite

Version badge

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:

Aseprite tags

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!