FERRETGame engine over Babylon.js
Ferret

@ferret/physics-actuators

forces, impulses, torques and motors at points of bodies on a schedule: profiles over time, angle, phase or a sensor.

37 exports · source in packages/physics-actuators/src

Classes

Bindings class

class Bindings

Runs a list of bindings against an actuators capability and the services of a world; step is called once per fixed step by the capability.

constructor(private world: World, private target: BindingTarget)
list(): BindingDef[]
errors(): Array<{ name: string; error: string }>
set(def: BindingDef): void
remove(name: string): void
clear(): void
step(): voidonce per fixed step: poll the input actions, and write the actuators' numbers to the animation graphs

packages/physics-actuators/src/bindings.ts:110

Functions

actuators function

function actuators(): ActuatorsCapability

packages/physics-actuators/src/index.ts:188

bodyTarget function

function bodyTarget(host: PhysicsHost, b: Body): ForceTarget

The body the kernel owns as a target.

packages/physics-actuators/src/index.ts:139

compileProfile function

function compileProfile(spec: ProfileSpec | undefined): Profile

packages/physics-actuators/src/profiles.ts:46

motionPhysics function

function motionPhysics(act: ActuatorsCapability, opts: { seed?: number } = {}): MotionCapability

packages/physics-actuators/src/motion.ts:49

netActuators function

function netActuators(cap: ActuatorsCapability, net: NetLike, opts: NetActuatorOptions): NetActuators

packages/physics-actuators/src/net.ts:38

parseQuantity function

function parseQuantity(v: unknown, kind: 'angle' | 'speed'): number

"90deg", "0.5turn", "30rpm" and plain numbers (SI) read at load; unit is what a bare number means.

packages/physics-actuators/src/profiles.ts:151

registerActuatorKind function

function registerActuatorKind(kind: string, spec: ActuatorKindSpec): void

packages/physics-actuators/src/index.ts:32

validateActuator function

function validateActuator(d: unknown, path = 'actuator'): string[]

packages/physics-actuators/src/index.ts:153

validateBinding function

function validateBinding(d: unknown, path = 'binding'): string[]

packages/physics-actuators/src/bindings.ts:68

validateProfile function

function validateProfile(spec: unknown, path = 'profile'): string[]

Problems with a profile spec, as messages (empty when it is good); path prefixes them.

packages/physics-actuators/src/profiles.ts:110

vesselTarget function

function vesselTarget(v: { pos: Vec3; q: Quat; v: Vec3; w: Vec3; applyForce(f: Vec3, at?: Vec3): void; applyTorque(t: Vec3): void; applyImpulse(j: Vec3, at?: Vec3): void }): ForceTarget

A vessel (or anything with pos, q, v, w and the three load methods) as a target: an oar on a boat.

packages/physics-actuators/src/index.ts:149

wave function

function wave(shape: Shape, u: number, duty: number): number

The wave of a shape at a fraction u of its period (0..1) and the duty: 0..1 (sine is -1..1 over the whole period).

packages/physics-actuators/src/profiles.ts:36

Interfaces

ActuatorDef interface

interface ActuatorDef
name: string
node: stringthe node (entity) of the body it acts on, or a target added with addTarget (a vessel, a shaft)
kind: ActuatorKind
at?: Vec3the point in the body's frame (metres); default the centre of mass
point?: stringor the name of a child node whose origin is the point (an empty authored in Blender or UE)
dir?: Direction | Vec3force and impulse: the direction; a plain vector is in the body's frame
axis?: Direction | Vec3torque and motor: the axis, same frames
magnitude?: numberN for force, N·s per firing for impulse, N·m for torque
speed?: number | string | { rpm: number }motor: the held speed (rad/s, or "30rpm") scaled by the profile, its torque limit and gain (N·m per rad/s of error)
maxTorque?: number
gain?: number
mode?: SpinMode | SpinMode[]spin: one mode or several (switchable combines with either of the others; alone it is an unstoppable shaft with a switch)
rampUp?: numberspin: seconds to speed up from a stop and to slow down to one (instant when missing)
rampDown?: number
initialAngle?: number | stringspin: the angle at time 0 (rad, or "90deg")
stallTime?: numberspin jammable: a held motor (speed under 10 % of the target with the torque at its limit) for this long is a stall (default 0.5 s)
profile?: ProfileSpec
over?: { angle?: string; turns?: number; phase?: string; sensor?: string }
instances?: Array<{ offset?: number | string }>several copies of one definition run at an offset along what the profile runs over (cylinders, oars)
offset?: number | string
command?: numberthe run-time multiplier: a throttle, set by input, a lever, a zone, a program or a command
on?: booleanon at load (default true)

packages/physics-actuators/src/index.ts:37

ActuatorKindSpec interface

interface ActuatorKindSpec
validate?(d: ActuatorDef, path: string): string[]
force(c: KindContext): KindForce

packages/physics-actuators/src/index.ts:30

ActuatorsCapability interface

interface ActuatorsCapability extends Capability
readonly actuators: Map<string, ActuatorState>
set(def: ActuatorDef): void
remove(name: string): void
list(): ActuatorDef[]
on(name: string): void
off(name: string): void
fire(name: string): void
command(name: string, value: number): void
state(name?: string): ActuatorState | ActuatorState[]
addTarget(node: string, target: ForceTarget): voida body that is not a RigidBody (a vessel, a shaft) as a target for actuators naming node
removeTarget(node: string): void
addSensor(name: string, read: () => number): voida named number a profile can run over: over: { sensor }
addSpinSink(node: string, sink: SpinSink): voida drivetrain speed source as the target of spin actuators naming node: the gears behind it see real torques
bind(def: BindingDef): voidwhat drives the commands: input actions, interactables, zones and events, and what the actuators give back to an animation (see BindingDef)
unbind(name: string): void
bindings(): BindingDef[]
has(name: string): boolean
target(node: string): ForceTarget | nullthe body (or vessel, or shaft) that actuators naming node push; null when there is none
owns?: (def: ActuatorDef) => booleanover the net: false means another machine owns the body and this one does not act on it (set by netActuators)

packages/physics-actuators/src/index.ts:106

ActuatorState interface

interface ActuatorState
name: string
on: boolean
command: number
time: number
value: number
phase: number
force: Vec3
torque: Vec3
power: number
work: number
fired: number
done: boolean
error?: string
speed?: numberspin: the speed now (rad/s about the axis), the angle (rad, unwrapped), and whether it is stalled
angle?: number
stalled?: boolean
at?: Vec3where the force acts now (world), for the inspector's arrows

packages/physics-actuators/src/index.ts:86

BindingDef interface

interface BindingDef
name?: string
actuator: string
as?: BindMode
action?: stringthe sources: exactly one of action, interactable, zone, event (and animate alone for the way back)
interactable?: string
zone?: string
event?: string
match?: Record<string, unknown>event: the payload fields that must match; a field holding an entity matches its name
actor?: stringzone: only this entity (by name) or tag (tag:player) counts
value?: numberthe command while active (default 1) and at rest (default 0); axis multiplies the value read by value
rest?: number
component?: 'x' | 'y'axis: which component of a two-axis action (default x)
animate?: { entity: string; /** a parameter of the graph that follows a number of the actuator */ param?: string; from?: 'phase' | 'value' | 'power' | 'speed' | 'command' | 'work'; scale?: number; /** or a trigger of the graph fired when the actuator starts, stops, is done, strokes or stalls */ trigger?: string; on?: 'start' | 'stop' | 'done' | 'stroke' | 'stall'; }

packages/physics-actuators/src/bindings.ts:16

BindingTarget interface

interface BindingTarget

What bindings need from the actuators capability.

command(name: string, value: number): void
on(name: string): void
off(name: string): void
fire(name: string): void
state(name?: string): any
has(name: string): boolean

packages/physics-actuators/src/bindings.ts:47

Direction interface

interface Direction
frame?: Frame
v: Vec3

packages/physics-actuators/src/index.ts:35

ForceTarget interface

interface ForceTarget

What an actuator pushes: a rigid body, a vessel, anything with a pose and the three ways to apply a load.

position(): Vec3
orientation(): Quat
velocity(): Vec3
angularVelocity(): Vec3
applyForce(f: Vec3, worldPoint?: Vec3): void
applyTorque(t: Vec3): void
applyImpulse(j: Vec3, worldPoint?: Vec3): void

packages/physics-actuators/src/index.ts:76

KindContext interface

interface KindContext

A kind of actuator that another package supplies (blade comes from

def: ActuatorDef
host: PhysicsHost
self: ForceTarget
dt: number
at: Vec3the point (world) the force acts at and its velocity
pointVelocity: Vec3
value: numberprofile value × command for this instance
time: numberthe scene time and the profile position (for strokes that follow the phase)

packages/physics-actuators/src/index.ts:19

MotionCapability interface

interface MotionCapability extends Capability

Physics in the language. The motion capability owns a MotionRuntime, ticks it once per fixed step before the actuators act, and gives programs the words that touch the world:

  actions (last while their form does)  force  torque  motor  flow-ramp
  instants                              impulse  command  actuator-on/off  fire  flow-on/off/source/move  list  world
  sensors                               speed speed-along angular-speed position height tilt rpm angle in-angle in-zone in-medium flow-at
                                        apparent-wind wind-speed wind-dir power work stalled phase
  macro                                 (over-angle shaft (from a b [axis]) body...)

A program has a target (the node of a body, from motion.run { target } or (bind "Boat" ...)); a level-wide program (weather) has none and can use only the flow words.

readonly rt: MotionRuntime
addPoint(name: string, node: string): voida named point on a body for force and impulse: oarlock-left is the node Oarlock_L
run(program: string | Form | unknown, opts?: { target?: string; params?: Record<string, Value> }): Program
setSource(name: string, source: string | unknown[]): string[]add or replace a source file (definitions and programs); programs of the file that are not definitions start now, and (bind "Node" ...) gives them a target
removeSource(name: string): void
sources(): Array<{ name: string; source: string }>
targetOf(p: Program): string | null

packages/physics-actuators/src/motion.ts:16

NetActuatorOptions interface

interface NetActuatorOptions
owns?: (def: ActuatorDef) => booleandoes this machine own the body the actuator acts on (default: every body is ours)
now: () => numberthe shared clock in seconds (the same on all machines, as NetService's now)
delay?: numberseconds between a command and its effect (default 0.15, the net's own delay)

packages/physics-actuators/src/net.ts:14

NetActuators interface

interface NetActuators
command(name: string, value: number): voidthe commands of a player: sent to all with an effect time, applied here at the same time
on(name: string): void
off(name: string): void
fire(name: string): void
step(): voidcall every fixed step: applies the commands whose time has come
pending(): numberthe commands still waiting for their time
dispose(): void

packages/physics-actuators/src/net.ts:25

NetLike interface

interface NetLike

Actuators over the net. Duck-typed on NetService, so this package does not depend on the net package. Rules: a force, torque or motor acts only on the machine that owns the body (the others get the body from replication); a spin that is not jammable is a function of the shared clock and runs on every machine. A command from any player goes to everyone with an effect time now() + delay and is applied at that time on every machine, so a switchable spin switches at the same moment everywhere.

readonly id: string
send(name: string, data: unknown): void
on(name: string, fn: (data: any, from: string) => void): () => void

packages/physics-actuators/src/net.ts:9

Profile interface

interface Profile
value(x: number): numberthe value at x
done(x: number): booleanthe profile has ended for good at x (for, a finite pulse, a curve that does not loop)
pulses(x0: number, x1: number): numberhow many pulses fire in [x0, x1): only a pulse has any (an impulse actuator fires on them)
readonly pulsed: booleana profile made of pulses (an impulse actuator fires on each), as against a value that is on and off

packages/physics-actuators/src/profiles.ts:19

SpinSink interface

interface SpinSink

Something a spin can drive instead of a body: a drivetrain speed source (Drivetrain.speedSource).

setSpeed(w: number, ramp?: number): void

packages/physics-actuators/src/index.ts:96

Types

ActuatorKind type

type ActuatorKind = 'force' | 'impulse' | 'torque' | 'motor' | 'spin' | 'blade'

actuators. Data that says where a force acts on a body, what it is and how it runs in time: force, impulse, torque and motor, with profiles over time, the angle of a body, the phase of another actuator or a sensor value. Everything acts in the field phase, so it enters the same integration as gravity and drag.

packages/physics-actuators/src/index.ts:13

ActuatorOp type

type ActuatorOp = 'command' | 'on' | 'off' | 'fire'

packages/physics-actuators/src/net.ts:22

BindMode type

type BindMode = 'hold' | 'press' | 'toggle' | 'axis' | 'inside' | 'on' | 'off' | 'set'

Bindings: what drives an actuator's command without code, and what the actuator gives back to an animation. Four sources, one rule each; all of them end in the same few calls on the actuators capability.

  action        an input action: `hold` (command while down), `press` (one impulse or cycle), `toggle`, `axis` (the stick or trigger value)
  interactable  `interact:use` of an entity (a lever, a capstan, a wheel): `toggle` (default), `press`, `on`, `off`
  zone          `zone:enter` / `zone:exit` of a zone: `inside` (default; command while anyone, or the named actor, is inside)
  event         any event of the world with a payload filter (`machine:stall`, `anim:notify` ...): `on`, `off`, `toggle`, `press`, `set`

value is the command while active (default 1), rest the command otherwise (default 0). animate goes the other way: a number of the actuator (its phase, power ...) is written to a parameter of an entity's animation graph every step, or a trigger of the graph fires on an actuator event.

packages/physics-actuators/src/bindings.ts:15

Frame type

type Frame = 'body' | 'world' | string

packages/physics-actuators/src/index.ts:34

Interp type

type Interp = 'step' | 'linear' | 'smooth'

packages/physics-actuators/src/profiles.ts:7

KindForce type

type KindForce = Vec3 | { force: Vec3; at: Vec3 } | null

A force, or a force at another point than the actuator's (a blade at the end of an oar): the point is in the world.

packages/physics-actuators/src/index.ts:29

ProfileSpec type

type ProfileSpec = | 'const' | { const: number } | { for: { duration: number; inner?: ProfileSpec } } | { delay: { after: number; inner?: ProfileSpec } } | { periodic: { period: number; duty?: number; phase?: number; shape?: Shape } } | { pulse: { period: number; count?: number } } | { curve: { keys: Array<[number, number]>; interp?: Interp; loop?: boolean } } | { ramp: { time: number } }

packages/physics-actuators/src/profiles.ts:9

Shape type

type Shape = 'square' | 'sine' | 'half-sine' | 'triangle' | 'saw'

Profiles of the plan: a value in -1..1 over one variable x. By default x is the seconds since the actuator was switched on; an actuator may run its profile over the angle of a body (x = turns / turns, so one cycle is x = 1), the phase of another actuator (x = its cycles) or a sensor value. A profile is a pure function of x: the same x gives the same value, on every peer and after any number of steps.

packages/physics-actuators/src/profiles.ts:6

SpinMode type

type SpinMode = 'unstoppable' | 'jammable' | 'switchable'

packages/physics-actuators/src/index.ts:33