/** Scalar helpers shared by the sim and the renderer. No three.js here. */ export const clamp = (x, a, b) => (x < a ? a : x > b ? b : x); export const lerp = (a, b, t) => a + (b - a) * t; export const smooth = (t) => t * t * (3 - 2 * t); /** Wrap to (-PI, PI]. */ export function wrapAngle(a) { let x = a; while (x > Math.PI) x -= Math.PI * 2; while (x <= -Math.PI) x += Math.PI * 2; return x; } /** Shortest-arc interpolation between two headings. */ export function lerpAngle(a, b, t) { return a + wrapAngle(b - a) * t; } /** Move `from` toward `to` by at most `step`, without overshooting. */ export function approach(from, to, step) { return Math.abs(to - from) <= step ? to : from + Math.sign(to - from) * step; } /** Same, on the circle. */ export function approachAngle(from, to, step) { const d = wrapAngle(to - from); return Math.abs(d) <= step ? wrapAngle(to) : wrapAngle(from + Math.sign(d) * step); }