---
name: ferret-motion
description: Use for writing or running programs in Ferret's motion language: timed sequences, parallel and racing motions, state machines, events, defmotion/defn, with a step budget, seeded random and snapshots; text and JSON forms.
---

# Motion language

## When to use
Anything that has to happen over time without a hand-written state machine: a stroke (force for 0.4 s while another thing waits), a door cycle, a patrol pause, a gust pattern.

## Steps
1. `new MotionRuntime({ seed, budget })`; add words with `define(name, fn)` (instant) and `action(name, { start })` (a hold: its arguments are read every step).
2. Write programs as text (`(seq (wait 0.4s) (emit "done"))`) or as the JSON tree (symbols are strings, literals `{ "s": "..." }`); `rt.load(text, file)` checks them.
3. `rt.run(mod, form, params)` and `rt.tick(dt)` every fixed step; feed with `p.set`, `p.trigger`, `rt.deliver`.
4. Time forms: `wait`, `wait-until`, `wait-event`; structure: `seq par race for while guard repeat loop on states`; units `30rpm 90deg 0.4s` fold at read.

## Check afterwards
`p.state()` shows what each thread waits for; `motion:error` carries file, line and form; `p.snapshot()` then `rt.restore(...)` continues the same run.

## What usually goes wrong
- A loop without `wait` hits the budget: add a wait or an event.
- A `defn` or lambda cannot wait or hold: use `defmotion` for anything that lasts.
- An action inside a calculation (`(+ 1 (force …))`) is an error: actions are statements.
- `states` with `:until` stays until the condition; without it the state ends when its body does.
- `(param x)` takes the name, not a value; an unbound symbol is just a name.

## Files

- `reference/motion.md` — physics/motion.md
- `reference/api-motion.md` — every export of `@ferret/motion` with signature and doc comment
