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.
| Effect | Cell | Frames | Grid | Sheet size |
|---|---|---|---|---|
fire/candle | 56×76 | 120 | 8×15 | 448×1140 |
fire/campfire | 128×128 | 90 | 8×12 | 1024×1536 |
fire/brazier | 112×148 | 90 | 8×12 | 896×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
<name>.png(RGBA): colour with light added, over transparency, ascompositemakes it. Draw it normally when your engine cannot blend additively. It reads correctly over dark backgrounds.<name>_color.png(RGBA, straight alpha): the colour layer only. Draw it normally.<name>_light.png(RGB): the light layer only. Draw it over the colour with additive blending (src + dst). Black adds nothing.
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
| Field | Meaning |
|---|---|
frames[].duration | Milliseconds per frame, round(1000 / fps). |
frames[].frame | The cell on the sheet. Cells are never trimmed or rotated. |
meta.frameTags | One tag spanning every frame, named after the effect. |
beanfx.pivot | The 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.end | true and "loop" for loops; false and "remove" for one-shots, which should be removed after the last frame. |
beanfx.sheet, color, light | File names of the three images, relative to the JSON. |
beanfx.blend_light, light_gain | Draw light with additive blending at gain 1. |
beanfx.rows | Always 1: pixfx writes one animation per sheet. The grid's own row count is ceil(frames / columns). |