# Hand

Five digits on a thumb with a real saddle joint. Fingers abduct about the palm normal, the thumb opposes across the palm, and the gap between the two pads is a number the solver produces rather than a shape the drawing implies.

> 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/robot-hand.json
```

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

## Notes

- The thumb has a real saddle. Two driven angles place the metacarpal — swung across the palm and lifted out of it — and the flexion plane rolls about that metacarpal, which is the rotation opposition really is. That is why tripod and lateral exist at all.
- Each finger is a three-link chain solved forward in a plane abducted about the palm normal, so spreading the hand is a pose rather than a second drawing, and a closing hand foreshortens instead of shrinking.
- The pinch gap is reported, never asserted. It is the distance between two pads, in world units; the hand is not holding anything and there is no contact, no grasp planning and no force anywhere in it.
- A curled hand in front elevation foreshortens into stubs, because that is what a hand pointed at a camera does. Use iso or profile to read a grip.

## Usage

```tsx
import { RobotHand } from "@/components/ui/robot-hand"

<RobotHand grasp="pinch" view="iso" />

// Controlled, posed digit by digit, or a hand you can close.
<RobotHand curl={0.8} grasp="power" side="left" spread={-0.4} />
<RobotHand digits={[0.2, 0, 1, 1, 1]} wristPitch={-25} />
<RobotHand interactive onCurlChange={setCurl} onGraspChange={setGrasp} />
```

## Props

| name | type | default | description |
| --- | --- | --- | --- |
| `view` | `"plan" | "front" | "profile" | "iso"` | `"front"` | Where the camera stands. One hand, four projections: straight down, straight on, side elevation, or three-quarter from above. |
| `curl` | `number` | — | Controlled closure, 0 open to 1 shut, scaling the grasp. Omit it and the hand runs behavior. |
| `grasp` | `"open" | "pinch" | "tripod" | "power" | "hook" | "point" | "lateral"` | `"power"` | Which grip the digits close into. Each names a per-digit closure, a thumb opposition and a finger fan that curl then scales. |
| `digits` | `(number | null)[]` | — | Per-digit closure, thumb first, overriding the grasp for any entry that is a finite number. A hand posed exactly rather than by name. |
| `spread` | `number` | — | Finger fan, -1 pressed together to 1 splayed. Defaults to the grasp's own. |
| `opposition` | `number` | — | Thumb across the palm, 0 alongside to 1 opposed. Defaults to the grasp's own. |
| `side` | `"left" | "right"` | `"right"` | A hand is handed. Left is right mirrored in x, not a second drawing. |
| `wristPitch` | `number` | `0` | Wrist flexion in degrees, positive toward the palm. Applied after the digits solve, so it never changes a grasp. |
| `wristYaw` | `number` | `0` | Wrist deviation in degrees, positive toward the thumb. |
| `behavior` | `"grip" | "wave" | "static"` | `"grip"` | Close onto the grip and open again, or ripple the digits one after another. |
| `speed` | `number` | `0.3` | Grips per second, or waves 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. |
| `interactive` | `boolean` | `false` | Drag up and down to close the hand; a click, Enter or Space steps to the next grasp. |
| `onCurlChange` | `(curl: number) => void` | — | Closure, 0–1, throughout a drag or a key press. |
| `onGraspChange` | `(grasp: HandGrasp) => void` | — | The grasp stepped to by a click or a key. |
| `showWrist` | `boolean` | `true` | Draw the wrist collar and cuff below the palm. |
| `showPinch` | `boolean` | `true` | Draw the caliper between the thumb pad and the index pad. |
| `label` | `string` | — | Caption below the grasp readout. |
| `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/robot-hand.tsx`
