Skip to content

Dynamics.applySoftBody()

Adds spring physics to an SVG <path>. It treats every point on the path like a physical object connected by invisible springs, creating a "jelly-like" effect.

Container Resolution

You don't need to manually select the <path>. Just pass the <svg> container to Dynamics.applySoftBody(svg) and AnimX will find all the paths automatically!

When your mouse (or another element) gets close, it pushes or pulls the edges of the shape.


1. Pointer Tracking

By default, the path tracks your mouse and pushes away from it.

Hover the path to see the deformation.
60 FPS
js
import { Dynamics } from 'animx/dynamics'

// applySoftBody now returns a { kill() } engine instance
const engine = Dynamics.applySoftBody(pathEl, {
  stiffness: 40,           // Low = wobbly jello. High = stiff rubber.
  damping: 5,              // Low = long bouncy wobble. High = instant settle.
  mass: 0.5,               // Lower mass = nodes accelerate faster under the cursor.
  neighborStiffness: 80,   // How strongly adjacent nodes link (transfers the wave).
  pullRadius: 180,         // Cursor influence radius in SVG units.
  pullForce: 800           // Push-away strength.
})

// Stop the simulation:
engine.kill()

2. Physics Configuration

You can change how the object feels (like jelly or rubber) by adjusting stiffness and damping.

Compare low vs high stiffness properties.
Jelly
Rubber
60 FPS
js
// Jelly: extremely loose — deforms wildly and wobbles for a long time
const jelly = Dynamics.applySoftBody(jellyPath, {
  stiffness: 15, damping: 2, neighborStiffness: 40
})

// Rubber: very stiff — resists hard and snaps back almost instantly
const rubber = Dynamics.applySoftBody(rubberPath, {
  stiffness: 600, damping: 35, neighborStiffness: 800
})

3. Custom Interactors

Instead of using the mouse, you can pass an array of HTML or SVG elements in the interactors option. The soft body will react to these elements as they move around the screen.

3a. Repulsion Forces

A high pullForce makes the path push away violently.

Repulsion with a high pullForce value.
60 FPS
js
const engine = Dynamics.applySoftBody(path, {
  interactors: [svgCircle],
  pullRadius: 50,
  pullForce: 2200   // High force = violent parting effect
})

3b. Multiple Interactors

You can pass multiple elements to interactors. Each one pushes the soft body independently.

Deformation driven by two distinct interactors.
60 FPS
js
const engine = Dynamics.applySoftBody(blob, {
  interactors: [ballA, ballB], // Both balls drive deformation simultaneously
  pullRadius: 75,
  pullForce: 1100
})
// Ball A sweeps left→right; Ball B sweeps right→left
// Different durations → they meet inside the blob at unpredictable moments
AnimX.animate(ballA, { x:  370, duration: 1.8, ease: 'sine.inOut', yoyo: true, repeat: -1 })
AnimX.animate(ballB, { x: -370, duration: 2.2, ease: 'sine.inOut', yoyo: true, repeat: -1 })

3c. Attractive Forces

If you use a negative pullForce, the path will be sucked towards the element instead of pushed away.

Attractive force via a negative pullForce.
60 FPS
js
const engine = Dynamics.applySoftBody(blob, {
  interactors: [attractor],
  stiffness: 30,
  damping: 3,
  pullRadius: 200,
  pullForce: -1400    // Negative = attracted toward interactor!
})

4. Programmatic Impulses

You can call punch(x, y, force, radius) directly on the <path> to hit it programmatically. Note that x and y must be inside the SVG's local coordinate system.

Click the SVG to trigger programmatic impulses.
60 FPS
js
// Convert screen click → SVG coordinate space, then punch
svgEl.addEventListener('pointerdown', (e) => {
  const pt = svgEl.createSVGPoint()
  pt.x = e.clientX
  pt.y = e.clientY
  const { x, y } = pt.matrixTransform(svgEl.getScreenCTM().inverse())

  // Negative = implodes inward. Positive = explodes outward.
  path.punch(x, y, -2000, 200)
})

Properties & Methods

Configuration Options

OptionTypeDefaultDescription
stiffnessnumber150Tension pulling nodes back to their original shape. 15 = loose jello. 600 = rigid rubber.
dampingnumber12Wobble resistance. 2 = bounces for a long time. 35 = settles instantly.
massnumber1Weight of each node. Lower mass = nodes respond faster to forces.
neighborStiffnessnumber300How tightly points are connected to each other. Higher values make the wave travel further.
pullRadiusnumber100How close the cursor needs to be before it affects the shape.
pullForcenumber150Force strength. Positive = push away. Negative = attract toward cursor.
interactorsElement[]undefinedElements that push the shape instead of the mouse.
interactivebooleantrueTracks the mouse. If true, the shape reacts to your cursor.

Engine Instance

MethodDescription
engine.kill()Stops the physics and cleans up event listeners.
path.punch(x, y, force, radius)Hits the path at the (x, y) coordinates.