Skiply.ai/main/shoe-animation-gsap.js
2026-08-19 13:41:35 +05:30

84 lines
2.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ================================================
Shoe Showcase Interactive GSAP Animation
================================================
- Uses GSAP for smooth easing and interpolation
================================================ */
document.addEventListener('DOMContentLoaded', () => {
const showcase = document.getElementById('showcase');
const bgRed = document.getElementById('bg-red');
const bgBlack = document.getElementById('bg-black');
const phoneRed = document.getElementById('phone-red');
const phoneBlack = document.getElementById('phone-black');
const contentLeft = document.getElementById('content-left');
const contentRight = document.getElementById('content-right');
function clamp(v, lo, hi) {
return Math.min(hi, Math.max(lo, v));
}
function lerp(a, b, t) {
return a + (b - a) * t;
}
function animateToRatio(ratio) {
// ratio is 0 (far left) to 1 (far right). Center is 0.5.
// 1. Calculate flex values for background panels
const redFlex = lerp(3.5, 0.3, ratio);
const blackFlex = lerp(0.3, 3.5, ratio);
// 2. Calculate bias for phones (+1 when red dominates, -1 when black dominates)
const bias = (0.5 - ratio) * 2;
const redScale = 1 + clamp(bias, 0, 1) * 0.3;
const redOpacity = clamp(1 + bias * 3, 0, 1);
const redShiftX = clamp(bias, 0, 1) * 60;
const blackScale = 1 + clamp(-bias, 0, 1) * 0.3;
const blackOpacity = clamp(1 - bias * 3, 0, 1);
const blackShiftX = clamp(-bias, 0, 1) * -60;
// 3. Animate using GSAP
// Using overwrite: "auto" ensures that new mouse movements smoothly override old animations
const animConfig = { duration: 0.5, ease: "power2.out", overwrite: "auto" };
gsap.to(bgRed, { flexGrow: redFlex, ...animConfig });
gsap.to(bgBlack, { flexGrow: blackFlex, ...animConfig });
gsap.to(phoneRed, {
scale: redScale,
x: redShiftX,
opacity: redOpacity,
...animConfig
});
gsap.to(phoneBlack, {
scale: blackScale,
x: blackShiftX,
opacity: blackOpacity,
...animConfig
});
gsap.to(contentLeft, { opacity: redOpacity, ...animConfig });
gsap.to(contentRight, { opacity: blackOpacity, ...animConfig });
}
// Set initial center state
gsap.set(bgRed, { flexGrow: 1 });
gsap.set(bgBlack, { flexGrow: 1 });
/* ---- Mouse tracking ---- */
showcase.addEventListener('mousemove', (e) => {
const rect = showcase.getBoundingClientRect();
const ratio = clamp((e.clientX - rect.left) / rect.width, 0, 1);
animateToRatio(ratio);
});
// Spring back to center on leave
showcase.addEventListener('mouseleave', () => {
animateToRatio(0.5);
});
});