# Animatronic

The whole animatronic: a solved biped under a breathing cage, an expressive head on top of it, hands on the end of it, and a centre of mass it keeps over the ground its 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-robot.json
```

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

## Notes

- Nothing in the drawing branches on a routine name. A routine resolves to an AnimatronicIntent — the whole body’s demand at an instant — and every field of it is also a prop, which is what makes the machine posable rather than merely animated. Supplying one prop leaves the routine driving the rest.
- Looking at something is a posture, not a number. solveAttention spends the eyes first (±30°), then the neck (±34° yaw), then the waist (±22° twist), each taking only what the one before it could not reach — so a small look is pure eyes and only a look over the shoulder costs a twist.
- The balance is measured, not asserted. centreOfMass sums Winter’s segment fractions at each segment’s own centre; supportPolygon is the convex hull of the footprints of the feet actually loaded, so it narrows to a toe at toe-off and vanishes in a run’s flight phase; the margin is the signed distance between the two. The correction is a rigid roll about the support centroid, so no bone changes length and the planted foot stays where it was.
- There is no dynamics. Nothing integrates a mass, computes a ground reaction or decides whether the machine falls — it corrects its posture toward its support polygon and reports the margin it has left. An unstable pose is drawn unstable and says so rather than being quietly fixed.
- The legs, feet and hands are the chassis robot-leg, robot-foot and robot-hand draw, on the same solvers and the same proportions: two strut actuators per leg whose stroke is a consequence of the pose, a sole turned about the ankle with a toe plate hinged at the ball, and a palm with a knuckle and a pad per digit. Nothing is redrawn per machine, so the four cannot drift apart.
- Solved: the legs and their rolling feet, the spine, the ribs, the arms, both hands, the skull’s exact silhouette, every face channel, and the balance. Illustrated: the shell panels, the chest core, and the ear and hip cans — they are drawn on the solved frame and drive nothing.
- One geometry, four projections. The head is the same ellipsoid-and-chart construction as the animatronic face, carried by the column’s lean, the shoulders’ twist and the balance roll, so the far eye turns away on its own at every angle.

## Usage

```tsx
import { AnimatronicRobot } from "@/components/ui/animatronic-robot"

// Runs itself, and watches the pointer anywhere on the page.
<AnimatronicRobot behavior="converse" />

// Every channel of the routine is also a prop, and a prop wins.
<AnimatronicRobot expression="doubt" speech={0.4} grip={0.8} grasp="power" lean={12} />

// Drive what it is looking at, and let it reach for that too.
<AnimatronicRobot attend={{ x: 0.6, y: 0.2 }} follow showBalance />

// The frame under the panels, walking.
<AnimatronicRobot chassis="frame" gait="walk" gaitPhase={0.25} />
```

## Props

| name | type | default | description |
| --- | --- | --- | --- |
| `view` | `"plan" | "front" | "profile" | "iso"` | `"front"` | Where the camera stands. One machine, four projections: straight down, straight on, side elevation, or three-quarter from above. |
| `behavior` | `"idle" | "greet" | "present" | "inspect" | "converse" | "walk" | "static"` | `"idle"` | The routine it runs with nobody driving it. A routine returns the whole body’s intent at an instant — gait, stance, lean, twist, reach, gaze, expression, breath and grip together — not a single number. |
| `chassis` | `"shell" | "frame"` | `"shell"` | Panels over the frame, or the frame on its own. Geometry is identical either way; only the shrouds come off. |
| `attend` | `Vec2 | null` | — | What it is looking at, −1..1 on both axes: x to its left on screen, y up. Supplying it stops the pointer tracking. |
| `onAttendChange` | `(point: Vec2 | null) => void` | — | Fires while it is dragged or keyed, so interaction works in controlled mode too. Null means it has been handed back to the routine. |
| `track` | `boolean` | `true` | Follow the pointer anywhere on the page. |
| `follow` | `boolean` | `true` | Reach for what it is attending to, as well as looking at it. |
| `interactive` | `boolean` | `true` | Drag across it to hold its attention, or focus it and use the arrow keys. Home centres the look; End hands it back to the routine. |
| `balance` | `boolean` | `true` | Roll the machine rigidly about its support centroid to bring its plumb line back inside the polygon its feet hold. A roll that does not improve the margin is not taken. |
| `showBalance` | `boolean` | `false` | Draw the support polygon, the centre of mass and the plumb line between them, and shade each pad of each sole by what it is carrying. |
| `showLoad` | `boolean` | — | The sole pads on their own. Follows showBalance unless you set it. |
| `gait / gaitPhase` | `"stand" | "walk" | "run" | "march" / number` | — | Footfall pattern and cycle fraction. Supplying the phase pins it. |
| `stance / stride / lift` | `number` | — | Hip height 0 crouched to 1 tall, stride length, and foot clearance. |
| `lean / twist` | `number` | — | Whole-column pitch and shoulders-against-pelvis, in degrees. |
| `neckYaw / neckPitch / neckRoll` | `number` | — | Head angles in degrees, clamped to ±34, ±22, ±20, on top of whatever the column already carries it through. |
| `look` | `Vec2 | null` | — | Pupil aim in −1..1 on both axes, over whatever the attention cascade gave the eyes. |
| `reach` | `Vec3 | null` | — | A point both hands solve to, in the body frame — right for carrying something. Null takes them out of a reach and back into the swing. |
| `reachLeft / reachRight` | `Vec3 | null` | — | A point one hand solves to, winning over reach for that side. This is what a wave is: the skeleton solver only takes a target both arms share, so without a per-side target every reaching pose comes out with the hands clasped. |
| `expression` | `"neutral" | "joy" | "surprise" | "sorrow" | "anger" | "fear" | "disgust" | "doubt" | "sleep" | FaceChannels` | — | The face rig’s shape, by name or as a channel vector you blended yourself. |
| `intensity / blink / speech` | `number` | — | How far the rig drives there, lid closure, and speech level — each 0–1, each composing rather than replacing. |
| `channels` | `Partial<FaceChannels>` | — | Drive individual face servos. Applied last, so these win outright. |
| `breath` | `number` | — | Chest expansion, 0 emptied to 1 filled. Omit and it breathes on its own. |
| `grasp / grip` | `HandGrasp / number` | — | What both hands are doing, and how far shut. |
| `effort` | `number` | `1` | How willingly the neck and waist join a look, and how hard the machine works to stay over its feet. At 0 a look stays in the eyes. |
| `ribs` | `number` | `7` | Hoops in the cage, clamped to 3–12. |
| `proportions` | `Partial<SkeletonProportions>` | — | Override any bone length. The default is the family’s, with an animatronic’s larger skull. |
| `showGround / showReadout` | `boolean` | `true` | Contact shadow, and the routine / look / margin line under the drawing. |
| `speed` | `number` | `0.5` | Routine cycles per second. |
| `animate` | `boolean` | `true` | Off parks the machine at phase and stops rendering. A reduced-motion preference does the same. |
| `paused` | `boolean` | `false` | Freeze where it stands. |
| `phase` | `number` | `0` | Seconds of offset, so a row of machines breaks step. |
| `label` | `string` | — | Caption under the machine. |
| `variant` | `"solid" | "outline" | "blueprint" | "wire"` | `"solid"` | How the machine is painted. Geometry never changes between variants. |
| `size` | `"xs" | "sm" | "md" | "lg" | "xl" | number` | `"md"` | Rendered width in pixels, or a step on the scale. |
| `color` | `string` | `var(--robot-shell)` | Body panels — the colour the machine reads as. |
| `accent` | `string` | `var(--robot-accent)` | Status colour: tip light, live tool, readouts. |
| `metal` | `string` | `var(--robot-metal)` | Bare machined parts: collars, bolts, tool bodies. |
| `dark` | `string` | `var(--robot-dark)` | Cast joints, base, shadow side. |
| `palette` | `Partial<RobotPalette>` | — | Override any subset of roles at once, including glow and grid. |

## Source

- `src/components/ui/animatronic-robot.tsx`
