---
title: "retarget"
description: "The retarget namespace — the engine's Luau API reference for retarget."
section: "API Reference"
slug: "api-retarget"
canonical: "https://origozero.ai/docs/api-retarget"
updated: "2026-09-05T23:13:47.111855043+00:00"
tags: ["api", "reference"]
---

# retarget

The `retarget` namespace — 25 functions.

## globals/retarget/animation {#globals-retarget-animation}

```lua
retarget.animation(clipRef: any?, targetMeshRef: any?, sourceMeshRef: any?) -> (boolean, string)
```

Retarget an animation clip onto a target rig, returning the VFS path of a
new `.anim` whose channels name the target skeleton's bones with bind-pose
corrected rotations. The source rig is the clip's embedded `rig.zmsh` (else
`sourceMeshRef`'s skin, else the skinned mesh beside the clip in its bundle);
the target rig is `targetMeshRef`'s skin. Play the result with
`animGraph.addClip(entity, path)`. Pure asset transform — no entity/ECS state.

**Parameters**

- `clipRef` `any` _(optional)_ — Animation asset to retarget.
- `targetMeshRef` `any` _(optional)_ — Target rig mesh whose skin defines the destination skeleton.
- `sourceMeshRef` `any` _(optional)_ — Source rig mesh the clip was authored for; omit to use the clip's embedded rig.

**Returns** `(boolean, string)` — Success flag and the retargeted clip's VFS path (empty on failure).

```lua
local ok, path = retarget.animation(clipRef, targetMeshRef)
```

## globals/retarget/extractRig {#globals-retarget-extractrig}

```lua
retarget.extractRig(meshBytes: buffer | string) -> string?
```

Strip a `.mesh` (ZMSH) payload to a lean skin-only rig: the skeleton with
geometry removed, re-encoded as a ZMSH whose only content is the skin. Returns
the rig bytes, or nil when the mesh carries no skin. A `.animation` composite
embeds this as `rig.zmsh` so a clip travels with its own source rig.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

**Returns** `string?` — Skin-only ZMSH rig bytes, or nil when the mesh has no skin.

```lua
local rig = retarget.extractRig(meshBytes)
```

## globals/retarget/humanoidProfile {#globals-retarget-humanoidprofile}

```lua
retarget.humanoidProfile(meshBytes: buffer | string) -> HumanoidHolder?
```

Derive the humanoid retarget holder for a rig from a `.mesh` (ZMSH)
payload, when that skeleton has the essential humanoid structure (a hips root,
a head or neck, at least one full arm chain and one full leg chain). Returns
nil for a rig that is not a humanoid — a prop, a plant whose leaves animate, a
quadruped — so a clip from it stays a plain clip rather than joining the shared
humanoid-animation pool. A rig whose bone hierarchy loops answers nil and a
message naming the bone edge that closes the loop, so a caller reading the
second return value can tell malformed input from a plain non-humanoid.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

**Returns** `HumanoidHolder?` — `{ base, boneCount, roles = { [role] = boneName } }`, or nil when the rig is not a humanoid; nil and a message naming the closing bone edge when its hierarchy loops.

```lua
local holder = retarget.humanoidProfile(meshBytes)
```

## globals/retarget/isHumanoid {#globals-retarget-ishumanoid}

```lua
retarget.isHumanoid(meshBytes: buffer | string) -> boolean
```

Whether a rig is a humanoid avatar — true when `humanoidProfile` resolves a
holder for it. Use this to tell a humanoid character apart from a generic
animated mesh (a prop, a plant, a quadruped) before treating its clips as
shareable humanoid animations.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

**Returns** `boolean` — True when the rig has the essential humanoid structure.

```lua
if retarget.isHumanoid(meshBytes) then ... end
```

## globals/retarget/serializeProfile {#globals-retarget-serializeprofile}

```lua
retarget.serializeProfile(holder: HumanoidHolder) -> string
```

Serialize a humanoid holder to the `humanoid.profile` file body: an
editable YAML role -> bone-name map. Roles list hips-first head-to-toe through
the limbs, then any extras name-sorted, so the file reads top-down and diffs
stably. Edit a value to correct an auto-derived mapping.

**Parameters**

- `holder` `HumanoidHolder` — A holder from `humanoidProfile`.

**Returns** `string` — The YAML body to store as `humanoid.profile`.

```lua
files["humanoid.profile"] = retarget.serializeProfile(holder)
```

## modules/retarget/README {#modules-retarget-readme}

```lua
require("@builtin/modules/retarget") -- retarget
```

Skeletal animation retargeting — map a clip authored on one rig onto another humanoid rig, preserving the target's shape. Pure, readable Luau: the behavior an agent follows and tweaks. `bake` is the cold, cached transform (clip + source rig + target rig -> a clip in the target's bone space); the hot path just samples the baked clip. `plan` reports which canonical roles map across the two rigs and which don't.

Usage: local retarget = require("@builtin/modules/retarget")

## modules/retarget/animation {#modules-retarget-animation}

```lua
animation(clipRef: any, targetMeshRef: any, sourceMeshRef: any?): (boolean, string)
```

Retarget an animation clip onto a target rig, returning the VFS path of a
new `.anim` whose channels name the target skeleton's bones with bind-pose
corrected rotations. The source rig is the clip's embedded `rig.zmsh` (else
`sourceMeshRef`'s skin, else the skinned mesh beside the clip in its bundle);
the target rig is `targetMeshRef`'s skin. Play the result with
`animGraph.addClip(entity, path)`. Pure asset transform — no entity/ECS state.

**Parameters**

- `clipRef` `any` _(optional)_ — Animation asset to retarget.
- `targetMeshRef` `any` _(optional)_ — Target rig mesh whose skin defines the destination skeleton.
- `sourceMeshRef` `any?` _(optional)_ — Source rig mesh the clip was authored for; omit to use the clip's embedded rig.

```lua
local ok, path = retarget.animation(clipRef, targetMeshRef)
```

## modules/retarget/aux {#modules-retarget-aux}

```lua
aux(bakeKey: string)
```

Read what was cached beside the bake at `bakeKey`.

**Parameters**

- `bakeKey` `string` — A key from `bakeKey()`.

## modules/retarget/bake {#modules-retarget-bake}

```lua
bake(clip, srcRig, tgtRig, opts)
```

Retarget a decoded clip from its source rig onto a target rig, producing
a clip in the TARGET's bone space (channels named for target bones). Per
frame it forward-kinematics the source pose on the rig AS AUTHORED (the bind
the clip's channel rotations are local to), measures each mapped role's world
rotation as a deviation from the source's CANONICAL bind, re-applies that
deviation to the target's CANONICAL bind, and converts back to a target-local
rotation through the target's ANIMATED parent. The target chain is rebuilt
top-down, so error never accumulates down a limb. Both rigs are re-posed to
the geometry-derived canonical T-pose (`normalizeToTPose`) for that deviation,
so the result depends only on the T-pose the two rigs share — never on
whatever arbitrary pose either was authored in (an A-pose source idle lands
the target's arms down, not splayed out at the A-pose offset). The apply path
seeds that same canonical rest. Translation routes through the role and is
size-scaled by the hip-height ratio; the apply path makes it relative to the
target's bind. This is the cold step — bake once per (clip, target rig) and
cache (see `bakeBytes`).

**Parameters**

- `clip` `any` _(optional)_ — A decoded clip table `{ name, duration, channels, bone_names }`
(e.g. `json.decode(skeleton.clipDecode(bytes))`).
- `srcRig` `any` _(optional)_ — Source rig the clip was authored on (parsed rig / table / JSON).
- `tgtRig` `any` _(optional)_ — Target rig to retarget onto (parsed rig / table / JSON).
- `opts` `any` _(optional)_ — Optional `{ symmetrize: boolean }` forwarded to `normalizeToTPose`.

## modules/retarget/bakeBytes {#modules-retarget-bakebytes}

```lua
bakeBytes(clipBytes, srcRig, tgtRig, cacheKey, opts)
```

Bake from clip BYTES to retargeted clip BYTES — `clipDecode` -> `bake`
-> `clipEncode` — with an in-memory cache. Retarget is cold: pass a stable
`cacheKey` (e.g. clip identity + target rig identity) and the second call
for the same pair returns the cached bytes. The hot path then just samples
the result like any native clip.

**Parameters**

- `clipBytes` `any` _(optional)_ — The source clip's `zanim` payload bytes.
- `srcRig` `any` _(optional)_ — Source rig (parsed rig / table / JSON).
- `tgtRig` `any` _(optional)_ — Target rig (parsed rig / table / JSON).
- `cacheKey` `any` _(optional)_ — Optional stable key; when given, the result is cached and reused.
- `opts` `any` _(optional)_ — Optional `{ symmetrize: boolean }` forwarded to `normalizeToTPose`
(absolute vs relative bind correction). Each mode caches separately.

## modules/retarget/bakeKey {#modules-retarget-bakekey}

```lua
bakeKey(cacheKey: string, opts): string
```

The key a bake is stored under, so a caller that derives something FROM
a bake can hold it under the same key and have it dropped at the same time.
Each correction mode bakes separately, which is what the suffix carries.

**Parameters**

- `cacheKey` `string` — The stable key passed to `bakeBytes`.
- `opts` `any` _(optional)_ — The same `{ symmetrize }` passed to `bakeBytes`.

## modules/retarget/clearCache {#modules-retarget-clearcache}

```lua
clearCache(cacheKey: string?)
```

Drop every cached bake and everything derived from it (or just
`cacheKey` when given). Call after editing a rig's profile so clips re-bake
against the corrected mapping.

**Parameters**

- `cacheKey` `string?` _(optional)_ — Optional single key to evict; omit to clear all. Accepts either
the key passed to `bakeBytes` or an already-composed `bakeKey()`.

## modules/retarget/extractRig {#modules-retarget-extractrig}

```lua
extractRig(meshBytes: buffer | string): string?
```

Strip a `.mesh` (ZMSH) payload to a lean skin-only rig: the skeleton with
geometry removed, re-encoded as a ZMSH whose only content is the skin. Returns
the rig bytes, or nil when the mesh carries no skin. A `.animation` composite
embeds this as `rig.zmsh` so a clip travels with its own source rig.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

```lua
local rig = retarget.extractRig(meshBytes)
```

## modules/retarget/humanoidProfile {#modules-retarget-humanoidprofile}

```lua
humanoidProfile(meshBytes: buffer | string): HumanoidHolder?
```

Derive the humanoid retarget holder for a rig from a `.mesh` (ZMSH)
payload, when that skeleton has the essential humanoid structure (a hips root,
a head or neck, at least one full arm chain and one full leg chain). Returns
nil for a rig that is not a humanoid — a prop, a plant whose leaves animate, a
quadruped — so a clip from it stays a plain clip rather than joining the shared
humanoid-animation pool. A rig whose bone hierarchy loops answers nil and a
message naming the bone edge that closes the loop, so a caller reading the
second return value can tell malformed input from a plain non-humanoid.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

```lua
local holder = retarget.humanoidProfile(meshBytes)
```

## modules/retarget/isHumanoid {#modules-retarget-ishumanoid}

```lua
isHumanoid(meshBytes: buffer | string): boolean
```

Whether a rig is a humanoid avatar — true when `humanoidProfile` resolves a
holder for it. Use this to tell a humanoid character apart from a generic
animated mesh (a prop, a plant, a quadruped) before treating its clips as
shareable humanoid animations.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

```lua
if retarget.isHumanoid(meshBytes) then ... end
```

## modules/retarget/loadRig {#modules-retarget-loadrig}

```lua
loadRig(ref)
```

Resolve a `.rig` asset and return its parsed, FK-enriched rig (ready for
`plan` / `bake`). The rig payload is the asset's `rig.json`.

**Parameters**

- `ref` `any` _(optional)_ — A `.rig` asset ref (identity / guid / path / handle).

## modules/retarget/normalizeToTPose {#modules-retarget-normalizetotpose}

```lua
normalizeToTPose(rig, opts)
```

Re-pose a rig's bind to the EXACT canonical T-pose, so a clip's source
rig and the avatar it drives share one reference pose. Retarget transfers
RELATIVE motion, so any residual bind mismatch (hands rolled the wrong way,
feet pointing askew, an A-pose vs a T-pose) shows up as broken hands/feet in
the result. Each bone is posed to a canonical world frame for its role —
direction AND roll: arms horizontal palms-down, legs straight down, spine up.
Only the limb bones whose bind direction differs between an A-pose and a
T-pose are aimed; limb ENDPOINTS (hands, feet, toes) and bones with no role
keep their authored orientation relative to the re-posed parent (their pose is
mesh-defined, so aiming them twists the hand / tips the foot). The whole body
is also rigidly de-rotated into an upright, forward-facing frame (handling a
baked root rotation) and centered on its sagittal plane.
Bind correction is RELATIVE by default — bone offsets/lengths/inverse-bind are
untouched, so the rig keeps its own proportions and any authored left/right
asymmetry. Pass `opts.symmetrize = true` for ABSOLUTE correction: left/right
bones are mirrored across the sagittal plane for a perfectly symmetric bind,
overriding the rig's authored asymmetry/proportions.

**Parameters**

- `rig` `any` _(optional)_ — The rig to normalize (parsed rig / table / JSON).
- `opts` `any` _(optional)_ — Optional `{ symmetrize: boolean }`. `symmetrize=true` = absolute
correction (force symmetry); default/false = relative (preserve proportions).

## modules/retarget/plan {#modules-retarget-plan}

```lua
plan(srcRig, tgtRig)
```

Report how a source rig's clips map onto a target rig: which canonical
roles both rigs fill (`mapped`), which the source has but the target lacks
(`unmappedSource` — those channels are dropped), and which the target has
spare (`unmappedTarget`). Use it to see why a retarget is partial and which
bone to hand-map in a rig's profile.

**Parameters**

- `srcRig` `any` _(optional)_ — Source rig — a parsed rig, a `.rig` table, or its JSON string.
- `tgtRig` `any` _(optional)_ — Target rig — same forms.

## modules/retarget/serializeProfile {#modules-retarget-serializeprofile}

```lua
serializeProfile(holder: HumanoidHolder): string
```

Serialize a humanoid holder to the `humanoid.profile` file body: an
editable YAML role -> bone-name map. Roles list hips-first head-to-toe through
the limbs, then any extras name-sorted, so the file reads top-down and diffs
stably. Edit a value to correct an auto-derived mapping.

**Parameters**

- `holder` `HumanoidHolder` — A holder from `humanoidProfile`.

```lua
files["humanoid.profile"] = retarget.serializeProfile(holder)
```

## modules/retarget/setAux {#modules-retarget-setaux}

```lua
setAux(bakeKey: string, value)
```

Cache a value beside the bake at `bakeKey`. It is dropped whenever that
bake is, so it cannot outlive the bytes it was derived from.

**Parameters**

- `bakeKey` `string` — A key from `bakeKey()`.
- `value` `any` _(optional)_ — The value to hold.

## typed/builtin//modules/api/engine/retarget/retarget/animation {#typed-builtin-modules-api-engine-retarget-retarget-animation}

```lua
retarget.animation(clipRef: any?, targetMeshRef: any?, sourceMeshRef: any?) -> (boolean, string)
```

Retarget an animation clip onto a target rig, returning the VFS path of a
new `.anim` whose channels name the target skeleton's bones with bind-pose
corrected rotations. The source rig is the clip's embedded `rig.zmsh` (else
`sourceMeshRef`'s skin, else the skinned mesh beside the clip in its bundle);
the target rig is `targetMeshRef`'s skin. Play the result with
`animGraph.addClip(entity, path)`. Pure asset transform — no entity/ECS state.

**Parameters**

- `clipRef` `any` _(optional)_ — Animation asset to retarget.
- `targetMeshRef` `any` _(optional)_ — Target rig mesh whose skin defines the destination skeleton.
- `sourceMeshRef` `any` _(optional)_ — Source rig mesh the clip was authored for; omit to use the clip's embedded rig.

**Returns** `(boolean, string)` — Success flag and the retargeted clip's VFS path (empty on failure).

```lua
local ok, path = retarget.animation(clipRef, targetMeshRef)
```

## typed/builtin//modules/api/engine/retarget/retarget/extractRig {#typed-builtin-modules-api-engine-retarget-retarget-extractrig}

```lua
retarget.extractRig(meshBytes: buffer | string) -> string?
```

Strip a `.mesh` (ZMSH) payload to a lean skin-only rig: the skeleton with
geometry removed, re-encoded as a ZMSH whose only content is the skin. Returns
the rig bytes, or nil when the mesh carries no skin. A `.animation` composite
embeds this as `rig.zmsh` so a clip travels with its own source rig.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

**Returns** `string?` — Skin-only ZMSH rig bytes, or nil when the mesh has no skin.

```lua
local rig = retarget.extractRig(meshBytes)
```

## typed/builtin//modules/api/engine/retarget/retarget/humanoidProfile {#typed-builtin-modules-api-engine-retarget-retarget-humanoidprofile}

```lua
retarget.humanoidProfile(meshBytes: buffer | string) -> HumanoidHolder?
```

Derive the humanoid retarget holder for a rig from a `.mesh` (ZMSH)
payload, when that skeleton has the essential humanoid structure (a hips root,
a head or neck, at least one full arm chain and one full leg chain). Returns
nil for a rig that is not a humanoid — a prop, a plant whose leaves animate, a
quadruped — so a clip from it stays a plain clip rather than joining the shared
humanoid-animation pool. A rig whose bone hierarchy loops answers nil and a
message naming the bone edge that closes the loop, so a caller reading the
second return value can tell malformed input from a plain non-humanoid.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

**Returns** `HumanoidHolder?` — `{ base, boneCount, roles = { [role] = boneName } }`, or nil when the rig is not a humanoid; nil and a message naming the closing bone edge when its hierarchy loops.

```lua
local holder = retarget.humanoidProfile(meshBytes)
```

## typed/builtin//modules/api/engine/retarget/retarget/isHumanoid {#typed-builtin-modules-api-engine-retarget-retarget-ishumanoid}

```lua
retarget.isHumanoid(meshBytes: buffer | string) -> boolean
```

Whether a rig is a humanoid avatar — true when `humanoidProfile` resolves a
holder for it. Use this to tell a humanoid character apart from a generic
animated mesh (a prop, a plant, a quadruped) before treating its clips as
shareable humanoid animations.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

**Returns** `boolean` — True when the rig has the essential humanoid structure.

```lua
if retarget.isHumanoid(meshBytes) then ... end
```

## typed/builtin//modules/api/engine/retarget/retarget/serializeProfile {#typed-builtin-modules-api-engine-retarget-retarget-serializeprofile}

```lua
retarget.serializeProfile(holder: HumanoidHolder) -> string
```

Serialize a humanoid holder to the `humanoid.profile` file body: an
editable YAML role -> bone-name map. Roles list hips-first head-to-toe through
the limbs, then any extras name-sorted, so the file reads top-down and diffs
stably. Edit a value to correct an auto-derived mapping.

**Parameters**

- `holder` `HumanoidHolder` — A holder from `humanoidProfile`.

**Returns** `string` — The YAML body to store as `humanoid.profile`.

```lua
files["humanoid.profile"] = retarget.serializeProfile(holder)
```
