Normalize sprite batch
Normalize a sprite batch without hand-positioning every frame
- image
- ui_widget
- image
- receipt
- image_list
Game sprite work has a dirty secret: AI-generated animation frames almost never come out the same size or in the same place. One frame's character is 180px tall, the next is 220px and shifted left, and before you can feed them to a game engine they all have to live on identical transparent canvases with the sprite anchored consistently. That's the exact job LF_NormalizeSpriteBatch was built for - and it does it as a batch, in one pass, with a shared transform instead of per-frame fudging.
The key word is shared. Most naive normalizers crop each frame independently, which makes a walking animation bob and breathe as the crop window chases the pixels. This node instead derives one batch-wide scale and horizontal pivot from a single reference frame, then lays every frame onto an exact-size canvas with per-frame alpha-baseline alignment. The result is a batch where the character stays a consistent size and sits on the ground line frame after frame - which is what makes a sprite animation actually look like one animation.
How it works
Each RGBA frame's alpha bounds are found (alpha above 1/255 counts; fainter alpha is preserved but doesn't steer the transform). The reference_frame_index frame (default 0) defines the scale - its alpha height is mapped to target_reference_alpha_height (default 224) - and its horizontal center becomes the shared x-pivot. Frames are scaled by that one factor, centered on the pivot, and placed with bottom_padding (default 16) transparent rows below every frame's alpha baseline. Everything lands on a canvas of exactly canvas_width × canvas_height (both default 256).
Two honest caveats from the author's own tooltips: bicubic edge filtering can add a small measured halo around the alpha, and frames with no visible sprite content (empty alpha) are rejected outright - every frame must contain something.
The inputs that matter
- image - the RGBA sprite batch, in frame order.
- canvas_width / canvas_height - the exact output canvas; this is what the engine wants.
- target_reference_alpha_height - the nominal height you want the reference frame's sprite to be.
- reference_frame_index - pick a representative frame (usually frame 0, or the frame where the character is at full height and center).
- bottom_padding - transparent ground margin; how the frames sit vertically.
Outputs are image (the normalized RGBA batch), image_list (the same frames as a per-frame list, in batch order - handy for feeding a sprite-sheet writer), and receipt, a deterministic lf.sprite_batch_normalizer.receipt.v1 record of the transform.
Installing and gotchas
It's one of ~138 nodes in the LF Nodes pack:
cd ComfyUI/custom_nodes
git clone https://github.com/lucafoscili/lf-nodes.git
then restart (ComfyUI Manager: search "LF Nodes"). Manager pulls the pack's requirements automatically - note Pillow is pinned to 12.2.0 in there. And the pack gotcha applies here too: the repo was rewritten and the old one archived in 2025, so install from lucafoscili/lf-nodes, not whatever old URL a tutorial cites.
Where people actually get stuck: a fully transparent frame (the node errors out deliberately rather than guessing), frames whose sprites have wildly different alpha shapes (the shared transform fits the reference, so outliers may clip or get letterboxed oddly - that's a property of "one scale for all," not a bug), and forgetting that input must be RGBA with real alpha content. If your frames come out of a generator with a solid background instead of transparency, remove the background first; this node aligns alpha, it doesn't invent it. Otherwise it's about as deterministic and reproducible as a sprite tool gets.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | RGBA sprite animation batch. Every frame needs alpha content above 1/255; fainter alpha is preserved but does not steer the transform. | |
| canvas_width | INT | 2561–4096 | Exact transparent output-canvas width in pixels. |
| canvas_height | INT | 2561–4096 | Exact transparent output-canvas height in pixels. |
| target_reference_alpha_height | INT | 2241–4096 | Nominal height for the reference frame's alpha bounds. It derives one batch-wide scale; bicubic edge filtering can add a small measured halo. |
| reference_frame_index | INT | 00–4095 | Frame whose alpha height and horizontal center define the shared batch transform. |
| bottom_padding | INT | 160–4095 | Transparent rows below every frame's alpha baseline. Only vertical baseline placement varies per frame. |
| ui_widgetopt | LF_MASONRY | [object Object] | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | RGBA batch on exact canvases, with one shared scale/x pivot and per-frame alpha baseline alignment. |
| receipt | JSON | Deterministic lf.sprite_batch_normalizer.receipt.v1 transform receipt. |
| image_list | IMAGE | Individual normalized RGBA frames in batch order. |