console.log(gsap.version); // need 3.9+ const slimes = gsap.utils.toArray(".star"); const tl = gsap.timeline(); tl.paused( true ) .to(".star", { keyframes:{ "25%":{y:0}, "50%":{y:-100, ease:"sine"}, "75%":{y:0, ease:"sine.in"}, "100%":{x:450, ease:"none"} }, duration:2, stagger:0.5 }) play.addEventListener("click", ()=> tl.restart());
Percentage-Based Keyframes
Keyframes
Ex)
// timeline let tl = gsap.timeline(); tl.to(".box", { x: 100 }) .to(".box", { y: 100 }) .to(".box", { x: 0 }) .to(".box", { y: 0 });
// keyframes gsap.to(".box", { keyframes: { 25%: {x:100, y:0}, 50%: {x:100, y:100}, 75%: {x:0, y:100, rotate: 360}, 100%: {y:0, x:0}, easeEach: 'none' }, duration: 4 });
// Array-based keyframes gsap.to(".box", { keyframes: { x: [0, 100, 100, 0, 0], y: [0, 0, 100, 100, 0], ease: "power1.inOut" }, duration: 2 });
// keyframes object gsap.to(".box", { keyframes: [ {x:100}, {y:100, ease:'power2.out'}, {x:0}, {y:0, ease:'power2.in'} ], rotate:360, transformOrigin:'center center' });
Object keyframes – v3.0
gsap.to(".elem", { keyframes: [ {x: 100, duration: 1, ease: 'sine.out'}, // finetune with individual eases {y: 200, duration: 1, delay: 0.5}, // create a 0.5 second gap {rotation: 360, duration: 2, delay: -0.25} // overlap by 0.25 seconds ], ease: 'expo.inOut' // ease the entire keyframe block });
Percentage keyframes – v3.9
gsap.to(".elem", { keyframes: { "0%": { x: 100, y: 100}, "75%": { x: 0, y: 0, ease: 'sine.out'}, // finetune with individual eases "100%": { x: 50, y: 50 }, easeEach: 'expo.inOut' // ease between keyframes }, ease: 'none' // ease the entire keyframe block duration: 2, })
Simple Array-based keyframes – v3.9
gsap.to(".elem", { keyframes: { x: [100, 0, 50], y: [100, 0, 50] easeEach: 'sine.inOut' // ease between keyframes ease: 'expo.out' // ease the entire keyframe block }, duration: 2, })
Test 1
gsap.set("svg", { opacity: 1 }); gsap.to(".ball", { keyframes: { "0%": { yPercent: 0, scaleX: 1, scaleY: 1 }, "7%": { yPercent: 5, scaleY: 0.9, scaleX: 1.1, ease: "sine.in" }, "25%": { yPercent: 100, scaleY: 1.15, scaleX: 0.9, ease: "sine.in" }, "50%": { yPercent: 500, scaleX: 1, scaleY: 1, ease: "none" }, "60%": { scaleX: 1.6, scaleY: 0.4, ease: "none" }, "65%": { yPercent: 500, scaleX: 1, scaleY: 1 }, "100%": { yPercent: 0, scaleX: 1, scaleY: 1 }, easeEach: "sine.out" }, duration: 0.8, repeat: -1, transformOrigin: "center bottom" }); gsap.to(".shadow", { scale: 0.7, duration: 0.4, repeat: -1, yoyo: true, ease: "sine.inOut", transformOrigin: "center" });
Test 2
gsap.to(".box", { keyframes: { y: [0, 80, -10, 30, 0], ease: "none", // <- ease across the entire set of keyframes (defaults to the one defined in the tween, or "none" if one isn't defined there) easeEach: "power2.inOut" // <- ease between each keyframe (defaults to "power1.inOut") }, rotate: 180, ease: "elastic", // <- the "normal" part of the tween. In this case, it affects "rotate" because it's outside the keyframes duration: 5, stagger: 0.2, repeat: -1 });
Callbacks
gsap.to(".elem", { keyframes: [ {x: 100, duration: 1}, {y: 200, duration: 1, onComplete: () => { console.log('complete')}}, {rotation: 360, duration: 2, delay: -0.25, ease: 'sine.out'} ] }); gsap.to(".elem", { keyframes: { "0%": { x: 100, y: 100}, "75%": { x: 0, y: 0, ease: 'power3.inOut'}, "100%": { x: 50, y: 50, ease: 'none', onStart: () => { console.log('start')} } }, duration: 2, })