pixfx

Sprite sheet format

What pixfx sheet writes: three PNGs laid out on one grid, and a JSON file that Aseprite-style loaders and beanfx both read.

Layout

Every frame is one cell of the same size, the effect's canvas (meta.size plus twice the margin; the CLI uses margin 0). Cells go left to right, at most 8 per row, then down.

EffectCellFramesGridSheet size
fire/candle56×761208×15448×1140
fire/campfire128×128908×121024×1536
fire/brazier112×148908×12896×1776

A loop has round(duration × fps) frames; frame i is the effect after i steps of 1/fps, so the last frame leads back into the first. A one-shot has one more frame, its last moment.

The three images

Drawing _color then _light additively gives the effect exactly as the live renderers show it, lighting whatever is under it.

JSON

The JSON follows Aseprite's "array" export, so Aseprite loaders (Phaser's load.aseprite, many others) read it, with beanfx's own fields under meta.beanfx. Abridged output for fire/candle:

{
  "frames": [
    {
      "filename": "fire_candle 0",
      "frame": { "x": 0, "y": 0, "w": 56, "h": 76 },
      "rotated": false,
      "trimmed": false,
      "spriteSourceSize": { "x": 0, "y": 0, "w": 56, "h": 76 },
      "sourceSize": { "w": 56, "h": 76 },
      "duration": 33
    }
    // ... one entry per frame
  ],
  "meta": {
    "app": "pixfx",
    "version": "1",
    "image": "fire_candle.png",
    "format": "RGBA8888",
    "size": { "w": 448, "h": 1140 },
    "scale": "1",
    "frameTags": [{ "name": "fire_candle", "from": 0, "to": 119, "direction": "forward" }],
    "beanfx": {
      "name": "fire_candle",
      "fps": 30,
      "frames": 120,
      "rows": 1,
      "frameSize": [56, 76],
      "columns": 8,
      "pivot": [28, 64],
      "loop": true,
      "end": "loop",
      "sheet": "fire_candle.png",
      "color": "fire_candle_color.png",
      "light": "fire_candle_light.png",
      "blend_light": "add",
      "light_gain": 1.0
    }
  }
}

Fields

FieldMeaning
frames[].durationMilliseconds per frame, round(1000 / fps).
frames[].frameThe cell on the sheet. Cells are never trimmed or rotated.
meta.frameTagsOne tag spanning every frame, named after the effect.
beanfx.pivotThe effect's origin within a cell, y down from the cell's top-left: meta.origin + margin. Place this point where the effect should stand.
beanfx.loop, beanfx.endtrue and "loop" for loops; false and "remove" for one-shots, which should be removed after the last frame.
beanfx.sheet, color, lightFile names of the three images, relative to the JSON.
beanfx.blend_light, light_gainDraw light with additive blending at gain 1.
beanfx.rowsAlways 1: pixfx writes one animation per sheet. The grid's own row count is ceil(frames / columns).