Jump to content

Search the Community

Showing results for tags 'scrolltrigger'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • GreenSock Forums
    • GSAP
    • Banner Animation
    • Jobs & Freelance
  • Flash / ActionScript Archive
    • GSAP (Flash)
    • Loading (Flash)
    • TransformManager (Flash)

Product Groups

  • Club GreenSock
  • TransformManager
  • Supercharge


There are no results to display.

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start



Personal Website



Company Website



  1. Good day, I'm looking for a freelancer who can help me with a page transition on https://bogun-dunkelau.de/referenzen Portfolio items are opening in modals, the link section before the footer should: - extend to the top of the screen - change background transparency towards 0 - change blurriness towards 0 - close modal with hideModal(currentURL); when end is reached. What I have created so far: https://codepen.io/hpmacher/pen/eYJLpbJ Unfortunately I don't get any further. Please send me a pm to let me know your hourly rate and how long this would take. Thank you! Johannes
  2. Hello! I am new to GSAP and React and I am struggling to find out how to use Scroll Trigger in GSAP v.3.3.4 in my react components. I have tried to do this in react hooks and with Class components but it does not work and spits out an warning saying TypeError: Window.getComputedStyle: Argument 1 is not an object.. I have attached the hook code and also the error that it results in . Apologies I do not have a codepen for my codes. I would appreciate any advices/help! Thank you!! My Hooks Code is: import React, { useRef, useEffect} from 'react'; import Layout from '../components/Layout' import {gsap} from "gsap"; import { ScrollTrigger } from 'gsap/ScrollTrigger'; import '../assets/styles/pages.scss'; gsap.registerPlugin(ScrollTrigger); const Gallery = () => { const purpleRef = useRef([]); const pRef = useRef([]); useEffect(() =>{ var tl = gsap.timeline({ scrollTrigger: { trigger: purpleRef, scrub: true, pin: true, start: "top top", end: "+=100%" } }); tl.from(pRef.current, {scale: 0.3, rotation:45, autoAlpha: 0, ease: "power2"}) .to(purpleRef.current, {backgroundColor: "#28a92b"}, 0); }) return ( <> <Layout> <section class="purple" ref={purpleRef}> <p ref={purpleRef} >This panel gets pinned in a similar way, and has a more involved animation that's wrapped in a timeline, fading the background color and animating the transforms of the paragraph in addition to the line, all synced with the scroll position perfectly.</p> </section> </Layout> </> ); }; export default Gallery; I used ScrollTrigger Scrub Animation demo (The purple panel) as an inspiration which I found on this code pen: https://codepen.io/GreenSock/pen/WNvVOWw
  3. Hi, I'm new to gsap, but didn't found any post according to my problem. The point is, that if I prepare a timeline itself and it's played outside scrolling trigger, all delays, segments are running well. But when I put a default scrollTrigger to the timeline attached to section#how-we-work it plays all of the animations at once without any delay. Looks like scrollTrigger ignoring all of delays set. Here below some code I use, thank you for any hint how to solve this: gsap.registerPlugin(ScrollTrigger); //gsap.registerPlugin(); ScrollTrigger.defaults({ toggleActions: 'play pause reverse none', markers: true, }); $( document ).ready(function() { var tl = gsap.timeline(); tl.from('#top-menu',{ y: -100, duration:1, ease: "back" }); var panel_how = gsap.timeline({ defaults:{ delay:2, duration: 1, opacity: 0, scrollTrigger:{ trigger: '#how-we-work', scrub: 1, pin: true, start: 'top 10%', end: 'bottom 50%', id: 'panel-how', } } }); panel_how .from('#cms404_module_31 .cms404_module_header',{x: 100, ease: 'back(2)'}) .from('#cms404_module_31 ._CMS4Toolbox p',{x: -100, ease: 'back(2)', }) .from('#cms404_module_31 ._CMS4Toolbox .btn',{y: 20, ease: 'back(2)', duation: 1}) .from('#lg-dots-1 ',{ scale: 0, duration:1, transformOrigin: '50% 50%' }) .from('#lg-dots-2 ',{ scale: 0, duration:2, transformOrigin: '50% 50%', delay: 0.5 }) .from('#lg-dots-3 ',{ scale: 0, duration:3, transformOrigin: '50% 50%' },'+=1') .from('#COG',{ y: "-5", scale: 0.5, transformOrigin: '50% 50%' },'+=1') .from('#CLOUD',{ y: "-5" }) .from('#EQ',{ y: "-5" }) .from('#LINE',{}); });
  4. I've had a look around to see if anyone else has asked about this but couldn't find anything in the sea of ScrollTrigger questions recently! Basically I want to know if there's a way to set up tweens for a page which have ScrollTrigger attached, but have the ScrollTrigger disabled/inactive until I say so. For example, when you're loading a page you'd build all your tweens, but you'd have a page loader/transition covering the page. Meaning the trigger elements are technically in view but you don't want them to trigger the tween until you've finished the loader/transition and hit go. I can't find anything in the docs apart from the enable/disable functions on a ScrollTrigger instance, but this doesn't seem to work, even if the tweens are paused before I run .enable().
  5. Hi, I'm trying to get an effect of a collection of shapes to come together and fit together (though some of the paths need a clean up 😅) I have made a few simple ScrollTrigger animations and can arrange the shapes into where they should be / the general animation however.... I'm really stuck on how to get the shapes on the bottom on the vector to act as a mask for the background image the animation is placed upon. I'm able to make a compound path a set the mask but wondered if anyone had any ideas around how I would be able to mask as well as animate the shapes independently (as they are moving on the y-axis at different heights). Any help would be appreciated!
  6. GreenSock

    GSAP 3.4 Released

    GSAP 3.4 has arrived with some significant improvements to ScrollTrigger like: Accommodating different setups for various screen sizes, like a mobile version and desktop version - ScrollTrigger.matchMedia() Batching and staggering elements that enter the viewport, similar to what's often done with IntersectionObserver - ScrollTrigger.batch() Integrating with smooth scrolling libraries - ScrollTrigger.scrollerProxy() ScrollTrigger.matchMedia() You can use standard media queries to seamlessly transition between different ScrollTriggers. It's surprisingly simple to set up and let ScrollTrigger automatically handle all of the creating, undoing, and destroying for you. Basic setup ScrollTrigger.matchMedia({ // desktop "(min-width: 800px)": function() { // setup animations and ScrollTriggers for screens 800px wide or greater (desktop) here... // These ScrollTriggers will be reverted/killed when the media query doesn't match anymore. }, // mobile "(max-width: 799px)": function() { // The ScrollTriggers created inside these functions are segregated and get // reverted/killed when the media query doesn't match anymore. }, // all "all": function() { // ScrollTriggers created here aren't associated with a particular media query, // so they persist. } }); See the Pen ScrollTrigger.matchMedia() Demo by GreenSock (@GreenSock) on CodePen. There's a new ScrollTrigger.saveStyles() method that can be useful with matchMedia(). It saves the current inline styles for any element(s) so that they're reverted properly if animations added other inline styles. It's explained in the video above. See the ScrollTrigger.matchMedia() docs for details. ScrollTrigger.batch() Normally, each ScrollTrigger fires its callbacks (onEnter, onLeave, etc.) immediately when they occur but what if you want to coordinate an animation (like with staggers) of ALL the elements that fired a similar callback around the same time? ScrollTrigger.batch() creates a coordinated group of ScrollTriggers (one for each target element) that batch their callbacks within a certain interval, delivering a neat Array so that you can easily do something like create a staggered animation of all the elements that enter the viewport around the same time. It's a great alternative to IntersectionObserver because it's more widely compatible and easier to work with. Plus you're not restricted to only entering or exiting the viewport - batch() can use ANY start and end values! Demo See the Pen ScrollTrigger.batch() Demo by GreenSock (@GreenSock) on CodePen. See the ScrollTrigger.batch() docs for details. ScrollTrigger.scrollerProxy() ScrollTrigger purposefully avoids "scrolljacking" (disabling the browser's native scrolling behavior in favor of a custom, non-standard scrolling solution). However, smooth scrolling was by far the most requested feature to pair with ScrollTrigger. There are plenty of smooth-scrolling libraries out there, so we created the .scrollerProxy() method to make it simple to integrate any of them with ScrollTrigger (or create your own effects). Here's a basic example using Locomotive Scroll but check out the .scrollerProxy() docs for examples with other libraries. See the Pen ScrollTrigger with LocomotiveScroll by GreenSock (@GreenSock) on CodePen. And more... GSAP 3.4 also delivers various bug fixes, so we'd highly recommend installing the latest version today. There are many ways to get GSAP - see the Installation page for all the options (download, NPM, zip, Github, etc.). Resources Full release notes on Github Full documentation Getting started with GSAP Learning resources Community forums ScrollTrigger Express video course from Snorkl.tv Happy tweening!
  7. Hello 😄 First time poster here. I'm trying to mimic the scrolling behavior of this site, where the text's vertical position lags behind the scroll position. The effect is most obvious in the navigation menu (click the hamburger icon in the top left). You'll notice that if you scroll down quickly to the bottom of the page, it takes about two seconds for the text to catch up to the scroll position. This looks like something I could use ScrollTrigger for. In the the docs page video at about 9:50, you can see that the orange box lags the .ghost box by one second when it has the setting scrub: 1. This is the behavior I want, except it should animate the text's vertical position on the screen. The problem is that, unlike with the horizontal position, the vertical position of the element in the DOM doesn't change -- only the scroll position changes. Any ideas how I can achieve this effect?
  8. Learn to control your animations on scroll with GreenSock's powerful ScrollTrigger in this mini-course by SnorklTV.
  9. Hi guys, having a little bit of trouble here with ScrollTrigger I'm trying to learn it's usage by following the tutorial for horizontal snapping sections found in the docs. Mine won't work for some reason however. I'm not sure what I'm doing wrong. I've tried to get gsap to register the ScrollTrigger plugin, and my animation is practically the same as theirs (minus the sections.length - 1 because I don't have that extra panel in the beginning. I'm not sure exactly what's going on. It's also of note that I'm trying to add this content in the midst of content already on my page. Any help would be appreciated. https://codepen.io/tonycre8/pen/bGEMyvx Edit: Please refresh, I've been working on just getting the codepen to render properly as a React component. Edit 2: It seems as if this code works on the code pen. But it will not work in actual code?? I'm not sure what's going on there. Here's a video of my code not working in an actual project. The code is identical to the one demonstrated in the codepen. CSS and everything. https://www.loom.com/share/bf002f5668034e418c9486204dbd8426
  10. Hello, im trying to use a function to return a dynamic number value for the position of 'scroller-start' of my scroll trigger // simplified scroll trigger here ScrollTrigger.create({ trigger: ".logo", start: "top DYNAMIC-VALUE-HERE", end: "+=500", scrub: 1, }); // function to return dynamic value function get_start() { return document.querySelector('.fixed-elements h2').offsetTop } I see that its possible to use functions in the start option, but how do use it only for the 2nd value as shown above?
  11. Hey, step by step, I figure out, how this fantastic plugin works, but there is one thing, I'm not understanding: The goal is, to make two different instances, which means, when the viewport is wider than 992px, it should load the instance for big screens. When it comes to smaller viewports (on resize), it should kill the actual instance and init a new one for smaller Screens. And that works perfectly with kill(), clearProps and then new init. But it works only on resize, when my scroll position is within the start and endpoint of the first screen instance (isActive). For example, I am on a big screen, scroll down for a while, after showing up my animation, I decide to change the screen size under 992px width. In that case, I get a blank viewport (the white pin-spacer gets visible). Any idea, how to solve this issue? You can see this behavior in the codepen demo. Just resize the demo at the start position and after, at the end of the page. You can see a different behavior. Thank you very much for your support!!!
  12. Hello everyone, I hope this is a simple question: Is it possible to jump/scroll to animations that are linked to ScrollTrigger (scrubbed)? With ScrollTrigger.scroll() I can't use timeline labels (like with Timeline.tweenTo()), ScrollToPlugin doesn't work either. Any ideas?
  13. Hello! I am trying to implement reveal of the multiple elements (stagger behavior) by scrolling. So I found this page in the docs - method batch After looking on this example https://codepen.io/GreenSock/pen/zYrxpmb which has the same situation as mine (with predefined y) I am trying to implement same technique, but don't quite understand how to use refreshInit method, if we have multiple sections with different reveal behavior. P.S. sorry for my english My example
  14. Hello people, I'm calling to you for help. I'm new to gsap and with Scroll Trigger too. After playing around I see that's very easy to set and make animations to elements, and I know that maybe what I'm asking is very easy, but I can't find how to do it, I've been struggling for a few days... maybe I'm not clearly understand the tween to and fromTo methods. So, the thing is: I have a group of layers one above the other due the z-index property which I set on start: gsap.set(".transformation-layer", { zIndex: (i, target, targets) => targets.length - i, //backgroundColor: (i, target, targets) => `#${Math.floor(Math.random()*16777215).toString(16)}`, }); Please ignore the background, this is the property that I have conflict with. I have 5 layers, which the first one gets z-index:5, the second one z-index: 4 and so on... They're inside a wrapper wich is the one who triggers the animation: gsap.to(".transformation-layer:not(:last-child)", { yPercent: -90, opacity: 0, ease: Power3.easeOut, stagger: 0.5, scrollTrigger: { trigger: ".transformation-wrapper", start: "top top", end: "bottom 20%", markers: true, scrub: 1, pin: true }, }); So, right now every layer is visible because there is no background, and I need it to be like that. So my question is how I should put the visibility from 0(start) then 1(meanwhile scroll trigger acts) and then to 0(when the scroll of the layer ends). Or having this visibility: hidden in the css as a starter state. Then when I scroll to the layer it appears on the beginning and hiddens again on the end. Wanna know if I'm explaining myself correctly. Thanks in advance
  15. Hi everone, I am new to Greensock and playing around with the recipies I have found in tutorials. I tried adding layered pinning from this example into React app. Pinning does work, but I have an issue with snapping. I am importing gsap and ScrollTrigger as module. Below is a simplified (no css classes) code // src/index.js import React from 'react' import { render } from 'react-dom' import { App } from './components/app' import { gsap, ScrollTrigger } from 'gsap/all' gsap.registerPlugin(ScrollTrigger) render( <App />, document.getElementById('root') ) // src/components/app/index.js import React, { useEffect, useRef } from 'react' import { ScrollTrigger } from 'gsap/all' export const App = () => { const refSlide1 = useRef(null) const refSlide2 = useRef(null) const refSlide3 = useRef(null) const refSlide4 = useRef(null) const refSlide5 = useRef(null) useEffect(() => { const sections = [refSlide1, refSlide2, refSlide3, refSlide4, refSlide5].map(ref => ref.current); sections.forEach((panel, i) => { ScrollTrigger.create({ trigger: panel, start: "top top", pin: true, pinSpacing: false }); }); ScrollTrigger.create({ snap: 1 / (sections.length - 1) }); }, [refSlide1, refSlide2, refSlide3, refSlide4, refSlide5]) return ( <div className={style.app}> <section ref={refSlide1} /> <section ref={refSlide2} /> <section ref={refSlide3} /> <section ref={refSlide4} /> <section ref={refSlide5} /> </div> ) } Full code can be found in the repo. npm install && npm run start would run it on localhost:3000. I am working it around by installing GSAP and ScrollTrigger via script tag (see master and diff), and then it works. But I'd like to eventually figure out how to make it work with imports. Any tips on how what to look at? Thanks, Sasha
  16. I want to disable the pinning of an element on mobile/tablet displays (i.e less than 767px) but have it enabled on larger displays. let timeout = false; window.addEventListener("resize", () => { clearTimeout(timeout); timeout = setTimeout(pinState, 250); }); function pinState() { let triggerState; if (window.innerWidth > 767) triggerState = true; else triggerState = false; ScrollTrigger.create({ trigger: ".welcomePage", start: "top top", pin: triggerState, }); } pinState(); This works when I open on mobile and desktop, but when I resize the browser window to less than 767px on desktop, the pinning still persist. I have to refresh the browser window to get it to work on the resized desktop browser. Is there a way to force ScrollTrigger to 'refresh' the pin state without refreshing the page?
  17. First off, I wanted my first post to be a big long sappy rant about how much I love GSAP and this community. When I first came back into web dev after a long hiatus (was a big Flash/AS fan) my dreams of a animated interactive web were restored because of you all, and had my eyes opened to a world I thought lost in this new era of webdesign. (PointC's post moved me, I then committed to start my own journey) So maybe I will write about it some time, but for now..... So I have a pinned object that is scrollable and then a pin a element inside it with a scrub an animation. Runs great on desktop from what I can tell, but in Chrome mobile the scrub animation causes the pinned element to hop/jump on the srollable axis. My issue is probably because I am doing something wrong, but I can't seem to figure it out. I tried to remake my issue super basic and was able to replicate in this codepen.
  18. Hi there! I´m using the brand new Scroll Trigger plugin, it´s amazing! But i´m having a problem using it with Smooth scroll: i have a link that scroll the page to some point, but after this scroll the Scroll Trigger markers move and the animation that should be triggered doesn´t start. If not scrolled, the script works as it should. Here is the example with markers: https://byhumans.works/area/cliente/roalca/ The bottom blue section have a countdown ( gsap timeline ) that is triggered once with Scroll Trigger. Click on buttons after "Nuestros Productos" title and you will see how the blue section with numbers below lost the trigger start point. I have to do something else after i smooth scroll the page? if i use other script to scroll the page same thing happens. This happens in all browsers, in pc, ipad and smartphone. Thanks My js: // scroll on click category var prodCatBtn = util.$$('.prod-cat-link'); // scroll util.on(prodCatBtn, 'click', function(){ gsap.to(window, { duration: 0.35, delay: .35, scrollTo: { y: ".switcher-prod", offsetY: 140 }, ease: "power2.inOut" }); }); // top boxes animation var counter1 = { var: 1950 }; var counter2 = { var: 0 }; var counter3 = { var: 0 }; var count1 = util.$(".number-1"); var count2 = util.$(".number-2"); var count3 = util.$(".number-3"); count1.innerHTML = counter1.var; count2.innerHTML = counter2.var; count3.innerHTML = counter3.var; gsap.registerPlugin(ScrollTrigger); // counter animation var tl = gsap.timeline({ repeat: false, ease: "none" }); tl.to(counter1, { var: 2004, duration: 3, onUpdate: function () { count1.innerHTML = Math.ceil(counter1.var); }, }) .to(counter2, { var: 16, duration: 3, onUpdate: function () { count2.innerHTML = Math.ceil(counter2.var); }, }, "-=2") .to(counter3, { var: 160, duration: 3, onUpdate: function () { count3.innerHTML = Math.ceil(counter3.var); }, }, "-=2"); ScrollTrigger.create({ trigger: ".counter-wrap", animation: tl, toggleActions: "play pause resume pause", start: "top bottom", markers: true, });
  19. Hey, thanks for making ScrollTrigger! One of the demos on the ScrollTrigger documentation page had different scrub values. Since I can't update the scrub value directly I was trying to replace the entire active ScrollTrigger, but that applied a tween of the start state till the current ScrollTrigger position on update. Is there a sensible way to replace the active ScrollTrigger with another one, without tweening from the start? I can see that there is a certain complexity to that, especially when you have a timeline hooked up. The tweens of the killed ScrollTrigger instance should keep their state and scrub to the state of the next ScrollTrigger instance with the new scrub value :-) Animation of the pen should be: scrolling down -> lower discs move first and upper disc drag behind, scrolling up -> upper discs move first and lower discs drag behind.
  20. Hi there, I’ve just started using the ScrollTrigger plugin, which is SO awesome - thank you for all the work put into this. I’m worried I’m over complicating things, especially in regards to making my ScrollTrigger instances responsive. Basically I have 2 ScrollTrigger instances for desktop (anything above 800px) and 1 tween with a ScrollTrigger instance for mobile (anything below 800px). I want the 2 desktop ScrollTrigger instances to only run on desktop and the mobile tween with ScrollTrigger to only run on mobile. Everything works great on initial load for both desktop and mobile, but if resizing the viewport, everything goes a bit whacky/breaks (things go out of place/overflow, and I can’t tell if the instances are duplicating or if just the markers are being repeated). As well, my desktop ScrollTrigger instances won’t run if resizing from mobile and my mobile tween with ScrollTrigger won’t run if resizing from desktop. I’ve been wracking my brain, searching high and low in the docs and forums trying different things for 3 days now, but I’m not quite getting it. Any help would be incredibly appreciated. Thank you so much.
  21. Hello, first I wan't to give a big thanks to gsap creators. gsap is insane and scrolltrigger is THE thing that was missing to make gsap perfect. But i have troubles with Scrolltrigger, scrolltrigger works perfectly when I load a page, but my website uses ajax transitions between pages, and I can't figure out how to make my animations works again when I navigate to another page. I don't have errors in console, but triggers just don't do anything. I tried to use the refresh() method, or kill() on my scrolltrigger instance and then reload the js, but they don't seems to do the job. My ScrollTrigger declaration looks like this : initMainAnimations() { const selector = ".feature h3, " + ".feature .img-container, " + ".feature p, " + ".feature a, " + "#see-also .other"; const targets = gsap.utils.toArray(selector); targets.forEach((target) => { ScrollTrigger.create({ trigger : target, onEnter : () => target.classList.add('active'), onEnterBack : () => target.classList.add('active'), start : "top 95%", id : 'main_scroll_trigger' }) }); } (I use barba.js for pages transitions) To be honest i'm lost and i don't really know even theoretically what to do to solve this problem. Maybe gsap can't find ajax loaded elements because of the DOM being modified ? Maybe there is a way to drop everything related to gsap and reload my js ? Maybe it's a noob's question and i'm really sorry if it's easy but i really have no idea of what to do... (sorry for bad english) Sorry i have no codepen to reproduce the case but I don't find a way to give you a small exemple of that, I can put the website online in case it helps. Let me know if you want to see more code. /* EDIT */ gsap actually find targets (it works if i log targets ) But if I set markers to true , I see that they are all on top of the page. even if I use the barba hook afterwhich fires my js after transition is fully done, gsap seems to create triggers before everything is loaded
  22. I'm having some problems getting scrolltrigger work the way I would like it to. My goal is to have the toggleActions work as they do now, but only when scrolling. Pretty much exactly as it is on https://weareferal.com under their projects section. In my codepen example I have it working almost as I would like to except for the fact that when I cross the startline the animation just keeps on going till the end. Could anyone point me in the right direction? I think that page is made with ScrollMagic, but I would rather use ScrollTrigger if possible.
  23. Hello Everyone, I am trying to animate the text using the new scrollTrigger Plugin, there is a glitch when the start point reaches the scroller-start, why is this happening? I am unable to figure it out. Please help me to fix this glitch issue. Thanks.
  24. I'm having a problem and i'm unsure as to whether it's either with Barba or Gsap ScrollTrigger itself I have no clue . So in my website , when I go from the homepage to the about page everything works as normal except the horizontal scroll part that I have put in (Facts Section) , thing is I do this very same action on mobile and it works perfectly sometimes and then other times it does the same as it does with the Desktop Version , so it's either my code and the way I have implemented the horizontal scroll but thing is when I go directly to the page as in not through the homepage and just initiate all the functions in about.js independently , everything including the horizontal scroll works as desired and perfectly , so I don't know which is causing the problem , could ye have a look maybe ?? So here is my homepage.js (Barba Init code) //Variable Declarations and Function Definitions let viewBox = "" heading_Pos = [0, 0] displayState = "" hamburger_display_button = Array.from($('.mobile_nav_sticky'))[0] opened_nav_buttons = document.querySelector('.options') logo = $(".Actual_Logo_Svg") // Morphing Circles and ellipses to paths to be able to morph them and checking the viewbox for device size MorphSVGPlugin.convertToPath("ellipse"); shapes = Array.from($('.Logo_In_Shapes path')) const homeInit = () => { viewBox = "", heading_Pos = [0, 0], displayState = "" hamburger_display_button = Array.from($('.mobile_nav_sticky'))[0] opened_nav_buttons = document.querySelector('.options') logo = $(".Actual_Logo_Svg"); // Morphing Circles and ellipses to paths to be able to morph them and checking the viewbox for device size MorphSVGPlugin.convertToPath("ellipse"); shapes = Array.from($('.Logo_In_Shapes path')) } const logo_tl_func = () => { let logo_tl = gsap.timeline({ onComplete: moveLogo, }) // Morphing into the Logo logo_tl.from(shapes, 1, { y: -600, autoAlpha: 0, ease: "bounce", stagger: 0.15 }) logo_tl.to(shapes, 1, { fill: '#F0C368', stagger: 0.05 }) let firstAnimation = gsap.to('.shapes', { duration: 2, morphSVG: ".Logo_Proper_Background" }); let secondAnimation = gsap.to('.textShape', { duration: 2, fill: '#1D373F', morphSVG: ".Logo_Proper_Text" }); logo_tl.add([firstAnimation, secondAnimation]) } const changeViewBox = media_query => { media_query.matches ? viewBox = "-150 -180 2495 890" : viewBox = "-150 -350 3574 880" media_query.matches ? heading_Pos = [-511, -15] : heading_Pos = [-1540, 40]; media_query.matches ? displayState = "none" : displayState = "block" } const moveLogo = () => { gsap.to(logo, { attr: { viewBox: viewBox }, duration: 3 }) fadeInHeadingAndLinks(); } const fadeInHeadingAndLinks = () => { gsap.to('.nav_links', { display: displayState, scale: 1, duration: 3 }) gsap.to('.logo_heading', { display: "block", x: heading_Pos[0], y: heading_Pos[1], // scale:1, duration: 3 }) gsap.to('.mobile_nav_sticky', { display: "block", scale: 1, duration: 5 }, "+=.7") } const pageTransition = () => { var tl = gsap.timeline(); tl.set('.loading_container img', { scale: 0.3 }) tl.to('.loading_container', { duration: 1.2, width: "100%", left: "0%", ease: "circ.out", }) .to('.loading_container img', { scale: 0.6, duration: 1 }, "-=1.2") .to('.loading_container', { duration: 1.2, width: "0%", right: "0%", ease: "circ.out", }) .to('.loading_container img', { scale: 0.3, duration: 1.2 }, "-=1.3") } // Helper Functions const delay = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)); } // Initialization Methods $(document).ready(() => { window.matchMedia("(max-width: 600px)").matches ? logo.attr('viewBox', '-350 -700 1274 1680') : logo.attr('viewBox', '-680 -380 2074 1080') var viewbox = window.matchMedia("(max-width: 600px)") changeViewBox(viewbox) }) hamburger_display_button.onclick = () => { opened_nav_buttons.classList.toggle('open') } barba.init({ sync: true, transitions: [{ name: 'transition-base', preventRunning: true, timeout: 5000, async leave() { const done = this.async(); pageTransition(); await delay(1000); done(); }, async enter() { window.scrollTo(0, 0); }, }], views: [ { namespace: 'home', afterEnter() { homeInit() window.matchMedia("(max-width: 600px)").matches ? logo.attr('viewBox', '-350 -700 1274 1680') : logo.attr('viewBox', '-680 -380 2074 1080') let viewbox = window.matchMedia("(max-width: 600px)") changeViewBox(viewbox) logo_tl_func(); hamburger_display_button.onclick = () => { opened_nav_buttons.classList.toggle('open') } }, }, { namespace: 'about', afterEnter() { aboutInit() face_tl_func() scroll_p_tl_func() scroll_skills_tl_func() scroll_facts_tl_func() }, } ], }); // //Global Hooks // barba.hooks.leave(() => { // const done = this.async(); // pageTransition(); // await delay(1000); // done(); // }) // barba.hooks.enter(() => { // window.scrollTo(0, 0); // }) and here's my about.js // Variable Declarations and Function Definitions let factsContainer_sm = document.querySelector(".factsContainer_sm") const aboutInit =() => { factsContainer_sm = document.querySelector(".factsContainer_sm") let head = document.getElementsByTagName('head')[0], link = document.createElement('link') link.rel = 'stylesheet' link.href= "../../Resources/CSS/about.css" head.appendChild(link); } const face_tl_func = () => { let face_tl = gsap.timeline(), paths = document.querySelectorAll('.My_Face path'), filledYellowElements = ['.Main_Hair_Part', '.Eyeball_2', '.Eyeball_1', '.Nostril_1', '.Nostril_2', '.Tongue_Part'], filledNavyElements = ['.Pupil_2', '.Pupil_1']; face_tl.set(filledNavyElements, { fill: 'unset' }), face_tl.set(filledYellowElements, { fill: 'unset' }), face_tl.fromTo(paths, { drawSVG: "0%" }, { duration: 1, drawSVG: "100% ", stagger: 0.15 }) let firstAnimation = gsap.to(filledYellowElements, { duration: 2, ease: "slow", fill: '#F0C368' }, "-=.7"), secondAnimation = gsap.to(filledNavyElements, { duration: 2, ease: "bounce", fill: '#1D373F' }, "-=.7") face_tl.add([firstAnimation, secondAnimation]) } const scroll_p_tl_func = () => { let scroll_tl = gsap.timeline({ scrollTrigger: { trigger: '.content', start: "top center", end: "+=1000", markers: true, scrub: true // pin: true } }) scroll_tl.to('.first', { transform: "rotateX(50deg) rotateZ(331deg) translateX(42px)", duration: .5, }), scroll_tl.to('.flag', { scale: 1 }, '-=.1'), scroll_tl.addLabel("first_down") scroll_tl.to('.second', { transform: "rotateX(50deg) rotateZ(331deg) translateX(42px)", duration: 2, }, "first_down-=.1") scroll_tl.addLabel("second_down") scroll_tl.to('.third', { transform: "rotateX(50deg) rotateZ(331deg) translateX(42px)", duration: 2, }, "second_down-=.01") } const scroll_skills_tl_func = () => { let scroll_tl = gsap.timeline({ scrollTrigger: { trigger: '.skillsContainer', start: "top center", markers: true, } }), barWidth = "", bars = [...document.querySelectorAll('.bar')] bars.map(bar => { barWidth = bar.dataset.width; let barAnimation = gsap.to(bar, { width: barWidth, }), percentageAniamtion = gsap.to('.percentage', { scale: 1, }) scroll_tl.add([barAnimation, percentageAniamtion]); }) } const scroll_facts_tl_func = () => { let scroll_tl = gsap.timeline({ scrollTrigger: { trigger: '.factsContainer', start: "top center", // pin: true, scrub: true, end: "+=300", markers: true, } }), facts = [...document.querySelectorAll('.fact')] scroll_tl.to('.factsContainer h2', { scale: 1.5, duration: 1, ease: "slow" }) scroll_tl.to(facts, { xPercent: -85 * (facts.length - 1), scrollTrigger: { trigger: ".factsContainer_sm", start: "center center", pin: true, // pinSpacing:false, markers: true, scrub: 1, snap: 1 / (facts.length - 1), // base vertical scrolling on how wide the container is so it feels more natural. end: () => `+=${factsContainer_sm.offsetWidth}` } }); } // //Initialization Methods aboutInit() face_tl_func() scroll_p_tl_func() scroll_skills_tl_func() scroll_facts_tl_func() Here's the website homepage - https://adamoceallaigh.netlify.app/ Here's the about page - https://adamoceallaigh.netlify.app/about.html Appreciate all the help ye can give , if ye can , can ye check both mobile and desktop versions. 🤙 Cheers Adam
  25. Hi! Can you explain what is the best practice animate one element with multiply triggers (ScrollTrigger) (different animations for one element)? Example (watch codepen): 1. pin parent div and fade-in box animation 2. if we scroll to 1/3 of parent height of pinned element - move box to right 3. if we scroll to 2/3 of parent height of pinned element - rotate box On my codepen demo i have some issues: 1. onRefresh (switch tabs on your browser) - broke my animation 2. i try to use toggleActions, but can't specify play("label") and reverse("label"), seek('label') or duration(1) 3. i think that control one timeline (nested timelines) harder than three timelines, but i try to use three timelines and three ScrollTrigger's and have much more issues with animation What i do wrong? What is the best practice to animate one element with different triggers? Thank you!