// get a random number between -100 and 100 (no snapping)
gsap.utils.random(-100, 100);
// a random number between 0 and 500
// snapped to the closest increment of 5
gsap.utils.random(0, 500, 5);
// get a random value from an array of colors
gsap.utils.random(["red", "blue", "green"]);
// get a reusable function
// that will randomly choose a value between -10 and 50
var random = gsap.utils.random(-10, 50, true);
// now we can call it anytime:
console.log(random());
Let tl - gsap.timeline()
...
tl.to(shapes, {
keyframes: [
{ y: () => { return gsap.utils.random(-80, -120); },
{ y: 0, scale: 0.3 }
],
ease: this.eases.airtime,
stagger: 0.15,
}
)
playTimeline() {
if (this.playing) return;
this.tl.invalidate().play(0);
}
Let tl - gsap.timeline()
...
tl.to(shapes, {
keyframes: [
{ y: () => { return gsap.utils.random(-80, -120); },
{ y: 0, scale: 0.3 }
],
ease: this.eases.airtime,
stagger: 0.15,
}
)
playTimeline() {
if (this.playing) return;
this.tl.invalidate().play(0);
}
gsap.to(".class", {
x: "random([0, 100, 200, 500])",
});
gsap.to(".class", {
x: "random([0, 100, 200, 500])",
repeat: -1,
repeatRefresh: true
});
// Set up our coordinate mapping with GSAP utils!
let mapWidth;
let mapHeight;
function setMaps() {
mapWidth = gsap.utils.mapRange(0, innerWidth, -50, 50);
mapHeight = gsap.utils.mapRange(0, innerHeight, -50, 50);
}
window.addEventListener('resize', setMaps);
setMaps();
//returns the corresponding value in the array
// wrapping back to the beginning when necessary)
let color = gsap.utils.wrap(["red", "green", "yellow"], 5);
// "yellow" (index 5 maps to index 2 in a 3-element Array)
// or use a range
let num = gsap.utils.wrap(5, 10, 12);
// 7 (12 is two more than the max of 10,
// so it wraps around to the start and goes two up from there)
// clamp to a range between 0 and 100
var transformer = gsap.utils.pipe(
// clamp between 0 and 100
gsap.utils.clamp(0, 100),
// then map to the corresponding position on the width of the screen
gsap.utils.mapRange(0, 100, 0, window.innerWidth),
// then snap to the closest increment of 20
gsap.utils.snap(20)
);
// now we feed one value in
// it gets run through ALL those transformations!:
transformer(25.874);
gsap.to(el, {
x: 400,
yoyo: true,
repeat: 1
})
// create
let mm = gsap.matchMedia();
// add a media query. When it matches, the associated function will run
mm.add("(min-width: 800px)", () => {
// this setup code only runs when viewport is at least 800px wide
gsap.to(...);
gsap.from(...);
ScrollTrigger.create({...});
return () => { // optional
// custom cleanup code here (runs when it STOPS matching)
};
});
// later, if we need to revert all the animations/ScrollTriggers...
mm.revert();
let mm = gsap.matchMedia();
mm.add("(min-width: 800px)", () => {
// desktop setup code here...
});
mm.add("(max-width: 799px)", () => {
// mobile setup code here...
});
let mm = gsap.matchMedia(),
breakPoint = 800;
mm.add(
{
// set up any number of arbitrarily-named conditions.
// The function below will be called when ANY of them match.
isDesktop: `(min-width: ${breakPoint}px)`,
isMobile: `(max-width: ${breakPoint - 1}px)`,
reduceMotion: "(prefers-reduced-motion: reduce)",
},
(context) => {
// context.conditions has a boolean property
// for each condition defined above indicating if it's matched
let { isDesktop, isMobile, reduceMotion } = context.conditions;
gsap.to(".box", {
rotation: isDesktop ? 360 : 180,
// spin further if desktop
duration: reduceMotion ? 0 : 2,
// skip to the end if prefers-reduced-motion
});
return () => {
};
}
);
let mm = gsap.matchMedia(),
breakPoint = 800;
mm.add(
{
// set up any number of arbitrarily-named conditions.
// The function below will be called when ANY of them match.
isDesktop: `(min-width: ${breakPoint}px)`,
isMobile: `(max-width: ${breakPoint - 1}px)`,
reduceMotion: "(prefers-reduced-motion: reduce)",
},
(context) => {
// context.conditions has a boolean property
// for each condition defined above indicating if it's matched
let { isDesktop, isMobile, reduceMotion } = context.conditions;
gsap.to(".box", {
rotation: isDesktop ? 360 : 180,
// spin further if desktop
duration: reduceMotion ? 0 : 2,
// skip to the end if prefers-reduced-motion
});
return () => {
};
}
);
let mm = gsap.matchMedia()
// this user has specified "reduced motion"
mm.add("(prefers-reduced-motion: reduce)", (context) => {
gsap.globalTimeline.timeScale(200);
});
@media screen and (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
}
}
el.onmouseover = function () {
gsap.to(timeline, {
timeScale: 0.1
});
}
el.onmouseout = function () {
gsap.to(timeline, {
timeScale: 1
});
}
let scrollTween = gsap.to(".container", {
xPercent: -100 * (sections.length - 1),
ease: "none", // <-- IMPORTANT!
scrollTrigger: {
trigger: ".container",
start: "top top",
end: "+=3000",
pin: true,
scrub: 0.5
}
});
gsap.to(".box", {
y: -100,
scrollTrigger: {
trigger: ".box",
start: "left center",
containerAnimation: scrollTween, // <-- NEW!!
}
});
const tl = gsap.timeline({ paused: true });
let exitTime = 0; // exit time
tl.from(".tooltip", {
scale: 0.2,
xPercent: -70,
});
tl.addPause();
exitTime = tl.duration(); // assign the exit time
tl.to(".tooltip", {
yPercent: 400,
rotation: "random([-90, 90, -45, 45, -180, 180])",
});
btn.addEventListener("mouseenter", () => {
if (tl.time() < exitTime) {
tl.play();
} else {
tl.restart();
}
});
btn.addEventListener("mouseleave", () => {
if (tl.time() < exitTime) {
tl.reverse();
} else {
tl.invalidate().play();
}
});