Jump to content
Search Community

BenjaminO

Members
  • Posts

    65
  • Joined

  • Last visited

Everything posted by BenjaminO

  1. Hi @Cassie, please check this link with screen recordings. https://mega.nz/folder/SxZlTRYR#cqwmb7caHUz9tjOFHt5EkQ. Tell me if you need more info ! EDIT : My scrolltrigger config gsap .timeline({ scrollTrigger: { trigger: '#contact-container', start: 'top 100%', toggleActions: 'play none none reset' // same results with 'play resume resume reset' } }) .to // ...
  2. Hello ?, I am using scrolltrigger for few animations on my website with toggle actions 'play none none reset'. While on desktop it is working as expected, it's not the case on mobile (especially IOS Safari). It seems that the toggle actions are called when address bar is showing / hiding. I tried the ignoreMobileResize options under ScrollTrigger.config and/or ScrollSmoother.create but it doesn't seems to work well on Safari. I found the following workaround : if (ScrollTrigger.isTouch === 1) { ScrollTrigger.config({ autoRefreshEvents: 'visibilitychange,DOMContentLoaded,load' }) window.addEventListener('orientationchange', () => { const promise1 = delay(100) promise1.then(() => { ScrollTrigger.refresh() }) }) } // Utils.ts export const delay = (n: number) => { n = n || 2000 return new Promise<void>((resolve) => { setTimeout(() => { resolve() }, n) }) } so I removed the resize event from autoRefreshEvents (because it was called on scroll hence causing the problem) and I added an event listener on orientationchange instead (with 100ms of delay before refreshing). I was wondering if maybe orientationchange could be added to autoRefreshEvents list because the following syntax doesn't work ? if (ScrollTrigger.isTouch === 1) { ScrollTrigger.config({ autoRefreshEvents: 'visibilitychange,DOMContentLoaded,load,orientationchange' }) }
  3. Hello everyone, I was scrolling in the forum to find a solution to a similar problem as @DK7. I wanted to share what I found in case someone, for some reason, doesn't wish to move the element out of smooth-wrapper. In my case I wanted to pin an element within a page but because I am using nuxt 3, I am initiating smoothscroller once in my app.vue file. Consequently, none of my page content can't be pull outside of smooth-wrapper (what is outside of smooth-wrapper should be common to all pages, like a layout) //app.vue file <script setup> import gsap from 'gsap' import ScrollSmoother from 'gsap/ScrollSmoother' import ScrollTrigger from 'gsap/ScrollTrigger' if (process.client) { gsap.registerPlugin(ScrollSmoother, ScrollTrigger) } onBeforeMount(() => { ScrollSmoother.create({ smooth: 2, normalizeScroll: true }) }) </script> <template> // All my fix content common between pages <div id="smooth-wrapper"> <div id="smooth-content"> <NuxtPage /> // my pages with dynamic content </div> </div> </template> To address my problem, I use Scrolltrigger to pin my element in my page like so : // Some page <script setup lang="ts"> import gsap from 'gsap' import ScrollTrigger from 'gsap/ScrollTrigger' if (process.client) { gsap.registerPlugin(ScrollTrigger) } onMounted(() => { ScrollTrigger.create({ trigger: '#gridgalerie_cell1', pin: true, pinSpacing: false, endTrigger: '#gridgalerie' // I changed the trigger to the root div of my page }) }) </script> <template> <div id="gridgalerie" class="grid md:grid-cols-[20%_80%]"> <div id="gridgalerie_cell1" class="h-screen">title</div> // I pinned this div <div id="gridgalerie_cell2"> <div class="h-screen bg-blue-500"></div> <div class="h-screen bg-blue-500"></div> <div class="h-screen bg-blue-500"></div> </div> </div> </template> The key element here is the endTrigger option that allow me to pin the element till the end of the page. It's not the prettiest workaround but I don't see other option at the moment. Happy tweening everyone ! ?
  4. Any plan to update this ? ? @GreenSock, @Cassie, @GSAP Helper
  5. Hey @Prasanna! Thank you for your response. I opted for another method using dotenv-cli https://www.npmjs.com/package/dotenv-cli. to update or install packages I just have to put the dotenv parameter before using npm : dotenv npm install dotenv npm install gsap@npm:@gsap/shockingly dotenv npm install gsap
  6. Hello ?, do you know how to specify env vars in local environment ? I am having a 403 error locally my config // .env file at the root of the project NPM_GREENSOCK_TOKEN=my_super_token // .npmrc at the root of the project //npm.greensock.com/:_authToken=${NPM_GREENSOCK_TOKEN} -- Note : putting directly the token here is working fine @gsap:registry=https://npm.greensock.com when I am running "npm i gsap@npm:@gsap/shockingly" npm ERR! code E403 npm ERR! 403 403 Forbidden - GET https://npm.greensock.com/@gsap%2fshockingly - bad authorization header. Please login again npm ERR! 403 In most cases, you or one of your dependencies are requesting npm ERR! 403 a package version that is forbidden by your security policy, or npm ERR! 403 on a server you do not have access to.
  7. Hey @Aerio, I managed to create a workaround for my code (not sure that it will suits your project). Basically I am locking the scroll, then I am doing an animation for the page transition (not needed for all cases) and finally I am releasing the scroll 100ms after the ScrollTrigger.refresh() event. At first I tried something like this : ScrollTrigger.refresh(true) // with the safe parameter true ScrollTrigger.addEventListener("refresh", () => smoother.paused(false)); // smoother is SmoothScroller instance but as described in the Documentation (https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.refresh()), with the safe parameter activated, it will wait for at least one requestAnimationFrame tick, and up to roughly 200ms before initiating the refresh so the user can be block if he tries to scroll during the page transition. I opted for the following approach : // app.vue <script setup lang="ts"> import gsap from 'gsap' import ScrollSmoother from 'gsap/ScrollSmoother' import ScrollTrigger from 'gsap/ScrollTrigger' import { scrollStore } from '~~/stores/piniaStore' import { delay } from '~~/assets/ts/utils' if (process.client) { gsap.registerPlugin(ScrollSmoother, ScrollTrigger) } const isLock = scrollStore() onBeforeMount(() => { if (ScrollTrigger.isTouch === 1) { ScrollSmoother.create({ ignoreMobileResize: true }) } else { ScrollSmoother.create({ smooth: 2, normalizeScroll: true }) } }) onMounted(() => { const Smooth = ScrollSmoother.get() isLock.$subscribe(() => { isLock.isReady === true ? Smooth.paused(true) : Smooth.paused(false) }) }) // const onLeave, onEnter not detailed // Check this doc : https://vuejs.org/guide/built-ins/transition.html#javascript-hooks const onBeforeLeave = (_el: HTMLDivElement) => { isLock.$patch({ isReady: true }) ScrollTrigger.getAll().forEach((t) => t.kill()) // kill all instance of ScrollTrigger except ScrollSmoother. ScrollTrigger.killAll() doesn't seem to work properly } const onAfterEnter = (_el: HTMLDivElement) => { ScrollTrigger.refresh() const promise1 = delay(100) promise1.then(() => { isLock.$patch({ isReady: false }) }) } </script> <!-- app.vue --> <template> <div id="smooth-wrapper"> <div id="smooth-content"> <router-view v-slot="{ Component }"> <!-- documentation : https://vuejs.org/guide/built-ins/transition.html#javascript-hooks --> <Transition mode="out-in" :css="false" @before-leave="onBeforeLeave" @leave="onLeave" @enter="onEnter" @after-enter="onAfterEnter" > <component :is="Component" /> </Transition> </router-view> </div> </div> </template> // utils.ts const delay = (n: number) => { n = n || 2000 return new Promise<void>((resolve) => { setTimeout(() => { resolve() }, n) }) } export { delay } // piniaStore.ts import { defineStore } from 'pinia' // I am using @pinia/nuxt, but you can manage without it https://github.com/vuejs/pinia/tree/v2/packages/nuxt export const scrollStore = defineStore({ id: 'smooth-store', state: () => { return { isReady: true } } })
  8. Hello @pixeldot, I can see that you didn't create the wrapper element as described in the doc. You can try this in the HTML : <body> <div id="wrapper"> <div id="content"> <div class="section"><p> a section</p></div> <div class="section"><p> a section</p></div> <div class="section"><p> a section</p></div> </div> </div> <!-- position: fixed elements can go outside ---> </body> and then create the ScrollSmoother instance like this : ScrollSmoother.create({ normalizeScroll: false, smoothTouch: 0.01, ignoreMobileResize: true, content: '#content', wrapper: '#wrapper', smooth: 1, effects: true, }); EDIT: You can follow the convention by naming the content : smooth-content and the wrapper : smooth-wrapper which allow you to skip the declaration when creating the instance : <body> <div id="smooth-wrapper"> <div id="smooth-content"> <div class="section"><p> a section</p></div> <div class="section"><p> a section</p></div> <div class="section"><p> a section</p></div> </div> </div> <!-- position: fixed elements can go outside ---> </body> ScrollSmoother.create({ normalizeScroll: false, smoothTouch: 0.01, ignoreMobileResize: true, smooth: 1, effects: true, });
  9. Hello @GreenSock, I know that the subject has already been discussed many times but I think it is needed in order to improve the ScrollSmoother plugin. As far as I know, the annoying behavior of showing/hiding of the address bar on mobile browsers can't be avoided with the plugin activated. I've looked into different approaches on the web and I found a very good website (https://anatoletouvron.fr/about) that prevent the address bar from showing/hiding all the time. The difference I noticed is that the body height = 100% in the shared website instead of page height with ScrollSmoother (same as #smooth-content div). I tried different CSS trick without success ?. I am sure that there is more differences and that the plugin took a different approach but it could be really nice to prevent this behavior with an option in the plugin because it destroys the UX on the webpage.
  10. I added the ScrollTo plugin in the demo and it is working as I would like the offset method to work. However, I don't want to incorporate this plugin only for few scroll as it add weight to my final bundle. Also I remarked that the Scrollto() method with smooth parameter set to true wasn't working on mobile browsers ! It jumps directly to target (see codepen above ?) cc @GreenSock
  11. Hello @GSAP Helper and thank you for the starter template. I created this CodePen where you'll be able to see the difference between the two methods. When the #third section is smaller than 100vh (above 1024px in my demo), you'll see a blank space below the section when using the offset() method to scroll down. Below 1024px, it is working as expected. Indeed I'd like to ease the scroll so I would prefer using the offset() method.
  12. Solved in GSAP 3.11.0 ! Thank you for this great update ?
  13. Hello, I am using the ScrollSmoother plugin and I created a button to smoothly scroll down to a specific element using : button.addEventListener('click', () => { gsap.to(Smooth, { scrollTop: Smooth.offset('#formsection', 'top top'), duration: 3, ease: 'power4.inOut' }) }) The problem is that the #formsection can be taller or smaller than 100vh. when #formsection is taller than the height of the screen (100vh) the code above is working as expected but when it is smaller, there is an overscroll. Indeed the section is placed at the bottom of the page. I tried to set up 'auto auto' as a second argument to the .offset() method but I think it is set to 'center center' by default. I would expect a behavior that match with the regular .scrollTo() method which is working fine without overscroll. button.addEventListener('click', () => { Smooth.scrollTo('#formsection', true) })
  14. Thank you ? @GreenSock !
  15. After digging in the docs I was thinking about this observer property (https://greensock.com/docs/v3/Plugins/Observer/isPressed). Maybe Draggable plugin is using it under the hood ? My code is working fine but I think it's always better avoiding ignoring warnings ?. I think it's also the same for the property tween which I can't reach as well. After testing it seems that xTo.pause() // throw error + not working xTo.tween.pause() // throw error but working EDIT: I think it is just a declaration problem as isPressed is present in the source code of the plugin _setDefaults(Draggable.prototype, { // Other parameters isPressed: false }); so maybe a future update of draggable.d.ts could be nice @GreenSock ?: readonly isPressed: boolean; I found also at the very end of the doc https://greensock.com/docs/v3/GSAP/gsap.quickTo() that .tween is needed to actually access methods and properties of the tween instance so maybe there is also room for future declaration update ?
  16. Hello @GreenSock ! I can't see the property ignoreMobileResize in the docs under https://greensock.com/docs/v3/Plugins/ScrollSmoother/static.create() but it is present here (https://greensock.com/docs/v3/Plugins/ScrollSmoother) ?
  17. Hello @iDad5 and thank you for your response ! I took a piece of code from @GreenSock that you can find below where you can find the property ’isPressed’. Also I'd like to remove all this keywords to clarify the code but I am a bit lost in translation ? const drag = Draggable.create(proxy, { onDrag() { xTo(this.x) yTo(this.y) }, // Other options })[0]
  18. Hello ?, I am using typescript in my project and I remarked that I have some types erros : The property 'isPressed' doesn't exists on type 'Draggable' due to the following code class DraggableImg { constructor(Image: HTMLElement) { const drag = Draggable.create(proxy, { //Draggable options })[0] drag.isPressed // throw error } } and also The property 'pause' doesn't exists on type 'Function' due to the following code : class DraggableImg { constructor(Image: HTMLElement) { const xTo = gsap.quickTo(Image, 'x', { duration: 0.3 }) const yTo = gsap.quickTo(Image, 'y', { duration: 0.3 }) const drag = Draggable.create(proxy, { onPressInit(){ xTo.pause() // throw error even with xTo.tween.pause() yTo.pause() // throw error even with yTo.tween.pause() } })[0] } } Can I do something to fix that ? Many thanks in advance ?
  19. Hello @GreenSock and thank you for your suggestion ?. I opted to add a class to fixed elements in order to separate them from the dynamic elements. I don't have the problem anymore. What the best option to check if a gsap animation is triggered multiple times on the same element ? my code const Cursor = document.getElementById('cursor') const fixedItems = document.querySelectorAll('a.fixed-el, button.fixed-el') ScaleMouse(fixedItems) isRoute.$subscribe(() => { gsap.to(Cursor, { scale: 1, duration: 1, ease: 'power4.out' }) const newItems = document.querySelectorAll( 'a:not(.fixed-el), button:not(.fixed-el), input, textarea, label, select' ) ScaleMouse(newItems) }) function ScaleMouse(Items) { Items.forEach((link) => { // On mouse enter scale the media-cursor to 2 link.addEventListener('pointerenter', () => { gsap.to(Cursor, { scale: 2, duration: 1, ease: 'power4.out' }) }) // On mouse leave scale the media-cursor to 1 link.addEventListener('pointerleave', () => { gsap.to(Cursor, { scale: 1, duration: 1, ease: 'power4.out' }) }) }) }
  20. hello @GreenSock and thank you for your response ! That was my thought indeed but I am not sure how to add some conditional logic in order to prevent a new event handler ? Is there an handy/easy way to conditionally defined elements triggered by gsap animation ? otherwise what could be the best way to target all animations related to an element in order to remove them -> maybe with animation.kill(Cursor, "scale") ?
  21. Hello ?, I created a mouse follower which scale up when hovering an anchor, button, input, textarea, label or select on a nuxt 3 project. The method I used is the following : function ScaleMouse(Items) { Items.forEach((link) => { // On mouse enter scale the media-cursor to 2 link.addEventListener('pointerenter', () => { gsap.to(Cursor, { scale: 2, duration: 1, ease: 'power4.out', }); }); // On mouse leave scale the media-cursor to 1 link.addEventListener('pointerleave', () => { gsap.to(Cursor, { scale: 1, duration: 1, ease: 'power4.out', }); }); }); } In order to refresh my list of elements (between pages), I am using a state management tool (Pinia) . I am defining a state to 0 which I increment from 1 when changing the page import { defineStore } from 'pinia'; export const routeStore = defineStore({ id: 'page-store', state: () => { return { isNewPage: 0, }; }, }); With the $subscribe method I can detect when the state is changed and thus resetting my variable Items isRoute.$subscribe(() => { Items = document.querySelectorAll( 'a, button, input, textarea, label, select' ); ScaleMouse(Items); }); My problem is that the ease effect (power4.out) I applied on scale is broken little by little when changing the page. This problem only affects fixed elements (containing buttons and anchors) that are in my app.vue file. I created a reproduction on StackBlitz : https://stackblitz.com/edit/nuxt-starter-ugbwzw?file=app.vue Steps to reproduce: Hover the fixed button and the dynamic link Navigate between pages without doing hard refresh Hover again and notice the difference between the fixed button and the link My question is : Is there another method to avoid this problem or is it a GSAP bug ? Thank you very much in advance for your responses ! ?
  22. Hello folks ?, I am trying to implement ScrollSmoother in a Nuxt3 ("nuxt": "3.0.0-rc.4") application and for now it works quite well. However when setting normalizeScroll: true and changing between pages I have the same problem as @Born05. Here is my setup for Nuxt 3: <!-- APP.VUE file --> <script setup> import { gsap } from 'gsap' import ScrollSmoother from 'gsap/ScrollSmoother' import ScrollTrigger from 'gsap/ScrollTrigger' if (process.client) { gsap.registerPlugin(ScrollSmoother, ScrollTrigger) } onMounted(() => { ScrollSmoother.create({ wrapper: "#smooth-wrapper", content: "#smooth-content", smooth: 2, effects: true, normalizeScroll: true, ignoreMobileResize: true, smoothTouch: 0.1, }) }) </script> <template> <!-- FIX CONTENT --> <!-- <li> <NuxtLink to="/">Home</NuxtLink> <NuxtLink to="/about">About</NuxtLink> <NuxtLink to="/gallery">Gallery</NuxtLink> </li> --> <div id="smooth-wrapper"> <div id="smooth-content"> <NuxtPage /> </div> </div> </template> Do you know how I can call ScrollTrigger.refresh() easily when passing to a new page ? Many thanks in advance for your suggestions ! ?
  23. Hello @GreenSock ! Indeed it solved my problem ! Thank you for your answer, I didn't thought about that ? Many thanks again ?
  24. Hello folks ?, I created a mouse follower with gsap.quickTo() method (https://greensock.com/docs/v3/GSAP/gsap.quickTo()) but when scrolling down, the mouse bubble offset. In order to compensate it, I thought that binding it to the bounds of my scrollSmoother wrapper would do the job. However, I wasn't able to reproduce my problem on the codepen I attached. Do you have some suggestions for me ? I saw tis topic but I didn't understood all part of the code : Thank you in advance for your help ! ? Benjamin
  25. Hello folks ?, I have a problem importing gsap plugin. When I try to bundle (with vite) my project I have this error : [vite-ssg] An internal error occurred. [vite-ssg] Please report an issue, if none already exists: https://github.com/antfu/vite-ssg/issues node:internal/process/promises:246 triggerUncaughtException(err, true /* fromPromise */); ^ Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/user/Documents/vite-project/node_modules/gsap/MorphSVGPlugin' imported from /Users/user/Documents/vite-project/.vite-ssg-temp/main.mjs Did you mean to import gsap/MorphSVGPlugin.js? at new NodeError (node:internal/errors:371:5) at finalizeResolution (node:internal/modules/esm/resolve:416:11) at moduleResolve (node:internal/modules/esm/resolve:932:10) at defaultResolve (node:internal/modules/esm/resolve:1044:11) at ESMLoader.resolve (node:internal/modules/esm/loader:422:30) at ESMLoader.getModuleJob (node:internal/modules/esm/loader:222:40) at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40) at link (node:internal/modules/esm/module_job:75:36) { code: 'ERR_MODULE_NOT_FOUND' } I am importing gsap package like this in a js file : import gsap from 'gsap' import MorphSVGPlugin from 'gsap/MorphSVGPlugin' gsap.registerPlugin(MorphSVGPlugin) of course I have access to the premium plugins (package.json) "dependencies": { "gsap": "npm:@gsap/shockingly@^3.10.4", ... }, I tried different type of imports (in the js file) without success: import gsap from 'gsap' import MorphSVGPlugin from 'gsap/dist/MorphSVGPlugin' // or 'gsap/MorphSVGPlugin.js' or 'gsap/dist/MorphSVGPlugin.js' gsap.registerPlugin(MorphSVGPlugin) even : import { gsap, MorphSVGPlugin } from 'gsap/all' // or 'gsap/all.js' gsap.registerPlugin(MorphSVGPlugin) Thank you in advance for your response ! ?
×
×
  • Create New...