Depth-Driven 2.5D Rigging Interface

Tags
Rigging
Animation
OpenSource
Description
How rig-c turns depth data into a controllable rig, with a prepared example and a per-part depth workflow
Published
Published Nov 2, 2026
On this page
notion image
I wanted a character in a painting to turn its head as its gaze moved. Tilting the whole face or sliding a few layers sideways did not give me the sense of volume I was after. The nose, cheeks, and ears sit at different depths. Hair and the torso need to move from their own positions too.
The main feature of this update is an interface for passing that depth into a rig. Attach depth information to the parts, declare how they should move, and the tools produce a 2.5D rig with controls for head yaw, head pitch, and the torso.
The public look example, rigged with @rig-c/parts 2.2.0 and @rig-c/core 3.1.0. A gaze path was added to the head, eye, and torso dials for this capture. The artwork, rig, and depth data are unchanged. The GIF joins frames produced by the Core renderer.

How depth becomes movement

A depth sheet describes how far forward each point on a part sits. During rigging, those values are attached to mesh vertices. As the head-turn value changes, the difference between the reference depth and each vertex's depth determines how far that vertex moves. Different areas of the same face move by different amounts, creating a sense of volume.
Below is the depth atlas from the public head-turn demo. It places depth information for separate parts, including the face, hair, and torso, in a single image. This atlas example is separate from the per-part depth preparation and application workflow described later.
Depth atlas used in the public head-turn demo
Depth atlas used in the public head-turn demo
Not every part should bend in the same way. The character configuration declares each part's role in turn.roles.
  • surface: samples a depth sheet and deforms the surface, as with a face or hair.
  • unit: preserves its shape and moves at one depth, as with eyes, a mouth, or eyebrows.
  • rear: gives a rear group a separate counter-motion.
Roles are not inferred from part names. Back hair can still be a surface when its shape needs to deform. The torso has its own declaration in turn.body.roles.
notion image
Selected moments from the depth-driven rig's motion.

Trying the prepared example

The public look example is a useful starting point. It includes the painting, separated parts, depth sheets, and configuration, so you can try the rigging process without a GPU running a depth model.
Download the look/ directory and run the following inside it. These commands assume Bun is installed and pin the package versions used for this example.
bun add @rig-c/[email protected] @rig-c/[email protected] bunx rig-parts assemble \ --source painting.png \ --full layers/full \ --head layers/head \ --config config.json \ --out assembled bunx rig-parts rig \ --config config.json \ --parts assembled/rig \ --out candidate bunx rigc build \ --rig candidate/rig.json \ --motion candidate/motion.json \ --out built \ --profile rig-play \ --pack --page-edges free --pack-shape polygon
assemble reads the painting and layers, assembles the parts, and registers their depth sheets. rig reads the roles and depth to produce meshes, deformation, and control dials. build compiles and validates the rig and motion, producing Spine data and rig-c's native model.
This assembly-to-build sequence was checked with public example commit ddfd314a2664effaf41c770e47e43f1418d6dba8 and the package versions above. The GIF and stills in this article come from the Core renderer. This does not establish browser playback of the same build through Play or Pixi.
The example's config.json is a starting point for your own character, but its depth and pivot values need to be adapted. The full input contract is described in the Depth guide.

Connecting depth to your own artwork

There are two input routes. If you already have depth sheets registered to your parts, connect them through the character's config.depth. To obtain new depth data, prepare the assembled parts for an external model one at a time.
flowchart TD A["Separated parts and character config"] --> B["assemble · assemble parts"] B --> C{"Depth input"} C --> D["Connect prepared depth sheets"] C --> E["depth-prepare · prepare inference images"] E --> F["External model · generate depth data"] F --> G["depth-apply · validate and convert"] D --> H["rig · generate meshes and dials"] G --> H H --> I["build · validate and export"] I --> J["Control dials · review and refine"]

Preparing and applying per-part depth

depth-prepare places each part on neutral gray, scales it, and adds padding to create an inference image. After an external model generates depth data from that image, depth-apply checks that the input and coordinates match, then converts the data into a sheet the rig can use.
The commands below assume that assembled/rig, the character configuration config.json, and a separate depth recipe depth.json already exist.
bunx rig-parts depth-prepare \ --parts assembled/rig \ --config depth.json \ --out inference # Run an external model on the inference images. # Save rig-parts-map/1 data at the paths declared in depth.json. bunx rig-parts depth-apply \ --parts assembled/rig \ --manifest inference/manifest.json \ --config depth.json \ --rig-config config.json \ --out mapped bunx rig-parts rig \ --parts mapped \ --config mapped/config.json \ --out candidate-depth
Then use the earlier build command with its input paths changed to candidate-depth. Output directories must be empty or not yet exist.
rig-c does not bundle a depth model or its weights. It defines the format for accepting a model's output and the steps that connect that output to a rig. This route uses the model's actual numerical data; a grayscale preview PNG is not a substitute.

Values in the depth recipe

A few values must be authored to place the model's relative shape within the character. The public recipe documentation includes an example, but its numbers are not universal defaults.
  • median: the reference depth at which the part sits.
  • relief: the amount of depth variation within the part.
  • near and zScale: the direction of depth values and their scale in the rig.
  • frame: whether the model output uses the original part, upscaled part, or padded input coordinates.
  • unitDepths: explicit depths for small parts when needed.
Changing the face's depth also means checking its relationship to ears and eyes. Replacing only the face data can leave an ear in front of the adjacent cheek. The tools check input bindings and some depth relationships, but the resulting movement still needs inspection.

Controlling the rig with dials

The resulting rig has dials for head yaw and pitch, with an optional independent torso dial. Connecting pointer coordinates or game state to these values lets the same rig respond to different situations.
The default head dial bones are yaw_dial and pitch_dial. The torso name is configurable; the public look example uses body_dial. Read the generated model's slider declarations rather than guessing names and ranges.
  • Pose: maps retargeted motion to the rig's sliders.
  • Review: provides a Turn pad for moving the dials and inspecting the result.
  • Play: sets dial values during pose adjustment. Adjustments must be applied for each pose.
The adapters look example shows how to connect a pointer to the dials. Its pointer helpers are example code, not default exports from the npm adapter.

Limits and human review

The default rated range is ±15 degrees of yaw and ±12 degrees of pitch. The tools do not draw a side of the face that was never present in the original image. Wider turns require additional drawings declared for those views.
This is a 2.5D projection using artwork and depth. It does not provide the lighting or silhouette changes of a full 3D model, and a successful build does not guarantee convincing movement.
The final result still needs to be watched, reviewed, and refined. Review helps identify the location and moment of a problem and pass it into the next revision. With the depth-to-rig process available as a tool interface, the work can focus on applying it to each character and improving the result.