At first glance the rabbit hole did not seem that deep, I might be wrong when I apply it across my entire application (I already notice that I should replace the setTimeouts with a delay for instance). But in short, this is how I approached it.
I have made a file that operates as a wrapper for gsap, it imports an external file that manages the state of the animations (a Pinia datastore in my case). Which has a boolean property called "showAnimations" to determine wether animations will be played or not.
/services/gsap-wrapper.ts
import gsap from "gsap"
import appStore from "@/stores/app"
const gsapWrapper = {...gsap}
gsapWrapper.to = (
target: gsap.TweenTarget,
durationOrVars: number | gsap.TweenVars,
vars?: gsap.TweenVars
) => {
let options = {} as gsap.TweenVars
if (typeof durationOrVars === "number") {
options.duration = durationOrVars
} else {
vars = durationOrVars
}
options = {
...options,
...vars,
} as gsap.TweenVars
// Pinia datastore
const app = appStore()
// Overwrite duration & delay when animations are not allowed
if (!app.showAnimations) {
options.duration = 0
options.delay = 0
options.ease = "none"
if (typeof options.stagger == "number") {
options.stagger = 0
} else if (typeof options.stagger === "object" && options.stagger !== null) {
options.stagger.each = 0
}
}
return gsap.to(target, options)
}
gsapWrapper.fromTo = (
target: gsap.TweenTarget,
durationOrFromVars: number | gsap.TweenVars,
fromOrToVars: gsap.TweenVars,
toVars?: gsap.TweenVars
) => {
let options = {} as gsap.TweenVars
let fromVars = fromOrToVars
if (typeof durationOrFromVars === "number") {
options.duration = durationOrFromVars
fromVars = fromOrToVars
} else {
toVars = fromOrToVars
fromVars = durationOrFromVars
}
options = {
...options,
...toVars,
} as gsap.TweenVars
// Pinia datastore
const app = appStore()
// Overwrite duration & delay when animations are not allowed
if (!app.showAnimations) {
options.duration = 0
options.delay = 0
options.ease = "none"
if (typeof options.stagger == "number") {
options.stagger = 0
} else if (typeof options.stagger === "object" && options.stagger !== null) {
options.stagger.each = 0
}
}
return gsap.fromTo(target, {
...fromVars,
}, options)
}
export default gsapWrapper
In the other files where I normally include gsap via import gsap from "gsap", I now simply import it as followed:
import gsap from "/services/gsap-wrapper"
This approach allows me to enable/disable all gsap animations from 1 single location which seem to have the following up- and downsides.
Upsides
I have on boolean variable that I can modify to disable ALL animations throughout my application
The code is relatively simple, and can be easily adjusted and expanded
It uses the default gsap library, so unless breaking changes occur in the gsap.to method. Everything will remain working with future gsap updates
Downsides
It is applicable to ALL gsap.to methods. As a workaround you could import both the gsap-wrapper and gsap into a file, but that could easily become a slippery slope
It can be quite a hassle to figure out how the wrapper function should be written to respect the original gsap method and its types