Skip to main content
Frames are overlay layers composited on top of the character image during rendering. Each frame defines the border, decorative elements, and dye behavior of a card. Hagaki ships with three built-in frame types.

Frame comparison

FrameIDDye supportStatic layerExtendable (kindled)Dimensions
Moonweaver0YesYesYes550×800 px
Essentia1YesNoNo550×800 px
Snowglow2NoYesYes550×800 px
All frames produce output at 550×800 px.

Layer model

Each frame can have up to two overlay layers, applied on top of the character image in order:

Static layer (static_model)

A fixed overlay that is composited without any color transformation. It contains frame decorations — borders, glows, icons — that should always appear exactly as authored regardless of the dye color. Moonweaver and Snowglow have a static layer; Essentia does not.

Color layer (color_model)

A dye-able overlay whose hue is shifted at render time using the dye field. This layer is composited using Oklab blending so the dye color blends perceptually. Moonweaver and Essentia have a color layer; Snowglow does not.
A frame can have both layers (Moonweaver), one layer (Essentia has only color; Snowglow has only static), or in theory neither — though all current frames have at least one.

Kindled state

The kindled field activates an enhanced visual variant of the frame. Kindled cards use a different set of asset files that typically feature more elaborate decorations or effects. Only frames with extendable: true support the kindled state. Moonweaver and Snowglow are extendable; Essentia is not.
If you set kindled: true on a frame that does not support it (Essentia), Hagaki silently falls back to the non-kindled version. The render succeeds and no error is returned. This behavior is intentional for backward compatibility.

Choosing a frame

Use Essentia when you want a clean dye effect without additional static decorations. It has a color layer but no static layer, and does not support kindled. Best for minimal card designs.
Use Snowglow when you want a fixed visual style that ignores dye entirely. It has a static overlay and supports kindled, but the dye field has no effect. Best for cards with a defined, unalterable color theme.

Asset file naming

Frame images are loaded from the ../asset/private/frame/ directory at startup. The filename pattern is:
{frame_name}{suffix}-{type}.png
Where:
  • {frame_name} is the lowercase name of the frame: moonweaver, essentia, or snowglow.
  • {suffix} is -kindled when loading the kindled variant, or empty string for the base variant.
  • {type} is color for the dye-able layer or static for the fixed layer.

Examples

FileFrameStateLayer
moonweaver-color.pngMoonweaverBaseColor (dye-able)
moonweaver-static.pngMoonweaverBaseStatic
moonweaver-kindled-color.pngMoonweaverKindledColor (dye-able)
moonweaver-kindled-static.pngMoonweaverKindledStatic
essentia-color.pngEssentiaBaseColor (dye-able)
snowglow-static.pngSnowglowBaseStatic
snowglow-kindled-static.pngSnowglowKindledStatic
Only the files corresponding to a frame’s actual layers are loaded. For example, essentia-static.png and snowglow-color.png are never referenced because Essentia has no static layer and Snowglow has no color layer.
All frame images are loaded once at startup and held in an in-memory cache. See Caching for details.

Build docs developers (and LLMs) love