Search the Community
Showing results for 'page transition' in content posted in GSAP.
-
I’m building route transitions in a React/Vite portfolio app (React Router + GSAP). I’m trying to reproduce a very specific motion style (I attached a reference video): one continuous incoming-page transition that feels like: slow creep (0–20%) fast whip (20–76%) very slow settle (76–100%) Animation requirements: incoming page: yPercent: 100 -> 0 opacity: 0 -> 1 one GSAP tween only (no keyframes, no chained phase tweens) custom ease curve for the 3-phase feel Current issue: If I enforce obvious 3-phase behavior, I get visible stutter/gear-shift feeling at speed changes. If I smooth it aggressively, it becomes almost one uniform speed and loses the creep/whip/settle character. In some iterations I also get end snapping/jank near completion. What I already did: gsap.set initial state before tween start (yPercent: 100, opacity: 0) one tween on a dedicated wrapper (gsap.to(...)) no layout props animated, only transform + opacity force3D: true, will-change: transform, opacity removed CSS transitions from animated element (transition: none) route swap only on onComplete gsap.killTweensOf before creating a new tween guard against duplicate/StrictMode double runs (run-id + active tween ref) Does somebody maybe have a code suggestion or any idea how to tackle this? 05803f59-64fd-4235-8196-da7197e2439f.mp4
-
Yeah, without a minimal demo it's almost impossible to troubleshoot but here are a few ideas off the top of my head: I wonder if you're setting up the ScrollTriggers in the wrong order. You should either create them in the order they actually occur on the page -OR- use refreshPriority to determine their order (see the docs). Do you have scroll-behavior: smooth on the page? Definitely avoid that because it's sorta like applying a CSS transition to something that GSAP is animating; when GSAP tries to set a value, the browser is like "NOPE! I'll do that gradually over time". ScrollTrigger needs to temporarily (and invisibly) set the scroll position of the page to 0 when refreshing, so if you've got scroll-behavior: smooth, that'll cause the browser to refuse to change the scroll when ScrollTrigger tells it to. Other than that, if you want more help you'll need to provide some kind of minimal demo so we can see exactly what's going on and tweak the code ourselves to see the results (CodePen or Stackblitz are perfect for this).
-
Im using GSAP's starter template for React page transition, and since it's using React transition group, I'm wondering how can we add scope, so we can target other elements inside page and not just root element? As you can see Im animating out boxes from the first page. Also I tried to do .revert() of timeline in this demo, is this the right way? It works but not sure if Im doing something wrong. Demo: https://stackblitz.com/edit/react-acgvpim9?file=src%2Frouter%2FRouter.js,src%2Fcontext%2FTransitionContext.js,src%2Fcomponents%2FTransition.js,src%2Fviews%2FBoxes.js Thanks
-
dynamically updating the scrollTrigger endpoint based on a non-scrubbed video duration
Benjamin Anderson posted a topic in GSAP
Hi, I've been practicing my gsap skills over the last couple days. Very power and fun to work with. I've run into an issue with timing a video though. Currently my project has two video streams. One video play's immediately in my hero section, called: "heroVideo" The second video plays as I'm scrolling away from the hero page to the next section called: "transitionVideo" In order to switch smoothly between the two videos I create two video elements in the DOM. They are stacked. When the user starts to scroll, I use the ScrollTrigger OnEnter event to swap the display properties on the elements. Makes it pretty smooth actually. Here is where things start going off the rails.... My issue happens because I want to have a certain amount of the transition video play before moving on to the next section with an animation (an overall fade of the hero section). By now you're thinking: "well that's easy, man! scrub the transition video into the animation based on the position of the next section in the window". I have indeed tried to scrub the video into the next section; however, I ran into a very choppy, and laggy experience. I thought maybe it was the frame rate of the video, or the aspect ratio. But still, no joy :( But wait! That's not all I tried! I thought, maybe I should extract frames from the transition video using ffmpeg, then instead of loading a video, I draw the frames on a "canvas". I could then have ScrollTrigger draw the transition frame by frame on the canvas YES! this works! 💥 But... (there is always a "But") the frames drawn on the canvas seem to be color shifted... red. After some research online, apparently this is common when comparing an image frame of a video drawn on an html canvas, and the frame being played in a video element. Side note: Whoa! I didn't realize that... But then... who actually wakes up in the morning and asks that the question: "What is the RGBA color shift percentage between an image drawn to an HTML canvas and video element?" <-- what a geek! 🤓 I will attach the canvas code, just in case anyone is actually interested in how I got it working. Some of it is taken form the GSAP github, with some alterations "avec moi!": imageSequence({ urls, // Array of image URLs canvas: "#scroll_animation", // <canvas> object to draw images to //clear: true, // only necessary if your images contain transparency //onUpdate: (index, image) => console.log("drew image index", index, ", image:", image), scrollTrigger: { start: 0, // start at the very top end: "+=6000", // 6000... uh px?? scrub: 20, // important! pin: true } }); //Good grief this took a long time to figure out! //this one seems to mimic a video contains well enough function drawContain(img, ctx, canvas) { let hRatio = canvas.width / img.width; let vRatio = canvas.height / img.height; let ratio = Math.min(hRatio, vRatio); let xShift = (canvas.width - img.width * ratio) / 2; let yShift = (canvas.height - img.height * ratio) / 2; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, 0, 0, img.width, img.height, xShift, yShift, img.width * ratio, img.height * ratio); } //Yeah this too.. geesh function drawCover(img, ctx, canvas) { let hRatio = canvas.width / img.width; let vRatio = canvas.height / img.height; let ratio = Math.max(hRatio, vRatio); let xShift = (canvas.width - img.width * ratio) / 2; let yShift = (canvas.height - img.height * ratio) / 2; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, 0, 0, img.width, img.height, xShift, yShift, img.width * ratio, img.height * ratio); } //returns the tween for in the canvas function imageSequence(config) { let playhead = { frame: 0 }, canvas = gsap.utils.toArray(config.canvas)[0] || console.warn("canvas not defined"), ctx = canvas.getContext("2d"), curFrame = -1, onUpdate = config.onUpdate, images, updateImage = function () { let frame = Math.round(playhead.frame); if (frame !== curFrame) { // only draw if necessary config.clear && ctx.clearRect(0, 0, canvas.width, canvas.height); drawContain(images[Math.round(playhead.frame)], ctx, canvas); curFrame = frame; onUpdate && onUpdate.call(this, frame, images[frame]); } }; images = config.urls.map((url, i) => { let img = new Image(); img.src = url; i || (img.onload = updateImage); return img; }); return gsap.to(playhead, { frame: images.length - 1, ease: "none", onUpdate: updateImage, duration: images.length / (config.fps || 30), paused: !!config.paused, scrollTrigger: config.scrollTrigger }); } So, what I have done then is the following: 1. load the heroVideo 2. wait for user to start ScrollTrigger 3. onEnter, swap video elements display properties, and play the transition video 4. delay a fade animation 5. scroll to section two, snap and pin Note: The fader is an absolute element with opacity:0 just sitting on top which animated to opacity:1. let scroll = gsap.timeline({ scrollTrigger: { trigger: ".section_2_inner", start: "top-=3000 bottom", scrub: 20, ///markers: true, onEnter: () => { transitionVideo.currentTime = 0; // Hide hero video instantly gsap.set(heroVideo, { display: "none" }); // Show transition video gsap.set(transitionVideo, { display: "block" }); transitionVideo.play(); heroVideo.currentTime = 0; gsap.timeline().to(".wrapper", { transform: "scale(2)", filter: "blur(6px)", opacity:0, ease: "power2.out", }) // Fade in fader after 3s .to(".fader", { opacity: 1, ease: "power2.out", delay:3 },"<"); // Pause hero video heroVideo.pause(); }, onLeaveBack: () => { // Reset videos transitionVideo.currentTime = 0; heroVideo.currentTime = 0; heroVideo.play(); gsap.timeline().to(".wrapper", { transform: "scale(1)", opacity:1, filter: "blur(0px)", ease: "power2.out" }) // Fade out fader .to(".fader", { opacity: 0, ease: "power2.out", }); // Hide transition video gsap.set(transitionVideo, { display: "none" }); // Show hero video gsap.set(heroVideo, { display: "block" }); } } }); This works, but let's face it, there is no control here, and if the user scrolls too fast, everything is missed. I've seen the YT videos, and the CodePens where other devs have insane transitions, allowing the user full control. I want to do that! Nothing is better than giving the user the feeling of control of application. Can I somehow update the scroll endpoint dynamically? Maybe using the ScrollTrigger.proxy? Thanks for any input, comments, or ideas. Links, articles, or code examples... Thanks, and have a lovely day, Ben -
GSAP SplitText Not Visible After Barba.js Page Transition - Need Help Hi GSAP Community, I’m quite new to GSAP and Barba.js, and I’ve run into an issue I can’t seem to solve. Everything else works perfectly, but the GSAP SplitText animation just doesn’t become visible as expected after transitioning to the new page. Context: I’m using Barba.js for smooth page transitions and GSAP SplitText to animate text on my project pages. When transitioning from one page to another, I want to trigger a SplitText animation that animates the text character by character. The image animation works just fine, and the page transitions themselves (in and out) are smooth, but for some reason, SplitText doesn’t display the animated text even though the animation runs (I can see the logs in the console). This is my Read-Only-Link: https://preview.webflow.com/preview/portfolio-81ef14?utm_medium=preview_link&utm_source=designer&utm_content=portfolio-81ef14&preview=747b7b5ad79fb03ec0425ecc1111ba19&workflow=preview I attached a Video that shows the Issue. Example.mov <!-- Include GSAP, ScrollTrigger, and SplitText --> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/ScrollTrigger.min.js"></script> <script src="https://cdn.prod.website-files.com/66fd5dee766f9835d57167dd/671a387c610c8e295f8bdc44_SplitText.txt"></script> <!-- Include Barba.js --> <script src="https://unpkg.com/@barba/core"></script> <script> // Function to initialize GSAP animations for the new content function initGSAP() { console.log("Initializing GSAP Animations..."); // Set initial opacity and position for text and image before the animation gsap.set("#main-text", { opacity: 0, y: 50, visibility: "visible" }); gsap.set(".portfolio-header7_image", { opacity: 0, y: 100, visibility: "visible" }); // SplitText animation: animate character by character if (document.querySelector('#main-text')) { if (typeof SplitText !== "undefined") { let splitText = new SplitText("#main-text", { type: "chars, words" }); console.log("SplitText successfully loaded and split:", splitText); // Animate the split characters gsap.to(splitText.chars, { opacity: 1, y: 0, // Text comes up from below stagger: 0.05, // Delay between characters duration: 1, ease: "power2.out" }); } else { console.error("SplitText could not be loaded."); } } // Image animation: opacity and position from below if (document.querySelector('.portfolio-header7_image')) { gsap.to(".portfolio-header7_image", { opacity: 1, y: 0, duration: 1, ease: "power2.out" }); } // Refresh ScrollTrigger to ensure new triggers are set correctly ScrollTrigger.refresh(); } // Kill all ScrollTriggers when leaving a page function killScrollTriggers() { ScrollTrigger.getAll().forEach(trigger => trigger.kill()); } // Barba.js initialization barba.init({ preventRunning: true, transitions: [ // Transition from Home to Project page { sync: true, from: { namespace: ["home-page"] }, leave(data) { return gsap.to(data.current.container, { opacity: 0, scale: 0.9, duration: 0.8, ease: "power2.inOut" }); }, enter(data) { $(data.next.container).addClass("fixed"); return gsap.fromTo( data.next.container, { opacity: 0, scale: 0.9 }, { opacity: 1, scale: 1, duration: 0.8, ease: "power2.inOut", onComplete: () => { $(window).scrollTop(0); $(data.next.container).removeClass("fixed"); resetWebflow(data); // Reset Webflow interactions after the page switch initGSAP(); // Initialize GSAP animations after the page switch } } ); } }, // Transition from Project page back to Home { sync: true, from: { namespace: ["project-page"] }, leave(data) { killScrollTriggers(); // Stop ScrollTrigger when leaving the page return gsap.to(data.current.container, { opacity: 0, scale: 0.9, duration: 0.8, ease: "power2.inOut" }); }, enter(data) { $(data.next.container).addClass("fixed"); return gsap.fromTo( data.next.container, { opacity: 0, scale: 0.9 }, { opacity: 1, scale: 1, duration: 0.8, ease: "power2.inOut", onComplete: () => { $(window).scrollTop(0); $(data.next.container).removeClass("fixed"); resetWebflow(data); // Reset Webflow interactions after the page switch initGSAP(); // Initialize GSAP animations after the page switch } } ); } } ] }); // Function to reset Webflow interactions after a page switch function resetWebflow(data) { let parser = new DOMParser(); let dom = parser.parseFromString(data.next.html, "text/html"); let webflowPageId = $(dom).find("html").attr("data-wf-page"); $("html").attr("data-wf-page", webflowPageId); window.Webflow && window.Webflow.destroy(); window.Webflow && window.Webflow.ready(); window.Webflow && window.Webflow.require("ix2").init(); } // Use Barba.js hooks to re-initialize GSAP after page transitions barba.hooks.afterEnter((data) => { initGSAP(); // Start GSAP animations after the page switch }); </script> What works: • Barba.js transitions work fine, both in and out animations are smooth. • Image animations (opacity and position changes) run as expected after the page transitions. • Webflow interactions reset correctly after the page transitions. What doesn’t work: • SplitText animations are not visible. The code runs, I can see the logs (SplitText successfully loaded and split), but the text remains hidden or not animated. I’ve tried different things, like setting the initial visibility and opacity with GSAP, but nothing seems to make the text visible. What I need help with: • I’m not sure if it’s an issue with how Barba.js handles the page transition or if I’m missing something about how SplitText should be initialized and animated. • Is there anything I should be aware of regarding timing, DOM readiness, or visibility when using SplitText with Barba.js? • Any insights from the GSAP pros on what I might be missing or doing wrong would be hugely appreciated!
-
Hi, I was looking for an example for mount and unmount animations in react. I stumbled upon your React examples. https://stackblitz.com/edit/react-6rzfpp?file=src%2Fcomponents%2FTransition.j I read your guide for React and the useGSAP hook. It says you should create all the animations using `contextSafe` function so it gets cleaned up after component unmounts. But in your example you directly call gsap in Transition callbacks without any context safety. Was that intentional? I am confused.
-
Hey GSAP Community, I'm currently working on a page transition using GSAP's flip plugin, and I'm encountering an issue where the element seems to "jump" from a lower position during the transition, which affects the UX. I'm using Barba.js for page transitions, and GSAP/Flip are used to animate the transition. The element in question is cloned and moved to a new container during the transition. I've attached a video that better explains my problem, and here's my JavaScript code that handles the transition. If you need more elements (HTML content, styles), don't hesitate to let me know! gsap.registerPlugin(ScrollTrigger, CustomEase, Flip); const $ = (el) => document.querySelector(el) let scroll; const BASIC_DURATION = 1.2; let transitionOffset = 1100; let staggerDefault = 0.07; CustomEase.create("primary-ease", "0.42, 0.1, 0.05, 0.89"); CustomEase.create("primary-ease-out", ".34, 1.56, 0.64, 1"); function leaveWorkSingle(container) { const tl = gsap.timeline({ default: { duration: BASIC_DURATION, ease: "primary-ease" } }) let transitionElements = document.querySelector('.transition-work-single'); let transitionElementsFooterImage = transitionElements.querySelector('.img-next'); let cloneTransitionElements = transitionElements.cloneNode(true); let transitionElementsNewContainer = document.querySelector('.transition-work-single-container'); let transitionElementsOldContainer = document.querySelector('.transition-work-single-old-container'); let transitionElementsState = Flip.getState(".transition-work-single"); transitionElementsNewContainer.classList.add('transitioning'); transitionElementsNewContainer.appendChild(transitionElements); transitionElementsOldContainer.appendChild(cloneTransitionElements); tl.set('main.main', { autoAlpha: 0 }) tl.add(Flip.from(transitionElementsState, { ease: "primary-ease", duration: 1.2, absolute: true, }), 0.5); tl.set(cloneTransitionElements, { autoAlpha: 0 }); } function enterWorkSingle(container) { // todo const tl = gsap.timeline({ default: { duration: BASIC_DURATION, ease: "primary-ease" } }) tl.set('main.main', { autoAlpha: 1, onComplete: () => { console.log('done') let r = $('.transition-work-single-container.transitioning .transition-work-single') console.log(r) r.remove() } }) } function delay(n) { n = n || 2000; return new Promise((done) => { setTimeout(() => { done(); }, n); }); } function initLenis() { scroll = new Lenis({ duration: 1 }) scroll.on('scroll', ScrollTrigger.update) gsap.ticker.add((time) => { scroll.raf(time * 1000); }) gsap.ticker.lagSmoothing(0) } function initTransitions() { history.scrollRestoration = "manual"; barba.hooks.afterEnter(() => { window.scrollTo(0, 0); ScrollTrigger.refresh(); }); barba.init({ sync: true, debug: false, timeout: 7000, transitions: [ { name: 'from-to-work-single', from: { namespace: ['work-single'] }, to: { namespace: ['work-single'] }, async leave(data) { leaveWorkSingle(data.current.container); await delay(1700); }, async enter(data) { enterWorkSingle(data.next.container); }, async beforeEnter(data) { // ScrollTrigger.getAll().forEach(t => t.kill()); initSmoothScroll(data.next.container); // initScript(); }, } ] }); function initSmoothScroll(container) { initLenis(); ScrollTrigger.refresh(); } } initTransitions(); Thank you in advance for your help. w_ybkKeqbJ.mp4
-
Page transition with xPercent property breaks ScrollTrigger and fixed elements (next.js)
laeioun posted a topic in GSAP
I am experiencing an issue with ScrollTrigger and fixed elements breaking after a page transition that uses a gsap timeline to animate xPercent. I am able to avoid it using an animation that doesn't animate xPercent, but then I'm only able to achieve a crossfade transition with opacity. What might be causing this? Is this just a fact of what happens to fixed elements when we animate the entire page? template.tsx which sits between layout and children (see next docs): "use client" import gsap from 'gsap' import { useGSAP } from '@gsap/react' import { animatePageIn } from './utils/animations' export default function Template({children}: Readonly<{children: React.ReactNode}>) { gsap.registerPlugin(useGSAP); useGSAP(() => { animatePageIn(); }, []); return children; } TransitionLink.tsx component: "use client" import { usePathname, useRouter } from "next/navigation" import { animatePageOut } from "../../utils/animations" interface Props { href: string } const TransitionLink = ({ href, children }: Props & { children: React.ReactNode }) => { const router = useRouter() const pathname = usePathname() const handleClick = () => { if (pathname !== href) { animatePageOut(href, router) } } return ( <div onMouseDown={handleClick} > {children} </div> ) } export default TransitionLink animatePageIn animation that causes the issue: export const animatePageIn = () => { const homePage = document.getElementById("home-page"); const servicesPage = document.getElementById("services-page"); if (homePage) { const tl = gsap.timeline(); tl.set(homePage, { opacity: 0, xPercent: 100, }).to(homePage, { opacity: 1, xPercent: 0, ease: "power1.out", }); } if (servicesPage) { const tl = gsap.timeline(); tl.set(servicesPage, { opacity: 0, xPercent: -100, }).to(servicesPage, { opacity: 1, xPercent: 0, ease: "power1.out", }); } } TransitionLink on one of my pages: <TransitionLink href="/services"> <div> <p>explore the possibilities</p> </div> </TransitionLink> -
Hi, I am building a portfolio inspired by this design https://jorisbrianti.fr/. I tried my best to do the page transition, But I can't acheive that buttery smooth animation of that transition. Can any one help me? Thanks and regards.
-
Thanks for the reply! I think we all get the idea of what's to be achieved. It's likely my fault, but I don't think my demo comprehensively illustrates the problem I'm running into. So I've adapted it to include more of the logic that I'm working with in my live project. https://codepen.io/tonycre8-the-bold/pen/EaPxLVq The idea is that we move all the sections off of the screen and force the user to the top when they click the toggle, then by bringing those back in at the end of the transition, I'd like to reset those animations so that they can be replayed. So the expected behaviour for the CodePen is the following: -> You scroll past the first box. The animation plays once. It cannot play again, even if you scroll to the top of the page and try to get it to trigger again. -> You click the toggle. Now all the elements animate out off the screen and back in again. During this transition, all ScrollTriggers are disabled. At the end of the transition, all ScrollTrigger's are reset and enabled again. -> You scroll past the first box again. Because we've reset the ScrollTrigger's by means of the transition, the animation plays once. However, it's that last step in particular that I can't achieve. Because I can't figure out how to reset the progress of the ScrollTriggers, I can't reset the animations for them to play again when we scroll past. Hopefully this demo illustrates my issue a bit better and we're able to figure this out!
-
Hi, I have created this page transition in my next.js app router, Now it works perfectly fine, However if i click on a link in navigation while the animation is running, it breaks the styling of pages, I found .revert() which will work , but instant reset of styling will lead to bad user experience, so what is before the new page animation to play is to wait for all the other animations to finish before starting, my page transition is exactly like this website:https://hagisbarbershop.de/, it just breaks if I change pages mid animation or too fast. page.jsx
- 2 replies
-
- page transition
- next js
-
(and 1 more)
Tagged with:
-
Hi, I have implemented horizontal scrolling on a component, and it works perfectly. However, if I add a page transition, the horizontal scrolling glitches and does not start properly. I checked the markers, and it seems that the triggering start shifts to the bottom of sectionRef,or 100vh lower instead of the top of section, which is how it should behave. Please try the horizonal scroll with page transition and without it, to see how it should work. You can comment the function in useGsap on page.jsx. Any improvements you can do to horizontal scroll would be appreciated:) what I found: The problem is related to the pin property, but it is necessary to keep, for functionality. The issue that pin spacer does not shift up with the other components it does not change it's position. here is the stackbiltz demo: https://stackblitz.com/edit/stackblitz-starters-61byf2?file=app%2Fpage.jsx
-
Hello, I am trying to recreate the interaction on this website: https://studiod.nu/projecten/witsen-site/, where the user is seamlessly redirected to the next page after scrolling to the bottom. I have created a simple prototype here: https://gsapflippage.netlify.app/#talents (only "Talent 1" has the functionality implemented). I have a few questions: Is GSAP Flip properly utilised in my prototype? Do I need another plugins such ScrollTrigger to achieve desired interaction? I aim for a seamless and smooth animation where the user barely notices the transition. Is FLIP the right choice for this? (You may notice a placement mismatch on the talent page that I need to address). Is triggering the next page based on scrolling to the "bottom" the best approach? Are there any alternative methods I should consider? Is it necessary to implement a page transition to achieve a smoother user experience? If so, what are some recommended practices or techniques? Thank you in advance for your feedback and guidance.
-
Nuxt3 Page Transitions - scroll jumping to top before page transition.
Windpixel posted a topic in GSAP
Working on Nuxt3 Page Transtions and want to the scroll position to be retained on the .page-transition-leave-active element. Currently if you scroll down from the top position, navigate to a new route, the page snaps to the top position before routing. https://stackblitz.com/edit/nuxt-starter-ncqyhu?file=pages%2Findex.vue To recreate the issue in the Stackblitz Min Dem. 1.) Go to the "ScrollTrigger" Route. 2). Scroll to the bottom (Orange Section) 3.) Click on the Layers Section Route. The orange section will snap to the blue (first section on the page), then animate out. A couple of things to assist. I have added the below css to allow the entering and leaving "pages" to overlap, creating more of a seamless transition. So this may play a role. .page-transiton-enter-active { position: fixed; height: 100%; width:100%; top:0; left:0; right:0; bottom:0; z-index:9; } .page-transiton-leave-active { position: fixed; height: 100%; width:100%; top:0; left:0; right:0; bottom:0; /* z-index:4; */ } I have also set the pageTransition mode property to null, this allows the enter/exit pages to be in the DOM at the same time const pageTransition = { name: 'page-transiton', // mode: '', onEnter: (el, done) => { Lastly, in my project I am using scrollSmoother, but was able to recreate the issue without S.M. Although, not sure if SM could be used as a tool to fix the issue. <template> <div id="smooth-wrapper" ref="wrapper"> <div id="smooth-content" ref="content"> </div> </div> Thanks in advance -
Hello there, Im trying to achieve a specific page transition using nuxt 3 and gsap. I saw the starter code of a simple page transition when you define a custom transition in a seprate file and import it in every page using definePageMeta function and the specify the pageTransition to the one you defined and it work, however i want a specific pattern. I'm going to explain my situation using tailwindcss What I'm trying to achieve is this: Make a page transition that have a div initially with 'absolute w-full h-full bg-black top-0 left-0 ' so this div is covering the hole page even the default layout. On onEnter i want to translateY by -100% so the page and the layout is visible. On onLeave set translateY by 100% then animate translateY by -100% ... This easely achievable using gsap However the implementation in nuxt 3 is hard i think, i couldn't do it because in the page transition if i the definePageMeta the el the return in the onEnter or onLeave is the root of the page ex: index.vue And if i add and another div in index.vue i got an error about the Transition component can't do animation if there is not one root element , i tried to make a seprate component for the transition and add this component inside every page however the animation did not triggered for the onEnter and onLeave methods when change routes using the NuxtLink component or use router.push('url'), i don't know where is the problem, if anyone knows how to do this, please help, Visit Dennis website and try to change routes you will understand what i want to achieve. And thank
-
Would this very cool page transition be possible without Canvas (threejs)? See video, and https://lamalama.nl/ I want to create a similar effect, I also want to use these blobs to create a text box where the text will appear. I hope it's possible with CSS animation or with SVG for example. I tried a couple of ways but can't replicate it.. Page transition.mp4
-
Hello, I'm doing a website and wanted to implement some page transitions. The goal would be to implement something like this - https://allhero.co.jp/. I already managed to do something similar, the entry animation* is what I intend. The output* is still not what I want because I got stuck in an error that happens during the animation. When I run the first time, it performs as I want, but when I run it again, there is one step it fails to do, and I can not figure out why. The step that does not seem to run is this, and jump straight to the set. transitionPage.to(transitionElement, 1, { left: '200%' }, 2 ); Entry animation* transitionPage.to( transitionElement, .8, { left: 0 } ); transitionLogo.from( transitionElementLogo, .5, { autoAlpha: .1 } ); transitionLogo.from(transitionElementLogo, .6, { scale: 5, transformOrigin:'100% 0' } ); Output animation* transitionPage.to(transitionElement, 1, { left: '200%' }, 2 ); transitionPage.set(transitionElement, { clearProps : 'left'}, '+=2'); transitionLogo.set(transitionElementLogo, { clearProps : 'autoAlpha, scale'}); I'm now starting to work with gsap. Any suggestion?
-
I want to make this kind of animation in Gsap and Pixijs, is there any way to do it? Click on the play button and it will zoom to the home screen background, then that zoom area will be the background of the game scene. https://barbajs-gsap-yar.webflow.io/
-
Hi Crew, I have slightly modified the existing stackblitz for Nuxt3/GSAP but simplifying the animation to one tween in and out for simplicity. Im trying to achieve a seamless side to side transition where effectively both the out animation and the in animation occur at the same time. I can achieve this effect with css only, but really want GSAP for the flexibility. I have tried playing around with the hooks, but cant get it to work. I think they hooks are right. https://stackblitz.com/edit/nuxt-starter-d3iqbd?file=helpers%2FtransitionConfig.js Thanks in advance.
-
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", }); };
-
Hey, this question is not directly related to GSAP but I thought you guys might have some good insight about this: I'm trying to create a page transition similar to this site: https://vucko.co/ but I struggle to find a way to make the page transition seamless so that the previous & next page are visible at the same time for a brief moment, this creates the effect that the page never changes while the next page is transitioning from bottom to top. My main problem is that when I create a javascript transition with Nuxt & GSAP the previous page has to go away before the next one even has a chance to be visible. I'm not an expert with page transitions so I might be missing something fundamental here. Here is a basic demo of a Nuxt transition setup I have been using: https://stackblitz.com/edit/nuxt-starter-lq1ckq?file=helpers%2FtransitionConfig.js
-
Hi Guys. This should be a very straight one. So i have this animation that uses scroll trigger and pinned the page. Pretty smooth with no issue. Check it out https://stackblitz.com/edit/circle-scroll-trigger?file=src%2FApp.js Now i have another project that uses React page transition. So i added the above animation to the scroll trigger page. Check it out here https://stackblitz.com/edit/react-spyzevefwe?file=src%2Fviews%2FScroll.js The issue comes when i switch between pages and i tried to scroll down to the animation, It just disappeared. But if i refresh the page, everything works fine. I think the page transition is interfering with the scroll trigger animation. Appreciate all the help i can get. Thanks.
-
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!
-
ScrollTrigger pin breaking on using react-transition-group page transition in Next js
CuteAppi posted a topic in GSAP
On clicking the link scrollTrigger in the below error demo and scrolling the section is not being pinned but on manually refreshing the page the it is getting pinned and works fine, on removing any transition animations the pin works as well still works. Here's a link to the same error that I replicated. https://stackblitz.com/edit/nextjs-rdx4ro?file=pages%2Fscroll.js P.S I am a gsap noob and im still learning- 4 replies
-
- nextjs
- scrolltrigger
- (and 6 more)
-
Hi guys. Here is a starter code provided by GSAP team on Page Transition with NextJS https://stackblitz.com/edit/nextjs-13cw4u?file=components%2FTransition.js I however discovered that it doesn't work with NextJS app router but works with page router. In app router, the exiting route and the entering route is always the same thing. I will appreciate if someone can create a template for this page transition using App Router. Thanks