# Gait kinematics

The footfall solver behind the horse, the pegasus and the camel: six named gaits as real touchdown sequences, a beat count derived from them rather than declared, the support pattern, and the share of the body's weight on every grounded foot — plus the three things that one number drives.

> 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/gait-kinematics.json
```

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

## Notes

- The beat count is read off the touchdown instants rather than declared, which is what makes walk-versus-trot a fact about the numbers. The pace and the trot both come out at two, on different diagonals — proof that the count alone does not name a gait.
- The load is a static weight distribution — the forehand's share divided among whichever feet are down — and not a dynamics solve. No acceleration, no ground reaction, no centre of pressure. It solves no legs either: the components own their own limb chains and read the load off this.
- fetlockSink, padSpread and footSinkage are all consequences of that one load number, which is why they live here rather than in the machines that spend them: a sprung joint, a foot that opens, and a ground that gives are the same arithmetic read three ways.

## Usage

```tsx
import { solveGait, fetlockSink, padSpread, footSinkage } from "@/lib/robocn/gait"

const pose = solveGait({ gait: "canter", phase: 0.4, lead: "left" })
pose.beats     // 3 — counted from the footfalls, not declared
pose.support   // how many feet are down right now
pose.legs      // id, fore, touchdown, contact, load, foot

// Three things the same load number drives.
fetlockSink(leg.load)                  // degrees the sprung pastern drops
padSpread(leg.load)                    // how far a splay pad opens
footSinkage(leg.load, 0.8)             // how deep it goes into soft ground
```

## API

| name | type | default | description |
| --- | --- | --- | --- |
| `solveGait` | `(options?: GaitOptions) => GaitPose` | — | One instant of a gait: who is down, when each limb landed, where its foot is, and what share of the standing weight it carries. |
| `GaitOptions` | `{ gait?, phase?, lead?, duty?, stride?, lift? }` | — | Gait is halt, walk, trot, pace, canter or gallop; lead is the foreleg that lands last and only the canter and the gallop have one; duty overrides the gait's own; stride and lift are normalized foot travel and swing height. |
| `GaitLeg` | `{ id, side, fore, touchdown, t, contact, load, foot: Vec2 }` | — | touchdown is where in the stride this limb lands, t is the time since it did, and load is its share of the body — 0 in the air, and summing to exactly 1 across every grounded limb. |
| `GaitPose` | `{ gait, beats, duty, lead, leadLeg, support, airborne, forehand, legs }` | — | beats is the number of distinct footfall instants, counted from the touchdowns; support is how many feet are down; airborne is the suspension. |
| `gaitBeats` | `(gait: EquineGait) => number` | — | The beat count on its own: 4 for a walk, 2 for a trot and a pace, 3 for a canter, 4 for a gallop, 0 for a halt. |
| `fetlockSink` | `(load: number) => number` | — | The sprung pastern: how far the fetlock drops, in degrees, under a load. A passive joint whose angle is an output of the gait. |
| `padSpread` | `(load: number) => number` | — | A splay pad opening under load, as a multiple of its own unloaded width. The same primitive as fetlockSink off the same number, with a different consequence. |
| `footSinkage` | `(load: number, ground: number, spread?: number) => number` | — | How far a foot goes into the ground, in world units. Pressure is load over contact area and ground is how soft it is, so a pad that opens under load sinks less than one that does not. A proportional rule, not a soil model. |
| `gaitLimits` | `{ reach: 16, clearance: 11, fetlock: 30, spread: 0.55, sinkage: 9 }` | — | What stride, lift, a full load, a fully opened pad and fully soft ground mean in world units and degrees. |

## Source

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