Thanks for your reply. I feel like a dummy because I didn't explain myself very well. We are initializing GSAP after loading the data but at the point the images haven't loaded yet. It's the images loading and shifting the DOM height that breaks the GSAP animations below that point. I've pasted an example component below. Hopefully it helps.
import { getLocalisationStrings, getTextIntro } from 'lib/services';
import { checkForMissingLocalisationStrings } from 'lib/utils/utils';
import { gsap } from 'gsap';
import React from 'react';
import TextIntro from '../components/common/TextIntro';
const i18nCodes = [
'TextIntro.Title',
'TextIntro.Text',
'TextIntro.ButtonLabel'
];
class TextIntroContainer extends React.Component {
constructor(props) {
super(props);
this.uid = `${this.props.attrs.apiId}__${Math.ceil(Math.random() * 100000)}`;
this.state = {
appStatus: 'init' // Can be 'init', 'busy' or 'ready'
};
}
componentDidMount() {
this.loadData();
}
loadData() {
this.setState(() => ({
appStatus: 'init'
}));
Promise.all([
getLocalisationStrings(undefined, i18nCodes).promise,
getTextIntro(undefined, this.props.attrs.apiId).promise
])
.then(responses => {
const i18n = checkForMissingLocalisationStrings(responses[0].translations);
const data = responses[1];
this.setState(() => ({
i18n,
data,
appStatus: 'ready'
}));
this.setAnimation();
})
.catch(() => {
this.setState(() => ({
appStatus: 'error'
}));
});
}
setAnimation() {
// target only this component by ID
const id = `.text-intro${this.uid}`;
// animation timeline connected to scroll
const tl = gsap.timeline({
scrollTrigger: {
trigger: id,
start: 'center 90%',
end: 'center 10%',
scrub: true
// markers: true
}
});
// fade in
tl.from(`${id} .text-intro__title`, {
duration: 4, y: '+=50', autoAlpha: 0, ease: 'Circ.easeOut'
});
tl.from(`${id} .text-intro__text`, {
duration: 4, y: '+=50', autoAlpha: 0, ease: 'Circ.easeOut'
}, '-=3');
tl.from(`${id} .text-intro__button`, {
duration: 4, y: '+=50', autoAlpha: 0, ease: 'Circ.easeOut'
}, '-=3');
// fade out
tl.to(`${id} .text-intro__title`, {
duration: 4, y: '-=50', autoAlpha: 0, ease: 'Circ.easeIn'
}, '+=8');
tl.to(`${id} .text-intro__text`, {
duration: 4, y: '-=50', autoAlpha: 0, ease: 'Circ.easeIn'
}, '-=3');
tl.to(`${id} .text-intro__button`, {
duration: 4, y: '-=50', autoAlpha: 0, ease: 'Circ.easeIn'
}, '-=3');
}
render() {
return (
<>
<TextIntro
id={this.uid}
i18n={this.state.i18n}
data={this.state.data}
modifiers='text-intro--small'
/>
</>
);
}
}
export default TextIntroContainer;