I'm learning a lot, ok i'll fork the original and try the above. ^ Sounds WAY simpler haha.
I think I spotted my real issue too. Last time I really read documentation for GSAP I was still learning everything else. If I read some of these things now, they would actually make sense so I think I'll slow down and just read more next time 🙃
So Solution 2 is way simpler. No store needed, awesome to just find ScrollSmoother anywhere in the app with ScrollSmoother.get().
Edit: I created a video explanation of the solution. Partially to check my understanding but also to explain this to anyone else who might be new and confused like I was.
Basically it was as simple as creating this component and injecting it in any page. Could add more logic to it but didn't feel a need for it.
Basic order of things:
Component with the logic to register ScrollTrigger & ScrollSmoother, whilst also setting up ScrollSmoother.
Of course you can just use this code in +layout.svelte, it does not matter for functionality. I just throw stuff into components. <GsapSetup.svelte />
Inject this component into +layout.svelte
Component with the following logic that runs when we are on a new route and the DOM (html elements) are loaded/mounted on a new page (like switching from homepage to the about page) <GsapPageRefresh />
Kill old-route effects (ScrollSmoother stores elements it is creating effects for in an array (list)
Inform ScrollSmoother of the new elements (so we killed home-elements and are now adding about-elements to our array (list)
We just need to refresh ScrollTrigger now and it will recalculate based on all of this information.
Inject this component into any route/page.
// GsapSetup.svelte
<script>
import gsap from "gsap-trial";
import { ScrollTrigger } from "gsap-trial/dist/ScrollTrigger";
import { ScrollSmoother } from "gsap-trial/dist/ScrollSmoother";
import {onMount} from 'svelte'
let smoother;
onMount(() => {
if(typeof window !== "undefined"){
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);
}
const ctx = gsap.context(() => {
smoother = ScrollSmoother.create({
smooth: 2,
normalizeScroll: false,
ignoreMobileResize: false,
effects: true
});
})
return () => ctx.revert();
})
</script>
Injected the above into +layout.svelte
// +layout.svelte
<script>
import GsapSetup from '$lib/GsapSetup.svelte'
// Other stuff...
</script>
<GsapSetup />
// Other stuff...
Created a component with our "Inform Gsap of our new-route elements whilst destroying old ones" logic.
// GsapPageRefresh.svelte
<script>
import {onMount} from 'svelte';
import { ScrollSmoother } from "gsap-trial/dist/ScrollSmoother";
import { ScrollTrigger } from "gsap-trial/dist/ScrollTrigger";
onMount(() => {
if(ScrollSmoother.get()){
let smoother = ScrollSmoother.get();
smoother.effects().forEach((effect) => effect.kill());
smoother.effects('[data-lag], [data-speed]');
ScrollTrigger.refresh()
}
})
</script>
Then I just used the GsapPageRefresh component in every route, it looks like this:
// home route (routes/+page.svelte) and about route (route/about/+page.svelte) has more or less identical code.
<script>
import PageGsapRefresh from '$lib/PageGsapRefresh.svelte'
const images = [
'https://source.unsplash.com/random/1000x1000/?volcano',
'https://source.unsplash.com/random/1001x1000/?volcano',
'https://source.unsplash.com/random/1002x1000/?volcano',
'https://source.unsplash.com/random/1003x1000/?volcano',
'https://source.unsplash.com/random/1004x1000/?volcano',
'https://source.unsplash.com/random/1005x1000/?volcano',
'https://source.unsplash.com/random/1006x1000/?volcano',
'https://source.unsplash.com/random/1007x1000/?volcano',
]
</script>
<PageGsapRefresh />
<!-- svelte:head stuff... -->
<div class="container">
{#each images as image, i}
<div class="img-container">
<img src="{image}" alt="nada!" class="img" data-speed="auto" data-lag="0" />
</div>
{/each}
</div>
<!-- Styling... -->
(A cleaner way would be to create onDestroy and onMount logic but this was sufficient for my understanding.)