Skip to content

Shapes

A Shape is one Element: the smallest thing motly draws. Its Spec is plain JSON with a kind and that kind’s fields. Draw one alone with gsap.effects.shape() or core’s Shape, or put it in a Burst’s children to draw many.

Every kind is drawn centred on its position and, at angle 0, pointing at 12 o’clock. The examples on this page repeat forever with GSAP’s repeat: -1, so you can watch them without clicking.

Each field takes a single value or Keyframes, an array that moves from one value to the next over the Element’s duration, and either can be handed out across a Burst’s Children with each(). The types say where: a circle’s Spec rejects points, and a star’s requires it.

Field Takes If left out
duration a time: seconds, or a string such as '400ms' 1
delay a time to wait before the first frame 0
restAt a progress from 0 to 1 the last frame
angle an angle, clockwise: degrees, or a string such as '0.5turn' 0
scale a number 1
opacity a number from 0 to 1 1
fill a color deeppink; none on a cross, line or zigzag
stroke a color none; deeppink on a cross, line or zigzag
strokeWidth a length: pixels, as a number or a string such as '4px' 0; 2 on a cross, line or zigzag
easing a Curve, or one per property linear

A cross, a line and a zigzag enclose nothing, so they are stroked rather than filled unless you say otherwise. Each style field you leave out takes its kind’s default, whatever the others say.

restAt is the Resting frame: the one still frame a viewer who prefers reduced motion sees instead of the motion. It is read from the Spec you create the Instance from, not from a Child’s. duration and delay are covered on the time page.

import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// The fields every kind takes. Each one here is Keyframes, so each one moves.
const spec = {
kind: 'polygon',
points: 4,
radius: 40,
angle: [0, 90],
scale: [0.5, 1.5],
opacity: [1, 0.3],
fill: ['deeppink', 'gold'],
stroke: 'white',
strokeWidth: [0, 6],
duration: 1.2,
restAt: 0.5,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

For dots, rings (with fill: 'none' and a stroke) and ripples.

Field Takes If left out
radius a length 50
import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// A ring: a circle with no fill and a stroke.
const spec = {
kind: 'circle',
radius: [0, 90],
fill: 'none',
stroke: 'deeppink',
strokeWidth: [16, 0],
duration: 1,
restAt: 0.4,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

For triangles, squares and hexagons: any regular shape with straight sides.

Field Takes If left out
points how many corners, 3 or more. The first is at 12 o’clock. required
radius a length, from the centre to each corner 50

points holds still for the Element’s whole life: it can be handed out with each(), but it is not Keyframes.

import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
const spec = {
kind: 'polygon',
points: 6,
radius: [20, 90],
angle: [0, 60],
fill: 'none',
stroke: 'gold',
strokeWidth: 4,
opacity: [1, 0],
duration: 1.2,
restAt: 0.4,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

For sparkles and celebration bursts.

Field Takes If left out
points how many tips, 2 or more. The first is at 12 o’clock. required
radius a length, from the centre to each tip 50
innerRadius how far in the notches sit, as a fraction of radius: 0 is spikes, 1 a polygon with twice the corners 0.5

As a fraction, innerRadius keeps a star’s shape while its radius animates.

import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// innerRadius is a fraction of radius: 0.2 is spiky, 0.8 is nearly a polygon.
const spec = {
kind: 'star',
points: 6,
radius: 80,
innerRadius: [0.2, 0.8, 0.2],
angle: [0, 60],
fill: 'gold',
duration: 1.6,
restAt: 0.25,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

For a plus sign, or an x when turned 45°.

Field Takes If left out
radius a length, from the centre to the end of each arm 50
import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// A cross encloses nothing, so it is stroked by default: deeppink, 2 px wide.
const spec = {
kind: 'cross',
radius: [10, 60],
angle: [0, 90],
strokeWidth: [10, 0],
duration: 0.9,
restAt: 0.4,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

For streaks and rays. A line runs from 12 o’clock to 6; turn it with angle.

Field Takes If left out
radius a length, from the centre to each end 50

In a Burst, give the Burst orient: true to turn each line along its throw; otherwise its angle is its own, like every Child’s.

import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// A line runs from 12 o'clock to 6; angle turns it.
const spec = {
kind: 'line',
radius: 80,
angle: [0, 180],
stroke: ['#06d6a0', '#118ab2'],
strokeWidth: 6,
duration: 1.2,
restAt: 0.25,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

For sparks and squiggles. A zigzag runs from 12 o’clock to 6.

Field Takes If left out
points how many corners, ends included, 2 or more, evenly spaced along the length required
radius a length, from the centre to each end 50
amplitude a length: how far each corner between the ends swings to either side a quarter of radius
import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// Turned 90° to run left to right; amplitude is how far each corner swings.
const spec = {
kind: 'zigzag',
points: 9,
radius: 110,
angle: 90,
amplitude: [0, 24, 0],
stroke: '#ffd166',
strokeWidth: 4,
duration: 1.4,
restAt: 0.5,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });

For any outline the other kinds do not draw, such as a heart.

Field Takes If left out
d an SVG path, drawn in a 100×100 box centred on (50, 50), as copied out of a design tool required
radius a length: half the width of that box once drawn, so 50 draws the path at the size it was written 50

Like points, d holds still: hand different paths out with each(), but do not animate one path into another.

import { Motly } from '@motly/gsap';
import { gsap } from 'gsap';
gsap.registerPlugin(Motly);
// Any SVG path, written in a 100×100 box centred on (50, 50). radius 50 draws it at that size.
const heart =
'M50 88C22 66 6 50 6 32C6 18 17 8 30 8C39 8 46 13 50 20C54 13 61 8 70 8C83 8 94 18 94 32C94 50 78 66 50 88Z';
const spec = {
kind: 'path',
d: heart,
radius: [20, 70],
fill: '#ff4d6d',
opacity: [1, 0],
duration: 1.1,
restAt: 0.3,
};
gsap.effects.shape('.origin', { spec, repeat: -1, repeatDelay: 0.5 });