// SCRIPT V 1.01
gsap.registerPlugin(ScrollTrigger, SplitText, AttrPlugin);
// Global variable to hold SplitText instances and split state
const splitTextData = {
instances: [], // An array for storing SplitText instances
elements: new Map() // Map to keep track of which elements are already broken
};
// SMOOTH
// Declare lenis globally
let lenis;
function Smooth() {
// Destroy previous Lenis instance if it exists
if (lenis) {
lenis.destroy();
}
// Initialize Lenis with your original settings
lenis = new Lenis({
duration: 2,
smoothTouch: false
});
// Attach ScrollTrigger update
lenis.on('scroll', ScrollTrigger.update);
// Attach GSAP ticker for Lenis RAF
gsap.ticker.add((time) => {
lenis.raf(time * 1000);
});
// Ensure lag smoothing is disabled
gsap.ticker.lagSmoothing(0);
// Lenis Start / Stop / Toggle Elements
$('[data-lenis-start]').on('click', function () {
lenis.start();
});
$('[data-lenis-stop]').on('click', function () {
lenis.stop();
});
$('[data-lenis-toggle]').on('click', function () {
$(this).toggleClass("stop-scroll");
if ($(this).hasClass("stop-scroll")) {
lenis.stop();
} else {
lenis.start();
}
});
// Remove previous keydown event listeners to prevent duplication
$(document).off('keydown.lenis');
// Handle keyboard scrolling with Arrow Up and Arrow Down
$(document).on('keydown.lenis', function (event) {
// Define the scroll step (in pixels)
const scrollStep = 300; // You can adjust this value
const currentScroll = lenis.actualScroll; // Current scroll position
// Arrow Down
if (event.key === 'ArrowDown') {
event.preventDefault(); // Prevent default browser scrolling
lenis.scrollTo(currentScroll + scrollStep, {
duration: 1, // Smooth scroll duration
easing: (t) => 1 - Math.pow(1 - t, 2.5) // Custom easing (cubic ease-out)
});
}
// Arrow Up
if (event.key === 'ArrowUp') {
event.preventDefault(); // Prevent default browser scrolling
lenis.scrollTo(currentScroll - scrollStep, {
duration: 1, // Smooth scroll duration
easing: (t) => 1 - Math.pow(1 - t, 2.5) // Custom easing (cubic ease-out)
});
}
});
} // SMOOTH
// Arrays to store timelines for each animation type
let headingIntoViewTimelines = [];
let textIntoViewTimelines = [];
let simpleElementsTimelines = [];
let buttonIntoViewTimelines = [];
let separatorLineTimelines = [];
let dropdownTimelines = [];
let footerTimelines = [];
let mediaTimelines = [];
function IntoView() {
// Media query handling with GSAP matchMedia
const mm = gsap.matchMedia();
// HEADING INTO VIEW
let headingIntoView = $('.text-block .heading').not(
'.section.hero .heading, .section.footer .heading, .cta-block .heading, .menu-overlay-block .heading, .dropdown-block .heading'
);
if (headingIntoView.length) {
gsap.utils.toArray(headingIntoView).forEach(function (elem) {
const innerSplit = new SplitText(elem, {
type: 'lines',
linesClass: 'text-line'
});
// Set initial state (hide lines)
gsap.set(innerSplit.lines, {
y: '110%',
opacity: 0,
//willChange: 'transform, opacity'
});
// Create paused timeline without auto-triggering
const splitTimeline = gsap.timeline({
paused: true,
onComplete: () => {
innerSplit.revert();
}
});
splitTimeline.to(innerSplit.lines, {
duration: 1.1,
y: 0,
opacity: 1,
ease: 'Power4.easeOut',
stagger: 0.12
});
// Create ScrollTrigger to track visibility
const scrollTrigger = ScrollTrigger.create({
trigger: elem,
scrub: false,
start: 'top 90%',
end: 'bottom 0%',
});
headingIntoViewTimelines.push({
timeline: splitTimeline,
scrollTrigger: scrollTrigger,
element: elem
});
});
}
// TEXT INTO VIEW
let textIntoView = $('.text-block .text, .w-richtext p, .w-richtext li').not(
'.text.w-richtext, .section.hero .text, .section.hero .text.w-richtext p, .section.footer .text, .cta-block .text, .button-block .text, .button-block .text, .form-wrapper .text, .menu-overlay-block .text, .dropdown-block .text'
);
if (textIntoView.length) {
gsap.utils.toArray(textIntoView).forEach(function (elem) {
// Fixing empty rows manually
elem.innerHTML = elem.innerHTML.replace(/
/g,
"
");
const innerSplit = new SplitText(elem, {
type: 'lines',
linesClass: 'text-line'
});
// Set initial state (hide lines and list items)
gsap.set(innerSplit.lines, {
y: '110%',
opacity: 0,
//willChange: 'transform, opacity'
});
if (elem.tagName.toLowerCase() === 'li') {
gsap.set(elem, {
opacity: 0,
//willChange: 'opacity'
});
}
// Create paused timeline
const splitTimeline = gsap.timeline({
paused: true,
onComplete: () => {
innerSplit.revert();
// Deleting empty lines
elem.querySelectorAll('.empty-line').forEach(line => line.remove());
}
});
// Animate list items (only opacity) and lines (with lift)
if (elem.tagName.toLowerCase() === 'li') {
splitTimeline.to(elem, {
duration: 1.1,
opacity: 1,
ease: 'Power4.easeOut'
}, 0); // Start at the beginning
}
splitTimeline.to(innerSplit.lines, {
duration: 1.1,
y: 0,
opacity: 1,
ease: 'Power4.easeOut',
stagger: 0.06
}, 0); // Sync with li animation
// Create ScrollTrigger to track visibility
const scrollTrigger = ScrollTrigger.create({
trigger: elem,
scrub: false,
start: 'top 90%',
end: 'bottom 0%',
});
textIntoViewTimelines.push({
timeline: splitTimeline,
scrollTrigger: scrollTrigger,
element: elem
});
});
}
// SIMPLE ELEMENTS FADE IN
let simpleElements = $(
'.vector.rating, .image, .video-block, .navbar-block, .button-block, .section.footer').not(
'.dropdown-block .image, .navbar-block .button-block, .section.footer .button-block');
if (simpleElements.length) {
gsap.utils.toArray(simpleElements).forEach(function (elem) {
// Set initial state (hide elements)
gsap.set(elem, {
opacity: 0,
//willChange: 'opacity'
});
// Create paused timeline
const fadeTimeline = gsap.timeline({
paused: true,
/*onComplete: () => {
gsap.set(elem, { willChange: 'auto' });
}*/
});
fadeTimeline.to(elem, {
duration: 1.5,
opacity: 1,
ease: 'Power2.easeOut'
});
// Create ScrollTrigger to track visibility
const scrollTrigger = ScrollTrigger.create({
trigger: elem,
scrub: false,
start: 'top 90%',
end: 'bottom 0%',
onEnter: () => fadeTimeline.play()
});
simpleElementsTimelines.push({
timeline: fadeTimeline,
scrollTrigger: scrollTrigger,
element: elem
});
});
}
// BUTTON INTO VIEW
/*let buttonIntoView = $('.button-block').not(
'.section.hero .button-block, .navbar-block .button-block, .cta-block .button-block, .section.footer .button-block, .back-to-top-wrapper .button-block'
);
if (buttonIntoView.length) {
gsap.utils.toArray(buttonIntoView).forEach((elem) => {
const buttonText = elem.querySelector('.text');
const buttonLineContainer = elem.querySelector('.button-line-container');
const arrowMask = elem.querySelector('.arrow-mask');
let textLine = null; // Variable for text-line
// Set initial state for elements
if (buttonText) {
// Create text-mask wrapper
const textMask = document.createElement('div');
textMask.className = 'text-mask';
// Create text-line wrapper
textLine = document.createElement('div');
textLine.className = 'text-line';
// Move buttonText content into textLine
while (buttonText.firstChild) {
textLine.appendChild(buttonText.firstChild);
}
// Add textLine to textMask, and textMask to buttonText
textMask.appendChild(textLine);
buttonText.appendChild(textMask);
// Set initial state for textLine
gsap.set(textLine, {
y: '150%',
//willChange: 'transform'
});
}
if (buttonLineContainer) {
gsap.set(buttonLineContainer, { scaleX: 0, transformOrigin: 'left' });
}
if (arrowMask) {
gsap.set(arrowMask, { scale: 0, transformOrigin: '0% 100%' });
}
// Create paused timeline
const tl = gsap.timeline({
paused: true
});
if (textLine) {
tl.to(textLine, {
duration: 0.8,
y: 0,
ease: 'Power4.easeOut',
stagger: 0.12,
}, 0);
}
if (buttonLineContainer) {
tl.to(buttonLineContainer, {
duration: 0.7,
scaleX: 1,
ease: 'Power3.easeOut',
}, 0.15);
}
if (arrowMask) {
tl.to(arrowMask, {
duration: 0.7,
scale: 1,
ease: 'Power4.easeOut',
}, 0.15);
}
// Create ScrollTrigger to track visibility
const scrollTrigger = ScrollTrigger.create({
trigger: elem,
scrub: false,
start: 'top 90%',
end: 'bottom 0%',
});
buttonIntoViewTimelines.push({
timeline: tl,
scrollTrigger: scrollTrigger,
element: elem
});
});
}*/
// FOOTER INTO VIEW
/*let footerSection = $('.section.footer');
if (footerSection.length) {
gsap.utils.toArray(footerSection).forEach(function (elem) {
// Select all text elements to animate
let footerText = $(elem).find('.text, .button-text .text, .text._14px');
let footerSocialIcons = $(elem).find('.vector.social');
let footerButtonBlocks = $(elem).find('.button-block');
// Split text into lines using SplitText
let footerTextSpitted = false;
function splitFooterText() {
gsap.utils.toArray(footerText).forEach(function (textElem) {
textElem.innerHTML = textElem.innerHTML.replace(/
/g,
"
");
const innerSplit = new SplitText(textElem, {
type: 'lines',
linesClass: 'text-line'
});
const outerSplit = new SplitText(textElem, {
type: 'lines',
linesClass: 'text-mask'
});
gsap.set(innerSplit.lines, {
y: '150%',
//willChange: 'transform'
});
gsap.set(outerSplit.lines, {
overflow: 'hidden',
display: 'block'
});
});
footerTextSpitted = true;
}
// Initial setup for social icons and button lines
gsap.set(footerSocialIcons, { opacity: 0, scale: 0.5 });
gsap.set(footerButtonBlocks.find('.button-line-container'), {
scaleX: 0,
transformOrigin: 'left'
});
// Split text if not already done
if (!footerTextSpitted) {
splitFooterText();
}
// Create paused timeline
const tl = gsap.timeline({
paused: true
});
tl.to($(elem).find('.text-line'), {
duration: 0.8,
y: 0,
ease: 'Power4.easeOut',
stagger: 0.1
}, 0)
.to(footerButtonBlocks.find('.button-line-container'), {
duration: 0.5,
scaleX: 1,
ease: 'Power3.easeOut',
stagger: 0.1
}, 0.2)
.to(footerSocialIcons, {
duration: 0.5,
opacity: 1,
scale: 1,
ease: 'Power2.easeOut',
stagger: 0.05
}, 0.3);
// Create ScrollTrigger to track visibility
const scrollTrigger = ScrollTrigger.create({
trigger: elem,
start: 'top 90%'
});
footerTimelines.push({
timeline: tl,
scrollTrigger: scrollTrigger,
element: elem
});
});
}*/
// SEPARATOR LINES INTO VIEW
let separatorLine = $('.separator-line').not(
'.section.hero .separator-line, .navbar-block .separator-line, .dropdown-block .separator-line'
);
if (separatorLine.length) {
gsap.utils.toArray(separatorLine).forEach(function (elem) {
// Set initial state
gsap.set(elem, { width: '0%' });
// Create paused timeline
const tl = gsap.timeline({
paused: true
});
tl.to(elem, {
duration: 1.5,
width: '100%',
ease: 'power4'
});
// Create ScrollTrigger to track visibility
const scrollTrigger = ScrollTrigger.create({
trigger: elem,
scrub: false,
start: 'top 90%',
end: 'bottom 0%',
});
separatorLineTimelines.push({
timeline: tl,
scrollTrigger: scrollTrigger,
element: elem
});
});
}
// DROPDOWN INTO VIEW
let dropdownBlocks = $('.dropdown-block');
// Check if dropdown blocks exist
if (dropdownBlocks.length) {
gsap.utils.toArray(dropdownBlocks).forEach(function (elem) {
// Select heading, image, separator line, and plus lines within the dropdown block
const heading = elem.querySelector('.heading');
const image = elem.querySelector('.image-block.dropdown img');
const separator = elem.querySelector('.separator-line.dropdown');
const plusLines = elem.querySelectorAll('.dropdown-plus-line .dropdown-plus-solid');
// Split heading into lines for animation
let innerSplit = null;
if (heading) {
innerSplit = new SplitText(heading, {
type: 'lines',
linesClass: 'text-line'
});
}
// Set initial states for heading lines, image, separator line, and plus lines
if (innerSplit) {
gsap.set(innerSplit.lines, {
y: '110%',
opacity: 0,
//willChange: 'transform, opacity'
});
}
if (image) {
gsap.set(image, {
opacity: 0,
//willChange: 'opacity'
});
}
if (separator) {
gsap.set(separator, {
width: '0%',
//willChange: 'width'
});
}
if (plusLines.length) {
gsap.set(plusLines, {
width: '0%',
//willChange: 'width, height'
});
}
// Create a paused timeline for the animation
const dropdownTimeline = gsap.timeline({
paused: true,
onComplete: () => {
if (innerSplit) innerSplit.revert(); // Revert SplitText only if it was created
/*gsap.set(image, { willChange: 'auto' });
gsap.set(separator, { willChange: 'auto' });
gsap.set(plusLines, { willChange: 'auto' });*/
}
});
// Animate heading lines with lift and fade-in
if (innerSplit) {
dropdownTimeline.to(innerSplit.lines, {
duration: 1.1,
y: 0,
opacity: 1,
ease: 'Power4.easeOut',
stagger: 0.12
});
}
// Animate plus lines with a delay of 0.2 seconds
if (plusLines.length) {
dropdownTimeline.to(plusLines, {
duration: 0.5,
width: '100%', // Expand horizontal line
ease: 'Power4.easeOut',
stagger: 0.2
}, 0.2);
}
// Animate separator line with a delay of 0.3 seconds
if (separator) {
dropdownTimeline.to(separator, {
duration: 1.5,
width: '100%',
ease: 'Power4.easeOut'
}, 0.3);
}
// Animate image if it exists, with a delay of 0.3 seconds
if (image) {
dropdownTimeline.to(image, {
duration: 1.5,
opacity: 1,
ease: 'Power2.easeOut'
}, 0.3);
}
// Create ScrollTrigger to start animation when element enters viewport
const scrollTrigger = ScrollTrigger.create({
trigger: elem,
scrub: false,
start: 'top 90%',
end: 'bottom 0%',
onEnter: () => dropdownTimeline.play()
});
// Add timeline to array for later initialization
dropdownTimelines.push({
timeline: dropdownTimeline,
scrollTrigger: scrollTrigger,
element: elem
});
});
}
// MEDIA BLOCKS INTO VIEW
/*const mediaBlocks = $('.image-block .image, .video-block').not('.dropdown-block .image');
// Create or find