Skip to content

Dynamics.applyOrbit()

Spins elements around a center point using either fixed circles or realistic gravity physics.


1. Kinematic Orbit (Rigid)

If you give it a radius, the elements are locked to a perfect circle (or oval) around the center. They will smoothly follow the center point, and you can use bounds to keep them trapped inside a container.

The elements follow the cursor but stop at the container boundaries.
60 FPS
js
import { Dynamics } from 'animx/dynamics'

// Selecting multiple elements automatically spreads them evenly
Dynamics.applyOrbit('.moon', {
  center: 'pointer', 
  radius: 80, // Activates Kinematic Mode
  speed: 2,   // Radians per second
  trackingLerp: 0.1, // Follow the cursor
  bounds: '.container' // Automatically pads bounds based on the orbit radius
});

2. Newtonian Orbit (Physics)

If you skip the radius and provide gravity instead, AnimX turns on real physics! It automatically calculates how far away your elements are from the center and injects the perfect amount of speed to create a stable, circular orbit.

If you have multiple elements, they act just like a real solar system—planets closer to the sun will naturally orbit much faster than planets far away.

Earth Years: 0
Sun
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune
60 FPS
js
const sun = document.querySelector('.sun');
const planets = document.querySelectorAll('.planet');
const panel = document.querySelector('.solar-panel');

let earthPrevAngle = null;
let earthYears = 0;

Dynamics.applyOrbit(planets, { 
  center: sun, 
  gravity: 1200000,
  autoRotate: false,
  onUpdate: ({ states }) => {
    // Earth is the 3rd planet in the DOM array (index 2)
    const earthState = states[2];
    
    // Calculate Earth's live angle relative to the sun
    const currentAngle = Math.atan2(earthState.y, earthState.x);
    
    // When Earth crosses the right-side horizontal axis, one full orbit is completed!
    if (earthPrevAngle !== null && earthState.x > 0 && earthPrevAngle < 0 && currentAngle >= 0) {
      earthYears++;
      panel.innerHTML = `Earth Years: ${earthYears}`;
    }
    
    earthPrevAngle = currentAngle;
  }
});

3. Elliptical Orbits (Kinematic)

You don't have to stick to perfect circles! By giving it a radiusX and radiusY, you can easily create ovals and elliptical orbits.

The element follows the defined elliptical path.
60 FPS
js
// The dashed path element tracks the pointer using a zero-radius orbit
Dynamics.applyOrbit('.o-path', {
  center: 'pointer',
  radius: 0,
  autoRotate: false
});

Dynamics.applyOrbit('.comet', {
  center: 'pointer',
  radiusX: 180, // Horizontal radius
  radiusY: 40,  // Vertical radius
  speed: 3
});

4. Orbital Decay (Physics)

If you add a little bit of friction, the elements will slowly lose their speed over time. This causes their orbits to decay, spiraling beautifully into the center.

The orbiting elements experience friction and spiral into the center.
60 FPS
js
// The black hole element follows the pointer (faster)
Dynamics.applyFollower('.blackhole', {
  leader: 'pointer',
  stiffness: 250,
  damping: 20
});

// The elements orbit the black hole element.
// Tighter orbit, faster speed
Dynamics.applyOrbit('.comet', {
  center: '.blackhole',
  gravity: 800000,
  friction: 0.98
});

5. Gravitational Softening

When an object gets too close to the center of gravity, it can get slingshotted away at insane speeds. The softening property smooths this out so it passes through the center gracefully.

A high softening value allows elements to float gently through the center, while a very low softening value preserves the massive gravitational slingshot effect.

The lower softening value causes the red element to experience a gravitational slingshot.
60 FPS
js
// High softening (graceful pass)
Dynamics.applyOrbit('.soft-comet', {
  center: '.blackhole',
  gravity: 1200000,
  softening: 40,
  friction: 0.98
});

// Low softening (gravitational slingshot)
Dynamics.applyOrbit('.stiff-comet', {
  center: '.blackhole',
  gravity: 1200000,
  softening: 5,
  friction: 0.98
});

6. Callbacks

Orbits don't have a set duration—they run forever! Because of this, AnimX gives you an onUpdate callback that fires every single frame. This is perfect for updating numbers on the screen or drawing trails.

The onUpdate function gives you the exact live coordinates of the center point (targetX and targetY), plus a states array containing the live speed and position of every orbiting element.

Move your cursor and watch the live telemetry update as the orbit decays.
ORBIT TELEMETRY
Distance: --
Velocity: --
60 FPS
js
const panel = document.querySelector('.debug-panel');

// Visual representation of the spacetime gravity well tracking the mouse
Dynamics.applyOrbit('.gravity-well', {
  center: 'pointer',
  radius: 0,
  autoRotate: false
});

Dynamics.applyOrbit('.comet-data', {
  center: 'pointer',
  gravity: 1500000,
  friction: 0.985,
  onUpdate: ({ states, targetX, targetY }) => {
    const s = states[0];
    
    // Calculate distance to the center
    const dx = targetX - (s.layoutX + s.x);
    const dy = targetY - (s.layoutY + s.y);
    const dist = Math.round(Math.sqrt(dx * dx + dy * dy));
    
    // Calculate velocity magnitude
    const speed = Math.sqrt(s.vx * s.vx + s.vy * s.vy).toFixed(1);
    
    // Update the UI panel
    panel.innerHTML = \`
      <div style="color:#10b981;font-weight:bold;margin-bottom:4px;">ORBIT TELEMETRY</div>
      <div>Distance: \${dist}px</div>
      <div>Velocity: \${speed} px/f</div>
    \`;
  }
});

Properties

OptionTypeDefaultDescription
centerstring | Element | {x, y}nullThe gravitational anchor point. Accepts 'pointer', a DOM element, or a coordinate object.
modestring'physics'Automatically switches to 'kinematic' if radius is provided.
boundsstring | ElementnullClamps the pointer tracking anchor inside an element or 'container'.
radiusnumber-Activates kinematic mode. The exact radial distance from the anchor.
speednumber1(Kinematic Mode) Angular velocity in radians per second.
gravitynumber500000(Physics Mode) The gravitational constant ($G \cdot M$).
softeningnumber30(Physics Mode) Prevents gravitational singularities (slingshots) when elements get too close to the center.
frictionnumber1.0(Physics Mode) Velocity multiplier per frame. E.g. 0.99 decays the orbit.
autoRotatebooleantrueIf true, automatically rotates the element to face its velocity vector (heading).
autoOrbitbooleantrue(Physics Mode) If true, automatically calculates and applies the exact tangential velocity needed for a stable circular orbit on the first frame.

onUpdate Payload

The onUpdate callback receives a single payload object with the following properties:

PropertyTypeDescription
targetXnumberThe live X coordinate of the gravitational center point.
targetYnumberThe live Y coordinate of the gravitational center point.
statesArrayAn array of physical state objects for every element in the orbit.

State Object Properties

Each item in the states array tracks the live properties of a single orbiting element:

PropertyTypeDescription
elHTMLElementThe raw DOM element being animated.
xnumberThe current horizontal translation (pixels).
ynumberThe current vertical translation (pixels).
vxnumberCurrent X velocity in pixels per frame (Physics Mode only).
vynumberCurrent Y velocity in pixels per frame (Physics Mode only).
anglenumberCurrent orbital phase in radians (Kinematic Mode only).
layoutXnumberThe original starting point (X coordinate) of the element before animation.
layoutYnumberThe original starting point (Y coordinate) of the element before animation.