Mathf

Scalar math helpers — the numbers-only functions you reach for inside a frame loop. Mathf is a plain object of functions and constants; nothing to construct. Vector, quaternion, and matrix math live on Vec2 / Vec3, Quat, and Mat4, not here.

At a glance

TypeScript
class Chase extends Aspect<'chase'> {
  target?: Node
  follow = Mathf.smoothDamp([0, 0, 0], 0.15)          // stateful damper: one per aspect, never per frame
  onAttach() { this.follow.setValue([...this.node.position]) }   // start from where the node is
  update(dt: number) {
    if (this.target) this.node.position = this.follow([...this.target.position], dt)
  }
}

const scene = new Scene()
const hero = Mesh.sphere({ material: Material.lit({ color: '#4f7cff' }), position: [3, 0, -5] })
const buddy = Mesh.sphere({ material: Material.lit({ color: '#e33' }) }).aspect(Chase, { target: hero })
scene.add(hero, buddy)
scene.open()

const hp = Mathf.clamp(120, 0, 100)                            // 100
const fill = Mathf.lerp(0, 200, Mathf.inverseLerp(0, 50, 20))  // 80: 20 of 50 → 40 % of 200
const angle = Mathf.repeat(370, 360)                           // 10
const zoom = Mathf.damp(1, 2, 10, 1 / 60)                      // one 60 Hz frame of a frame-rate-independent ease

Constants & angle conversion

TypeScript
Mathf.PI            // Math.PI
Mathf.TAU           // 2π — a full turn in radians
Mathf.EPSILON       // 1e-6
Mathf.DEG2RAD       // π / 180
Mathf.RAD2DEG       // 180 / π
Mathf.deg2rad(deg): number
Mathf.rad2deg(rad): number
Note

DEG2RAD / RAD2DEG also exist as bare compile-time globals (no Mathf. prefix) — see conventions for which APIs take degrees vs radians.

Ranges & interpolation

TypeScript
Mathf.clamp(v, min, max): number
Mathf.clamp01(v): number                              // clamp into [0, 1]
Mathf.lerp(a, b, t): number                           // a + (b − a)·t
Mathf.inverseLerp(a, b, v): number                    // where v sits in [a, b] as 0..1 (0 if a === b)
Mathf.remap(v, inMin, inMax, outMin, outMax): number  // map v from one range onto another
Mathf.sign(x): number                                 // -1, 0, or 1 (Math.sign)
Mathf.repeat(t, length): number                       // loop t into [0, length)
Mathf.pingPong(t, length): number                     // bounce t back and forth in [0, length]

Easing toward a value

TypeScript
Mathf.moveTowards(a, b, maxDelta): number         // step linearly, never overshoots
Mathf.damp(a, b, lambda, dt): number              // exponential approach, frame-rate independent

damp is the frame-rate-safe replacement for a = lerp(a, b, 0.1) every frame: lambda is the rate (higher = snappier; good defaults 5..15), dt is the frame's seconds (the dt of update(dt)). It is stateless — pass last frame's value back in.

smoothDamp — critically-damped follow (Unity SmoothDamp)

TypeScript
Mathf.smoothDamp(initial: number,   smoothTime, maxSpeed?): Damper<number>
Mathf.smoothDamp(initial: number[], smoothTime, maxSpeed?): Damper<number[]>  // vec2/vec3 arrays

const damper = Mathf.smoothDamp([0, 0], 0.15)
damper(target, dt)          // call every frame → the new eased value
damper.setValue(v)          // snap internal state (teleport) — kills the rubber-band

Returns a stateful damper that tracks its own velocity, so motion eases in and out without overshoot. smoothTime is roughly the settle time in seconds; maxSpeed (default Infinity) caps the speed — for arrays the cap applies to the vector magnitude, not per component. The array form returns a new array every call. Chase in At a glance is the usual shape: the damper is a field of the aspect, called from update(dt).

Note

create the damper once — a field, not a local of update. A fresh damper every frame resets its velocity and defeats the smoothing. On teleports call setValue so the follower doesn't chase from the old spot.

Random

TypeScript
Mathf.random(min?, max?): number      // float in [min, max); default 0..1
Mathf.randomInt(min, max): number     // integer, INCLUSIVE of both ends

See also

  • Vec2 & Vec3 — vector lerp / distance / normalize live on the vector types
  • Conventions — dt is seconds; degrees-vs-radians rules