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

# skeleton

The `skeleton` namespace — 31 functions.

## globals/skeleton/applyPose {#globals-skeleton-applypose}

```lua
skeleton.applyPose(sinkHandle: number, poseBuffer: Substrate.TypedBuffer) -> boolean
```

Snapshot the buffer's first `layout.total_floats` values and
queue a pending apply for the next ECS drain. Returns false on
unknown sink/buffer or buffer too small for the layout. The
Buffer is unchanged.

**Parameters**

- `sinkHandle` `number` — Sink handle from `bindPose`.
- `poseBuffer` `Substrate.TypedBuffer` — The pose buffer to apply.

**Returns** `boolean` — True on success.

## globals/skeleton/bindClip {#globals-skeleton-bindclip}

```lua
skeleton.bindClip(zanimBytes: buffer | string, boneOrder: { string }) -> ClipBindInfo?
```

Decode a `zanim` payload and bind it to `boneOrder`,
precomputing which of the clip's channels feed each bone so
per-frame `sampleClip` is allocation-free. Returns
`{ handle, matched, total, duration }`, or nil on a malformed
payload / empty bone order. Check `matched`: 0 means the clip
drives none of these bones.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).
- `boneOrder` `{ string }` — Output bone names — one stride-10 record per bone.

**Returns** `ClipBindInfo?` — `{ handle, matched, total, duration }`, or nil.

## globals/skeleton/bindPose {#globals-skeleton-bindpose}

```lua
skeleton.bindPose(entityId: (string | entityRef)?, opts: SkeletonLayout) -> number?
```

Register a pose sink targeting `entityId`. The opts table
carries the layout: `boneOrder` is the bone-name array
(`{"hip", "spine", ...}`), `stride` defaults to 10
(translation.xyz + rotation.xyzw + scale.xyz). Pass `entityId`
as nil to use the current component's owning entity.

**Parameters**

- `entityId` `(string | entityRef)` _(optional)_ — Engine entity id or proxy, or nil for the current entity.
- `opts` `SkeletonLayout` — `{ boneOrder, stride }`.

**Returns** `number?` — Sink handle, or nil.

```lua
local h = skeleton.bindPose(nil, { boneOrder = bones, stride = 10 })
```

## globals/skeleton/clipBones {#globals-skeleton-clipbones}

```lua
skeleton.clipBones(zanimBytes: buffer | string) -> { string }?
```

Decode a `zanim` payload and return its bone-name array. Pure:
build a bind order or a retarget map from a clip without binding a
sampler. Returns nil on bytes that aren't a valid zanim payload.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).

**Returns** `{ string }?` — Bone names referenced by the clip, or nil.

```lua
local names = skeleton.clipBones(vfs.read(path .. "/data.zanim"))
```

## globals/skeleton/clipDecode {#globals-skeleton-clipdecode}

```lua
skeleton.clipDecode(zanimBytes: buffer | string) -> string?
```

Decode a `zanim` payload to its readable JSON form
(`{ name, duration, channels, bone_names }`). The binary parse is
the engine's; `json.decode` the result to inspect or transform a
clip's channels (e.g. the retarget bake) in Luau. Returns nil on
bytes that aren't a valid zanim payload. Inverse of `clipEncode`.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).

**Returns** `string?` — The clip as a JSON string, or nil.

```lua
local clip = json.decode(skeleton.clipDecode(bytes))
```

## globals/skeleton/clipEncode {#globals-skeleton-clipencode}

```lua
skeleton.clipEncode(jsonString: string) -> string?
```

Encode a clip's JSON form (the shape `clipDecode` returns) back
to a `zanim` payload — the bytes a `.animation` stores and
`bindClip`/`sampleClip` consume. Inverse of `clipDecode`. Returns
nil on invalid JSON.

**Parameters**

- `jsonString` `string` — A clip JSON document.

**Returns** `string?` — The clip's `zanim` payload bytes, or nil.

```lua
local bytes = skeleton.clipEncode(json.encode(clip))
```

## globals/skeleton/jointTransforms {#globals-skeleton-jointtransforms}

```lua
skeleton.jointTransforms(entityId: string | entityRef) -> table
```

Read a skinned entity's per-joint world transforms for the
current animated pose.

**Parameters**

- `entityId` `string | entityRef` — Engine entity id or proxy of a skinned entity.

**Returns** `table` — Array of joint transforms: `{ position, matrix, parent, name }`.

```lua
local joints = skeleton.jointTransforms(meshId)
```

## globals/skeleton/sampleClip {#globals-skeleton-sampleclip}

```lua
skeleton.sampleClip(handle: number, time: number, poseBuffer: Substrate.TypedBuffer) -> boolean
```

Sample the bound clip at `time` (clamped to `[0, duration]`)
and write one stride-10 pose record per bound bone into the
Buffer, starting at index 0. Bones the clip does not drive are
written as identity. Returns false on unknown handle/buffer or a
buffer too small for the bone count.

**Parameters**

- `handle` `number` — Sampler handle from `bindClip`.
- `time` `number` — Sample time in seconds.
- `poseBuffer` `Substrate.TypedBuffer` — The stride-10 pose buffer written into.

**Returns** `boolean` — True on success.

## globals/skeleton/unbindClip {#globals-skeleton-unbindclip}

```lua
skeleton.unbindClip(handle: number) -> boolean
```

Drop the bound clip sampler from the registry.

**Parameters**

- `handle` `number` — Sampler handle to remove.

**Returns** `boolean` — True if the sampler existed.

## globals/skeleton/unbindPose {#globals-skeleton-unbindpose}

```lua
skeleton.unbindPose(sinkHandle: number) -> boolean
```

Remove the sink from the registry.

**Parameters**

- `sinkHandle` `number` — Sink handle to remove.

**Returns** `boolean` — True if the sink was present.

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

```lua
require("@builtin/modules/api/engine/skeleton") -- skeleton (also available as global 'skeleton')
```

The skeleton pose-data pipeline: sample a clip into a pose buffer, and bind/apply a pose buffer onto a Skeleton + Model entity. Public Luau surface over the `__skeleton` and `__clip` Internal FFI namespaces.

Usage: local skeleton = require("@builtin/modules/api/engine/skeleton")
Also available as global: skeleton

## modules/skeleton/applyPose {#modules-skeleton-applypose}

```lua
applyPose(sinkHandle: number, poseBuffer: Substrate.TypedBuffer): boolean
```

Snapshot the buffer's first `layout.total_floats` values and
queue a pending apply for the next ECS drain. Returns false on
unknown sink/buffer or buffer too small for the layout. The
Buffer is unchanged.

**Parameters**

- `sinkHandle` `number` — Sink handle from `bindPose`.
- `poseBuffer` `Substrate.TypedBuffer` — The pose buffer to apply.

## modules/skeleton/bindClip {#modules-skeleton-bindclip}

```lua
bindClip(zanimBytes: buffer | string, boneOrder: { string }): ClipBindInfo?
```

Decode a `zanim` payload and bind it to `boneOrder`,
precomputing which of the clip's channels feed each bone so
per-frame `sampleClip` is allocation-free. Returns
`{ handle, matched, total, duration }`, or nil on a malformed
payload / empty bone order. Check `matched`: 0 means the clip
drives none of these bones.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).
- `boneOrder` `{ string }` — Output bone names — one stride-10 record per bone.

## modules/skeleton/bindPose {#modules-skeleton-bindpose}

```lua
bindPose(entityId: (string | entityRef)?, opts: SkeletonLayout): number?
```

Register a pose sink targeting `entityId`. The opts table
carries the layout: `boneOrder` is the bone-name array
(`{"hip", "spine", ...}`), `stride` defaults to 10
(translation.xyz + rotation.xyzw + scale.xyz). Pass `entityId`
as nil to use the current component's owning entity.

**Parameters**

- `entityId` `(string | entityRef)?` _(optional)_ — Engine entity id or proxy, or nil for the current entity.
- `opts` `SkeletonLayout` — `{ boneOrder, stride }`.

```lua
local h = skeleton.bindPose(nil, { boneOrder = bones, stride = 10 })
```

## modules/skeleton/clipBones {#modules-skeleton-clipbones}

```lua
clipBones(zanimBytes: buffer | string): { string }?
```

Decode a `zanim` payload and return its bone-name array. Pure:
build a bind order or a retarget map from a clip without binding a
sampler. Returns nil on bytes that aren't a valid zanim payload.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).

```lua
local names = skeleton.clipBones(vfs.read(path .. "/data.zanim"))
```

## modules/skeleton/clipDecode {#modules-skeleton-clipdecode}

```lua
clipDecode(zanimBytes: buffer | string): string?
```

Decode a `zanim` payload to its readable JSON form
(`{ name, duration, channels, bone_names }`). The binary parse is
the engine's; `json.decode` the result to inspect or transform a
clip's channels (e.g. the retarget bake) in Luau. Returns nil on
bytes that aren't a valid zanim payload. Inverse of `clipEncode`.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).

```lua
local clip = json.decode(skeleton.clipDecode(bytes))
```

## modules/skeleton/clipEncode {#modules-skeleton-clipencode}

```lua
clipEncode(jsonString: string): string?
```

Encode a clip's JSON form (the shape `clipDecode` returns) back
to a `zanim` payload — the bytes a `.animation` stores and
`bindClip`/`sampleClip` consume. Inverse of `clipDecode`. Returns
nil on invalid JSON.

**Parameters**

- `jsonString` `string` — A clip JSON document.

```lua
local bytes = skeleton.clipEncode(json.encode(clip))
```

## modules/skeleton/jointTransforms {#modules-skeleton-jointtransforms}

```lua
jointTransforms(entityId: string | entityRef): table
```

Read a skinned entity's per-joint world transforms for the
current animated pose.

**Parameters**

- `entityId` `string | entityRef` — Engine entity id or proxy of a skinned entity.

```lua
local joints = skeleton.jointTransforms(meshId)
```

## modules/skeleton/sampleClip {#modules-skeleton-sampleclip}

```lua
sampleClip(handle: number, time: number, poseBuffer: Substrate.TypedBuffer): boolean
```

Sample the bound clip at `time` (clamped to `[0, duration]`)
and write one stride-10 pose record per bound bone into the
Buffer, starting at index 0. Bones the clip does not drive are
written as identity. Returns false on unknown handle/buffer or a
buffer too small for the bone count.

**Parameters**

- `handle` `number` — Sampler handle from `bindClip`.
- `time` `number` — Sample time in seconds.
- `poseBuffer` `Substrate.TypedBuffer` — The stride-10 pose buffer written into.

## modules/skeleton/unbindClip {#modules-skeleton-unbindclip}

```lua
unbindClip(handle: number): boolean
```

Drop the bound clip sampler from the registry.

**Parameters**

- `handle` `number` — Sampler handle to remove.

## modules/skeleton/unbindPose {#modules-skeleton-unbindpose}

```lua
unbindPose(sinkHandle: number): boolean
```

Remove the sink from the registry.

**Parameters**

- `sinkHandle` `number` — Sink handle to remove.

## typed/builtin//modules/api/engine/skeleton/skeleton/applyPose {#typed-builtin-modules-api-engine-skeleton-skeleton-applypose}

```lua
skeleton.applyPose(sinkHandle: number, poseBuffer: Substrate.TypedBuffer) -> boolean
```

Snapshot the buffer's first `layout.total_floats` values and
queue a pending apply for the next ECS drain. Returns false on
unknown sink/buffer or buffer too small for the layout. The
Buffer is unchanged.

**Parameters**

- `sinkHandle` `number` — Sink handle from `bindPose`.
- `poseBuffer` `Substrate.TypedBuffer` — The pose buffer to apply.

**Returns** `boolean` — True on success.

## typed/builtin//modules/api/engine/skeleton/skeleton/bindClip {#typed-builtin-modules-api-engine-skeleton-skeleton-bindclip}

```lua
skeleton.bindClip(zanimBytes: buffer | string, boneOrder: { string }) -> ClipBindInfo?
```

Decode a `zanim` payload and bind it to `boneOrder`,
precomputing which of the clip's channels feed each bone so
per-frame `sampleClip` is allocation-free. Returns
`{ handle, matched, total, duration }`, or nil on a malformed
payload / empty bone order. Check `matched`: 0 means the clip
drives none of these bones.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).
- `boneOrder` `{ string }` — Output bone names — one stride-10 record per bone.

**Returns** `ClipBindInfo?` — `{ handle, matched, total, duration }`, or nil.

## typed/builtin//modules/api/engine/skeleton/skeleton/bindPose {#typed-builtin-modules-api-engine-skeleton-skeleton-bindpose}

```lua
skeleton.bindPose(entityId: (string | entityRef)?, opts: SkeletonLayout) -> number?
```

Register a pose sink targeting `entityId`. The opts table
carries the layout: `boneOrder` is the bone-name array
(`{"hip", "spine", ...}`), `stride` defaults to 10
(translation.xyz + rotation.xyzw + scale.xyz). Pass `entityId`
as nil to use the current component's owning entity.

**Parameters**

- `entityId` `(string | entityRef)` _(optional)_ — Engine entity id or proxy, or nil for the current entity.
- `opts` `SkeletonLayout` — `{ boneOrder, stride }`.

**Returns** `number?` — Sink handle, or nil.

```lua
local h = skeleton.bindPose(nil, { boneOrder = bones, stride = 10 })
```

## typed/builtin//modules/api/engine/skeleton/skeleton/clipBones {#typed-builtin-modules-api-engine-skeleton-skeleton-clipbones}

```lua
skeleton.clipBones(zanimBytes: buffer | string) -> { string }?
```

Decode a `zanim` payload and return its bone-name array. Pure:
build a bind order or a retarget map from a clip without binding a
sampler. Returns nil on bytes that aren't a valid zanim payload.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).

**Returns** `{ string }?` — Bone names referenced by the clip, or nil.

```lua
local names = skeleton.clipBones(vfs.read(path .. "/data.zanim"))
```

## typed/builtin//modules/api/engine/skeleton/skeleton/clipDecode {#typed-builtin-modules-api-engine-skeleton-skeleton-clipdecode}

```lua
skeleton.clipDecode(zanimBytes: buffer | string) -> string?
```

Decode a `zanim` payload to its readable JSON form
(`{ name, duration, channels, bone_names }`). The binary parse is
the engine's; `json.decode` the result to inspect or transform a
clip's channels (e.g. the retarget bake) in Luau. Returns nil on
bytes that aren't a valid zanim payload. Inverse of `clipEncode`.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).

**Returns** `string?` — The clip as a JSON string, or nil.

```lua
local clip = json.decode(skeleton.clipDecode(bytes))
```

## typed/builtin//modules/api/engine/skeleton/skeleton/clipEncode {#typed-builtin-modules-api-engine-skeleton-skeleton-clipencode}

```lua
skeleton.clipEncode(jsonString: string) -> string?
```

Encode a clip's JSON form (the shape `clipDecode` returns) back
to a `zanim` payload — the bytes a `.animation` stores and
`bindClip`/`sampleClip` consume. Inverse of `clipDecode`. Returns
nil on invalid JSON.

**Parameters**

- `jsonString` `string` — A clip JSON document.

**Returns** `string?` — The clip's `zanim` payload bytes, or nil.

```lua
local bytes = skeleton.clipEncode(json.encode(clip))
```

## typed/builtin//modules/api/engine/skeleton/skeleton/jointTransforms {#typed-builtin-modules-api-engine-skeleton-skeleton-jointtransforms}

```lua
skeleton.jointTransforms(entityId: string | entityRef) -> table
```

Read a skinned entity's per-joint world transforms for the
current animated pose.

**Parameters**

- `entityId` `string | entityRef` — Engine entity id or proxy of a skinned entity.

**Returns** `table` — Array of joint transforms: `{ position, matrix, parent, name }`.

```lua
local joints = skeleton.jointTransforms(meshId)
```

## typed/builtin//modules/api/engine/skeleton/skeleton/sampleClip {#typed-builtin-modules-api-engine-skeleton-skeleton-sampleclip}

```lua
skeleton.sampleClip(handle: number, time: number, poseBuffer: Substrate.TypedBuffer) -> boolean
```

Sample the bound clip at `time` (clamped to `[0, duration]`)
and write one stride-10 pose record per bound bone into the
Buffer, starting at index 0. Bones the clip does not drive are
written as identity. Returns false on unknown handle/buffer or a
buffer too small for the bone count.

**Parameters**

- `handle` `number` — Sampler handle from `bindClip`.
- `time` `number` — Sample time in seconds.
- `poseBuffer` `Substrate.TypedBuffer` — The stride-10 pose buffer written into.

**Returns** `boolean` — True on success.

## typed/builtin//modules/api/engine/skeleton/skeleton/unbindClip {#typed-builtin-modules-api-engine-skeleton-skeleton-unbindclip}

```lua
skeleton.unbindClip(handle: number) -> boolean
```

Drop the bound clip sampler from the registry.

**Parameters**

- `handle` `number` — Sampler handle to remove.

**Returns** `boolean` — True if the sampler existed.

## typed/builtin//modules/api/engine/skeleton/skeleton/unbindPose {#typed-builtin-modules-api-engine-skeleton-skeleton-unbindpose}

```lua
skeleton.unbindPose(sinkHandle: number) -> boolean
```

Remove the sink from the registry.

**Parameters**

- `sinkHandle` `number` — Sink handle to remove.

**Returns** `boolean` — True if the sink was present.
