Turn a geometric promise into a number
A holonomic constraint is a function of configuration that should remain zero:
For a particle restricted to a circle of radius :
The gradient is the constraint Jacobian . Differentiation gives velocity and acceleration conditions:
For the circle, , , and . The runnable test verifies against a finite difference of .
Constraint forces live along Jᵀ
Start from unconstrained dynamics and add an unknown constraint force:
Substitution into the acceleration constraint yields the Schur-complement system:
is whatever force magnitude makes the forbidden acceleration vanish. Ideal constraint forces do no work along valid velocity because .
Acceleration correctness does not erase position error
Numerical integration can leave even when each computed acceleration satisfies locally. The solver then evolves on the wrong nearby surface.
Baumgarte stabilization asks the residual to behave like a damped oscillator:
Projection instead moves the numerical state back onto the manifold after integration. For the circle:
Stabilization is force-like and gradual; projection is geometric and immediate. Both can inject or remove energy if tuned or applied carelessly.
Experiment 1: keep a particle on a circle
Compare four constraint treatments
Why does a mathematically correct multiplier still accumulate positional drift?

Failure modes: omit the curvature term, choose stabilization gains too large for the timestep, normalize a nearly zero position, or project position without removing radial velocity.
- Expected result
- The command exits successfully and reproduces the numerical or visual relationship described in this card.
- Failure modes
- Non-finite values, a reversed trend, a failed assertion, or a materially different plot means the assumptions, seed, timestep, build, or backend should be inspected before continuing.
A revolute joint is several scalar constraints
In 3D, a revolute joint keeps two anchor points coincident (three scalar rows) and aligns two axes (two independent rows). Rotation about the common axis remains free. A limit adds a unilateral row only when the measured angle crosses its bound.
LavenderSim solves velocity rows repeatedly with sequential impulses, integrates bodies, then performs two positional projection passes. Error-reduction bias turns anchor displacement into a corrective target velocity.
diagnostics = sim.constraint_data()
# columns:
# anchor xyz, anchor norm, angular error,
# limit violation, anchor relative speed, coordinate
worst_anchor = diagnostics[:, 3].max()Experiment 2: inspect the public diagnostics
Perturb a joint by a known amount
Does the engine report the same geometric residual we can calculate by hand?
The test translates a revolute child by metres without advancing time. The API reports exactly that anchor-error vector and norm within float32 tolerance.
The same eight-column buffer is exported from the shared C++ engine as sim_constraint_data_ptr, bound by native Python, and read by the WebAssembly browser API.
sync_render_data() derives diagnostics from authoritative poses and velocities. constraint_data() exposes a copy or zero-copy NumPy view.- Expected result
- The command exits successfully and reproduces the numerical or visual relationship described in this card.
- Failure modes
- Non-finite values, a reversed trend, a failed assertion, or a materially different plot means the assumptions, seed, timestep, build, or backend should be inspected before continuing.
Experiment 3: sweep timestep and iterations
Measure native revolute accuracy
Which numerical knobs reduce anchor and axis residuals?

LavenderSim internally caps native substeps at 1/240 s. A requested 1/120 s frame therefore becomes two substeps, which explains why its cells resemble 1/240 rather than behaving like one large integration step.
Failure modes: measure only final error and miss an early spike, compare frame dt without knowing internal substeps, or expect more velocity iterations to replace positional projection.
- Expected result
- The command exits successfully and reproduces the numerical or visual relationship described in this card.
- Failure modes
- Non-finite values, a reversed trend, a failed assertion, or a materially different plot means the assumptions, seed, timestep, build, or backend should be inspected before continuing.
Paw-check: diagnose the promise
- Derive the circle multiplier with a constant external force.
- Sweep Baumgarte and mark stable and unstable regions.
- Plot energy alongside residual for projection.
- Trigger a revolute limit and inspect column 5.
- Compare a spherical joint's zero angular residual with a fixed joint's orientation residual.
- Publish anchor-error vectors as Python-defined browser overlays.
What should I be able to say now?
A constraint is a residual and its Jacobian. Lagrange multipliers generate forces along forbidden directions, but acceleration-level correctness can still drift after numerical integration. Baumgarte feedback and geometric projection control that drift with different energy and tuning tradeoffs. A 3D joint contributes multiple scalar rows, and solver quality should be evaluated with public residuals rather than visual appearance alone.