Skip to content

Math Helpers

The SDK ships small math namespaces — v2 / v3 (vectors), col (colors), and scalar (numbers) — that operate on the same canonical types your components use ({x, y} vectors, {r, g, b, a} colors in 0..1). Every helper is pure: it returns a new value and never mutates its inputs. For what the numbers mean — world units, design pixels, physics meters, and the Y-up coordinate system — see Transforms, Units & Coordinates.

v2 covers 2D vector math; v3 mirrors the core operations for 3D.

import { v2 } from 'esengine';
// Move a point by a velocity over dt.
const next = v2.add(pos, v2.scale(vel, dt));
// Aim: unit direction from pos to target, then a step of length speed*dt.
const dir = v2.normalize(v2.sub(target, pos));
const step = v2.scale(dir, speed * dt);
v2.dist(pos, target); // distance (for a range check)
v2.fromAngle(Math.PI / 2, 10); // { x: 0, y: 10 }
v2.rotate({ x: 1, y: 0 }, Math.PI); // { x: -1, y: 0 }
  • Arithmetic: add / sub / scale / mul (component-wise) / neg.
  • Products & length: dot, cross, len / len2, dist / dist2.
  • Direction: normalize, angle, fromAngle, rotate, perp (90° CCW).
  • Also: create, clone, lerp, equals (epsilon compare).

col builds and blends colors on the {r, g, b, a} (0..1) convention — white is {1, 1, 1, 1}. The namespace is col because the bare color name is already an SDK export.

import { col } from 'esengine';
col.rgb(1, 0, 0); // opaque red (0..1 channels)
col.from255(255, 128, 0); // from 0..255 channels
col.fromHex('#ff8800'); // #rgb / #rgba / #rrggbb / #rrggbbaa
col.lerp(red, blue, 0.5); // blend halfway (e.g. a damage flash)
col.withAlpha(white, 0.3); // fade
col.multiply(base, tint); // per-channel tint
  • Build: create, rgb, from255, fromHex (throws on malformed input), clone.
  • Blend: lerp, withAlpha, multiply, scaleRgb; serialize with toHex.

scalar collects the common number helpers for gameplay and tuning:

import { scalar } from 'esengine';
scalar.clamp01(hp / maxHp); // 0..1
scalar.lerp(a, b, 0.25); // interpolate
scalar.remap(x, 0, 100, 0, 1); // rescale one range onto another
scalar.smoothstep(0, 1, t); // eased 0..1 ramp
scalar.deg2rad(90); // degrees -> radians

Also: clamp, inverseLerp, rad2deg, approximately, mod, sign.

Transform.rotation is a quaternion; in 2D you only ever rotate about Z, and a handful of exports cover the angle ↔ quaternion round trip:

import { quat, quaternionToAngle2D, facingFromQuat, normalizeAngle } from 'esengine';
// Angle -> quaternion. NOTE: the factory takes w FIRST — quat(w, x, y, z).
const a = Math.PI / 3;
const rot = quat(Math.cos(a / 2), 0, 0, Math.sin(a / 2));
// Quaternion -> angle (radians), from the z/w components.
const facing = quaternionToAngle2D(rot.z, rot.w); // Math.PI / 3
facingFromQuat(rot.z, rot.w); // same math, the AI/perception spelling
// Wrap to (-π, π] — the shortest signed turn from facing toward a target angle.
const delta = normalizeAngle(targetAngle - facing);
Helper Description
quat(w?, x?, y?, z?) Quaternion factory; no arguments gives the identity {w: 1, x: 0, y: 0, z: 0}.
quaternionToAngle2D(rz, rw) Z angle in radians from a quaternion’s z/w (2 * atan2(z, w)).
facingFromQuat(z, w) Identical math under its AI/perception name.
normalizeAngle(a) Wrap any angle to (-π, π] for shortest-turn comparisons.

For direction vectors instead of rotations, stay in v2: fromAngle / angle / rotate. A full worked example (turrets facing the cursor) is in Transforms, Units & Coordinates.

  • Transforms, Units & Coordinates — what the numbers mean: world units = design pixels, physics meters, Y-up, and rotating entities with quaternions.
  • Physics — the meter-based unit surface these helpers feed into.