# Animatronic kinematics

The whole-humanoid layer over the biped: one routine intent for the entire body, an attention cascade through the eyes, the neck and the waist, and a centre of mass measured against the ground the feet actually hold.

> For the complete index, see [llms.txt](https://robocn.dev/llms.txt). A Markdown version of any page is available by appending `.md` to its URL or by sending an `Accept: text/markdown` header.

## Install

```bash
bunx --bun shadcn@latest add https://robocn.dev/r/animatronic-kinematics.json
```

Registry item: `animatronic-kinematics` · [`https://robocn.dev/r/animatronic-kinematics.json`](https://robocn.dev/r/animatronic-kinematics.json)

## Notes

- No React, no three.js, no dependencies, and nothing is mutated. It sits on skeleton, face and hand kinematics rather than duplicating any of them.
- The balance correction is a rigid rotation about a pivot on the floor, so every bone is the same length before and after and the planted foot stays where it was. It is also verified: the rolled pose is measured, and a roll that does not improve the margin is discarded rather than applied on faith.
- There is still no dynamics. Nothing integrates a mass or computes a ground reaction; the margin is a measurement and the roll is a posture, not a fall being averted.

## Usage

```tsx
import { routineIntent, solveAttention, solveAnimatronic, balanceOf } from "@/lib/robocn/animatronic"

const intent = routineIntent("converse", clock)   // the whole body at one instant
const look = solveAttention({ x: 0.8, y: 0.1 })   // eyes, then neck, then waist
const body = solveAnimatronic({ ...intent, balance: true })

body.balance.margin   // signed distance from the plumb line to the support polygon
body.roll             // the rigid roll taken to get there, in degrees
```

## API

| name | type | default | description |
| --- | --- | --- | --- |
| `routineIntent` | `(routine: AnimatronicRoutine, clock: number) => AnimatronicIntent` | — | The self-control loop: gait, stance, lean, twist, reach, gaze, expression, breath and grip together, as a pure function of the clock. |
| `blendIntent` | `(a, b, t) => AnimatronicIntent` | — | Cross-fade two intents. Discrete fields — the gait, the grasp — take whichever side the fade is past halfway to; there is no halfway between a walk and a stand. |
| `solveAttention` | `(target: Vec2 | null, effort?: number) => Attention` | — | Split a look across the eyes (±30°), the neck (±34° yaw) and the waist (±22° twist), each taking only what the one before it could not reach. |
| `centreOfMass` | `(pose: SkeletonPose) => Vec3` | — | Winter’s segment fractions, each at its own segment’s centre rather than at a joint. |
| `supportPolygon` | `(pose, halfWidth?) => Vec2[]` | — | The convex hull of the footprints of the feet actually loaded, in the ground plane. A foot in swing contributes nothing. |
| `balanceOf` | `(pose, halfWidth?) => Balance` | — | The weight, its plumb line, the polygon, and the signed margin between them. Positive is inside. |
| `balanceRoll` | `(pose, effort?, halfWidth?) => number` | — | The roll about the support centroid that puts the plumb line back over it, clamped to what an animatronic’s waist has. |
| `reachArm` | `(arm, target, proportions?) => SkeletonArm` | — | Re-solve one arm to a target of its own, against the pose the skeleton returned — same shoulder, same bone lengths. The per-side override the shared reach target cannot express. |
| `solveAnimatronic` | `(options?: AnimatronicOptions) => AnimatronicBody` | — | The whole machine: the biped, the cage it breathes with, the face rig and neck, both hands, and where its weight is standing. |
| `ribCage` | `(spine: Vec3[], options?) => Rib[]` | — | Hoops hung off the thoracic vertebrae, drawn in the transverse plane. Breath opens them in depth about three times as much as in width. |

## Source

- `src/lib/robocn/animatronic.ts`
