Skip to content

Values

Every field on the Shapes, Burst and Swirl pages takes one of the values on this page. A Spec stays plain JSON whatever it holds: JSON.stringify it, store it, and pass it back in, and it draws the same thing.

An array is Keyframes: successive values spread evenly over the Element’s duration. Two values move from the first to the second; four values reach the second a third of the way through, and so on.

import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// Four radius Keyframes and three fill Keyframes, each spread evenly over the 2 seconds.
const spec = {
kind: 'circle',
radius: [10, 70, 30, 90],
fill: ['deeppink', 'gold', '#06d6a0'],
duration: 2,
restAt: 0.5,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

Every animated field takes Keyframes: lengths, angles, numbers and colors. A field that holds still for the Element’s whole life, such as a polygon’s points or a path’s d, does not. There is no { from: to } syntax: write [from, to].

An array always means Keyframes, as it does in GSAP and Motion. To give each Child of a Burst a different value, use each(), below.

rand() and each() are Descriptors: small tagged objects that stay JSON inside the Spec and are resolved only when the Spec is drawn. Both are exported from @motly/core and @motly/gsap, and with script tags they are Motly.rand and Motly.each.

A number drawn between min and max, separately for each Instance and each Child. Use it wherever a number should vary from one Child to the next: sizes, spins, durations, delays, a Burst’s radius. Inside Keyframes each rand() draws its own number, so [rand(4, 14), 0] gives each Child its own starting size. count, points and restAt take a plain number only.

import { Motly, rand } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// Every Child draws its own size, spin and duration. The Seed stays the same for the whole tween,
// so each repeat is identical; Replay starts a new tween with a new Seed.
const spec = {
kind: 'burst',
count: 14,
radius: [0, rand(80, 120)],
restAt: 0.4,
children: {
kind: 'star',
points: 5,
radius: [rand(4, 14), 0],
angle: [0, rand(-360, 360)],
fill: 'gold',
duration: rand(0.6, 1.4),
},
};
gsap.effects.burst('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

In JSON, rand(4, 14) is { "__motly": "rand", "min": 4, "max": 14 }, which a design tool can write too.

Every rand() resolves from the Instance’s Seed. With the same Spec and the same Seed, motly draws exactly the same thing, on every run and every machine. Pass seed to get that:

  • In @motly/gsap, seed in vars. The element or point at index i draws from seed + i.
  • In @motly/core, seed beside renderer in the second argument.

Without a Seed, each tween or Instance draws a random one and keeps it: a repeat, a restart and a scrub all show the same burst. The GSAP guide shows seeded and random bursts side by side.

Hands values to a Burst’s Children in turn: the first value to the first Child, the second to the second, and round again when the values run out. It works on any field of a Child, including points, and on children itself, to mix kinds of Child.

import { each, Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// each() hands values out in turn: colors on one cycle of three, points on a cycle of two.
const spec = {
kind: 'burst',
count: 12,
radius: [0, 100],
restAt: 0.4,
children: {
kind: 'star',
points: each([4, 6]),
radius: [12, 0],
fill: each(['#ef476f', '#ffd166', '#118ab2']),
duration: 1,
},
};
gsap.effects.burst('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

each() picks a value first, then any rand() in that value draws, so each([rand(2, 4), rand(8, 12)]) alternates small and large Children of random sizes.

A plain number is pixels for a length, degrees for an angle, and seconds for a time. A string with a unit says otherwise:

Kind of value Plain number Strings
Length (radius, strokeWidth, amplitude) pixels '40px'
Angle (angle, a Swirl’s size) degrees '90deg', '1.5rad', '0.5turn'
Time (duration, delay, stagger) seconds '0.4s', '400ms'

scale, opacity, a star’s innerRadius and restAt are plain numbers.

import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// A plain number is px, degrees or seconds. A string names another unit.
const spec = {
kind: 'star',
points: 5,
radius: '70px',
angle: [0, '1turn'],
fill: 'none',
stroke: '#ffd166',
strokeWidth: 4,
duration: '1500ms',
restAt: 0.2,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

A color that holds still can be any CSS color, including var(--brand) with the SVG Renderer. Keyframes of colors are named colors, hex, rgb() or rgba(), since motly has to mix them: it moves the red, green, blue and alpha from one Keyframe to the next together.

import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// Keyframed colors: named, hex, rgb() or rgba(). A single color can be any CSS color.
const spec = {
kind: 'polygon',
points: 6,
radius: 70,
fill: ['tomato', '#ffd166', 'rgb(6, 214, 160)', 'rgba(17, 138, 178, 0.3)'],
stroke: 'white',
strokeWidth: 3,
duration: 2,
restAt: 0.4,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

'none' means no fill or no stroke. It cannot be a Keyframe, because there is nothing to mix it with; fade with opacity instead.

The canvas Renderer only understands colors a canvas does, so no var() there.

easing says how a property moves between its Keyframes. It is linear when left out. A Curve is one of three things, all of them data:

  • a CSS keyword: 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out';
  • a cubic-bezier, as four numbers: [0.7, -0.4, 0.3, 1.4], which may overshoot;
  • an SVG path in a 100×100 box, as copied from a design tool, for a curve with more than one bend: x is progress from 0 to 100 and y runs down, so it starts at M0,100 and ends at 100,0.

The named curves are constants you import that hold one of these: sine, quad, cubic, quart, quint, expo, circ and back as cubic-beziers, and bounce and elastic as paths, each as In, Out and InOut, such as cubicOut or bounceInOut.

import { bounceOut, cubicOut, Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// A Burst of one Child throws it straight up, so the Burst's easing is the dot's path in time.
const curves = ['linear', cubicOut, [0.7, -0.4, 0.3, 1.4], bounceOut];
document.querySelectorAll('.origin').forEach((origin, index) => {
const spec = {
kind: 'burst',
count: 1,
radius: [0, 150],
easing: curves[index],
restAt: 1,
children: { kind: 'circle', radius: 8, fill: '#ffd166', duration: 1.2 },
};
gsap.effects.burst(origin, { spec, repeat: -1, repeatDelay: 0.5 });
});

A Burst’s easing moves its own radius, which is how the dots above travel. On a Shape, easing is one Curve for every property, or one per property with default for the rest:

easing: { radius: bounceOut, opacity: 'ease-in', default: 'linear' }
import { bounceOut, Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// A Curve per property, and `default` for the rest: radius bounces, opacity eases in.
const spec = {
kind: 'circle',
radius: [10, 80],
opacity: [1, 0.2],
fill: ['deeppink', 'gold'],
easing: { radius: bounceOut, opacity: 'ease-in', default: 'linear' },
duration: 1.4,
restAt: 0.6,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

Under @motly/gsap, ease in vars is different: it warps the whole tween’s time on top of every easing in the Spec. See the vocabulary rule.