FERRETGame engine over Babylon.js
Ferret

Motion language

Skill ferret-motion · download all skills · SKILL.md

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#