Skip to content

2D Rigs

A 2D rig bends one image the way a skeleton bends a body. You make it in the editor from any PNG, with no separate animation program and no third-party format. Spine and DragonBones keep working beside it; use whichever a character was made in.

  • .esrig is what you edit: the parts cut from an image, the bones under them, and what each vertex follows.
  • Saving writes .esmesh and .esprefab beside it. Scenes use those, so a built game carries no authoring data.
  • Bones are entities. Each is an ordinary entity with a Transform, so clips, the Animator, masks and code reach them like anything else.

Right-click an image in the Content Browser and choose Create 2D Rig. Then work through the modes along the top, which are in the order a character is made:

Mode What you do
Parts Split by Transparency cuts a sheet of limbs into parts. Drag them into a character. The list on the right sets which draws on top.
Bones With New, drag a bone out. Start on another bone’s end and it carries on from it. With Select, drag an end to aim a bone and the rest to move it.
Mesh Every part starts covered by a grid. Smaller cells bend more smoothly and cost more. Drag a vertex to adjust it.
Weights By Distance binds what is nearest, then paint what that got wrong: pick a bone on the right and drag. Shift inverts, Ctrl smooths, [ and ] change the radius. Whole Part to Selected Bone is for a piece that does not bend.
Deforms New Shape, then drag to push vertices: a breath, a smile, a bulge.

Try Pose turns bones to see how the weights hold up. It changes nothing in the rig, and Bind Pose puts it back. Place in Scene saves and instantiates the prefab. Saving again updates every instance in the open scene at once, keeping what a scene added to one.

A character is never locked to the skeleton it was weighted on.

  • Move a bone. In Bind Pose, dragging a bone or typing its length or rotation changes the bind pose itself. The picture stays where it is, so a bone placed wrong can just be moved.
  • New parent. In Bones, pick Parent for the selected bone, or None (root). It keeps its place in the picture, and so does everything below it.
  • Rename or remove. Removing a bone hands its children and vertices to its parent.
  • Recompute weights. By Distance again, or Whole Part to Selected Bone, then paint.
  • Another rig’s skeleton. Under Skeleton, pick another .esrig and Rebind to This Skeleton. Bones are matched by name. A vertex on a bone with no namesake goes to its nearest matched parent. Rigs that share a skeleton have the same bone names and paths, so they play the same clips.

Saving keeps up what depended on the old names:

  • Clips (.estimeline) and Animator layer masks (.esanimator) that named a renamed or reparented bone by its path are rewritten. A clip counts as this rig’s when most of its paths are this rig’s bones. A track on a removed bone keeps its path, and the save says how many there are.
  • Each bone keeps an id, which is what its prefab entity is named by. What the scene added to a bone, such as an IK2D or a sword parented to the hand, stays on that bone through reordering, reparenting and removal elsewhere.

In the scene, select an entity with a MeshSkin and use Rebind To in Details: pick another skeleton in the scene and Rebind Joints by Name. Each joint finds the entity of its name below that skeleton. When a name appears twice, as hand does under both arms, the parents’ names decide. A joint with no match keeps its entity and is named. This works for 3D skins too, for example a jacket bound to a body.

Select the character and key its bones in the Sequencer like any other entity. A bone is named by its path under the root, such as hips/spine/arm. A deform is a weight on the MeshMorph component, which keys the same way.

Blending is the Animator’s job, as for any other character: 1D and 2D blends, layers, masks and transitions all work on bones.

Add IK2D to the last bone of a limb and point target at an entity. The end of that bone reaches for it, after the animation has played, so a hand can hold what it holds whichever clip is running.

Field Meaning
target The entity to reach for.
chainLength How many bones bend, counting this one. Two solve exactly and keep their bend; more take an iterative solve.
bend With two bones, the way the middle joint bends: 1 counter-clockwise or -1.
weight How far from the animated pose towards the solve. Clips can key it.
matchTargetRotation Also turn this bone to the target’s rotation, for a foot flat on a slope.

Add BoneConstraint2D to a bone. Constraints run after IK, from the trunk out:

kind What it does
Limit Rotation Keeps the local rotation between min and max. An IK chain through the bone keeps to them too.
Copy Rotation Takes source’s world rotation, plus offset.
Copy Position Stands on source’s world position.
Look At Points the bone’s +x at source, plus offset.

IK and constraints run in play mode. Both follow a character mirrored by a negative scale on its root.

Rigs are plain data, so a game or a tool can make one:

import {
autoWeightPart, bakeRig, coverRigPart, createRig, rigImageFromRGBA, spawnRig, IK2D,
} from 'esengine/rig2d';
const image = rigImageFromRGBA(width, height, rgba);
const rig = createRig('hero.png', width, height);
rig.bones.push(
{ name: 'upper', parent: -1, x: 0, y: 0, rotation: 0, length: 50 },
{ name: 'lower', parent: 0, x: 50, y: 0, rotation: 0, length: 50 },
);
const rect = { x: 0, y: 0, w: width, h: height };
const part = { name: 'arm', rect, x: 0, y: height / 2, ...coverRigPart(image, rect), weights: [] };
rig.parts.push(part);
autoWeightPart(rig, part);
const mesh = assets.createMesh(bakeRig(rig));
const { bones } = spawnRig(world, rig, { mesh, texture });
world.insert(bones[1], IK2D, { target, chainLength: 2, bend: 1, weight: 1, matchTargetRotation: false, enabled: true });
  • A rig is one mesh, drawn in one draw call, up to 256 bones. A vertex follows at most 4.
  • Parts of one rig draw in the order you set. Against the rest of the scene, a rig sorts by MeshRenderer.layer and then by z, as a mesh does.
  • A selected rig’s outline shows its bind pose, not its current pose.