Install
Download cranberry-forge-spring-0.1.0.tgz from the Spring page, then install the local archive:
npm install ./cranberry-forge-spring-0.1.0.tgzThe archive is an ES module with TypeScript declarations. You can also copy index.js into your project and import that file directly. This repository does not imply that the package is published to the public npm registry.
import { Spring } from "@cranberry-forge/spring";
const recoil = new Spring({ frequency: 3, dampingRatio: 0.65 });
function onAction() {
recoil.impulse(8); // velocity units per second
}
function update(dt) {
mesh.position.y = restY + recoil.step(dt); // dt in seconds
}What the two controls mean
frequency is the undamped natural frequency in hertz, not a duration. dampingRatio is dimensionless:
| Ratio | Motion |
|---|---|
0 |
Undamped; oscillation continues. |
Between 0 and 1 |
Underdamped; decaying oscillation. |
1 |
Critical damping. A target change from rest approaches without overshoot. |
Above 1 |
Overdamped; two decaying modes, without sustained oscillation. |
An existing velocity can carry even a critically damped or overdamped spring across the target. Spring preserves that velocity. It does not silently clamp crossings or snap at a hidden rest threshold.
The implementation evaluates the closed-form solution of x″ + 2ζω x′ + ω²(x − target) = 0, with ω = 2π × frequency. These are the standard damped-oscillator regimes described in MIT OpenCourseWare’s damped harmonic oscillator lesson.
Guarantees and boundaries
- For a constant target and unchanged settings, one step and several steps totaling the same time agree up to floating-point rounding. If target changes or impulses happen between steps, split at those event times for equivalent results.
- Under-, critical-, and overdamping use analytic formulas. Near-critical damping uses stable
sinc/expm1forms; overdamping avoids overflowingsinhintermediates. - Scalar and XYZ operations validate finite inputs. Failed configuration, impulses, or numerical-limit checks preserve the previous state. XYZ stepping commits all three axes together.
- Getters return detached data. The object supplied to the pure
stepSpringfunction is not mutated. - Time steps are
0..60seconds; frequency is0.01..100Hz; ratio is0..10. Each scalar value, target, velocity, and impulse component must have magnitude at most1e12. Computed states exceeding that limit throw rather than clip. - Spring owns no resources to dispose. Stop calling
stepto pause. Callsnap()when your product wants reduced motion, and stop applying decorative impulses.
Read the API reference or follow the integration tutorial. The repository’s nine focused tests cover analytic reference values, energy, timestep equivalence, momentum, XYZ parity, resets, and atomic rejection.
Optional local HTTP endpoint
The Cranberry Forge repository server also exposes POST /api/v1/spring/step for explicit numeric requests:
{
"state": { "value": 0, "target": 1, "velocity": 0 },
"dt": 0.016,
"options": { "frequency": 2, "dampingRatio": 0.65 }
}It returns { "state": { "value": ..., "velocity": ..., "target": ... } }. This optional repository service is separate from the standalone package; ordinary animation should step locally in its own frame loop. See the repository’s HTTP API documentation.
Original implementation and Jellyworks procedural toys: MIT. No third-party animation code is bundled.