Jump to content
Search Community

Search the Community

Showing results for 'page transition' in content posted in GSAP.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

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

Product Groups

  • Club GreenSock
  • TransformManager
  • Supercharge

Categories

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Personal Website


Twitter


CodePen


Company Website


Location


Interests

Found 654 results

  1. Hello! I haven't asked for help in a while, but I haven't used Gsap in a while, so I'm a little rusty. I'm having trouble with a transition that I think should be pretty easy, but I'm getting tangled, I just need the section to be pinned, and that as you scroll, a card is positioned in the middle at the title level, and in the next scroll, that card goes up, and the second one remains, etc.. then I have I have to refer it to a page that is on the right side vertically, but I later see how to solve it, mainly I am getting dizzy with the snap and stagger
  2. Hi everyone, Can anyone help me figure out on how to do this type of animation on scroll. It is a canvas with svg patterns, and when the user scrolls it will start scaling the 1st row from a smaller size to the initial svg width and height. Not sure how to make this one work Would really appreciate if someone can help me. I have had an attempt, maybe it is a good start but I can't figure it out properly. I have also break down the code into parts from the https://remote.com/global-hr/contractor-invoicing-and-payments https://i.imgur.com/hXHepSI.mp4 HTML <div class="sc-f1d6031c-0 hjWElG pattern-transition" from="white" to="red500"> <canvas width="5080" height="868"></canvas> <svg width="78" height="40" viewBox="0 0 78 40" xmlns="http://www.w3.org/2000/svg" class="pattern duo-petal pattern-ref" style="fill: pink;"> <path d="M39 39.9939C47.9212 39.939 60.9436 36.5061 67.7442 29.6951C74.3072 23.122 77.7258 14.2683 78 5.54268V0H76.507C66.495 0.195122 56.2148 2.82317 48.5672 10.4878C43.4911 15.5732 40.3162 21.8232 39 28.378C37.6838 21.8232 34.5089 15.5732 29.4328 10.4878C21.7852 2.82317 11.505 0.195122 1.49297 0H0V5.54878C0.280313 14.2744 3.69891 23.128 10.2558 29.7012C17.0564 36.5122 30.0727 39.9451 39 40"></path> </svg></div> CSS .hjWElG { position: relative; width: 100%; display: grid; margin-top: -0.5px; margin-bottom: -0.5px; background-color: #ffffff; } /*!sc*/ .hjWElG canvas { width: 100%; height: auto; } /*!sc*/ .hjWElG .pattern-ref { position: absolute; visibility: hidden; pointer-events: none; } document.addEventListener("DOMContentLoaded", function() { const canvas = document.querySelector('canvas'); const ctx = canvas.getContext('2d'); const svgPath = document.querySelector('svg path').getAttribute('d'); const patternColor = 'pink'; // Color of the SVG fill let pattern; let maxScale = 1; // Maximum scale at the bottom of the page // Function to draw the SVG path into a canvas pattern function drawPattern(scale) { const scaledWidth = 78 * scale; const scaledHeight = 40 * scale; const blob = new Blob([`<svg xmlns='http://www.w3.org/2000/svg' width='${scaledWidth}' height='${scaledHeight}'><path fill='${patternColor}' d='${svgPath}' transform='scale(${scale})'/></svg>`], {type: 'image/svg+xml'}); const url = URL.createObjectURL(blob); const img = new Image(); img.onload = function() { pattern = ctx.createPattern(img, 'repeat'); updateCanvas(scale); URL.revokeObjectURL(url); }; img.src = url; } // Function to update canvas drawing based on scroll function updateCanvas(scale) { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = pattern; ctx.save(); ctx.scale(scale, scale); ctx.fillRect(0, 0, canvas.width / scale, canvas.height / scale); ctx.restore(); } // Update the canvas on scroll window.addEventListener('scroll', function() { const scrollPercent = window.scrollY / (document.body.scrollHeight - window.innerHeight); const scale = Math.max(scrollPercent, 0.1) * maxScale; // Scale starts from 0.1 to 1 drawPattern(scale); }); // Resize canvas dynamically and redraw pattern window.addEventListener('resize', function() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; const scale = window.scrollY / (document.body.scrollHeight - window.innerHeight) * maxScale; drawPattern(Math.max(scale, 0.1)); }); // Initial setup canvas.width = window.innerWidth; canvas.height = window.innerHeight; drawPattern(0.5); // Start with the smallest scale });
  3. Hi, (stack : Next JS) i'm close to achieve an effect but am stuck! Here is the result of where i am for now : https://youtu.be/tXUPHLRPiDA As you can see, I'd like to make a transition on clicking to a project thumbnail. Problem : I don't want the container to scaleY up, but i want to keep the infos/image inside to a normal ratio. I tied to animate height, instead of scaleY, but then I have to also animation the scrollTo, and it was a bit messy... Here is the ProjectThumb component (I do have a project list with several ProjectThumb) : import React, { useRef, useState } from "react"; import { useGSAP } from "@gsap/react"; import gsap from "gsap"; import { lineAnimation, projectContainerAnimation, scrollAnimation, subtitleAnimation, titleAnimation, } from "../animations/animations"; import { ScrollToPlugin } from "gsap/ScrollToPlugin"; import { ScrollTrigger } from "gsap/ScrollTrigger"; import Image from "next/image"; import { useRouter } from "next/navigation"; gsap.registerPlugin(ScrollTrigger); gsap.registerPlugin(ScrollToPlugin); const ProjectThumb = ({ project, setClicked, clicked, }: { project: any; setClicked: React.Dispatch<React.SetStateAction<number | null>>; clicked: number | null; }) => { const lineRef = useRef<HTMLDivElement>(null); const thumbContainerRef = useRef<HTMLDivElement>(null); const titleRef = useRef(null); const subTitleRef = useRef(null); const imageRef = useRef(null); const router = useRouter(); const [timeline, setTimeline] = useState<any>(); const [timeline2, setTimeline2] = useState<any>(); // set line animation timeline up useGSAP(() => { if (lineRef.current) { const tl2 = gsap.timeline({ scrollTrigger: { trigger: lineRef.current, start: "top 85%", toggleActions: "play end resume reverse", }, }); tl2.add(lineAnimation(lineRef)); setTimeline2(tl2); } }, [lineRef]); // Set project elements timeline up useGSAP(() => { const tl = gsap.timeline(); setTimeline(tl); // show off all project container but the one clicked if (clicked && clicked !== project.id && thumbContainerRef.current) { timeline.to( thumbContainerRef.current, { opacity: 0, duration: 0.5, }, `<${Math.abs((clicked - project.id) * 0.5) / 3}` ); } }, [clicked, thumbContainerRef]); const handlePlayAnimation = () => { if ( thumbContainerRef.current && subTitleRef.current && titleRef.current && timeline2 && timeline ) { setClicked(project.id); timeline2.clear(); timeline2.to(lineRef.current, { scaleX: 0, duration: 0.5, }); const offset = window.innerHeight * 0.5 - thumbContainerRef.current.getBoundingClientRect().height / 2 - 32; const thumbContainerScale = window.innerHeight / thumbContainerRef.current.getBoundingClientRect().height; timeline .add(scrollAnimation(thumbContainerRef, offset)) .add(titleAnimation(titleRef), "-=0.4") .add(subtitleAnimation(subTitleRef), "-=0.25") .add( projectContainerAnimation(thumbContainerRef, thumbContainerScale), "<=0.3" ); // .then(() => router.push(`/projects/${project.id}`)); } }; return ( <div className={`project_container_${project.id} overflow-hidden min-h-[25vh] relative`} ref={thumbContainerRef} > <div ref={lineRef} className="projectLine scale-x-0 h-2 bg-slate-500 opacity-100" ></div> <div onClick={handlePlayAnimation} className="project_infos button absolute w-full h-full z-10 cursor-pointer" > <div></div> <div className="project_title flex gap-4 p-8 items-end text-white" key={project.id} > <h3 ref={titleRef} className="project_title text-2xl w-full text-slate-800" > {project.title} </h3> <p ref={subTitleRef} className="project_subtitle w-full text-slate-800" > {project.subtitle} </p> </div> </div> <Image ref={imageRef} src={project.images.thumbnail} width={1920} height={1080} alt={project.title} className="h-full object-cover aspect-square opacity-30 absolute" /> </div> ); }; export default ProjectThumb; And here are the animations called by the previous component : import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; import { ScrollToPlugin } from "gsap/ScrollToPlugin"; gsap.registerPlugin(ScrollTrigger); gsap.registerPlugin(ScrollToPlugin); export const lineAnimation = (ref: any) => { return gsap.to(ref.current, { scaleX: 1, transformOrigin: "left", duration: 0.75, }); }; export const thumbContainerAnimation = (ref: any) => { return gsap.to(ref.current, { height: "100vh", transformOrigin: "top center", duration: 1, ease: "expo.in", }); }; export const scrollAnimation = (ref: any, offset: number) => { return gsap.to(window, { duration: 0.75, scrollTo: { y: ref.current, offsetY: offset }, ease: "expo.inOut", }); }; export const titleAnimation = (ref: any) => { return gsap.to(ref.current, { duration: 0.4, y: -50, opacity: 0, ease: "expo.in", }); }; export const subtitleAnimation = (ref: any) => { return gsap.to(ref.current, { duration: 0.35, y: -50, opacity: 0, ease: "expo.in", }); }; export const projectContainerAnimation = (ref: any, scale: number) => { return gsap.to(ref.current, { scaleY: scale, transformOrigin: "center", duration: 1.2, ease: "power4.inOut", }); };
  4. Hello there, as OP mentioned, I understand this is a gsap forum but I can't seem to get an answer to this barba js problem. For context, Currently I have a base transition with gsap nothing too fancy and in the contact page a script to load a multistep form. I can't get barba to reload that script in that specific namespace 'contacto'. Anyone with any updated solutions? I've tried using views and hooks but nothing seems to be working. TLDR: init script everytime barba transitions to a this specific page.
  5. So I THINK i have worked this out - after a huge amount of time! I noticed that the section worked fine, a long as there was NO other blocks on the page. But no single block seemed to be the issue - it was ANY block on the page. The only common denominator they had was the padding (which I ruled out) and they each had a heading - which was, believe it or not, the issue. It was cause by the css transition: all .3s ease-in-out; Which had been applied, to every heading. When resizing quickly (for example on ipad orientation change), scroll trigger calculates WHILE the headings are still in the process of resizing - thus, throwing off the calcultaions. Fingers crossed this is it, but it appears to have fixed the issue Edit - false alarm..... it has not
  6. Hello, I have a Flip transition that animates between a single column and a grid layout. This works, however there is further control + logic required to get the transition to feel smooth and to handle which images transition into view, as well as the position of the viewport during this transition. Here is my current implementation: Stackblitz and here is a good example of what I am trying to achieve with a smooth transition on another website (click the `index` button in the top right corner of the page to see the transition I am aiming for). This may not be strictly a GSAP question, and if not please disregard, though I am curious if anyone may have any pointers on what could help to get my transition closer to the linked example website. From what I can observe, the linked example improves the Flip by achieving the following: From grid view > column view, the grid view keeps track of which row is at the top of the viewport and always transitions so that the top row are the images that move into view in the single column view From column view > grid view, the image in view transitions into the top row of the grid The change in the height of the page is managed so that the viewport position does not end up away from the items on which the transition started, i.e. the items in view at the start of the transition stay in view throughout and until the end of the transition
  7. Hello, it's my first time I use Gsap so I'ma bit confused. I followed this video tutorial that was really good. My goal is create a site in React composed (at the moment) of only two "sections": each section should fill the entire browser window. Below the design: As you can see, the first section contains a button (next) in the center of the page and some squares (some in red and other in orange). The squares should move (and rotate) in loop with a smooth, random and natural way. I immagine that each square moves very slowly and when it reaches the border of the screen, it continues its movement in the opposite direction. When the user clicks on the next button, it goes to the second section. The transition between the first and the second section should be something like this: orange squares go to opacity = 0 next button goes to opacity = 0 red squares continue to move in the meantime some other red squares appear from the outside of the screen and from opacity 0 goes to opacity 1 also a label (alpaca) appears. Ok, now we are at section #2. Here squares moves as before but their space to move is smaller then before so they are closer to the center of the screen. This seems too complicate to me so I need some suggestions before start to write code: there is a similar example (codesandbox, codepen, ...) I can look at that can help me? the site can be a single page application, I don't necessary need to use routes so section#1 and section#2 can be both on the same route (for example mysite.com/test) how can I handle animations and transitions with gsap? This is my code at the moment: https://codesandbox.io/p/sandbox/gsap-animation-4qcwxn?file=%2Fsrc%2FApp.js. It doesn't work well. First of all the squares animation it's very strange, second of all I didn't know how to animate squares between first and second section. Can someone help me? Thanks a lot!
  8. I'm currently in the process of setting up a slideshow utilizing timelines, morphSVG, and motionPath along with BarbaJS Page Transitions in Webflow.. Everything works flawlessly when I reload the page on all pages. However, I've encountered an issue when navigating from the homepage, where I've incorporated motionPath with a delay, to the about page. It seems that this transition breaks all animations. Interestingly, when I remove the delay from the motionPath, the animations function smoothly without any errors during navigation between pages. It appears that the delay within the motionPath is causing conflicts or disruptions during page transitions, leading to animation issues. If you have any insights or suggestions on how to resolve this issue, I would greatly appreciate your input. function slideshowAnimation(e) { let tween; function animateOnPath() { let progress = tween ? tween.totalProgress() : 0; tween && tween.revert(); tween = gsap.timeline({ repeat: -1 }); tween.to(".slideshow_item_large-5", { opacity: 1, duration: 0 }) .to(".slideshow_svg_large-5", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.5 }, duration: 0 }, "<") .to(".slideshow_img_item_large-5", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.5 }, duration: 0, }) .to(".slideshow_item_large-5", { duration: 0.5, ease: "cubic.out", opacity: 1, delay: 4 }) .to(".slideshow_svg_large-5", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.8 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_img_item_large-5", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.8 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_item_large-5", { duration: 0.5, ease: "cubic.out", opacity: 0, delay: 0.5 }, "<") .to(".slideshow_item_large-1", { duration: 0.5, ease: "cubic.in", opacity: 1, delay: 0 }, "-=1") .to(".slideshow_svg_large-1", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.2, end: 0.5 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_img_item_large-1", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.2, end: 0.5 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_svg_large-1", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.8 }, duration: 1, ease: "cubic.inOut", delay: 4 }) .to(".slideshow_img_item_large-1", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.8 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_item_large-1", { duration: 0.5, ease: "cubic.out", opacity: 0, delay: 0.5 }, "<") .to(".slideshow_item_large-2", { duration: 0.5, ease: "cubic.in", opacity: 1, delay: 0 }, "-=1") .to(".slideshow_svg_large-2", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.2, end: 0.5 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_img_item_large-2", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.2, end: 0.5 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_svg_large-2", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.8 }, duration: 1, ease: "cubic.inOut", delay: 4 }) .to(".slideshow_img_item_large-2", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.8 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_item_large-2", { duration: 0.5, ease: "cubic.out", opacity: 0, delay: 0.5 }, "<") .to(".slideshow_item_large-3", { duration: 0.5, ease: "cubic.in", opacity: 1, delay: 0 }, "-=1") .to(".slideshow_svg_large-3", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.2, end: 0.5 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_img_item_large-3", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.2, end: 0.5 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_svg_large-3", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.8 }, duration: 1, ease: "cubic.inOut", delay: 4 }) .to(".slideshow_img_item_large-3", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.8 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_item_large-3", { duration: 0.5, ease: "cubic.out", opacity: 0, delay: 0.5 }, "<") .to(".slideshow_item_large-4", { duration: 0.5, ease: "cubic.in", opacity: 1, delay: 0 }, "-=1") .to(".slideshow_svg_large-4", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.2, end: 0.5 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_img_item_large-4", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.2, end: 0.5 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_svg_large-4", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.8 }, duration: 1, ease: "cubic.inOut", delay: 4 }) .to(".slideshow_img_item_large-4", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.5, end: 0.8 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_item_large-4", { duration: 0.5, ease: "cubic.out", opacity: 0, delay: 0.5 }, "<") .to(".slideshow_item_large-5", { duration: 0.5, ease: "cubic.in", opacity: 1, delay: 0 }, "-=1") .to(".slideshow_svg_large-5", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.2, end: 0.5 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<") .to(".slideshow_img_item_large-5", { motionPath: { path: "#path", align: "#path", alignOrigin: [0.5, 0.5], autoRotate: true, start: 0.2, end: 0.5 }, duration: 1, ease: "cubic.inOut", delay: 0 }, "<"); tween.totalProgress(progress); } animateOnPath(); window.addEventListener("resize", animateOnPath); }
  9. Hello, I am having trouble with keeping the state that controls various parts of a layout in sync with the use of Flip toggle on that page. A little context: I am working on a image gallery page that uses GSAP's Flip plugin to toggle between two layout states: a grid four-column view and a full single-column view. The state (`isGridView`) is used to control the srcSet that is provided to the images — so that the appropriate size images are rendered depending on the layout. Additionally other parts of the layout depend on the state but must be sequenced in the correct order of the Flip animation, i.e. when we transition to the grid view, we need to fade in captions for the images after the animation completes, but when we transition to the full view we need to fade out those captions before the animation. My problem: when the page transitions a couple of times, the state stops being matched to the correct Flipped layout. This results in captions showing in the full view (incorrect) or images appearing blurry (incorrect srcSet). I have tried to set up my Flip to depend on the state of the layout. However my main difficulty is not knowing when / how best to update the React state before / during / after the Flip transition. I am currently using onComplete, but that only updates after the captions have completed their staggered fade-in, and it is very plausible that the user clicks to transition again before the stagger animation has completed, and as a result the state never gets updated for that cycle. I have tried to test with onStart and onUpdate, but onStart means that the srcSet changes too early, resulting in flashes during the transition, and onUpdate seems unreliable for keeping the state in sync in my testing too. I have a feeling I am not setting this up in the best React way. I would be so grateful if anyone has time to take a glance at my StackBlitz reproduction linked in this post to see where I am going wrong. I currently have a function `performLayoutFlip` that is called to do the Flip transition; it could be nice to have a timeline that gets reversed, but I need to account for controlling the captions (fade in after a delay vs fade out immediately) so I don't know how I would manage a timeline that isn't exactly symmetrical. (PS If you click on the images to transition a few times you should see the captions and images come out of sync). Let me know if I can help clarify anything, many thanks in advance! Stackblitz minimal reproduction
  10. Hi Cassie ty for response. Considering that there are two different systems, I tried to reproduce all the conditions, trying to get close to a probable issue. I created the CodePen. In the CodePen, I apply a class to the scroll event on the header named .sticky. While in WordPress, the class on the header is applied on scroll by the settings of the module named .elementor-sticky--effects. As you'll notice in the CodePen, when the header is sticky, I change the color of 'a' elements, forcing it with !important. This is because in WordPress, I'm forced to override the module's rule in order to change the color of the menu items on sticky. The CSS on the website is as follows: .header_container.elementor-sticky--effects .myMenu .menu-item a { color: #0C2638 !important; transition: all 0.3s; } As you'll notice from the CodePen, when I interact with the menu items while the header is sticky and then return to the top of the page, the color of 'a' elements doesn't reset but remains red. This is probably because the CSS rule is taking precedence ? So, I wonder why the rule resets when I don't interact ? How can I avoid this problem considering that I must have the CSS rule with !important? https://codepen.io/Antonio-Nocella/pen/XWQRdzQ
  11. Hi Zach Saucier, I'm working on a project where I have a series of sections (e.g., "rooms" like your example) that I navigate through by scrolling. My goal is to add animations to elements within these sections that not only animate in as I scroll down to them but also perform a reverse animation as I'm about to leave the section to move on to the next one. Here's the desired user experience: I load the page, and the text in the first section animates in. As I start scrolling down towards the second section, I want the text in the first section to perform an exit animation before the page actually moves to the next section. Upon entering the second section, the text there animates in, and the process repeats for each subsequent section. Is this achievable using ScrollTrigger? I'm looking for a way to trigger the exit animation of the current section's elements before scrolling into the next section, essentially giving control over the transition between sections. I'm using this code of yours as a start. Any guidance or examples on how to implement this would be greatly appreciated. Thank you in advance for your help!
  12. Guys, I'm here, unfortunately not with a demo on CodePen but with a website developed in WordPress. I've created a sort of mega dropdown menu using GSAP. Below is the code, which I would describe as spaghetti (and I welcome any advice on how to improve it). But let's get to the problem. When I hover over the "Group" menu item, the mega menu appears, and at the same time, with GSAP, I change the background of the header and the menu items to blue. When the header becomes sticky, I change the menu items' color using CSS by targeting the auto-generated class ".elementor-sticky--effects" from the module I'm using. The issue arises when the header becomes sticky without interacting first with the menu. While it's sticky, if I hover over the "Group" menu item and then scroll back to the top of the page, the menu items remain blue instead of resetting to the default white color. It's as if the reverse of GSAP goes in tilt. What could I do? Is there a way with GSAP to detect when the menu has that specific class (.elementor-sticky-effects) and change the menu color with GSAP while it's sticky? This is the dev website: https://devmanelli.ioslab.it/ This is the full code:/*mega menu gruppo*/ let menu = document.querySelector(".gruppo_menu"); let menu_item = [".other"]; let element = document.querySelector(menu_item); let drop = document.querySelector(".menu_content"); let col = document.querySelector(".elementor-location-header"); let col_menu = [".menu", ".pre-menu", ".post-menu"]; let element2 = document.querySelector(col_menu); let line = document.querySelector(".menu-item .elementor-item-active"); let container_logo = document.querySelector(".container-logo"); let animation = gsap.timeline({ paused: true }); animation.set(drop, { y: -20, zIndex: 1,}, 0); animation.to(drop, { display: "block", opacity: 1, duration: 0.3, delay: 0.2, ease: "power3.out", y: 0, }, 0); menu.addEventListener("mouseenter", () => animation.play()); element.addEventListener("mouseenter", () => animation.reverse()); element2.addEventListener("mouseenter", () => animation.reverse()); container_logo.addEventListener("mouseenter", () => animation.reverse()); col.addEventListener("mouseleave", () => animation.reverse()); document.body.addEventListener("click", () => animation.reverse()); /*mega menu progetti*/ const voice_progetti = document.querySelector(".progetti"); let drop_progetti = document.querySelector(".progetti_content"); let animation_progetti = gsap.timeline({ paused: true}); animation_progetti.set(drop_progetti, { y: -20, zIndex: 1,}, 0); animation_progetti.to(drop_progetti, { display: "block", opacity: 1, duration: 0.3, delay: 0.2, ease: "power3.out", y: 0, }, 0); voice_progetti.addEventListener("mouseenter", () => animation_progetti.play()); voice_progetti.addEventListener("mouseenter", () => animation.reverse()); voice_progetti.addEventListener("mouseenter", () => animation2.play()); col.addEventListener("mouseleave", () => animation_progetti.reverse()); element.addEventListener("mouseenter", () => animation_progetti.reverse()); /*change color header and menu*/ let header = document.querySelector(".myHeader"); let header_gradient = document.querySelector(".myHeader.elementor-sticky--effects"); let li = document.querySelectorAll(".myMenu .menu-item a:not(.custom-icon .sub-menu li a)"); let chevron = document.querySelectorAll(".custom-icon .elementor-item"); let logo = document.querySelector("#logo img"); let overlay = document.querySelector(".overlay"); let animation2 = gsap.timeline({ paused: true }); animation2.to(header, { background: "#fff", delay: 0.2, duration: 0, ease: "power2.inOut", borderBottom: "1px solid #80c5c2" }, 0); animation2.to(logo, { duration: 0.1, delay: 0.2, attr: { src: "/wp-content/uploads/2024/03/logo-manelli-mobile-blue.svg" } }, 0); animation2.to(overlay, { opacity: 0.6, display: 'block', duration: 0, }); animation2.to(li, { color: "#0C2638", duration: 0, delay: 0.2, }, 0); animation2.to(chevron, { fill: "#0C2638", duration: 0, delay: 0.2, }, 0); animation2.to(line, { '--e-global-color-d35985e': "#0C2638", duration: 0, delay: 0.2, }, 0); menu.addEventListener("mouseenter", () => animation2.play()); overlay.addEventListener("mouseenter", () => animation2.reverse()); element.addEventListener("mouseenter", () => animation2.reverse()); element2.addEventListener("mouseenter", () => animation2.reverse()); container_logo.addEventListener("mouseenter", () => animation2.reverse()); col.addEventListener("mouseleave", () => animation2.reverse()); document.body.addEventListener("click", () => animation2.reverse()); /////// This is the css that i used to color menu item on scroll effects: .header_container.elementor-sticky--effects .myMenu .menu-item a { color: #0C2638 !important; transition: all 0.3s; } A thank you to anyone willing to help me.
  13. It's a protection against scroll-behavior: smooth which messes things up. Some CSS libraries apply that, so we're overwriting it. In order for ScrollTrigger to do its magic, it must temporarily set the scroll position of the page back to the top (0), do all of its calculations and pre-optimize, and then restore the scroll position (it's invisible to the user), but if you apply scroll-behavior: smooth, that basically prevents that from working. It's sorta like setting a CSS transition to a value that GSAP animates - the CSS transition intercepts the value application and says "NOPE! I won't allow that right now...I'll drag it out over the course of a certain duration". In short, it's protecting you 😉
  14. Hi @christopherha and welcome to the GSAP Forums! I wouldn't call it a pattern soto speak, is more about the right tool for the right job. When animating routes (especially when you want to animate the entire page) the conundrum is to animate out the current route, unmount it when the animation is completed, then mount the page for the next route and finally animate that page in. Routing in these type of frameworks doesn't have a timing or anything of the sort to handle that. React Transition Group does that, that's why we use it. Unfortunately React hasn't pay attention to animations (unlike Angular, Vue and Svelte - just to mention three) so there is no way for developers to handle that directly with React, hence the solution has to come from third party libraries. There is no documentation on this particular subject because there is not a lot to document actually, it basically stems from my explanation above: Change route Animate current route out When animation out is complete, unmount current route Mount next route Animate next route in The demo you see is the simplest and most reliable way to handle all that, trust me, before Transition Group created the SwitchTransition component was even more convoluted and complicated. That's why (and I know this is not your case) when people are starting I recommend leaning towards either Vue or Svelte rather than React: Hopefully this clear things up. Happy Tweening!
  15. @Rodrigo Hi, I'm coming from Framer Motion where the /app/ router issue for page route transitions has been a widely discussed topic for a while and still remains unfixed. I'm currently building a project with Next.js App Router + GSAP for work, but plan to migrate to Next.js Page Router + GSAP in order to utilize page route transitions for my next project. From what I understand, the solution you linked uses React Transition Group as a wrapper to handle onEnter and onExit, where we are using GSAP to animate some components. Is this the most common pattern? I'm looking for further documentation on this and would appreciate if there was a link to the origins of this example or if there was more documentation around page transitions Next.js pages router and GSAP (with useGSAP hook). Thanks!
  16. Hi, In no case this means that React can't work with GSAP, you can use GSAP in react environments without any issues. The problem stems from a shortcoming (and this is 100% a personal opinion and in no case a reflection of the thoughts of GreenSock on the subject) in the way React was created, since at no point a native animation solution was considered. By this I don't mean React creating an animation library or anything like that is about controlling animations, that's why developers have to resort to external libraries and packages to handle some aspects of the animations (like animate before unmounting, right after mounting, control render states, etc.), which sometimes feels quite hacky and convoluted. On the other hand Vue did considered animations and added them to it's core: https://vuejs.org/guide/built-ins/transition.html Using the JS hooks in Vue is super simple and reduces the hassle you have to go through in order to create animations and you don't need any external libraries to make it work. Of course Nuxt abstracts this even more making something simple even simpler: https://nuxt.com/docs/getting-started/transitions If you're still on the fence of which framework to choose, I'd strongly recommend you to go the Vue/Nuxt route (again 100% personal opinion), they general approach is simpler and cleaner. Directives are far more intuitive IMHO than JSX, you can scope your styles on an easier way with Vue, they keep JS out of the HTML and Vue is compatible with the web component API: https://developer.mozilla.org/en-US/docs/Web/API/Web_components I haven't dig on Svelte but I heard nothing but great things about it. I know that @Dipscom uses it on his projects and that's good enough for me. Also @SteveS one of our superstars here in the forums made a nice presentation for the Svelte summit that you can find here: Finally demos, because those speak more than words. Page Transitions in Next: https://stackblitz.com/edit/nextjs-13cw4u Page Transitions in Nuxt: https://stackblitz.com/edit/nuxt-starter-bthjlg Hopefully this helps. If you have more questions feel free to ask. Happy Tweening!
  17. Hey Rodrigo, thanks for quick answer! Yeah, this is also my first time trying out astro, but i really liked its performance and a new view transitions feature. I know, i tried to use useGSAP hook also, but i guess it should work even in useEffect. I dont think the problem here is React. I created a minimal demo, just with astro components, without react. You can see, that after first render of the app, scrollSmoother is working well. after transition to another page, scroll smoother breaks ( you can check that there are no inline styles in body ). When you instantiate ScrollSmoother outside of the lifecycle function, after transition use is able to scroll, but without scrollSmoother effect. Link to demo: https://stackblitz.com/edit/github-2hpcon-axifnq?file=src%2Fcomponents%2FLayout.astro,src%2Fpages%2Fabout.astro,src%2Fpages%2Findex.astro,package.json Thanks for your time!
  18. Hello, Im just trying to get ScrollSmoother working on astro web, with new astro view transition Api. During the first page load, everything work as expected. But when Im transitioning to another page, the scrollSmoother stops working. It looks like during the initialisation of ScrollSmoother, it doesnt inject styles into the <body> tag, so there is scrollbar missing and users cant scroll the page. I also tried to set the styles manually loke this: useEffect(() => { const wrapperHeight = document.getElementById("smooth-content")?.offsetHeight; const smoother = ScrollSmoother.create({ smooth: 0.4, effects: true, }); if (document) { document.body.style.height = `${wrapperHeight}px`; document.body.style.overscrollBehavior = "none"; document.body.style.scrollBehavior = "auto"; } return () => { smoother.kill(); if (document) { document.body.style.height = ""; document.body.style.overscrollBehavior = ""; document.body.style.scrollBehavior = ""; } }; }, []); But unfortunatelly, the height is calculated wrong ( shorter than it should be ), and the ScrollSmoother is flickering ( somewhere about the half of the page, it jumps to the top of the page ). I've also tried to initialize and kill ScrollSmoother in Astro lifecycle hooks, in React component, and even in Vue components. Without view transitions, everything works as expected. Thanks for answer.
  19. Hi, The best course of action right now is to use React Transition Group as shown in this demo: https://stackblitz.com/edit/nextjs-13cw4u?file=Layouts%2FLayout.js,components%2FTransition.js,context%2FTransitionContext.js Due to the way this works, there is no need for the useGSAP hook in the transition component since those are one off animations that will be elegible for garbage collection after they're completed. Is necessary to point out that you have to use the pages router for this approach (animating in and out each page) since this is not possible with the app router regardless of the animation solution you use (Transition Group with either GSAP or CSS, Framer, etc). This is a known issue that hasn't been resolved in over a year by the Next team, nothing to do with GSAP, Framer or other libraries: https://github.com/vercel/next.js/discussions/42658 Here you can find a way to create overlay transitions (the pages are not animated, just an overlay animates over the layout) with GSAP using the app router: https://medium.com/@josiah.webdev/page-transitions-with-gsap-next-js-app-router-5508cee43a80 Finally you can stick with the pages router for simple static websites if you want to use the other way, there is nothing essentially wrong in using the pages router IMHO. Hopefully this helps. Happy Tweening!
  20. Hello! I am currently testing out GSAP with Next.js and i'm trying to create a zoom-in on scroll transition, where I use GSAP to zoom into the text, which is white, until it covers the screen, before ending up on the next section which has a white background. However, I can't seem to make it work. I've tried using useRef (the current code uses this) as well as just using class names. StackBlitz - Did a demo with the code in StackBlitz as well, for some reason, I have to open the demo in a separate page, scroll all the way down, then scroll all the way up for the text to show up... But except for that, the problems are the same, as the code is the same, except that I had to pin the textElement, instead of the heroElement to make it somewhat work, and with some other unnecessary components, and classes removed. The two problems I'm having are: 1. When scrolling, the text zooms in (or rather, scales up), however, at the same time the text moves up, out from view as shown in the gif below, which I don't want. 2. I'm trying to also make it zoom into a specific letter, because I think the transition would be smoother (although, this part is not necessary, if the text-zoom looks good and can cover the screen) I've looked around the forums, asked AI and tried myself for two weeks but I just can't figure it out. If anyone has an idea on how to fix this, or make it work that I would be really thankful!! Ps: the "hero_title" = @apply 2xl:text-[72px] sm:text-[64px] text-[50px] font-extrabold origin-center; 'use client' import React, {useRef, useEffect} from 'react' import HeroCanvas from './HeroCanvas' import gsap from 'gsap' import { ScrollTrigger } from 'gsap/dist/ScrollTrigger' import { useGSAP } from '@gsap/react' gsap.registerPlugin(ScrollTrigger) const Hero = () => { const heroRef = useRef(null) const textRef = useRef(null) const letterRef = useRef(null) const container = useRef(null) useGSAP(() => { const heroElement = heroRef.current; const textElement = textRef.current; const letterElement = letterRef.current; const tl = gsap.timeline ({ scrollTrigger: { trigger: heroElement, start: 'top top', end: '+=5000', scrub: true, markers: true, pin: heroElement, } }); tl.fromTo (textElement, {scale: 1}, { scale: 100, ease: 'none', smoothOrigin: true, }); tl.fromTo (letterElement, {scale: 1}, { scale: 100, ease: 'none', smoothOrigin: true, }); }, {scope: container}) return ( <div ref={heroRef} className='flex min-h-screen flex-col justify-between p-24 items-center'> <div ref={textRef} className='flex-1 pt-36 padding-x'> <h1 className='hero_title uppercase tracking-widest text-center'> <span> Testi</span><span ref={letterRef}>n</span><span>g</span> <span className='bg-gradient-to-r from-accent-3 via-accent-2 to-accent-1 inline-block text-transparent bg-clip-text'> GSAP </span> <br /> <span> Placeholder </span> <span className='bg-gradient-to-r from-accent-3 via-accent-2 to-accent-1 inline-block text-transparent bg-clip-text'> Text </span> </h1> </div> <HeroCanvas /> </div> ) } export default Hero
  21. Hi, I am building a slider based on this example https://codepen.io/andrei-savu/pen/BaPqzvX It works when it's alone on a page, https://yaojuilan.art/gsap While it isn't working when there is something else https://yaojuilan.art/system_of_conductors/field-walk#kinmen (the slider works sometime. it is unstable. ) I tried logging out the observer onChange, the event does trigger, but the items just would not do the horizontal transition. I am wondering if observer has some sort of limitation, or maybe observer listener is interfering with something? Sorry i did not create a codepen, because this component does works standalone. Here is the slider component export default async function Page() { const data= await getPageContent() return ( <div id='intro' className='relative h-auto w-full overflow-x-hidden'> <div className='h-[50vh] w-full'> some content </div> <Slider items={data?.carousel_img?.images} /> <div className='h-[200vh] w-full bg-red-100'> some content </div> </div> ) } export default function Slider({ items, section }) { useGSAP(() => { let loop = horizontalLoop(`.carousel-${section} li`, { repeat: -1 }) let slow = gsap.to(loop, { timeScale: 0, duration: 0.5 }) loop?.timeScale(0) Observer.create({ target: `.carousel-${section}`, type: 'pointer,touch,wheel', wheelSpeed: -1, preventDefault: true, onChange: (self) => { loop.timeScale(Math.abs(self.deltaX) > Math.abs(self.deltaY) ? -self.deltaX : -self.deltaY) // whichever direction is bigger slow.invalidate().restart() // now decelerate }, }) }) return ( <div className='absolute bottom-12 w-full cursor-grab overflow-hidden'> <ul className={`carousel-${section} carousel flex flex-nowrap pl-0`}> {items?.map((item, i) => ( <li key={i}> <Image alt={'collective of images'} src={item} width={150} height={150} sizes='100vw' className='pointer-events-none touch-none select-none ' /> </li> ))} </ul> </div> ) } function horizontalLoop(items, config) { items = gsap.utils.toArray(items) if (!items.length) return config = config || {} let tl = gsap.timeline({ repeat: config.repeat, paused: config.paused, defaults: { ease: 'none' }, onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100), }), length = items.length, startX = items[0].offsetLeft, times = [], widths = [], xPercents = [], curIndex = 0, pixelsPerSecond = (config.speed || 1) * 100, snap = config.snap === false ? (v) => v : gsap.utils.snap(config.snap || 1), // some browsers shift by a pixel to accommodate flex layouts, so for example if width is 20% the first element's width might be 242px, and the next 243px, alternating back and forth. So we snap to 5 percentage points to make things look more natural totalWidth, curX, distanceToStart, distanceToLoop, item, i gsap.set(items, { // convert "x" to "xPercent" to make things responsive, and populate the widths/xPercents Arrays to make lookups faster. xPercent: (i, el) => { let w = (widths[i] = parseFloat(gsap.getProperty(el, 'width', 'px'))) xPercents[i] = snap((parseFloat(gsap.getProperty(el, 'x', 'px')) / w) * 100 + gsap.getProperty(el, 'xPercent')) return xPercents[i] }, }) gsap.set(items, { x: 0 }) totalWidth = items[length - 1].offsetLeft + (xPercents[length - 1] / 100) * widths[length - 1] - startX + items[length - 1].offsetWidth * gsap.getProperty(items[length - 1], 'scaleX') + (parseFloat(config.paddingRight) || 0) for (i = 0; i < length; i++) { item = items[i] curX = (xPercents[i] / 100) * widths[i] distanceToStart = item.offsetLeft + curX - startX distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, 'scaleX') tl.to( item, { xPercent: snap(((curX - distanceToLoop) / widths[i]) * 100), duration: distanceToLoop / pixelsPerSecond }, 0, ) .fromTo( item, { xPercent: snap(((curX - distanceToLoop + totalWidth) / widths[i]) * 100) }, { xPercent: xPercents[i], duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond, immediateRender: false, }, distanceToLoop / pixelsPerSecond, ) .add('label' + i, distanceToStart / pixelsPerSecond) times[i] = distanceToStart / pixelsPerSecond } function toIndex(index, vars) { vars = vars || {} Math.abs(index - curIndex) > length / 2 && (index += index > curIndex ? -length : length) // always go in the shortest direction let newIndex = gsap.utils.wrap(0, length, index), time = times[newIndex] if (time > tl.time() !== index > curIndex) { // if we're wrapping the timeline's playhead, make the proper adjustments vars.modifiers = { time: gsap.utils.wrap(0, tl.duration()) } time += tl.duration() * (index > curIndex ? 1 : -1) } curIndex = newIndex vars.overwrite = true return tl.tweenTo(time, vars) } tl.next = (vars) => toIndex(curIndex + 1, vars) tl.previous = (vars) => toIndex(curIndex - 1, vars) tl.current = () => curIndex tl.toIndex = (index, vars) => toIndex(index, vars) tl.times = times tl.progress(1, true).progress(0, true) // pre-render for performance if (config.reversed) { tl.vars.onReverseComplete() tl.reverse() } return tl }
  22. Hi GSAP Community, I have built a react web app, These are the component list is: 1) Landing page 2) About Page 3) Traction 4) Services 5) Ecosystem 6) Partners I have used GSAP in all pages for their title reveal. In traction component i have added horizontal scroll. Now after this the scroll animations after that coponent are all altered. I saw that two pairs of markers were visible for the Partner component title reveal even though there was only one scroll trigger. So help me sort out this issue. Tractions.jsx import React, { useRef, useEffect } from 'react'; import './Traction.css'; import gsap from 'gsap'; import ScrollTrigger from 'gsap/ScrollTrigger'; import NorthEastIcon from '@mui/icons-material/NorthEast'; import { isMobile } from 'react-device-detect'; gsap.registerPlugin(ScrollTrigger); export default function Traction() { useEffect(() => { gsap.set('.cursor', { xPercent: -50, yPercent: -50 }); let cursor = document.querySelector('.cursor'); let hand = document.querySelector('.hand'); let subPanels = document.querySelectorAll('.sub-panel'); let mouseX; let mouseY; window.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; gsap.to(cursor, 0.5, { x: mouseX, y: mouseY }); }); subPanels.forEach(subPanel => { subPanel.addEventListener('mouseenter', () => { gsap.to(hand, 1, { scale: 1, opacity: 1, top: '-75px', left: '-75px', rotate: 0, ease: 'elastic.out(1, 0.3)', }); }); subPanel.addEventListener('mousemove', () => { gsap.to(hand, 1, { x: mouseX, y: mouseY, }); }); subPanel.addEventListener('mouseleave', () => { gsap.to(hand, 0.2, { scale: 0, opacity: 0, top: '10', left: '40', rotate: 45, }); }); }); }, []); const component = useRef(); const slider = useRef(); if (!isMobile) { console.log("Not a mobile") useEffect(() => { let ctx = gsap.context(() => { let panels = gsap.utils.toArray(".panel"); gsap.to(panels, { xPercent: -100 * (panels.length - 1), ease: "none", scrollTrigger: { trigger: slider.current, pin: true, scrub: 1, snap: 1 / (panels.length - 1), end: () => "+=" + slider.current.offsetWidth, } }); }, component.current); return () => ctx.revert(); },[]); } return ( <div className='pin'> <div className="traction" ref={component}> <div ref={slider} className="container"> <div className="cursor"></div> <div className="hand">View</div> <div className="panel"> <div className="sub-panel"> <div className='traction-content'> <h3> <span>21+ Universities</span> connected together in one community with equal opportunities to learn, connect and grow. </h3> <h4> View stats <NorthEastIcon className="arrow" /> </h4> </div> </div> <div className="sub-panel"> <div className='traction-content'> <h3> <span>21+ Comrades</span> working together to make a difference. </h3> <h4> View stats <NorthEastIcon className="arrow" /> </h4> </div> </div> </div> <div className="panel"> <div className="sub-panel"> <div className='traction-content'> <h3> <span>10+ Events</span> conducted to connect students, developers, job seekers to enrich their knowledge and skills. </h3> <h4> View stats <NorthEastIcon className="arrow" /> </h4> </div> </div> <div className="sub-panel"> <div className='traction-content'> <h3> <span>4+ States</span> united together to establish blockchain clubs in universities, fostering web3 culture. </h3> <h4> View stats <NorthEastIcon className="arrow" /> </h4> </div> </div> </div> <div className="panel"> <div className="sub-panel"> <div className='traction-content'> <h3> <span>1000+ Students</span> working together to build a effective web3 community. </h3> <h4> View stats <NorthEastIcon className="arrow" /> </h4> </div> </div> <div className="sub-panel"> <div className='traction-content'> <h3> <span>Immense Expansion</span> of the Web3 ecosystem is ongoing... </h3> <h4> View stats <NorthEastIcon className="arrow" /> </h4> </div> </div> </div> </div> </div> </div> ); } Traction.css: .container { width: 300vw; height: 100vh; display: flex; flex-wrap: wrap; } .lastContainer { display: flex; height: 100vh; background-color: black; margin: 0; } .panel { width: 100vw; height: 100vh; color: var(--bg-color); background-color: black; display: flex; align-items: center; justify-content: space-around; } .sub-panel { height: 60%; width: 30%; border-radius: 30px; background-color: #2A2A39; padding: 4rem; color: #9DA7C4; cursor: pointer; } .sub-panel h3 { font-size: 1.4rem; line-height: 1.5; } .sub-panel h4 { font-size: 16px; margin: 1.33rem 0px; font-weight: bold; } .sub-panel span { color: white; } svg { vertical-align: 0; } .arrow { margin-bottom: -0.4rem; } .cursor, .hand { position: fixed; left: 0; border-radius: 50%; pointer-events: none; transition: transform .1s; } .cursor { z-index: 999; } .hand { background: rgb(155, 0, 255); top: 50%; width: 80px; height: 80px; z-index: 9999; display: grid; place-content: center; transform: rotate(45deg); opacity: 0; } @media screen and (max-width:800px) { .traction { margin-top: -0.1rem; } .container { width: 100vw; height: 300vh; display: flex; flex-direction: column; flex-wrap: nowrap; } .panel { display: flex; flex-direction: column; width: 100%; height: 100vh; } .sub-panel { padding: 1rem; width: 100%; height: 50vh; padding: 0; margin-bottom: 2rem; } .traction-content { padding: 2rem; } .cursor, .hand { display: none; } } Partner.jsx: import React, { useEffect, useRef } from 'react'; import gsap from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; import './Partner.css'; import push from '../assets/img/push.png'; import shardeum from '../assets/img/shardeum.png'; import buildbear from '../assets/img/buildbear.svg'; gsap.registerPlugin(ScrollTrigger); const Partner = () => { const partnerRef = useRef(null); useEffect(() => { const partner = partnerRef.current gsap.to(partner.children, { y: 0, stagger: 0.05, delay: 0.5, duration: 0.5, ease: "back.out", scrollTrigger: { trigger: partner, }, onComplete: () => { console.log("Partners animation") } }); }, []); return ( <div className='partner-container container-fluid d-flex'> <div className='partner-title col-md-5 d-flex align-item-center my-auto'> <h1 className='mx-auto d-flex flex-column' ref={partnerRef}> {Array.from("PARTNERS").map((letter, index) => ( <div key={index} className="letter">{letter}</div> ))} </h1> </div> <div className='partner-content col-md-7 d-flex my-auto'> <span> <img src={push} alt='push-protocol' /> <p className='partner-text mt-5'>Push Protocol</p> </span> <span> <img src={shardeum} alt='shardeum' /> <p className='partner-text mt-5'>Shardeum</p> </span> <span> <img src={buildbear} alt="build bear" /> <p className='partner-text mt-5'>Build Bear</p> </span> </div> </div> ); } export default Partner; partner.css: .partner-container { background-color: black; color: white; height: 70vh; width: 100%; display: flex; align-items: center; flex-direction: column; } .partner-title { align-self: flex-start; padding-left: 3.5rem; } .partner-title h1 { font-size: 7rem; width: 100%; font-weight: bold; display: flex; clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%); } .partner-title h1 div { transform: translateY(140px); transition: transform .5s; } .partner-content { display: flex; align-items: center; justify-content: space-evenly; width: 100%; } .partner-content img { width: auto; height: 150px; margin: 0px 50px; padding: 0px 0px; } .partner-text { font-size: 1.2rem; font-weight: 600; padding: 0; justify-content: center; text-align: center; width: 100%; } /* .partner-title h1 .char{ transform: translateY(140px); transition: transform .5s; } */ @media screen and (max-width:800px) { .partner-title h1 { font-size: 3.5rem; } .partner-title { padding-left: 2rem; } .partner-content { flex-direction: column; gap: 3rem; } .partner-content img { margin: 0; height: 100px; } } I am ready to provide other details please check
  23. Hello! It’s great to see your enthusiasm for GSAP, React, and route transitions. 😊 The StackBlitz link you shared provides simple examples for setting up animated page transitions in React using GSAP, React Router, and React Transition Group. It’s an excellent starting point for anyone diving into this exciting combination of technologies. The main concept is there, even if it’s a work in progress. For those interested, the link demonstrates how to create smooth transitions between different routes in a React app. By leveraging GSAP’s animation capabilities and integrating them with React Router and React Transition Group, you can achieve delightful page transitions. If you’re looking for more examples or have questions, feel free to explore the provided link. And stay tuned for additional news and examples related to GSAP + React (NextJS/Gatsby)! Happy tweening! 🚀🎉
  24. Hi! If I switch pages within the same namespace, with a async page-transition in between, the delay time I assign to the timeline for this namespace doubles. This only happens when I switch between pages in the same namespace and not between pages in different namespaces. Does anyone have an idea how I can solve this? I appreciate any help you can provide. Thanks!
  25. @Rodrigo Thanks for providing this approach for page transitions in React I'm finding it really helpful in my learning. I was wondering is there a simple way to make it execute the enter and exit transitions at the same time? That's the part I can't figure out as it seems to have to run the exit first, then run the enter transition. Thanks!
×
×
  • Create New...