RiggyTry it

Pseudo-3D head turn from a flat image in Spine

Spine is 2D: there is no third axis in the format. Yet a coin, a gem or a head drawn as one flat image can turn as if it had volume. The trick is to put each vertex of a mesh where the projection of a 3D point would land — the runtime just draws triangles. Here is how it works and where it stops working.

Why a region attachment is not enough

A region is a rectangle moved by its bone: translate, rotate, scale, shear — one affine matrix for the whole picture. A turn needs points of the picture to move differently: the edge coming towards you grows and the far edge shrinks. That takes a mesh, whose vertices can be moved one by one with deform keys.

The math of the turn

Relief. The flat image gets a pseudo-depth that depends only on the position across the turning axis, u from 0 to 1: a round profile relief · cos(π·(u − ½)) for a smooth side (a coin, a ball, a head), a ridge relief · (1 − 2·|u − ½|) for a faceted stone or a folded card, and flat for a plate. A relief of 0.15 to 0.35 of the part's width looks solid; more looks inflated.

Rotation. Each vertex turns in the horizontal plane: x′ = x·cos θ + z·sin θ, z′ = −x·sin θ + z·cos θ.

Perspective. A camera at distance d makes nearer points larger: k = d / (d − z′), X = x′·k, Y = y·k. With d at 2 to 4 widths of the part the effect reads as volume; far away it collapses into a plain squeeze.

Offsets. Deform keys store offsets from the setup vertices, and the base is the same projection at zero angle, not the flat vertices. The artist already drew the part with its volume: at 0° it must stay exactly as drawn, and every offset must be zero, or the loop would start with a jerk.

flat image, 0°turned 30°
The same 7×7 mesh before and after a turn of 30° with a round relief: the near half is wider and taller than the far one.

How it is written in the JSON

Deform keys live under animations.<name>.attachments.<skin>.<slot>.<mesh>. A key without vertices means the setup shape, which is a convenient start and end of a loop:

"deform": [
  {},
  { "time": 0.6667, "vertices": [ 3.31, 7.27, 11.86, 4.59, … ],
    "curve": [ 0.8889, 0, 1.1111, 1 ] },
  { "time": 1.3333 }
]

The curve of a deform key is always exactly four numbers, because its value is one: progress from one shape to the next. So cy runs from 0 to 1, and scaling the strength of a turn multiplies the vertices, never the curve. The format details of curves are in Spine 4.2 Bezier curves in JSON, explained.

Three quiet traps

  • The V axis points down. In the texture v = 0 is the top row of pixels, while the world Y axis points up. Get it backwards and the image is mirrored — with no error, and on a symmetric part with no visible sign.
  • A deform key on a missing or non-mesh attachment fails the loading of the whole skeleton, not one animation.
  • The mesh is too coarse. The runtime maps texture onto triangles affinely, without perspective correction, so a big triangle bends the picture along its diagonal. A 7×7 grid holds a turn of 30° without visible kinks; 3×3 does not.

Where the trick stops

Spine has no per-vertex color, so highlights and shading painted on the image do not move while it turns. Up to about 30–40° the eye accepts it; beyond that it expects the light to shift and sees a deformed sticker instead. For big angles the honest answer is swapping images frame by frame, which costs atlas space but does not lie about light.

A head nod in Riggy

In Riggy this is one tool, and the AI calls it when you ask a part to turn. It turns the part into a mesh, picks the grid density for the angle and writes the keys. It refuses angles past 45° and names an alternative instead, because the painted light would contradict the turn.

A nod is not a turn around the middle of the head: the neck stays put and the crown comes forward. So the turn has a pivot — the bottom or top edge for a nod, the left or right edge for a side turn — and can be one-sided, going from one angle to another and back instead of swinging both ways. A nod is axis x, pivot bottom, from 0 to −25. The calculation runs in the image's own frame, not the bone's: a head's bone set from the neck points up, and “bottom” in the bone's frame would turn the head sideways.

How the AI decides which tool to call, and what the code measures for it, is in How we generate Spine 4.2 JSON with an LLM; finished rigs are in the examples, and a hand-edited file can be checked with the Spine JSON validator.

Turn your own art

Sign up, drop a layered PSD and ask a part to turn.

Animate your own PSD