Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091export interface SpringConfig { stiffness: number; damping: number; mass: number;}
export const CELL: SpringConfig = { stiffness: 2080, damping: 68, mass: 0.45 };export const HOME: SpringConfig = { stiffness: 600, damping: 54, mass: 1 };export const VEIL: SpringConfig = { stiffness: 1040, damping: 68, mass: 0.8 };
const SAMPLE = 0.005;
const solve = (config: SpringConfig, x0: number, v0: number): ((t: number) => number) => { const omega = Math.sqrt(config.stiffness / config.mass); const zeta = config.damping / (2 * Math.sqrt(config.stiffness * config.mass));
if (Math.abs(zeta - 1) < 1e-6) return (t) => Math.exp(-omega * t) * (x0 + (v0 + omega * x0) * t);
if (zeta < 1) { const wd = omega * Math.sqrt(1 - zeta * zeta); return (t) => Math.exp(-zeta * omega * t) * (x0 * Math.cos(wd * t) + ((v0 + zeta * omega * x0) / wd) * Math.sin(wd * t)); }
const spread = omega * Math.sqrt(zeta * zeta - 1); const fast = -zeta * omega + spread; const slow = -zeta * omega - spread; const a = (v0 - slow * x0) / (fast - slow); const b = x0 - a; return (t) => a * Math.exp(fast * t) + b * Math.exp(slow * t);};
export class Motion { current = $state(0); #velocity = 0; #frame: number | null = null;
constructor(initial: number) { this.current = initial; }
stop(): void { if (this.#frame === null) return; cancelAnimationFrame(this.#frame); this.#frame = null; }
set(value: number): void { this.stop(); this.#velocity = 0; this.current = value; }
animate(target: number, config: SpringConfig, done?: () => void): void { this.stop();
const x0 = this.current - target; if (x0 === 0 && this.#velocity === 0) { done?.(); return; }
const at = solve(config, x0, this.#velocity); const restDelta = Math.max(Math.abs(x0), 1e-3) * 1e-3; const restSpeed = restDelta * 30; const start = performance.now();
const step = (now: number): void => { const t = (now - start) / 1000; const x = at(t); const velocity = (at(t + SAMPLE) - x) / SAMPLE;
if (Math.abs(x) < restDelta && Math.abs(velocity) < restSpeed) { this.#frame = null; this.#velocity = 0; this.current = target; done?.(); return; }
this.#velocity = velocity; this.current = target + x; this.#frame = requestAnimationFrame(step); };
this.#frame = requestAnimationFrame(step); }}