MotionPath
Quick Start
CDN Link
gsap.registerPlugin(MotionPathPlugin)
Minimal usage
gsap.to("#div", {
motionPath: {
path: "#path",
},
transformOrigin: "50% 50%",
duration: 5,
});
Animate any object along a path (or even through arbitrary property values). The motionPath can be defined as any of the following:
An SVG
<path>
element (selector text or direct reference) like:motionPath: "#pathID";
A string of SVG path data like:
motionPath: "M9,100c0,0,18-41,49-65";
An Array of objects with x,y coordinates. By default, it will draw a curved path through these coordinates, but set
type: "cubic"
if they describe a cubic bezier:// plot a curve through these coordinates. The target's current coordinates will automatically be added to the start:
motionPath: [{x:100, y:50}, {x:200, y:0}, {x:300, y:100}]
// cubic bezier coordinates (anchor, two control points, anchor, two control points, etc.):
motionPath: {
path: [{x:0, y:0}, {x:20, y:0}, {x:30, y:50}, {x:50, y:50}],
type: "cubic"
}An Array of objects defining other properties (doesn't need to be "x" and "y"). This will basically smooth out the velocity changes as it hits each value:
// property values through which to animate (the target's current property values will be added to the start):
motionPath: [
{ scale: 0.5, rotation: 10 },
{ scale: 1, rotation: -10 },
{ scale: 0.8, rotation: 3 },
];A configuration object that has a
path
property with any of the above formats, plus other configuration details like:motionPath: {
path: "#pathID",
align: "#pathID",
alignOrigin: [0.5, 0.5],
autoRotate: true,
start: 0.25,
end: 0.75
}
Other features
- Magical
align
capabilities that bend coordinate systems in order to position the target exactly on top of the path (or move the path to the target), regardless of how deeply nested they are inside different transformed containers! This is insanely convenient and no other tool on the web offers this functionality. **autoRotate**
makes the target rotate automatically in the direction of the path as it moves.- Define specific
start
and/orend
positions on the path (progress values from 0-1). Even wrap around or go backwards! - A separate MotionPathHelper tool for Club GSAP members enables interactive editing of the path directly in the browser!
- No need to supply an SVG path - you can provide raw coordinates through which to plot a curved path, complete with adjustable curviness
- Loads of helper methods for doing advanced things like:
- Convert native SVG shapes like
<circle>
,<rect>
, etc. into an equivalent<path>
(convertToPath()) - Calculate the relative position data between any two DOM elements so that you can move one to align perfectly with another, even if they're inside different containers that have various transforms applied! (getRelativePosition())
- Convert SVG
<path>
data into raw cubic bezier data/numbers (or the other way around) (stringToRawPath()/rawPathToString()) - Convert between coordinate spaces (convertCoordinates()/getGlobalMatrix()/getAlignMatrix())
- Convert native SVG shapes like
Special Properties
The motionPath
can be used as either a shorthand for the path
(described below) or as a configuration object with any of the following properties: The below code would align a div to an SVG <path>
. It assumes that there is a DOM element with an id
of "div"
and an SVG <path>
with an id
of "#path"
.
String | Element | Array [required] The motion path along which to animate the target(s). This can be any of the following:
- An SVG
element (selector text or direct reference) like:// selector text: motionPath: { path: "#pathID" } // or direct reference to a
element: let myPath = document.querySelector("#pathID"); ... motionPath: { path: myPath } - A string of SVG path data like:
// path data: motionPath: { path: "M9,100c0,0,18-41,49-65" }
- An Array of objects with x,y coordinates. A curved path will be plotted through these coordinates, or set
type: "cubic"
to have them interpreted as sequential cubic bezier coordinates (ordered like: anchor, two control points, anchor, two control points, etc.):// plot a curve through these coordinates (the target's current coordinates will automatically be added to the start): motionPath: { path: [{x:100, y:50}, {x:200, y:0}, {x:300, y:100}] } // cubic bezier coordinates (anchor, two control points, anchor, two control points, etc.): motionPath: { path: [{x:0, y:0}, {x:20, y:0}, {x:30, y:50}, {x:50, y:50}], type: "cubic" }
- An Array of objects defining other properties (doesn't need to be "x" and "y"). This will basically smooth out the velocity changes as it hits each value:
// property values through which to animate (the target's current property values will be added to the start): motionPath: { path: [{scale:0.5, rotation:10}, {scale:1, rotation:-10}, {scale:0.8, rotation:3}] }
- An SVG
- String | Element - By default, the raw coordinate values from the
path
data are plugged directly into the target's x/y transforms but thealign
property bends coordinate spaces in order to position the target exactly on top of the path (or move the path to the target) regardless of how deeply nested they are inside different transformed containers! You can align to thepath
too. In other words,path
andalign
can point to the same element.align
can be any of the following:- Selector text, like
"#path"
would select the element with the ID of "path" and move the tween's target so that its top left corner is aligned perfectly with that "#path" element. If you'd rather center the target on the spot, usealignOrigin: [0.5, 0.5]
- Element, like a reference to a DOM element.
"self"
moves the path to the tween's targets so that they don't jump initially. In other words, it's as if the path was drawn from their current position(s).
offsetX
andoffsetY
to fine-tune alignment. - Selector text, like
- Array - Determines the point on the target that gets aligned with the path.
alignOrigin
is an Array with progress values along the x and y axis, so[0.5, 0.5]
would be in the center,[1, 0]
would be the top right corner, etc. Setting analignOrigin
also automatically sets thetransformOrigin
to the corresponding place on the target for convenience. (added in GSAP 3.2.0) - Boolean | Number - Rotates the element in the direction of the path.
true
matches the angle of the path exactly, but you can offset the angle by any amount by definingautoRotate
as a number (in degrees). For example,autoRotate: 90
would add 90 degrees to the rotation as it moves along the path. If you’d like the element to rotate from its center, simply settransformOrigin: "50% 50%"
. To align the path with the center of the target, either usealignOrigin: [0.5, 0.5]
or setxPercent: -50, yPercent: -50
on the target before the motionPath tween. - Number - The position along the path at which to start, where 0 is the beginning and 1 is the end and 0.5 is the middle. It can be any positive or negative decimal number. For example,
0.3
would start the element at the 30% point along the curve. Default is 0. - Number - The position along the path at which to end, where 0 is the beginning, 1 is the end, and 0.5 is in the middle. It can be any positive or negative decimal number, including a value that's less than the start (which would make the object travel backwards). For example,
0.3
would have the element end at the 30% point along the curve. 1.5 would make it loop around back to the beginning and stop at the halfway point. Default is 1. - Number - Only applies when the
path
is an Array of points through which to plot a curve. This determines how "curvy" the resulting path is. So 0 would make straight lines (hard corners), 1 (the default) creates a nicely curved path, and 2 would make it much more curvy. Think of it like pulling the control points further and further outward from the anchors as the number goes higher. Default is 1. - Number - An amount to add to the x coordinate(s) for fine-tuning alignment. Default is 0.
- Number - An amount to add to the y coordinate(s) for fine-tuning alignment. Default is 0.
- Boolean - When
false
, causes it NOT to include the current property values in an Array that's passed in for thepath
. For example, if the target is currently atx: 0
,y: 0
and then you do amotionPath: {path: [{x: 100, y: 100}, {x: 200, y: 0}, {x: 300, y: 200}]}
tween, by default it would add{x: 0, y: 0}
to the start of that Array so that it animates smoothly from wherever it currently is but you can setfromCurrent: false
to avoid that and just have it jump to x: 100, y: 100 at the start of that tween. (added in 3.7.0) - Boolean - Only applies when
path
is an Array. Iftrue
, each successive value is interpreted as relative to the previous one. For example, if the target's x starts at 100 and the path is[{x:5}, {x:10}, {x:-2}]
, it would first move to 105, then 115, and finally end at 113. - String - Only applies when
path
is an Array of objects with x/y properties - settype: "cubic"
to have them interpreted as a sequence of cubic beziers in the following order: anchor, two control points, anchor, two control points, anchor, etc. for as many iterations as you want but obviously make sure that it starts and ends with anchors. - Number - Only applies when
path
is an Array. Due to the nature of bezier curves, plotting the progression of an object on the path over time can make it appear to speed up or slow down based on the placement of the control points and the length of each successive segment on the path. So MotionPathPlugin implements a technique that reduces or eliminates that variance, but it involves breaking the segments down into a certain number of pieces which is whatresolution
controls. The greater the number, the more accurate the time remapping. But there is a processing price to pay for greater precision. The default value of 12 is typically perfect, but if you notice slight pace changes on the path you can increase theresolution
value. Or, if you want to prioritize speed you could reduce the number. - Boolean - If true, the the value passed to the rotation will use radians instead of degrees. This is particularly helpful when working with other scripts or libraries that default to radians like Pixi.js. Default is false.
Property
Description
Demo
gsap.to("#div", {
motionPath: {
path: "#path",
align: "#path",
alignOrigin: [0.5, 0.5],
autoRotate: true,
},
transformOrigin: "50% 50%",
duration: 5,
ease: "power1.inOut",
});
loading...
When you align
the motionPath, those calculations are done at the very start of the animation - it is NOT responsive, so if the screen gets resized in a way that affects the path, the alignment won't get re-applied. Why? It would be too expensive CPU-wise to constantly be checking and re-calculating on each tick. But you could definitely set up your own resize listeners and handle it manually in that case (store the progress of the tween, progress(0).kill()
it, create a new tween and jump to the recorded progress).
Animating through other properties (not coordinates)
You can pass in an Array of objects defining other properties (doesn't need to be "x" and "y") and it will basically smooth out the velocity changes as it hits each value. In the example below, we animate through various scale
values with a curviness of 0 and 2; notice how the velocity changes are smoother with a higher curviness:
loading...
Video
Demos
Methods
MotionPathPlugin.arrayToRawPath( values:Array, vars:Object ) : RawPath Array | Takes an Array of coordinates and plots a curve through them, returning a corresponding RawPath Array. If |
MotionPathPlugin.convertCoordinates( fromElement:Element | window, toElement:Element | window, point:Object ) : Object (point or Matrix2D) | Converts a point from one element's local coordinates into where that point lines up in a different element's local coordinate system regardless of how many nested transforms are affecting the elements! |
MotionPathPlugin.convertToPath( shape:String | Element, swap:Boolean ) : Array | Converts SVG shapes like |
MotionPathPlugin.getAlignMatrix( fromElement:Element | window, toElement:Element | window, fromOrigin:Array, toOrigin:Array | String ) : Matrix2D | Gets a Matrix2D for translating between coordinate spaces, typically so that you can move the |
MotionPathPlugin.getGlobalMatrix( element:Element, inverse:Boolean, adjustGOffset:Boolean ) : Matrix2D | Gets the Matrix2D that would be used to convert the element's local coordinate space into the global coordinate space. So, for example, if you take a point |
MotionPathPlugin.getLength( path:Element | String | RawPath ) : Number | Returns the length of a path |
MotionPathPlugin.getPositionOnPath( rawPath:Array, progress:Number, includeAngle:Boolean ) : Object | Calculates the x/y position (and optionally the angle) corresponding to a particular progress value along the RawPath |
MotionPathPlugin.getRawPath( value:String | Element ) : RawPath (Array) | Gets the RawPath (Array) for the provided element or raw SVG <path> data. A RawPath is essentially an Array containing one Array for each contiguous segment with alternating x, y, x, y cubic bezier data. |
MotionPathPlugin.getRelativePosition( fromElement:Element | window, toElement:Element | window, fromOrigin:Array | Object, toOrigin:Array | Object | String ) : Object | Gets the x and y distances between two elements regardless of nested transforms! feed two elements to this method and it'll return the gap between them as a point {x, y} according to the coordinate system of the fromElement's parent. |
MotionPathPlugin.pointsToSegment( points:Array, curviness:Number ) : Array | Plots a curved cubic bezier path through the provided x,y point coordinates, returning a segment Array that's typically dropped into a RawPath Array |
MotionPathPlugin.rawPathToString( rawPath:Array ) : String | |
MotionPathPlugin.sliceRawPath( rawPath:Array, start:Number, end:Number ) : RawPath | Slices the provided RawPath Array at the designated start/end positions and returns the resulting (new, sliced) RawPath |
MotionPathPlugin.stringToRawPath( data:String ) : RawPath |
FAQs
How do I include MotionPathPlugin in my project?
See the installation page for all the options (CDN, NPM, download, etc.) where there's even an interactive helper that provides the necessary code. Easy peasy. Don't forget to register MotionPathPlugin like this in your project:
gsap.registerPlugin(MotionPathPlugin)
Is this included in the GSAP core?
Is this only for Club GSAP members?
No, it's available to everyone for free! But Club GSAP is pretty awesome...just sayin'.
It works fine during development, but suddenly stops working in the production build! What do I do?
Your build tool is probably dropping the plugin when tree shaking and you forgot to register MotionPathPlugin (which protects it from tree shaking). Just register the plugin like this:
gsap.registerPlugin(MotionPathPlugin)