Skip to content

Burst

A Burst is an Emitter: it throws count copies of one Child outward around the Origin, spread evenly clockwise from 12 o’clock unless you aim it. It draws nothing of its own. It has no duration: a Burst lasts as long as its longest-running Child.

Field Takes If left out
children the Child spawned count times: a Shape, another Burst, or a Swirl around either required
count how many Children 5
radius a length: the distance from the Origin to each Child, animated over the Burst’s duration [0, 50]
easing a Curve for the Burst’s own radius. Its Children take their own easing. linear
stagger a time between one Child’s start and the next; see Stagger 0
delay a time to wait before the Burst starts: before any Child starts, and before it throws them 0
restAt the Resting frame, a progress from 0 to 1 the last frame
angle an angle: where the rays point, clockwise from 12 o’clock. One value, not Keyframes. 0
spread an angle from 0 to 360: the arc the rays cover, centred on angle 360
orient true to turn each Child to face its ray off

The Burst’s radius and each Child’s own fields are separate. radius: [10, 110] on the Burst moves every Child from 10 to 110 pixels out, while radius on a circle Child is that circle’s own size.

import { Motly, rand } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
const spec = {
kind: 'burst',
count: 8,
// The Burst's own radius: how far its Children are from the Origin.
radius: [10, 110],
easing: 'ease-out',
restAt: 0.4,
children: { kind: 'circle', radius: [rand(6, 12), 0], fill: 'deeppink', duration: 1 },
};
gsap.effects.burst('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

A Burst’s last frame is usually empty, because its Children shrink or fade away, so give it a restAt where it still shows something.

angle turns the rays, and spread narrows them to an arc. The two rules differ on purpose:

  • At spread: 360, the default, the rays ring the Origin: the first at angle, the rest 360 / count apart, so the last does not land on the first.
  • Below 360, the arc is centred on angle, both edges included, spread / (count − 1) apart. You aim a cone by its middle: angle: 0, spread: 70 is a cannon pointing straight up.
import { each, Motly, rand } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// Each piece holds its size for most of its flight, then shrinks away.
const piece = {
fill: each(['#ffd166', '#ef476f', '#06d6a0']),
scale: [1, 1, 0],
duration: rand(1.1, 1.6),
};
// A cannon: 14 clumps fanned over 70°, centred on angle 0, straight up. Each clump is a small
// Burst of its own, so the confetti scatters instead of lining up on one arc.
const spec = {
kind: 'burst',
count: 14,
angle: 0,
spread: 70,
radius: [0, rand(170, 220)],
easing: 'ease-out',
restAt: 0.35,
children: {
kind: 'burst',
count: 6,
radius: [0, rand(10, 45)],
delay: rand(0, 0.1),
children: each([
{ kind: 'polygon', points: 4, radius: rand(3, 6), angle: [0, rand(-180, 180)], ...piece },
{ kind: 'circle', radius: rand(2, 4), ...piece },
]),
},
};
gsap.effects.burst('.origin', { spec, repeat: -1, repeatDelay: 0.4 });

A single Child goes along angle, so count: 1 with an angle is one aimed throw. spread: 0 sends every Child along the same ray; with a stagger they leave one after another, as a jet.

import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// spread 0 sends every Child along one ray; stagger lets them out one after another.
const spec = {
kind: 'burst',
count: 14,
angle: 50,
spread: 0,
stagger: 0.06,
radius: [0, 240],
easing: 'ease-out',
restAt: 0.5,
children: { kind: 'circle', radius: [7, 1], fill: ['#22d3ee', '#8b5cf6'], duration: 0.9 },
};
gsap.effects.burst('.origin', { spec, repeat: -1, repeatDelay: 0.3 });

angle takes rand(), so each Instance can be turned differently, and each(), so each Burst in a Burst of Bursts can point its own way.

A Child’s angle is its own: a line runs from 12 o’clock to 6 whichever way it is thrown. orient: true turns each Child to face its ray, with its own angle added on top, so streaks, sparks and arrows point outward.

import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// Streaks: a line runs from 12 o'clock to 6, so without orient every one points straight up.
const streaks = (orient) => ({
kind: 'burst',
count: 12,
radius: [15, 80],
orient,
restAt: 0.5,
children: {
kind: 'line',
radius: [3, 18, 0],
stroke: '#ffd166',
strokeWidth: 3,
duration: 0.8,
},
});
const [left, right] = document.querySelectorAll('.origin');
gsap.effects.burst(left, { spec: streaks(false), repeat: -1, repeatDelay: 0.4 });
gsap.effects.burst(right, { spec: streaks(true), repeat: -1, repeatDelay: 0.4 });

A Burst Child turns its rays with it, so a fan inside a ring points outward. The Child a Swirl wraps faces the ray, not the Swirl’s curve. The turn is worked out once, when the Spec is resolved, so orienting costs nothing per frame.

children takes each([...]) to hand different Children out in turn: the first Child gets the first Spec, the second the second, and so on, starting over at the end.

import { each, Motly, rand } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// each([...]) hands different Children out in turn: circle, star, polygon, circle, …
const shared = { radius: [rand(6, 12), 0], angle: [0, rand(-180, 180)], duration: 1 };
const spec = {
kind: 'burst',
count: 12,
radius: [0, 110],
restAt: 0.4,
children: each([
{ kind: 'circle', fill: '#ef476f', ...shared },
{ kind: 'star', points: 5, fill: '#ffd166', ...shared },
{ kind: 'polygon', points: 3, fill: '#06d6a0', ...shared },
]),
};
gsap.effects.burst('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

A Child can itself be a Burst. Each inner Burst is thrown by the outer one and opens where it was thrown, which is how fireworks are built.

import { each, Motly, rand } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// A Burst whose Children are Bursts: each one opens where its parent threw it.
const spec = {
kind: 'burst',
count: 6,
radius: [0, 90],
restAt: 0.5,
children: {
kind: 'burst',
count: 8,
radius: [0, rand(20, 35)],
delay: 0.25,
children: {
kind: 'circle',
radius: [rand(3, 5), 0],
fill: each(['#ffd166', '#ef476f', '#118ab2']),
duration: 0.8,
},
},
};
gsap.effects.burst('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

rand() in an inner Burst resolves separately for each copy, so no two inner Bursts are the same unless you want them to be.