Skip to content

Dynamics.applyExplosion()

Applies a sudden outward radial velocity impulse to a group of elements, simulating an explosion or blast wave. The engine computes per-element trajectories from a central origin point, integrates gravity and air resistance each frame, and bounces elements off a configurable floor with restitution. Returns an instance with a kill() method to halt the simulation.

Click to re-detonate.
BOOM
CLICK TO RE-DETONATE
60 FPS
---

1. Basic Radial Burst

When no originX / originY is provided, the engine derives the epicenter from the geometric center of all targeted elements' bounding boxes. Each element receives a randomized outward velocity scaled by force and forceVariation, with gravity and floor bounce applied each frame.

Click to detonate.
60 FPS
js
import { applyExplosion } from 'animx/plugins/Dynamics';

applyExplosion('.fragment', {
  force: 1500,
  gravity: 1200,
  bounds: '#stage', // confines all four walls to the container
  restitution: 0.6, // 60% energy retained per bounce
  spin: 720,        // up to 720° of random rotation per element
  decay: 0.96       // air resistance per frame
})

2. Custom Epicenter

originX and originY accept explicit viewport-space coordinates, overriding the auto-computed center. Binding these to a pointer event directs the impulse away from the exact click or touch position, enabling aimed or interactive explosions.

Click anywhere to aim the blast epicenter.
60 FPS
js
canvas.addEventListener('click', (e) => {
  applyExplosion('.fragment', {
    force: 1400,
    gravity: 1000,
    bounds: '#stage',
    spin: 600,
    originX: e.clientX, // viewport-space X of the blast epicenter
    originY: e.clientY  // viewport-space Y of the blast epicenter
  });
}, { once: true }); // fire only on the first click

3. Blast Radius Confinement

The radius property defines a circular blast zone around the origin. Elements whose center lies beyond this distance receive zero impulse and remain stationary. This enables localized detonations within a larger field of elements - such as proximity explosions or zone-of-effect mechanics.

Click to fire - only elements inside the ring are blasted.
radius: 60px
60 FPS
js
applyExplosion('.fragment', {
  force: 1400,
  gravity: 1100,
  bounds: '#stage',
  spin: 450,
  radius: 60  // Elements farther than 60px from the origin receive no impulse
})

4. Zero-Gravity Shockwave

Setting gravity: 0 eliminates the downward pull entirely. Elements drift outward along their initial trajectory, decelerating only by decay (air resistance). With decay close to 1.0, elements travel long distances before halting - applicable to space, underwater, or slow-motion dissipation effects.

Click to scatter - elements drift in zero gravity.
60 FPS
js
applyExplosion('.fragment', {
  force: 480,
  decay: 0.993,  // Near-zero air resistance - elements drift freely
  gravity: 0,    // No gravitational pull
  spin: 180
})

// Fade elements as they drift out of view
animate('.fragment', { duration: 4, delay: 0.8, opacity: 0, ease: 'quad.in' })

5. High-Bounce Confetti

A restitution value near 1.0 produces near-perfectly elastic collisions with the floor. Combined with a high spin and tight floor constraint, elements ricochet chaotically before settling - effective for celebration bursts, card flick animations, or particle-field effects.

Click to burst the confetti.
60 FPS
js
applyExplosion('.confetti', {
  force: 700,
  forceVariation: 0.7,  // High variance - each piece travels a different distance
  gravity: 1600,
  floor: 260,
  restitution: 0.88,    // 88% energy preserved per bounce - highly elastic
  spin: 1080,           // Up to 3 full rotations per piece
  decay: 0.97
})

6. Chain Reaction

timeline().call() schedules physics callbacks at precise time offsets without requiring native timers. Each call fires independently against a distinct element group, producing a staggered multi-cluster detonation with escalating force values.

Click to trigger the chain reaction.
60 FPS
js
import { timeline } from 'animx';
import { applyExplosion } from 'animx/plugins/Dynamics';

const tl = timeline();

// Each call() fires at a specific time offset (seconds)

<LivePreview :code="demoCode7" :height="380" hint="Click - gravity pulls rightward instead of down.">
<template #stage>
  <div style="position:absolute;inset:0;background:#0f172a;cursor:pointer;">
    <div class="dir-block" style="position:absolute;left:calc(38% - 56px);top:calc(50% - 56px);width:32px;height:32px;background:#818cf8;border-radius:50%;box-shadow:0 0 16px rgba(129,140,248,0.7);"></div>
    <div class="dir-block" style="position:absolute;left:calc(38% - 16px);top:calc(50% - 56px);width:32px;height:32px;background:#c084fc;border-radius:50%;box-shadow:0 0 16px rgba(192,132,252,0.7);"></div>
    <div class="dir-block" style="position:absolute;left:calc(38% + 24px);top:calc(50% - 56px);width:32px;height:32px;background:#f472b6;border-radius:50%;box-shadow:0 0 16px rgba(244,114,182,0.7);"></div>
    <div class="dir-block" style="position:absolute;left:calc(38% - 56px);top:calc(50% - 16px);width:32px;height:32px;background:#38bdf8;border-radius:50%;box-shadow:0 0 16px rgba(56,189,248,0.7);"></div>
    <div class="dir-block" style="position:absolute;left:calc(38% - 16px);top:calc(50% - 16px);width:32px;height:32px;background:#a78bfa;border-radius:50%;box-shadow:0 0 16px rgba(167,139,250,0.7);"></div>
    <div class="dir-block" style="position:absolute;left:calc(38% + 24px);top:calc(50% - 16px);width:32px;height:32px;background:#fb923c;border-radius:50%;box-shadow:0 0 16px rgba(251,146,60,0.7);"></div>
    <div class="dir-block" style="position:absolute;left:calc(38% - 56px);top:calc(50% + 24px);width:32px;height:32px;background:#4ade80;border-radius:50%;box-shadow:0 0 16px rgba(74,222,128,0.7);"></div>
    <div class="dir-block" style="position:absolute;left:calc(38% - 16px);top:calc(50% + 24px);width:32px;height:32px;background:#60a5fa;border-radius:50%;box-shadow:0 0 16px rgba(96,165,250,0.7);"></div>
    <div class="dir-block" style="position:absolute;left:calc(38% + 24px);top:calc(50% + 24px);width:32px;height:32px;background:#f43f5e;border-radius:50%;box-shadow:0 0 16px rgba(244,63,94,0.7);"></div>
    <div style="position:absolute;bottom:12px;right:14px;font-size:11px;color:rgba(255,255,255,0.22);pointer-events:none;">gravity ?</div>
  </div>
</template>
</LivePreview>

```js
applyExplosion('.fragment', {
  force: 1200,
  gravity: 900,
  direction: 'x',   // pulls elements rightward instead of downward
  bounds: '#stage',
  restitution: 0.55,
  spin: 540
})

8. Gravity Angle

gravityAngle sets the exact pull direction in degrees. 90 = down (default), 0 = right, 180 = left, 270 = up. Any angle in between produces a diagonal pull. Drag the slider to pick an angle - the compass needle shows the live gravity direction - then click the stage to detonate.

Set angle with the slider, then click to detonate.
gravityAngle: 90°
360°
60 FPS
js
const slider = document.querySelector('#ga-slider')

slider.addEventListener('input', () => {
  const deg = +slider.value
  document.querySelector('#ga-arrow').style.transform = `rotate(${deg - 90}deg)`
  document.querySelector('#ga-label').textContent = `gravityAngle: ${deg}°`
})

canvas.onclick = (e) => {
  if (e.target.closest('#ga-slider-wrap')) return
  applyExplosion('.fragment', {
    force: 1200,
    gravity: 1000,
    gravityAngle: +slider.value, // 90 = down, 0 = right, 180 = left, 270 = up
    bounds: '#stage',
    restitution: 0.55,
    spin: 480
  })
}

API Reference

PropertyTypeDefaultDescription
forcenumber1000Base outward velocity applied to each element at the moment of detonation.
forceVariationnumber0.2Randomizes the applied force per element. 0.2 means ±20% variance from force.
decaynumber0.95Air resistance multiplier applied each frame. Values closer to 1.0 result in longer flight distances.
gravitynumber0Downward acceleration (px/s²) applied after detonation. 0 disables gravitational pull.
direction'y' | 'x''y'Gravity pull axis. 'y' pulls downward, 'x' pulls rightward. Overridden by gravityAngle.
gravityAnglenumber90Direction of gravity in degrees. 90 = down, 0 = right, 180 = left, 270 = up. Overrides direction.
floornumberInfinityY-offset (px) below the element's initial position at which bounce collisions are detected.
restitutionnumber0.5Fraction of vertical velocity preserved per floor bounce. 0 is fully inelastic; 1 is perfectly elastic.
spinnumber360Maximum random rotational velocity (degrees) applied to each element.
radiusnumberInfinityBlast zone radius (px). Elements whose center exceeds this distance from the origin are unaffected.
originX / originYnumber(computed)Viewport-space coordinates of the blast epicenter. Defaults to the bounding-box center of all targets.
boundsElementundefinedA container element whose edges define hard collision walls on all four sides.
onUpdatefunction-Called each frame with the particles array. Each particle exposes el, x, y, vx, vy, active.

Returned Instance

MethodDescription
kill()Immediately halts the physics simulation and unregisters the frame callback.