Hi Community! I’m new here and wanted to get some help with custom code in webflow using JS + GSAP library. I am looking to recreate the interaction from the demo site (below), and I am struggling with the position of the images. They do not seem to line up with the cursor. The example site was also created using Webflow, so it must be possible, right?
Is that interaction happening through Webflow’s interaction tools or is it custom code?
Would appreciate any help in breaking this down! Thank you!
Here is my site Read-Only: test site
here is my JS code:
<!-- Include GSAP and plugins -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/TextPlugin.min.js"></script>
<script>
// Debugging start message
console.log('Custom script loaded and running');
// Set initial properties for hover images
gsap.set('.hover-image', {
yPercent: -50,
xPercent: -50,
opacity: 0,
});
console.log('Initial hover image properties set.');
// Map each hover-text to its corresponding hover-image by index
const hoverTexts = document.querySelectorAll('.hover-text');
const hoverImages = document.querySelectorAll('.hover-image');
// Log the elements found for hover texts and hover images
console.log('Hover texts found:', hoverTexts);
console.log('Hover images found:', hoverImages);
hoverTexts.forEach((el, index) => {
const image = hoverImages[index];
console.log(`Setting up hover interaction for text element ${index + 1}:`, el);
console.log(`Corresponding image element ${index + 1}:`, image);
const setX = gsap.quickSetter(image, 'x', 'px'),
setY = gsap.quickSetter(image, 'y', 'px');
const align = e => {
console.log('Mouse position:', e.clientX, e.clientY);
setX(e.clientX);
setY(e.clientY);
};
const startFollow = () => {
console.log('Start following mouse for image:', image);
document.addEventListener('mousemove', align);
};
const stopFollow = () => {
console.log('Stop following mouse for image:', image);
document.removeEventListener('mousemove', align);
};
const fade = gsap.to(image, {
autoAlpha: 1, // Controls both opacity and visibility
duration: 0.2,
ease: 'power1.out',
paused: true,
onReverseComplete: stopFollow
});
el.addEventListener('mouseenter', (e) => {
console.log('Mouse entered:', el);
fade.play(); // Play the fade animation
startFollow(); // Start following the mouse
align(e); // Immediately position it under the cursor
// Dim all normal text and other hover-text spans
document.querySelectorAll('.intro-text span').forEach(span => {
if (span !== el) {
console.log('Dimming text span:', span);
span.style.opacity = '0.25'; // Dim all other text
}
});
// Ensure hovered text stays at full opacity
el.style.opacity = '1';
});
el.addEventListener('mouseleave', () => {
console.log('Mouse left:', el);
fade.reverse(); // Reverse the fade animation to hide the image
// Reset opacity for all text
document.querySelectorAll('.intro-text span').forEach(span => {
console.log('Resetting opacity for span:', span);
span.style.opacity = '1'; // Reset all text to full visibility
});
});
});
console.log('Event listeners set for all hover texts.');
</script>