OrgPad logo

Physics-based animations in OrgPad

Created by Pavel Klavík

A high-level explanation of how physics-based motion makes a spatial canvas feel continuous, responsive, and understandable.

#animation, #orgpad, #physics

Physics-based animations in OrgPad

Overdamped example

For c=3 and k=2, the roots are

s_1=-1,\qquad s_2=-2.

So the solution is x(t) = Ae^{-t} + Be^{-2t} for some A,B \in \mathbb R.

For the initial conditions x(0)=1 and x'(0)=1, we find A and B by solving this linear system

\left[\begin{array}{cc|c}1 & 1 & 1 \\ -1 & -2 & 1\end{array}\right]

This gives A=3 and B=-2, so the full spring trajectory is

x(t) = 3e^{-t} - 2e^{-2t}.

Finding a particular solution

For fixed parameters c and k, we get a family of possible solutions, one for each choice of A,B \in \mathbb R.

A particular solution is obtained by computing A and B from the initial position x(0) and velocity x'(0). This requires solving a 2 \times 2 system of linear equations.

Extending ongoing animations

This lets an animation continue smoothly when its target changes mid-motion. The engine takes the current position and velocity, and uses them as the starting point for the next spring animation.

Overdamped

When \boldsymbol{c^2-4k > 0}:

Usually calm, monotone movement with no repeated overshoot. It is useful when an animation should feel stable and restrained.

s_{1,2}=\frac{-c\pm\sqrt{c^2-4k}}{2}

\begin{aligned}x(t)&=Ae^{s_1t}+Be^{s_2t}\\x'(t)&=As_1e^{s_1t}+Bs_2e^{s_2t}\end{aligned}

spring-overdamped-1000-orgpad-palette

Critically damped

When \boldsymbol{c^2-4k = 0}:

The fastest calm movement that settles without repeated wobbling. It is useful when the interface should feel direct but not jumpy.

\begin{aligned}x(t)&=(A+Bt)e^{-ct/2}\\x'(t)&=\bigl(B-c/2 \cdot (A+Bt)\bigr)e^{-ct/2}\end{aligned}

spring-critical-1000-orgpad-palette

Animations using springs

Spring animations make OrgPad feel natural. Objects move in ways we recognize from everyday life. The animation stays out of the way and helps you follow what changed in the document.

OrgPad uses a custom animation library with roughly 5,000 lines of ClojureScript to orchestrate detailed animations throughout the app.

Equation of spring motion

The differential equation for spring motion is:

x'' + c x' + kx = 0.

Depending on the value of c^2-4k, the solution takes one of three forms.

Underdamped

When \boldsymbol{c^2-4k < 0}:

Lively movement that can cross the target repeatedly before settling. Used sparingly in the OrgPad interface.

\delta=\frac{\sqrt{4k-c^2}}{2}

\begin{aligned}x(t)&=e^{-ct/2}\bigl(A\cos(\delta t)+B\sin(\delta t)\bigr)\\x'(t)&=e^{-ct/2}\bigl((B\delta-cA / 2)\cos(\delta t)-(A\delta+cB/2)\sin(\delta t)\bigr)\end{aligned}

spring-underdamped-1000-orgpad-palette

Rendering like a game engine

OrgPad’s animation layer works more like a small game engine than a traditional document redraw system. While objects move, it runs a fast render loop: each frame advances the animation state, updates what's visible, and renders the result.

During each frame, OrgPad:

  1. Computes the current spring values from time, targets, and motion parameters.
  2. Applies those values to the camera, moving cells, links, and other animated elements.
  3. Recalculates which cells and links are visible on screen.
  4. For DOM rendering, mutates element styles according to the current animation state.
  5. For 2D canvas rendering, draws the visible cells and links, reusing cached rendering where possible.
  6. Schedules the next frame while something is still moving.

The loop is driven by browser animation frames:

(when start-playing
(.requestAnimationFrame js/window
#(dispatch! [:frame-anim/set-frame %])))

Spring profiles in code

Profiles are named choices of stiffness k and damping c. The animation engine computes the motion type and eigenvalues from these numbers.

{:spring/id          :spring/canvas-camera
:spring/stiffness 55
:spring/damping 25
:spring/type :spring/overdamped
:spring/eigenvalues [-2.437694101250946 -22.562305898749052]}
{:spring/id :spring/unit-drag
:spring/stiffness 850
:spring/damping 98
:spring/type :spring/overdamped
:spring/eigenvalues [-9.617262664969566 -88.38273733503044]}
{:spring/id :spring/unit-pulse
:spring/stiffness 150
:spring/damping 6
:spring/type :spring/underdamped
:spring/eigenvalues [-3 11.874342087037917]}
{:spring/id :spring/panel-opacity
:spring/stiffness 64
:spring/damping 16
:spring/type :spring/critically-damped
:spring/eigenvalues [-8]}

Different motions for different jobs

Dragging, camera movement, feedback pulses, and opening content should not all move the same way.

Spring physics lets OrgPad tune motion with two meaningful quantities: