Jump to content
Search Community

All Activity

This stream auto-updates

  1. Past hour
  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. OK I think I figured it out. Wasnt as complicated as I thought... https://codesandbox.io/p/sandbox/react-gsap-starter-template-y8z5hd?file=%2Fsrc%2Findex.js
  4. Today
  5. Pleased to meet you @mvaneijgen, I'm a Jr. SWE who is now doing a R&D(Research and Development) on figuring out the tech stack that can provide me huge advantage of animating our company's site and it's under development so we have plenty of time to do it. And so provided the design from our company I found a reference https://www.anyways.co/ footer, in which they have inertial effects. I am trying to achieve it but when I glanced through the GSAP docs I found that inertial effect is a club plugin. Also sorry for the less information which I gave you before.
  6. Hi @Rodrigo, it took me a while to come back to this, but with a fresh head I came up with a slightly different idea. With a combination of a dynamic top of the viewport value for the start marker and ScrollTrigger.refresh(); it works fine: https://codepen.io/emjay/pen/YzMbmvg/b470cafeaf6e4f2fd39203126e8f3f67 I think it's totally fine to do it that way, don't you?
  7. Hi guys Stackblitz is not working for me for whatever reason, but codesanbox seems fine. Is there a react gsap starter template for codesandbox somebody can point me to please, or briefly describe how I can set one up please?
  8. Hi @Sharath Lingam welcome to the forum! Sure you can, but the question is how much time do you have and what is your skill level? The beauty of GSAP is you can build anything you like! So there is probably a way with the tools GSAP gives you can build your own inertia logic, but that means you also have to do all the debugging and all the trouble shooting your self, so the question becomes how much time do you want to spend figuring this out? Our reply will be "just use the inertia plugin, there is a lot of time spend figuring it all out, so that you don't have to!". Your question feels a bit like asking a carpenter if you can borrow all their professional tools, but without their tools they can't do their job... But again feel free to roll your own logic, there is nothing wrong with a bit of coding and figuring things out by your self. In theory inertia is just animating something and slowly getting to a 0 value that feels correct, but I think when you do go the roll your own route you'll come across a lot of hurdles that will take a lot to figure out. Hope it helps and happy tweening!
  9. Hi @Manoj Khatri welcome to the forum! Check out the post by our own @Carl
  10. Can I create inertia like effect without InertiaPlugin, with only by using free plugins?
  11. How we can create this type of carousel using GSAP? Anyone who knows can help
  12. Yesterday
  13. Hi, This is the simplest way I can think of doing that: https://codepen.io/GreenSock/pen/LYvoaNb Hopefully this helps. Happy Tweening!
  14. I'd go even simpler with yoyo tweens and repeatDelay. Something like this. https://codepen.io/PointC/pen/JjVqxgY/63a3e8ecfaf75286961b6e2ec36abed7 Just my 2 cents. YMMV. Happy tweening. Just FYI - the original pen that I forked had tweens with a 0.1 → 1 second duration on a timeline that was 100 seconds long. With scrub set to true they were animating super fast because they were only a tiny fraction of the duration. .1% - 1%.
  15. I doubt you'll run into performance problems with this TBH, since you have a rather small collection of elements. IMHO though this seems simpler to understand, follow and maintain: const blockElements = gsap.utils.toArray(".block"); const block1 = blocks.querySelector(".block-1"); const block2 = blocks.querySelector(".block-2"); const block3 = blocks.querySelector(".block-3"); const blockSettings = [ { element: block1, position: 30 }, { element: block2, position: 50 }, { element: block3, position: 60 } ]; blockSettings.forEach((b, i) => { const block = blockElements[i]; const otherBlocks = blockElements.filter((block, j) => i !== j); tl.add(() => { gsap.to(block, { opacity: 1, duration: 1, scale: 1 }); gsap.to(otherBlocks, { opacity: 0, duration: 1, scale: 1.2 }); }, b.position); }); You don't have to resort to that conditional block and anything that results in simpler and shorter code, is going to make more sense if you have to look at it in 6 months. Here is a fork of your demo: https://codepen.io/GreenSock/pen/oNORmKL Is worth mentioning that using the add() to add an anonymous function is the same as using call(): const tl = gsap.timeline(); tl.add(() => {}, position); // Exactly the same tl.call(() => {}, [/*parameters*/], position); Hopefully this helps. Happy Tweening!
  16. Hi @MarOne, You can check the resources in the Webflow installation page on our Learning Center: https://gsap.com/resources/Webflow#installation Also we have a brand new installation video, where @Cassie goes into a lot of detail including webflow: This starts right with webflow, but you can go to youtube and check the chapters on the video so you can jump directly to a specific section. Hopefully this helps. Happy Tweening!
  17. wow it works fine, i replaced the useEffect with useGsap thanks a lot
  18. After more tinkering, i think i found a solution: https://codepen.io/Valentin-Ilas/pen/ZEZNVRX?editors=1111 Basically I'm using tl.add() to run animations independently from the scrub on the parent container. Then i can specify for each one where during the progress it should run. Seems to work backwards too. But is this approach efficient? or do you see any performance issues?
  19. Can Anybody please tell me how to use Gsap Club plugins in a webflow project? It's soooo complicated and it shouldn't be like that?
  20. 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", }); };
  21. So basically i saw this demo here: https://codepen.io/snorkltv/pen/vYVBPJq and decided to try it out in react but for some reason the code only actvates when i've scrolled to the bottom is there any reason why? here's mine : https://stackblitz.com/edit/vitejs-vite-83dipo?file=src/App.jsx
  22. I've been trying to use the position parameter and I feel like I'm close but not quite there yet I noticed some interesting behaviour: if scrub is set to true, then the a duration seems to be needed. So i added duration: 100 which seems to work more as a percentage If i use the position parameter on each block, with values such as 20, 30 50 etc, they seem to trigger based on the percentage as well. Now what i can't seem to be able to do is to make the fade-in more animated instead of running it instantly and how to control the duration of the fade in. Please see the example below: https://codepen.io/Valentin-Ilas/pen/abxrRYe
  23. I'm not 100% sure I follow what you're trying to do. I forked the codepen and made some changes to it: https://codepen.io/GreenSock/pen/wvZbQKX At the end the pinnedContainer config is not needed since any of the pinned elements is adding any vertical space. Hopefully this helps. Happy Tweening!
  24. Just so you know, you could just call tween.revert() instead of doing both kill() and clearProps. You could also record the progress in your resize handler, and then re-apply that to make things continuous: https://codepen.io/GreenSock/pen/ZEZNmpz?editors=0010
  25. That is exactly what the position parameter can do. Another way is to keep the logic you have now, but find a way to run it just once and not everytime the GSAP instance updates, that's too wasteful. Happy Tweening!
  26. Hi Rodrigo, I tried to illustrate it in the following codepen but I think i didn't get it quite right. So the idea is that there is a pinned container which is connected to a scroll trigger and at precise moments in the timeline, for example when the progress is 0.3 then the block 1 should appear. If the progress goes to 0.74 then block 2 should appear. All 3 blocks are in the same position just only 1 visible at a time. https://codepen.io/Valentin-Ilas/pen/abxrRYe?editors=1111
  27. That is mostly because GSAP handles all the transforms using the 3D transform matrix: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix3d While setting a single transform using CSS does just that, applies a single transform. When you do that and then animate the same property with GSAP, GSAP takes that value applied by CSS and uses it's own method for transforms. That is why we recommend doing what you tried and worked, use GSAP to set all the initial transforms that will be animated with GSAP, to avoid that extra step when the animation first runs. Also sometimes is a good idea to use the advice from the FOUC article to prevent annoying flashes before the JS runs. Happy Tweening!
  28. Hi, Just create a loop for the cards, add a couple of to() instances to the timeline and using the position parameter create an overlap with the previous card: https://codepen.io/GreenSock/pen/WNWBaKz Hopefully this helps. Happy Tweening!
  1. Load more activity
×
×
  • Create New...