1$(document).ready(function () { 2 // Discover our products 3 let $disProdList = $('.str-prodlist-slides'); 4 let $insgtOtherSlides = $('.insights-oth-slider'); 5 let $insgtTeamSlides = $('.insights-team-slider'); 6 let $insgtRETeamSlides = $('.insights-re-team-slider') 7 8 $disProdList.length && $disProdList.slick({ 9 dots: false, 10 infinite: false, 11 speed: 300, 12 slidesToShow: 4, 13 slidesToScroll: 2, 14 draggable: false, 15 responsive: [ 16 { 17 breakpoint: 1024, 18 settings: { 19 slidesToShow: 3, 20 slidesToScroll: 1, 21 infinite: false, 22 dots: false, 23 draggable: false, 24 }, 25 }, 26 { 27 breakpoint: 767, 28 settings: { 29 slidesToShow: 2, 30 slidesToScroll: 1, 31 draggable: true, 32 }, 33 }, 34 { 35 breakpoint: 600, 36 settings: { 37 slidesToShow: 1, 38 slidesToScroll: 1, 39 draggable: true, 40 }, 41 } 42 ], 43 }); 44 45 $insgtOtherSlides.slick({ 46 dots: false, 47 infinite: false, 48 speed: 500, 49 slidesToShow: 2.5, 50 slidesToScroll: 2, 51 draggable: false, 52 responsive: [ 53 { 54 breakpoint: 1025, 55 settings: { 56 slidesToShow: 2, 57 slidesToScroll: 2 58 }, 59 }, 60 { 61 breakpoint: 767, 62 settings: { 63 slidesToShow: 1, 64 slidesToScroll: 1, 65 draggable: true, 66 }, 67 } 68 ], 69 }); 70 71 $insgtTeamSlides.slick({ 72 dots: false, 73 infinite: false, 74 speed: 300, 75 slidesToShow: 3, 76 slidesToScroll: 2, 77 draggable: false, 78 responsive: [ 79 { 80 breakpoint: 1024, 81 settings: { 82 slidesToShow: 3, 83 slidesToScroll: 1, 84 infinite: false, 85 dots: false, 86 draggable: false, 87 }, 88 }, 89 { 90 breakpoint: 992, 91 settings: { 92 slidesToShow: 2, 93 slidesToScroll: 1, 94 infinite: false, 95 dots: false, 96 }, 97 }, 98 { 99 breakpoint: 600, 100 settings: { 101 slidesToShow: 1, 102 slidesToScroll: 1, 103 }, 104 }, 105 ], 106 }); 107 108 $insgtRETeamSlides.slick({ 109 dots: false, 110 infinite: false, 111 speed: 300, 112 slidesToShow: 4, 113 slidesToScroll: 3, 114 draggable: false, 115 responsive: [ 116 { 117 breakpoint: 1500, 118 settings: { 119 slidesToShow: 3, 120 slidesToScroll: 2, 121 infinite: false, 122 dots: false, 123 draggable: false, 124 }, 125 }, 126 { 127 breakpoint: 992, 128 settings: { 129 slidesToShow: 2, 130 slidesToScroll: 1, 131 infinite: false, 132 dots: false, 133 }, 134 }, 135 { 136 breakpoint: 600, 137 settings: { 138 slidesToShow: 1, 139 slidesToScroll: 1, 140 }, 141 }, 142 ], 143 }); 144 145 146 // Check if the device supports touch 147 const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0; 148 149 if (isTouchDevice) { 150 // MOBILE: Tap to toggle open/closed 151 $('.flipcard-float-text').on('click', function (e) { 152 e.preventDefault(); 153 $('.insights-re-multidev-flipcard .flip-card-hld').toggleClass('flip-card--active'); 154 }); 155 } else { 156 // DESKTOP: Smooth hover in and out 157 $('.flipcard-float-text').hover( 158 function () { $('.insights-re-multidev-flipcard .flip-card-hld').addClass('flip-card--active'); }, 159 function () { $('.insights-re-multidev-flipcard .flip-card-hld').removeClass('flip-card--active'); } 160 ); 161 } 162 163 /* GSAP OnLoad Banner Animation */ 164 let bannerSplit; 165 let fadeInUpOnLoad = { 166 y: 50, 167 autoAlpha: 0, 168 duration: 1, 169 stagger: 0.1, 170 ease: "power2.inOut" 171 } 172 173 const heroTl = gsap.timeline({ 174 defaults: { ease: "power2.inOut" } 175 }); 176 177 gsap.set(".starr-content_banner--insights h1, .banner--profile-badge", { opacity: 1, y: 0 }); 178 179 heroTl.from(".starr-content_banner--insights h1 span", fadeInUpOnLoad).from(".banner--profile-badge", fadeInUpOnLoad, "-=0.5"); 180}); 181 182document.addEventListener("DOMContentLoaded", (event) => { 183 // Target the video element 184 const myVideo = document.querySelector(".re-capital-vid-hld video"); 185 if (myVideo) { 186 myVideo.playbackRate = 0.35; 187 } 188 189 190 // you only need to define the configuration settings you want to CHANGE. Omitted properties won't be affected. 191 gsap.config({ 192 nullTargetWarn: false, 193 }); 194 195 gsap.registerPlugin(ScrollTrigger); 196 197 const heroBannerSc = document.querySelector('.starr_hero_banner'); 198 if (heroBannerSc && heroBannerSc.classList.contains('starr-smooth-scroll-lenis')) { 199 const lenis = new Lenis(); 200 // Synchronize Lenis scrolling with GSAP's ScrollTrigger plugin 201 lenis.on('scroll', ScrollTrigger.update); 202 203 // Add Lenis's requestAnimationFrame (raf) method to GSAP's ticker 204 // This ensures Lenis's smooth scroll animation updates on each GSAP tick 205 gsap.ticker.add((time) => { 206 lenis.raf(time * 1000); // Convert time from seconds to milliseconds 207 208 // Disable lag smoothing in GSAP to prevent any delay in scroll animations 209 gsap.ticker.lagSmoothing(0); 210 211 });
212 } 213 214 ScrollTrigger.defaults({ 215 anticipatePin: 1, // Gives the engine a buffer to calculate layout shifts 216 }); 217 218 // gsap code here! 219 // media query 220 let mm = gsap.matchMedia(), 221 breakPoint = 768; 222 223 224 /* fn - Global Header group animation */ 225 function createScrollTrigger(triggerElmt, timeline, startDesktop = 75, startMob = 85, markers = false) { 226 ScrollTrigger.create({ 227 trigger: triggerElmt, 228 start: () => { 229 return window.innerWidth >= 768 ? `top ${startDesktop}%` : `top ${startMob}%`; 230 }, 231 end: "bottom center", 232 markers: markers, 233 onEnter: () => timeline.play(), 234 onLeaveBack: () => { 235 // Reverse animation when scrolled past 236 timeline.reverse(); 237 } 238 }); 239 } 240 241 /* fn - Zigzag Line Animation */ 242 function fnZigzagSVGAnime(svgPathID, duration = 1, start = "top bottom", end = "bottom 70%", scrub = 1) { 243 if (svgPathID) { 244 let path = document.querySelector(`#${svgPathID}`); 245 if (path) { 246 let pathLength = path.getTotalLength(); 247 gsap.set(path, { strokeDasharray: pathLength }); 248 249 let shipfleetTL = gsap.timeline(); 250 shipfleetTL.fromTo( 251 path, { 252 strokeDashoffset: pathLength 253 }, 254 { 255 strokeDashoffset: 0, 256 duration: duration, 257 ease: "power2.in", 258 scrollTrigger: { 259 trigger: path, 260 start: start, 261 end: end, 262 scrub: scrub 263 } 264 } 265 ) 266 } 267 } 268 } 269 270 /* fn - Global fadein up stagger list animation */ 271 function gsapFadeInUpStagger(el, y = 50, duration = 1, stagger = 0.3, ease = "power2.inOut") { 272 let elArr = gsap.utils.toArray(el); 273 let tL = gsap.timeline({ ease: ease, paused: true }); 274 if (elArr.length) { 275 tL.from(el, { 276 y: y, 277 autoAlpha: 0, 278 duration: duration, 279 stagger: stagger 280 }, createScrollTrigger(el, tL)); 281 } 282 } 283 284 let mainNav = document.querySelector(".starr-menubar .header"); 285 let mainNavH = mainNav ? mainNav.clientHeight : ""; 286 287 mm.add({ 288 isDesktop: `(min-width: ${breakPoint}px)`, 289 isMobile: `(max-width: ${breakPoint - 1}px)` 290 }, (context) => { 291 // Extract context conditions for easy reference if needed 292 let { isDesktop, isMobile } = context.conditions; 293 /* ==== 294 ** All pinned Animationn Should keep to top ---- 295 ** Pinned Animation Start 296 =====*/ 297 298 /* Shipfleet section Tab Animaiton */ 299 let tabCards = gsap.utils.toArray(".anime-horiz-tab-content .insights-tab-content"); 300 if (tabCards.length) { 301 let tabCardsContainer = document.querySelector(".anime-horiz-tab-content"); 302 let tabTotalscroll = tabCardsContainer.scrollWidth - (tabCards[0].offsetWidth); 303 let tabShipImg1 = tabCards[0].querySelector(".insights-tab-img-xl"); 304 let tabEllipseImg1 = tabCards[0].querySelector(".insights-tab-ellipse"); 305 306 let tabCards1TL = gsap.timeline({ 307 scrollTrigger: { 308 trigger: tabCards[0], 309 start: "top 70%", 310 end: "top top", 311 scrub: true 312 } 313 }); 314 315 tabCards1TL.from(tabShipImg1, { 316 xPercent: -80, 317 duration: 1, 318 }) 319 .from(tabEllipseImg1, { 320 scale: 0, 321 autoAlpha: 0, 322 duration: 1, 323 }) 324 325 let scrollTrackTL = gsap.timeline({ 326 scrollTrigger: { 327 trigger: ".insights-tab-scroller", 328 start: `top ${mainNavH}px`, 329 end: `+=${tabTotalscroll}`, 330 pin: true, 331 scrub: true, 332 } 333 }); 334 335 scrollTrackTL.to(tabCardsContainer, { 336 x: -tabTotalscroll, 337 duration: tabCards.length, 338 ease: "none" 339 }); 340 341 tabCards.forEach(tab => { 342 let tabContent = tab.querySelectorAll(".insights-content"); 343 let tabShipImg = tab.querySelector(".insights-tab-img-xl"); 344 let tabEllipseImg = tab.querySelector(".insights-tab-ellipse"); 345 346 scrollTrackTL.from(tabEllipseImg, { 347 scale: 0, 348 autoAlpha: 0, 349 duration: 1, 350 scrollTrigger: { 351 trigger: tab, 352 start: "left 70%", 353 end: "center center", 354 containerAnimation: scrollTrackTL, 355 scrub: true, 356 } 357 },) 358 359 if (tab.classList.contains("insights-tab-content--grey")) { 360 scrollTrackTL.from(tabShipImg, { 361 xPercent: -80, 362 duration: 1, 363 scrollTrigger: { 364 trigger: tab, 365 start: "left 75%", 366 end: "left 40%", 367 containerAnimation: scrollTrackTL, 368 scrub: true, 369 } 370 }, "<") 371 } 372
373 if (tab.classList.contains("insights-tab-content--shadow")) { 374 scrollTrackTL.from(tabShipImg, { 375 yPercent: -100, 376 duration: 1, 377 scrollTrigger: { 378 trigger: tab, 379 start: "left 75%", 380 end: "left 40%", 381 containerAnimation: scrollTrackTL, 382 scrub: true, 383 } 384 }, "<") 385 } 386 387 }); 388 389 } 390 391 /* Stack Card pined Animation */ 392 393 /* Stacked Image Card Intro Animation */ 394 gsapFadeInUpStagger(".anime-stacked-card-col", 100); 395 396 /* Stacked Image Card Pinned Animation */ 397 let stackCardItems = gsap.utils.toArray(".stack-card-item"); 398 if (stackCardItems.length) { 399 let stackContainer = document.querySelector(".stacked-card-panel"); 400 let stackContainerHeight = parseInt(stackContainer.getBoundingClientRect().height); 401 402 403 gsap.set(stackCardItems[0], { y: 0, autoAlpha: 1, display: "block" }); 404 405 const stackCardTl = gsap.timeline({ 406 scrollTrigger: { 407 trigger: ".stacked-card-panel", 408 start: () => { 409 return window.innerWidth >= 768 ? "top 8%" : "top 50px"; 410 }, 411 end: () => "=+" + (stackContainerHeight * stackCardItems.length), 412 scrub: 1, 413 pin: true 414 } 415 }); 416 417 stackCardItems.forEach((el, i) => { 418 if (i === 0) return; 419 420 let prevItem = stackCardItems[i - 1]; 421 let stepLable = `step_${i}`; 422 423 stackCardTl.addLabel(stepLable); 424 425 // move previous card content to top 426 stackCardTl.to(prevItem, { 427 y: -25, 428 autoAlpha: 0, 429 duration: 0.6, 430 ease: "power2.inOut", 431 display: "none" 432 }, stepLable); 433 434 435 //Transition in for current card 436 stackCardTl.fromTo(el, { 437 autoAlpha: 0, 438 y: 50, 439 display: "none" 440 }, { 441 y: 0, 442 autoAlpha: 1, 443 duration: 0.6, 444 ease: "power2.inOut", 445 display: "block" 446 }, `${stepLable}+=0.4`); 447 }); 448 449 stackCardTl.to({}, { duration: 0.3 }); 450 } 451 452 /* Regions Map slideup */ 453 let regionMapTL = gsap.timeline({ 454 scrollTrigger: { 455 trigger: ".regions-map-hld", 456 start: () => { 457 return window.innerWidth >= 768 ? "top 70%" : "top 80%"; 458 }, 459 toggleActions: "play none none reverse" 460 } 461 }); 462 463 regionMapTL.to(".regions-map-imghld svg", { autoAlpha: 1, duration: 0.6, ease: "power2.inOut" }); 464 465 const popupMapCards = gsap.utils.toArray(".regions-map-popover"); 466 const popupMapPointers = gsap.utils.toArray(".popover-circle"); 467 468 if (popupMapCards.length) { 469 const mcTotalLen = popupMapCards.length; 470 const mcTotalScroll = mcTotalLen * 1000; 471 472 const mcTL = gsap.timeline({ 473 scrollTrigger: { 474 trigger: ".regions-map-hld", 475 start: isDesktop ? "top 70px" : "top 12%", 476 end: `+=${mcTotalScroll}`, 477 pin: true, 478 scrub: 1 479 } 480 }); 481 482 popupMapCards.forEach((card, index) => { 483 const pointerEl = popupMapPointers[index]; 484 gsap.set(card, { yPercent: isDesktop ? -25 : 0, display: "none" }); 485 486 mcTL.to(card, { 487 autoAlpha: 1, 488 yPercent: isDesktop ? -50 : -15, 489 duration: isDesktop ? 1 : 0.6, 490 ease: "power2.inOut", 491 display: "flex", 492 onStart: () => pointerEl && pointerEl.classList.add('active'), 493 onReverseComplete: () => pointerEl && pointerEl.classList.remove('active') 494 }) 495 .to({}, { duration: isDesktop ? 0.5 : 0.3 }); 496 497 if (index < mcTotalLen - 1) { 498 mcTL.to(card, { 499 autoAlpha: 0, 500 yPercent: isDesktop ? -75 : -25, 501 duration: isDesktop ? 1 : 0.6, 502 display: "none", 503 ease: "power2.inOut", 504 onComplete: () => pointerEl && pointerEl.classList.remove('active'), 505 onInterrupt: () => pointerEl && pointerEl.classList.add('active'), 506 onReverseComplete: () => pointerEl && pointerEl.classList.add('active') 507 }) 508 } 509 }); 510 } 511 512 /* RE Stacked icon sldier */ 513 const stackIconGrp = gsap.utils.toArray(".anime-stack-icon-grp li"); 514 if (stackIconGrp.length) { 515 const stackIconGrpLen = stackIconGrp.length * 200; 516 517 const stackIconTL = gsap.timeline({ 518 scrollTrigger: { 519 trigger: ".anime-stack-icon-sec", 520 start: isDesktop ? "top 35%" : "top 75%",
521 end: isDesktop ? `+=${stackIconGrpLen}` : "+=70%", 522 scrub: isDesktop ? 1 : true, 523 pin: isDesktop ? true : false 524 } 525 }); 526 527 stackIconGrp.forEach((element, index) => { 528 stackIconTL.from(element, { 529 autoAlpha: 0, 530 y: 100, 531 xPercent: isDesktop ? 70 : 0, 532 duration: 1, 533 }) 534 }); 535 } 536 537 /* RE Category Slider */ 538 const catSliderPanels = document.querySelectorAll(".stack-catslider-sec"); 539 540 if (catSliderPanels.length) { 541 542 const sliderIntroTL = gsap.timeline({ 543 scrollTrigger: { 544 trigger: ".regions-stack-wrapper", 545 start: "top 60%", 546 toggleActions: "play none none reverse" 547 } 548 }); 549 550 sliderIntroTL.from(".re-regions-stack-header", { autoAlpha: 0, y: 70, duration: 1.2, ease: "power2.inOut" }) 551 .from(".stack-catslider-container", { autoAlpha: 0, y: 70, duration: 0.8, ease: "power2.inOut" }, "-=0.5"); 552 553 const catTotalCards = document.querySelectorAll(".catslider").length; 554 const carScrollDistance = window.innerWidth >= 768 ? catTotalCards * 800 : catTotalCards * 600; 555 556 gsap.set(".stack-catslider-sec:not(:first-of-type) h3", { autoAlpha: 0, y: isDesktop ? 50 : 20 }); 557 gsap.set(".catslider:not(.stack-catslider-sec:first-of-type .catslider:first-of-type)", { autoAlpha: 0, y: isDesktop ? 50 : 20, pointerEvents: "none" }); 558 559 gsap.set(".stack-catslider-sec:first-of-type .catslider:first-of-type", { autoAlpha: 1, y: 0, pointerEvents: "auto" }); 560 561 const catSliderTL = gsap.timeline({ 562 scrollTrigger: { 563 trigger: ".regions-stack-wrapper", 564 start: isDesktop ? "top 6%" : "top 40px", 565 end: `+=${carScrollDistance}`, 566 scrub: 1, 567 pin: true, 568 anticipatePin: 1, 569 pinnedContainer: ".regions-stack-wrapper" 570 } 571 }); 572 573 catSliderPanels.forEach((panel, panelIndex) => { 574 const heading = panel.querySelector("h3"); 575 const cards = panel.querySelectorAll(".catslider"); 576 577 catSliderTL.set(panel, { className: "stack-catslider-sec active" }); 578 579 if (panelIndex > 0) { 580 catSliderTL.to(heading, { autoAlpha: 1, y: 0, duration: 1 }); 581 } 582 583 cards.forEach((card, cardIndex) => { 584 const isFirstCard = (panelIndex === 0 && cardIndex === 0); 585 const isLastCard = (panelIndex === catSliderPanels.length - 1) && (cardIndex === cards.length - 1); 586 587 588 if (!isFirstCard) { 589 catSliderTL.to(card, { autoAlpha: 1, y: 0, duration: 1.3, pointerEvents: "auto" }, "+=0.2") 590 .to({}, { duration: 0.5 }); 591 } 592 593 if (!isLastCard) { 594 catSliderTL.to({}, { duration: 0.5 }) 595 .to(card, { autoAlpha: 0, y: isDesktop ? -50 : -20, duration: 1.2, pointerEvents: "none" }, "+=0.8"); 596 } 597 }); 598 599 if (panelIndex < catSliderPanels.length - 1) { 600 catSliderTL.to(heading, { autoAlpha: 0, y: isDesktop ? -50 : -20, duration: 1 }, "-=0.4") 601 .set(panel, { className: "stack-catslider-sec" }); 602 } 603 }); 604 } 605 606 /* RE Stacked gloab card animation */ 607 const stackGloabCradList = gsap.utils.toArray(".re-acc-market-content li"); 608 if (stackGloabCradList.length) { 609 const stackGloabCradTL = gsap.timeline({ 610 scrollTrigger: { 611 trigger: ".acc-market-map-container", 612 start: "top 18%", 613 end: "+=1000", 614 pin: true, 615 scrub: 1 616 } 617 }); 618 619 stackGloabCradList.forEach((card, index) => { 620 stackGloabCradTL.to(card, { 621 autoAlpha: 1, 622 y: 0, 623 pointerEvents: "auto", 624 duration: 1 625 } 626 ) 627 .to({}, { duration: 0.8 }); 628 629 630 if (index < stackGloabCradList.length - 1) { 631 stackGloabCradTL.to(card, { 632 autoAlpha: 0, 633 y: -50, 634 pointerEvents: "none", 635 duration: 1 636 } 637 ) 638 } 639 }); 640 } 641 642 /*RE Home clip Animation */ 643 const svgClipTL = gsap.timeline({ 644 scrollTrigger: { 645 trigger: ".insights-re-claim-panel", 646 start: "top 25%", 647 end: "+=600", 648 scrub: 1, 649 pin: true, 650 } 651 });
652 svgClipTL.to("#home_clip_rect", { 653 attr: { 654 y: 0, 655 height: 321 656 }, 657 duration: 1, 658 ease: "none" 659 }) 660 661 /* ==== Pinned Animation End =====*/ 662 663 let glHeaderGrp = gsap.utils.toArray(".anime-header-grp"); 664 if (glHeaderGrp.length) { 665 glHeaderGrp.forEach((header, index) => { 666 let hdrGrpH2 = header.querySelector(".insights-sec-header"); 667 let hdrGrpContent = header.querySelectorAll(".insights-content p"); 668 let hdrGrpContentBtn = header.querySelector(".anim-insights-content-btn"); 669 670 let headingTl = gsap.timeline({ ease: "power2.inOut", paused: true }); 671 672 headingTl.from(hdrGrpH2, { 673 yPercent: 100, 674 autoAlpha: 0, 675 duration: 1, 676 }) 677 .from(hdrGrpContent, { 678 yPercent: 100, 679 autoAlpha: 0, 680 duration: 1, 681 stagger: 0.3 682 }, "-=0.3") 683 .from(hdrGrpContentBtn, { 684 yPercent: 100, 685 autoAlpha: 0, 686 duration: 1, 687 }, "-=0.5"); 688 createScrollTrigger(header, headingTl); 689 }); 690 } 691 692 /* Global shipping section Animaiton */ 693 let wavyTextGrp = gsap.utils.toArray(".globalship-wrapper .anime-wavytext svg, .globalship-wrapper .anime-content"); 694 if (wavyTextGrp.length) { 695 wavyTextGrp.forEach(element => { 696 let tl = gsap.timeline({ ease: "power2.out", paused: true }); 697 let textPath = element.querySelector("textPath"); 698 const getOffset = element.getAttribute('data-start-offset'); 699 gsap.set(textPath, { opacity: 0 }) 700 tl.to(textPath, { 701 attr: { 702 startOffset: `${getOffset}%` 703 }, 704 duration: 1, 705 autoAlpha: 1, 706 }); 707 708 if (element.classList.contains("anime-content")) { 709 let emlt = element.querySelectorAll("p"); 710 tl.from(emlt, { 711 y: 50, 712 autoAlpha: 0, 713 stagger: 0.3, 714 duration: 1, 715 }, "-=0.3"); 716 } 717 createScrollTrigger(element, tl); 718 }); 719 } 720 721 /* All Zigzag SVG line Animation */ 722 fnZigzagSVGAnime("zigzagP1"); 723 fnZigzagSVGAnime("zigzagP2", 1, "top bottom", "top 60%", 1); 724 fnZigzagSVGAnime("zigzagP3"); 725 726 /* Follow the Oil Section */ 727 let folList = gsap.utils.toArray(".follow-oil-list li"); 728 729 if (folList.length) { 730 gsap.set(".follow-oil-list li", { y: 100, autoAlpha: 0, ease: "power3", duration: 1 }); 731 ScrollTrigger.batch(".follow-oil-list li", { 732 interval: 0.2, // time window (in seconds) for batching to occur. 733 batchMax: 3, // maximum batch size (targets). Can be function-based for dynamic values 734 onEnter: batch => gsap.to(batch, { autoAlpha: 1, y: 0, stagger: { each: 0.20, grid: [1, 3] }, duration: 1, overwrite: true }), 735 onLeaveBack: batch => gsap.to(batch, { autoAlpha: 0, y: 100, duration: 0.5, overwrite: true }), 736 start: "top 80%", 737 end: "top center", 738 }); 739 740 // return a gsap.set() in the listener, it'll automatically revert it after the refresh()! 741 ScrollTrigger.addEventListener("refreshInit", () => gsap.set(".follow-oil-list li", { y: 0, autoAlpha: 1 })); 742 743 } 744 745 /* Explosive expansion Section */ 746 let rippleCont = document.querySelector(".insights-ripple-cont"); 747 let rippleContList = gsap.utils.toArray(".insights-ripple-cont li"); 748 let movingShipHld = document.querySelector(".insights-ship-moving"); 749 let movingShip = document.querySelector(".insights-ship-moving img"); 750 let cargoSec = document.querySelector(".cargo-container"); 751 752 753 let rippleTL = gsap.timeline({ 754 paused: true, 755 repeat: -1, 756 delay: 0.2, 757 scrollTrigger: { 758 trigger: ".insights-ripple-main", 759 start: "top center", 760 end: "bottom center", 761 toggleActions: "play pause resume pause", // onEnter, onLeave, onEnterBack, onLeaveBack 762 } 763 }); 764 rippleTL.fromTo('.insights-ripple-img #circle3', { scale: 0, autoAlpha: 0.5, transformOrigin: "center center" }, 765 { 766 scale: 1, autoAlpha: 1, duration: 1 767 }) 768 .fromTo('.insights-ripple-img #circle2', { scale: 0, autoAlpha: 1, transformOrigin: "center center" }, 769 { 770 scale: 1, autoAlpha: 0.7, duration: 1, 771 }, "-=0.5") 772 .fromTo('.insights-ripple-img #circle1', { scale: 0, autoAlpha: 1, transformOrigin: "center center" }, 773 { 774 scale: 1, autoAlpha: 0.5, duration: 1, 775 }, "-=0.5"); 776 777 if (rippleContList.length) { 778 rippleContTL = gsap.timeline({ paused: true });
779 780 rippleContTL.from(rippleContList, { 781 y: 50, 782 autoAlpha: 0, 783 duration: 1, 784 stagger: 0.3, 785 delay: 1 786 }) 787 createScrollTrigger(rippleContList, rippleContTL); 788 } 789 790 function fnGetPosX(section, xPercent) { 791 const rect = section.getBoundingClientRect(); 792 return { 793 x: parseInt(rect.left + rect.width * xPercent - (window.innerWidth / 2)) 794 }; 795 } 796 797 if (movingShip) { 798 let movingShipH = movingShip.offsetHeight; 799 let cargoSecH = cargoSec.offsetHeight; 800 let totalTL = Math.round((movingShipH + cargoSecH) / movingShipH); 801 let shipY = parseInt((window.innerHeight - (movingShipHld.clientHeight + mainNavH + 10)) / (totalTL + 1)); 802 803 let shipTL = gsap.timeline({ 804 rotate: 0, 805 x: 0, 806 y: 0, 807 scrollTrigger: { 808 trigger: ".insights-ship-moving-outer", 809 start: `top ${mainNavH}`, 810 end: "bottom bottom", 811 endTrigger: cargoSec, 812 pin: movingShipHld, 813 scrub: true, 814 invalidateOnRefresh: true 815 } 816 }); 817 818 shipTL.to(movingShip, { 819 x: 0, 820 y: `+=${shipY}`, 821 rotation: 45, 822 duration: 1, 823 transformOrigin: "50% 15%" 824 }) 825 for (let i = 1; i <= totalTL; i++) { 826 shipTL.to(movingShip, { 827 x: () => isMobile ? -fnGetPosX(cargoSec, 0.85).x : -fnGetPosX(cargoSec, 0.8).x, 828 y: `+=${shipY}`, 829 rotate: 0, 830 duration: 1, 831 },) 832 } 833 } 834 835 /* Cargo Section */ 836 gsap.set(".cargo-cont-listhld li", { y: 100, autoAlpha: 0, ease: "power3", duration: 1 }); 837 838 ScrollTrigger.batch(".cargo-cont-listhld li", { 839 interval: 0.2, // time window (in seconds) for batching to occur. 840 batchMax: 3, // maximum batch size (targets). Can be function-based for dynamic values 841 onEnter: batch => gsap.to(batch, { autoAlpha: 1, y: 0, stagger: { each: 0.15, grid: [1, 3] }, duration: 1, overwrite: true }), 842 onLeaveBack: batch => gsap.to(batch, { autoAlpha: 0, y: 100, duration: 0.5, overwrite: true }), 843 start: "top 80%", 844 end: "bottom top" 845 }); 846 847 // return a gsap.set() in the listener, it'll automatically revert it after the refresh()! 848 ScrollTrigger.addEventListener("refreshInit", () => gsap.set(".cargo-cont-listhld li", { y: 0, autoAlpha: 1 })); 849 850 /* Discover Slides */ 851 let discSlidesArr = gsap.utils.toArray(".str-prodlist-slides .str-prodlist-slides-box"); 852 let discTL = gsap.timeline({ paused: true }); 853 if (discSlidesArr.length) { 854 discTL.from(discSlidesArr, { 855 y: 50, 856 autoAlpha: 0, 857 duration: 1, 858 stagger: 0.3 859 }, createScrollTrigger(discSlidesArr, discTL)); 860 } 861 862 863 /* Image Reveal Animation */ 864 let imgRevealList = gsap.utils.toArray(".anime-imgreveal-hld"); 865 if (imgRevealList.length) { 866 imgRevealList.forEach(wrapper => { 867 let imgHld = wrapper.querySelector(".anime-imgreveal"); 868 let img = wrapper.querySelector(".anime-imgreveal img"); 869 870 let tl = gsap.timeline({ 871 paused: true, 872 scrollTrigger: { 873 trigger: wrapper, 874 toggleActions: "play none none reverse", 875 start: "top 70%", 876 } 877 }); 878 tl.set(imgHld, { autoAlpha: 1 }); 879 tl.from(imgHld, 1.5, { 880 xPercent: -100, 881 ease: "power2.out" 882 }); 883 tl.from(img, 1.5, { 884 xPercent: 100, 885 scale: 1.3, 886 delay: -1.5, 887 ease: "power2.out", 888 onComplete: function () { 889 const element = this.targets()[0]; 890 const mainWrapper = element.closest(".anime-imgreveal-hld"); 891 892 if (mainWrapper) { 893 mainWrapper.classList.add("anime-imgreveal-done"); 894 } 895 }, 896 onUpdate: function () { 897 const element = this.targets()[0]; 898 const mainWrapper = element.closest(".anime-imgreveal-hld"); 899 if (mainWrapper) { 900 mainWrapper.classList.remove("anime-imgreveal-done"); 901 } 902 } 903 }); 904 }); 905 } 906 907 /* Other insights */ 908 let otherSlider = gsap.utils.toArray(".insights-oth-slider-item figcaption"); 909 let otherSliderTL = gsap.timeline({ paused: true });
910 if (otherSlider.length) { 911 otherSliderTL.from(otherSlider, { 912 y: 50, 913 autoAlpha: 0, 914 duration: 1, 915 stagger: 0.2 916 }, createScrollTrigger(otherSlider, otherSliderTL, 90, 90)); 917 } 918 919 /* ======= Insights RE Animation -- Start ======== */ 920 921 /* anime-content-box-grp */ 922 let reContBox = gsap.utils.toArray(".anime-content-box-grp"); 923 if (reContBox.length) { 924 reContBox.forEach((item, index) => { 925 let topPara = item.querySelectorAll(".re-content-box-para p"); 926 let boxCont = item.querySelector(".insights-re-content-box"); 927 let boxContEl = boxCont?.querySelectorAll("p, .card-profile-badge"); 928 let reContBoxTl = gsap.timeline({ ease: "power2.inOut", paused: true }); 929 930 reContBoxTl.from(topPara, { 931 yPercent: 100, 932 autoAlpha: 0, 933 duration: 1, 934 stagger: 0.3 935 }) 936 .from(boxCont, { 937 yPercent: 50, 938 autoAlpha: 0, 939 duration: 0.6, 940 }, "-=0.5") 941 .from(boxContEl, { 942 yPercent: 50, 943 autoAlpha: 0, 944 duration: 0.8, 945 stagger: 0.2 946 }, "-=0.3"); 947 createScrollTrigger(item, reContBoxTl); 948 }); 949 } 950 951 /* Price counter up */ 952 gsap.utils.toArray(".anime-price").forEach((el, index) => { 953 const countObj = { min: 0, max: 0 }; 954 955 const targetMin = parseFloat(el.dataset.min); 956 const targetMax = parseFloat(el.dataset.max); 957 958 gsap.to(countObj, { 959 min: targetMin, 960 max: targetMax, 961 duration: 1.8, 962 ease: "power2.out", 963 delay: index * 0.15, 964 scrollTrigger: { 965 trigger: ".anime-pricing-stack", 966 // Starts 100px BEFORE the container hits 75% of the viewport (adds an entry buffer) 967 start: "top bottom", 968 end: "bottom center", 969 // play (on enter), reverse (on leave), play (on enter back), reverse (on leave back) 970 toggleActions: "play none none reverse" 971 }, 972 onUpdate: function () { 973 el.innerText = `${Math.floor(countObj.min)}-${Math.floor(countObj.max)}`; 974 } 975 }); 976 }); 977 978 /* RE capital list Fade up*/ 979 const reCapitalList = gsap.utils.toArray(".insights-re-capital-list li"); 980 981 if (reCapitalList.length) { 982 gsap.set(reCapitalList, { y: 100, autoAlpha: 0, ease: "power2.inOut", duration: 1 }); 983 ScrollTrigger.batch(reCapitalList, { 984 interval: 0.2, // time window (in seconds) for batching to occur. 985 batchMax: 3, // maximum batch size (targets). Can be function-based for dynamic values 986 onEnter: batch => gsap.to(batch, { autoAlpha: 1, y: 0, stagger: { each: 0.20, grid: [1, 3] }, duration: 1, overwrite: true }), 987 onLeaveBack: batch => gsap.to(batch, { autoAlpha: 0, y: 100, duration: 0.5, overwrite: true }), 988 start: "top 80%", 989 end: "top center", 990 }); 991 992 // return a gsap.set() in the listener, it'll automatically revert it after the refresh()! 993 ScrollTrigger.addEventListener("refreshInit", () => gsap.set(reCapitalList, { y: 0, autoAlpha: 1 })); 994 995 } 996 997 998 /* RE Continue para with line animation */ 999 const continuePara = document.querySelectorAll(".anime-continue-para p"); 1000 1001 if (continuePara.length) { 1002 const continueParaTL = gsap.timeline({ ease: "power2.inOut", paused: true }); 1003 1004 continueParaTL.from(continuePara, { 1005 y: 50, 1006 autoAlpha: 0, 1007 duration: 1, 1008 stagger: 0.3 1009 }) 1010 .from(".anime-continue-line", { 1011 scaleY: 0, 1012 transformOrigin: "top", 1013 duration: 1 1014 }, "-=0.2", createScrollTrigger(".anime-continue-hld", continueParaTL, 50, 60)); 1015 } 1016 1017 /* Flip card floated text line animation*/ 1018 1019 const textLineX = gsap.utils.toArray(".flipcard-float-text"); 1020 if (textLineX.length) { 1021 gsap.to(".flipcard-float-text", { 1022 scrollTrigger: { 1023 trigger: ".anime-flipcard-float-text-wrap", 1024 start: "top 60%", 1025 toggleActions: "play none none reverse", 1026 onEnter: () => document.querySelector(".flipcard-float-text").classList.add("anime-fliptext-line"), 1027 onLeaveBack: () => document.querySelector(".flipcard-float-text").classList.remove("anime-fliptext-line") 1028 } 1029 }); 1030 } 1031 1032 }); 1033 1034 // End DOMContentLoaded event 1035}); 1036 1037 1038 1039 1040 1041
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.