Jump to content
Search Community

All Activity

This stream auto-updates

  1. Past hour
  2. Hello! I am developer and have been writing CSS for longer than I care to remember. Actually started with tables back in the 90's. I'm building a creative agency website (my own) and have been working on integrating GSAP and Locomotive Scroll. Some things that should seemingly be simple are giving me a tough time. For example, I want to have a sticky header where the logo and nav switches out after scrolling down the page. Maybe a couple "pinned" animations as well. Just simple effects for someone who knows what they are doing. Our site build in in WordPress, but I can send static code for this project and then re-integrate with WordPress later. We will be able to provide the coded homepage layout with all graphics, content etc. Just need help with the animation aspects of it. Would love to work with someone who is an expert, especially with GSAP and Locomotive. Locomtive V5 is in beta and we are open to using that (might even be preferred). Thanks in advance!
  3. Today
  4. Hello, thanks for the help. Though i get the concept on the basic slider using vanilla, now, I wanna apply gsap animations to it like every change or slide of image, there's an easing or some effect. and at the end, it will go back directly to the 1st slide, not sliding from end to start. Because, this is the animation I want to achieve for the hero section: https://www.resortkaskady.com/ here's my fiddle: https://jsfiddle.net/9zmuqgxe/62/ or how to wrap this line: slide.style.transform = `translateX(-${counter * 100}%)`; so that I can animate this. Cheers, Louie V.
  5. Hi, I am using ScrollSmoother.js on my website. I have sticky elements inside the main wrapper, which I cannot place outside. How can I mitigate this? Thank you, Adrian
  6. Are you using that approach in your layout file in astro? In your demo I don't see that. That basically seems to be something Astro is doing behind the scenes. ScrollSmoother works without any issues with Next, Nuxt, SvelteKit and other SSR systems. If with that approach it doesn't work honestly IDK what to tell you. Sorry I can't be of more assistance. Happy Tweening!
  7. My case if of course far more complex, but I never thought about this notion of progress. I will play with this. But note that the difficulty in my case is to add a new sibling after the one that is already animated (appearing with opacity for instance) and make it as such it joins the movement. I'm afraid that whatever solution if found, getting my async data and adding the new DOM node takes time and therefore will have a bad effect on the ongoing animation, making it jerky. I'm traveling during a few days, so will come back on this in the middle of next week. Thanks for all.
  8. Hi, Maybe something like this: https://codepen.io/GreenSock/pen/mdYeGQr Hopefully this helps. Happy Tweening!
  9. Hi, Maybe these demos can help: https://codepen.io/GreenSock/pen/BamxvZW https://codepen.io/GreenSock/pen/qBryorx Hopefully this helps. Happy Tweening!
  10. Yesterday
  11. Yes, I know, the problem I'm facing is exactly that. With viewTransition, it doesn't work, but without it, ScrollSmoother works perfectly. However, viewTransition is an important part of the site's flow and design.
  12. Gotcha - thanks for the super duper quick response. Y'all rock!
  13. Pseudo elements are not accessible to JavaScript. That's a browser limitation, unrelated to GSAP. Usually a good workaround is to use CSS variables (GSAP can animate those), but that might be tricky for a drawSVG effect. If you can use a normal element, that's probably best.
  14. https://codepen.io/alananal/pen/dyEYjdq I'm trying to create a logo for my website. Ideally, I would like all four letters to liquid-morph into a single blob, which then morphs into a fist. Doesn't have to be in two stages. Currently, they morph but not in a sleek or natural way. Letters 'F' and 'I' shrink and disappear, while the rest is also just meh. As you can see, I've played with shapeIndex, type, map, origin. Nothing gave me the desired result. Do you have any tips or recommendations? Thank you in advance.
  15. Hi, I am trying to use drawSVG on a ::before pseudo element, is this possible? Thank you!
  16. Thank you for the reply. For some reason, the elastic animation is not as smooth as the original. I'm gonna play with it some more.
  17. One other guess: make sure you register the useGSAP hook and ScrollTrigger: gsap.registerPlugin(useGSAP, ScrollTrigger);
  18. I've come up with a solution but it's probably not very elegant or DRY. https://codepen.io/1976ltd/pen/qBGOygM
  19. Rodrigo! I'm trying to scroll to my green container once I have reached the bottom of the red one. But I need to disable the scroll for the user, so it doesn't mess with the GSAP animation. Is it possible?
  20. I know, the idea is a way to enable/disable or destroy/create the ScrollSmoother instance on a route change. My objective is to share that particular approach, give you an idea of how to proceed: import ScrollTrigger from "gsap-trial/ScrollTrigger"; import ScrollSmoother from "gsap-trial/ScrollSmoother"; import {gsap} from "gsap" gsap.registerPlugin(ScrollTrigger, ScrollSmoother); const constructScroller = () => { ScrollSmoother.create({ smooth: 1 }) } document.addEventListener("astro:page-load", constructScroller) document.addEventListener("DOMContentLoaded", constructScroller); Hopefully this helps. Happy Tweening!
  21. Thanks @Cassie. That seems to work really well in your video with the rotating boxes but in the Codepen when clamp is added the first h2 doesn't animate in. Is this something to do with it being a 'from' rather than 'to' tween?
  22. Hi, Your demo is not using ScrollTrigger, so I don't really know what you're trying to do here and how to implement Observer in your demo. You only have a Tween using the ScrollTo Plugin, so you can pause that tween and then resume it. Happy Tweening!
  23. Hi, The main concept in my demo is this: const createTween = () => { t && t.kill(); t = gsap .to(".box", { x: () => window.innerWidth - 20 - 75, // paddings & box width duration: 5, ease: "none" }) .seek(2.5) .timeScale(0); if (typeof currentProgress !== "undefined") { t.progress(currentProgress); } }; Basically you kill the instance (if is defined) and then, if the progress has been stored, you set the progress of the new instance. The key in the animation is getting the x value correctly based on the screen width and the width of the element. Hopefully this helps. Happy Tweening!
  24. Thanks @thehaes. This is a nice idea but I need this to work for multiple pages where sometimes the first h2 will be in the viewport on page load and sometimes it will be further down the page. Basically I want to have my cake and eat it, ie; each h2 should scrub animate on scroll but if it's already in the viewport it should animate automatically into place.
  25. Hello, I created an infinite vertical scroll like effect for my cards, it took a while but with the helps of forums and some demos, it worked perfectly for me on local. However, when I check production, I see that it's not working properly, cards are appearing small and origin seems like below, some cards get bigger some are not, and most ambiguous one is if i scroll up, animation works properly for like 4-5 cards, but when i scroll down card disappears immediately. I deploy with vercel and there is no club plugin as you can see. Can you please enlighten me about the issue? I suspected with some css conflict but couldn't find a way to solve it. It took my whole day and decided to ask some help here. Purpose of animation ( in case there is a much more basic or consistent way to do this ) -Avoid page scroll over container and avoid animation work when page is scrolled outside card container. -Give a seamless vertical scroll effect without showing any scroll bar. Stack: - Next14, Typescript, Vercel for deployment Thank you for your help. local.mov ``` import React, { useEffect } from "react"; import { gsap } from "gsap"; import { IWorkOption, workOptions } from "../../utilities"; import styles from "./card-container.module.css"; const scrollSpeedMultiplier = 0.0001; const CardContainer = ({ setItemSelected }: { setItemSelected: React.Dispatch<React.SetStateAction<IWorkOption>> }) => { useEffect(() => { const cards = Array.from(document.querySelectorAll(".single-one-pair")); const spacing = 0.1; const seamlessLoop = buildSeamlessLoop(cards, spacing, animateCard); const playhead = { offset: 0 }; const scrub = gsap.to(playhead, { offset: 0, onUpdate: () => { seamlessLoop.time(wrapTime(-playhead.offset)); }, duration: 0.5, ease: "power3", paused: true, }); function animateCard(element: Element) { const tl = gsap.timeline(); tl.fromTo(element, { scaleX: 0.8, scaleY: 0.1 }, { scaleX: 1, scaleY: 0.9, opacity: 1, duration: 0.5, yoyo: true, repeat: 1, ease: "power1.in", immediateRender: false }).fromTo( element, { yPercent: -400 }, { yPercent: 400, duration: 1, ease: "none", immediateRender: false }, 0 ); return tl; } function buildSeamlessLoop(items: Element[], spacing: number, animateFunc: (element: Element) => gsap.core.Timeline) { let rawSequence = gsap.timeline({ paused: true }), seamlessLoop = gsap.timeline({ paused: true }); items .concat(items) .concat(items) .concat(items) .forEach((item, i) => { let anim = animateFunc(items[i % items.length]); rawSequence.add(anim, i * spacing); }); seamlessLoop.fromTo(rawSequence, { time: spacing * items.length }, { time: `+=${spacing * items.length}`, duration: spacing * items.length, ease: "none" }); return seamlessLoop; } function wrapTime(offset: number) { return gsap.utils.wrap(0, seamlessLoop.duration())(offset); } const ulElement = document.querySelector(".pair-container"); function handleMouseEnter() { ulElement?.addEventListener("wheel", handleWheel as EventListener); ulElement?.addEventListener("touchstart", handleTouchStart as EventListener); ulElement?.addEventListener("touchmove", handleTouchMove as EventListener); ulElement?.addEventListener("touchend", handleTouchEnd as EventListener); scrub.play(); // Start the animation when the mouse enters } function handleMouseLeave() { ulElement?.removeEventListener("wheel", handleWheel as EventListener); ulElement?.removeEventListener("touchstart", handleTouchStart as EventListener); ulElement?.removeEventListener("touchmove", handleTouchMove as EventListener); ulElement?.removeEventListener("touchend", handleTouchEnd as EventListener); scrub.pause(); // Pause the animation when the mouse leaves } function handleWheel(event: WheelEvent) { event.stopPropagation(); event.preventDefault(); console.log("Wheel event deltaY:", event.deltaY); // Log deltaY for debugging scrub.vars.offset += event.deltaY * scrollSpeedMultiplier; // Adjust scroll speed as necessary scrub.invalidate().restart(false); } let touchStartY = 0; function handleTouchStart(event: TouchEvent) { touchStartY = event.touches[0].clientY; } function handleTouchMove(event: TouchEvent) { const touchEndY = event.touches[0].clientY; const deltaY = touchStartY - touchEndY; touchStartY = touchEndY; // Update the start position for the next move console.log("Touch move deltaY:", deltaY); // Log deltaY for debugging scrub.vars.offset += deltaY * scrollSpeedMultiplier; // Adjust scroll speed as necessary scrub.invalidate().restart(); event.preventDefault(); } function handleTouchEnd(event: TouchEvent) { touchStartY = 0; // Reset the touch start position } ulElement?.addEventListener("mouseenter", handleMouseEnter); ulElement?.addEventListener("mouseleave", handleMouseLeave); return () => { ulElement?.removeEventListener("mouseenter", handleMouseEnter); ulElement?.removeEventListener("mouseleave", handleMouseLeave); ulElement?.removeEventListener("wheel", handleWheel as EventListener); ulElement?.removeEventListener("touchstart", handleTouchStart as EventListener); ulElement?.removeEventListener("touchmove", handleTouchMove as EventListener); ulElement?.removeEventListener("touchend", handleTouchEnd as EventListener); gsap.killTweensOf(playhead); }; }, []); return ( <div className={styles.body}> <ul className="pair-container" style={{ width: "100%", height: "100%", display: "flex", alignItems: "center" }}> {workOptions.map((card, i) => ( <li key={i} className="single-one-pair" style={{ listStyle: "none", padding: 0, margin: 0, width: "100%", height: "80%", position: "absolute", display: "flex", justifyContent: "center", alignItems: "center" }} > <div key={i} className={styles.pairItem} style={{ backgroundColor: "red" }} onClick={() => setItemSelected(card)}> <div className={styles.overlay}> <h2 className={styles.overlayText}>{i}</h2> </div> </div> </li> ))} </ul> </div> ); }; export default CardContainer; ``` prod.mov
  26. thank you. this one seems to work but this isn't what I wanted to achieve. by default, all the boxes should show and when scrolling, the first box, scrolls to the back of the stacked card, and the second card becomes the current. the active box is always on top of the blurred card and the inactive boxes are beneath or at the back of the blurred card. that's what I want to achieve. sorry for the late response as well
  27. Hi, The video link is going 404, so there is nothing to see there. The only thing is that something else is creating an issue, unfortunately without a minimal demo that clearly illustrates the issue is really hard for us to find the problem. On top of that I strongly recommend you to not animate the same element you're using as a trigger and pin on ScrollTrigger: gsap.to("#voting", { scrollTrigger: { trigger: "#voting", pin: "#voting", start: "top top", end: "bottom top", }, }); Here you can find our React and Next collections in Stackblitz: https://stackblitz.com/@gsap-dev/collections/gsap-react-starters https://stackblitz.com/@gsap-dev/collections/gsap-nextjs-starters Hopefully this helps. Happy Tweening!
  1. Load more activity
×
×
  • Create New...