@widelab-nc/widehue 1.0.45 → 1.0.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@widelab-nc/widehue",
3
- "version": "1.0.45",
3
+ "version": "1.0.46",
4
4
  "description": "Widelab starter template based on Finsweet template + add-ons.",
5
5
  "homepage": "https://widelab.co",
6
6
  "license": "ISC",
package/src/index.js CHANGED
@@ -7,12 +7,9 @@ import { CustomEase } from "gsap/CustomEase";
7
7
  import { SplitText } from 'gsap/SplitText';
8
8
  import Splide from '@splidejs/splide';
9
9
 
10
-
11
10
  // GSAP plugins register and custom easing
12
11
  gsap.registerPlugin(ScrollTrigger, ScrollToPlugin, CustomEase, SplitText);
13
12
 
14
- console.log('SplitText:', typeof SplitText);
15
- console.log('Registered plugins:', gsap.plugins);
16
13
 
17
14
  function customGsapEasing() {
18
15
  CustomEase.create('loader', '0.83, 0, 0.17, 1');
@@ -27,7 +24,6 @@ let contactFormOpen;
27
24
 
28
25
  function refreshScrollTriggersAfterLoad() {
29
26
  window.addEventListener('load', () => {
30
- console.log('[ScrollTrigger] Page fully loaded — refreshing all triggers');
31
27
  setTimeout(() => {
32
28
  ScrollTrigger.refresh();
33
29
  }, 100); // bufor na przypadkowe opóźnienia, możesz zwiększyć
@@ -66,9 +62,6 @@ function contactFormOpenAnimation() {
66
62
 
67
63
  if (checkboxElement) {
68
64
  checkboxElement.click(); // Click on the checkbox element
69
- console.log(`Clicked on checkbox for ${projectCategoryValue}`);
70
- } else {
71
- console.log(`No checkbox found for ${projectCategoryValue}`);
72
65
  }
73
66
  });
74
67
  });
@@ -91,6 +84,19 @@ const lenis = new Lenis({
91
84
  easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
92
85
  });
93
86
  function lenisScroll() {
87
+ // Configure ScrollTrigger to use Lenis as the scroller
88
+ ScrollTrigger.scrollerProxy(window, {
89
+ scrollTop(value) {
90
+ if (arguments.length) {
91
+ lenis.scrollTo(value, { immediate: true });
92
+ }
93
+ return lenis.scroll || lenis.actualScroll || window.pageYOffset || 0;
94
+ },
95
+ getBoundingClientRect() {
96
+ return { top: 0, left: 0, width: window.innerWidth, height: window.innerHeight };
97
+ }
98
+ });
99
+
94
100
  lenis.on('scroll', ScrollTrigger.update);
95
101
  gsap.ticker.add((time)=>{
96
102
  lenis.raf(time * 1000)
@@ -180,7 +186,6 @@ function revealFooter() {
180
186
  function checkElementExists(selector) {
181
187
  const element = document.querySelector(selector);
182
188
  if (!element) {
183
- console.warn(`Element ${selector} not found - skipping animation`);
184
189
  return false;
185
190
  }
186
191
  return true;
@@ -188,14 +193,12 @@ function checkElementExists(selector) {
188
193
 
189
194
  // Fallback function when loader elements don't exist
190
195
  function initBasicAnimations() {
191
- console.log('Initializing basic animations without loader');
192
196
 
193
197
  if (typeof lenis !== 'undefined') {
194
198
  try {
195
199
  lenis.scrollTo(0, { immediate: true });
196
200
  lenis.start();
197
201
  } catch (e) {
198
- console.warn('Lenis initialization failed:', e);
199
202
  window.scrollTo(0, 0);
200
203
  }
201
204
  } else {
@@ -204,7 +207,6 @@ function initBasicAnimations() {
204
207
  }
205
208
 
206
209
  function pageLoadAnimation() {
207
- console.log('pageLoadAnimation function called');
208
210
 
209
211
  // Check if all required loader elements exist
210
212
  const requiredElements = [
@@ -222,11 +224,9 @@ function pageLoadAnimation() {
222
224
  }
223
225
 
224
226
  const loaderAnimationIn = gsap.timeline({});
225
- console.log('GSAP timeline created');
226
227
 
227
228
  loaderAnimationIn
228
229
  .add(function() {
229
- console.log('First animation step triggered: scrollRestoration and scrollTo');
230
230
  history.scrollRestoration = 'manual';
231
231
 
232
232
  // Safari-safe scroll to top
@@ -234,7 +234,6 @@ function pageLoadAnimation() {
234
234
  try {
235
235
  lenis.scrollTo(0, { immediate: true });
236
236
  } catch (e) {
237
- console.warn('Lenis scrollTo failed, using fallback:', e);
238
237
  window.scrollTo(0, 0);
239
238
  }
240
239
  } else {
@@ -261,7 +260,6 @@ function pageLoadAnimation() {
261
260
  '<'
262
261
  )
263
262
  .add(function() {
264
- console.log('lenis started');
265
263
  if (typeof lenis !== 'undefined' && lenis.start) {
266
264
  lenis.start();
267
265
  }
@@ -270,26 +268,20 @@ function pageLoadAnimation() {
270
268
  display: 'none',
271
269
  duration: 0.1,
272
270
  onComplete: function() {
273
- console.log('.loader_wrapper set to display:none');
274
271
  }
275
272
  }, '>');
276
273
 
277
- console.log('Animation timeline defined');
278
274
 
279
275
  // Update on screen resize - with element existence check
280
276
  window.addEventListener('resize', function () {
281
- console.log('Window resize event triggered');
282
277
  setTimeout(function () {
283
278
  if (document.querySelector('.loader_wrapper')) {
284
- console.log('Set .loader_wrapper to display:none on resize');
285
279
  gsap.set('.loader_wrapper', { display: 'none' });
286
280
  } else {
287
- console.warn('Loader wrapper not found on resize');
288
281
  }
289
282
  }, 50);
290
283
  });
291
284
 
292
- console.log('Resize event listener added');
293
285
  }
294
286
 
295
287
 
@@ -431,22 +423,10 @@ window.standardHeaderScrollAnimation = function() {
431
423
  const leaveBackTimeline = gsap.timeline({ paused: true });
432
424
 
433
425
  enterTimeline
434
- .to('.navbar_brand.scale', { scale: 0.25, duration: 1 })
435
- .to('.wideletter', {
436
- y: '-150%',
437
- duration: 1,
438
- ease: 'loader2',
439
- stagger: 0.1,
440
- }, 0); // 0 to start simultaneously with the previous animation
426
+ .to('.navbar_brand.scale', { scale: 0.25, duration: 1 });
441
427
 
442
428
  leaveBackTimeline
443
- .to('.navbar_brand.scale', { scale: 1, duration: 1 })
444
- .to('.wideletter', {
445
- y: '0%',
446
- duration: 1,
447
- ease: 'loader2',
448
- stagger: 0.1,
449
- }, 0);
429
+ .to('.navbar_brand.scale', { scale: 1, duration: 1 });
450
430
 
451
431
  ScrollTrigger.create({
452
432
  start: 'top+=100 top', // Triggers when the user has scrolled 100px
@@ -493,134 +473,177 @@ window.customCursorText = function(e) {
493
473
 
494
474
 
495
475
  window.heroAnimationOnLoad = function(e) {
496
- console.log('heroAnimationOnLoad function started');
497
-
498
- const hasPlayedAnimation = window.name.includes('heroPlayed');
476
+ const video = document.getElementById('herovideo');
499
477
 
500
478
  gsap.set('.wideletter', { y: '-150%', scale: 1 });
501
479
 
502
480
  if (typeof lenis !== 'undefined') {
503
- console.log('Lenis instance found, attempting to scroll to top');
504
- setTimeout(() => {
505
- lenis.scrollTo(0, { duration: 0, easing: (t) => t });
506
- console.log('Lenis scrollTo action called after delay');
507
- }, 100);
508
- } else {
509
- console.log('Lenis instance not found');
510
- }
511
-
512
- const videoMask = e.querySelector('.hero_headline_ract-mask');
513
- const video = e.querySelector('video.lazyload');
514
- const heroAnimation = gsap.timeline({});
515
- const homeHeroHeading = new SplitText('#heroHeading', {
516
- type: 'lines',
517
- linesClass: 'hero-line',
518
- });
519
- const homeHeroHeadingMask = new SplitText('#heroHeading', {
520
- type: 'lines',
521
- linesClass: 'hero-line-mask',
522
- });
523
-
524
- const heroLines = document.querySelectorAll('.hero-line');
525
- if (heroLines.length === 0) {
526
- console.error('GSAP target .hero-line not found.');
527
- return;
481
+ setTimeout(() => lenis.scrollTo(0, { duration: 0, easing: (t) => t }), 100);
528
482
  }
529
483
 
530
- function updateVideoSources() {
531
- const isMobile = window.innerWidth < 992;
532
- const mobileMp4 = video.getAttribute('mobile-mp4');
533
- const mobileWebm = video.getAttribute('mobile-webm');
534
- const mp4Source = video.querySelector('source[type="video/mp4"]');
535
- const webmSource = video.querySelector('source[type="video/webm"]');
536
-
537
- if (isMobile) {
538
- if (mobileMp4) mp4Source.setAttribute('data-src', mobileMp4);
539
- if (mobileWebm) webmSource.setAttribute('data-src', mobileWebm);
540
- } else {
541
- mp4Source.setAttribute('data-src', mp4Source.getAttribute('data-src').replace('mobile-', ''));
542
- webmSource.setAttribute('data-src', webmSource.getAttribute('data-src').replace('mobile-', ''));
543
- }
544
- }
545
-
546
- updateVideoSources();
547
- window.addEventListener('resize', updateVideoSources);
548
-
484
+ let videoPlayListener = null;
549
485
  if (video) {
486
+ video.pause();
487
+ video.currentTime = 0;
488
+ function updateVideoSources() {
489
+ const isMobile = window.innerWidth < 992;
490
+ const mobileMp4 = video.getAttribute('mobile-mp4');
491
+ const mobileWebm = video.getAttribute('mobile-webm');
492
+ const mp4Source = video.querySelector('source[type="video/mp4"]');
493
+ const webmSource = video.querySelector('source[type="video/webm"]');
494
+ if (mobileMp4 && mp4Source) mp4Source.setAttribute('data-src', mobileMp4);
495
+ if (mobileWebm && webmSource) webmSource.setAttribute('data-src', mobileWebm);
496
+ if (!isMobile && mp4Source) mp4Source.setAttribute('data-src', mp4Source.getAttribute('data-src')?.replace('mobile-', '') || '');
497
+ if (!isMobile && webmSource) webmSource.setAttribute('data-src', webmSource.getAttribute('data-src')?.replace('mobile-', '') || '');
498
+ }
499
+ updateVideoSources();
500
+ window.addEventListener('resize', updateVideoSources);
550
501
  video.setAttribute('data-no-autoplay', 'true');
551
502
  video.addEventListener('loadeddata', () => {
552
503
  if (video.hasAttribute('data-no-autoplay')) {
553
504
  video.pause();
505
+ video.currentTime = 0;
554
506
  }
555
507
  });
508
+ videoPlayListener = () => {
509
+ console.log('[heroAnimationOnLoad] Video play event! currentTime:', video.currentTime);
510
+ if (video.hasAttribute('data-no-autoplay')) {
511
+ console.log('[heroAnimationOnLoad] Video has data-no-autoplay, forcing pause');
512
+ video.pause();
513
+ video.currentTime = 0;
514
+ }
515
+ };
516
+ video.addEventListener('play', videoPlayListener);
517
+ } else {
556
518
  }
557
519
 
558
- if (!hasPlayedAnimation) {
559
- console.log('Initial settings applied to hero lines');
520
+ function run() {
521
+ const introBrand = document.querySelector('.preloader [intro-brand]');
522
+ const preloader = introBrand ? introBrand.closest('.preloader') : document.querySelector('.preloader');
523
+ const wrapIt = document.querySelector('.wrap-it') || preloader?.closest('.wrap-it') || preloader;
524
+ const introSubtitle = preloader ? preloader.querySelector('[intro-subtitle]') : null;
525
+ const widelettersIntro = introBrand ? introBrand.querySelectorAll('.wideletter-intro') : [];
526
+
527
+ let savedScrollY = 0;
528
+ const preventScroll = (e) => e.preventDefault();
529
+
530
+ function lockScroll() {
531
+ savedScrollY = window.scrollY || document.documentElement.scrollTop;
532
+ document.body.style.position = 'fixed';
533
+ document.body.style.top = `-${savedScrollY}px`;
534
+ document.body.style.left = '0';
535
+ document.body.style.right = '0';
536
+ document.body.style.width = '100%';
537
+ document.body.style.overflow = 'hidden';
538
+ document.documentElement.style.overflow = 'hidden';
539
+ history.scrollRestoration = 'manual';
540
+ if (typeof lenis !== 'undefined' && lenis.stop) lenis.stop();
541
+ document.addEventListener('wheel', preventScroll, { passive: false });
542
+ document.addEventListener('touchmove', preventScroll, { passive: false });
543
+ }
560
544
 
561
- gsap.set('.navbar_brand_lottie', { opacity: 1 });
562
- gsap.set('#heroHeading', { opacity: 0 });
563
- gsap.set('.hero-line', { y: '100%' });
545
+ // Lock scroll IMMEDIATELY at the start - before any animation
546
+ lockScroll();
564
547
 
565
- heroAnimation.to('.navbar_brand_lottie', {
566
- duration: 1.5,
567
- onComplete: function() {
568
- console.log('Lottie animation completed');
569
- gsap.to('.navbar_brand_lottie', { opacity: 0, duration: 0.25 });
570
- }
571
- });
548
+ function unlockScroll() {
549
+ document.body.style.position = '';
550
+ document.body.style.top = '';
551
+ document.body.style.left = '';
552
+ document.body.style.right = '';
553
+ document.body.style.width = '';
554
+ document.body.style.overflow = '';
555
+ document.documentElement.style.overflow = '';
556
+ document.removeEventListener('wheel', preventScroll);
557
+ document.removeEventListener('touchmove', preventScroll);
558
+ window.scrollTo(0, savedScrollY);
559
+ if (typeof lenis !== 'undefined' && lenis.start) lenis.start();
560
+ }
572
561
 
573
- heroAnimation.to('#heroHeading', {
574
- opacity: 1,
575
- duration: 0.1,
576
- ease: 'none',
577
- }, '+=0.1');
562
+ const heroAnimation = gsap.timeline({});
563
+
564
+ if (preloader && introBrand && introSubtitle && widelettersIntro.length > 0) {
565
+ gsap.set(widelettersIntro, { y: '-150%' });
566
+
567
+ heroAnimation.to({}, { duration: 0.1 });
568
+ heroAnimation.set('.grab', { opacity: 1 });
569
+ heroAnimation.set(introBrand, { opacity: 1 });
570
+ heroAnimation.to(widelettersIntro, { y: '0%', duration: 1, ease: 'loader2', stagger: 0.1 });
571
+ heroAnimation.to({}, { duration: 1 });
572
+ heroAnimation.to(widelettersIntro, { y: '-150%', opacity: 0, duration: 0.6, ease: 'power2.in', stagger: 0.03 });
573
+ heroAnimation.fromTo(introSubtitle, { y: '50%', opacity: 0 }, { y: '0%', opacity: 1, duration: 0.6, ease: 'power2.out' });
574
+ heroAnimation.to({}, { duration: 2 });
575
+ // 5. .wrap-it: height 100vh → 0vh (2s). Video play na START animacji height.
576
+ // Set position: absolute before height animation to prevent body height change
577
+ // NOTE: lockScroll() is already called at the start of run() function
578
+ heroAnimation.set(wrapIt, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100vh', overflow: 'hidden', zIndex: 9999 });
579
+ heroAnimation.to(wrapIt, {
580
+ height: '0vh',
581
+ duration: 2,
582
+ ease: 'power2.out',
583
+ onStart: () => {
584
+ if (video) {
585
+ video.currentTime = 0;
586
+ // Remove attribute and play listener before playing to prevent conflicts
587
+ video.removeAttribute('data-no-autoplay');
588
+ if (videoPlayListener) {
589
+ video.removeEventListener('play', videoPlayListener);
590
+ }
591
+ video.play().then(() => {
592
+ }).catch(err => {
593
+ });
594
+ }
595
+ },
596
+ onComplete: () => {
597
+ unlockScroll();
598
+ gsap.set(wrapIt, { visibility: 'hidden', pointerEvents: 'none' });
599
+ // Refresh ScrollTrigger after height animation completes to recalculate positions
600
+ ScrollTrigger.refresh();
601
+ },
602
+ });
603
+ } else if (wrapIt) {
604
+ // NOTE: lockScroll() is already called at the start of run() function
605
+ heroAnimation.set(wrapIt, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100vh', overflow: 'hidden', zIndex: 9999 });
606
+ heroAnimation.to(wrapIt, {
607
+ height: '0vh',
608
+ duration: 2,
609
+ ease: 'power2.out',
610
+ onStart: () => {
611
+ if (video) {
612
+ video.currentTime = 0;
613
+ video.removeAttribute('data-no-autoplay');
614
+ if (videoPlayListener) {
615
+ video.removeEventListener('play', videoPlayListener);
616
+ }
617
+ video.play();
618
+ }
619
+ },
620
+ onComplete: () => {
621
+ unlockScroll();
622
+ gsap.set(wrapIt, { visibility: 'hidden', pointerEvents: 'none' });
623
+ // Refresh ScrollTrigger after height animation completes to recalculate positions
624
+ ScrollTrigger.refresh();
625
+ },
626
+ });
627
+ }
578
628
 
579
- heroAnimation.fromTo('.hero-line', {
580
- y: '100%'
581
- }, {
582
- duration: 0.75,
583
- y: '0%',
584
- stagger: 0.2,
585
- ease: 'loader2',
586
- }, '<');
629
+ heroAnimation.from('#heroBottomWrapper', { opacity: 0, duration: 1, ease: 'loader2' }, '>-0.4');
587
630
 
588
- heroAnimation.to('#heroHeading', {
589
- opacity: 0,
590
- duration: 0.3,
591
- ease: 'loader2',
592
- }, '+=1');
631
+ // Literki IN as last step in timeline (initial state)
632
+ const wideletters = document.querySelectorAll('.wideletter');
633
+ if (wideletters.length > 0) {
634
+ heroAnimation.fromTo(wideletters,
635
+ { y: '-150%', opacity: 0 },
636
+ { y: '0%', opacity: 1, duration: 1, ease: 'loader2', stagger: 0.1 },
637
+ '>-0.6'
638
+ );
639
+ }
640
+ }
593
641
 
594
- window.name += 'heroPlayed;';
642
+ if (document.readyState === 'complete') {
643
+ run();
595
644
  } else {
596
- console.log('Skipping initial hero line animations as they have already been played in this session');
645
+ window.addEventListener('load', run);
597
646
  }
598
-
599
- heroAnimation.to('.preloader', {
600
- scaleY: 0,
601
- display: "none",
602
- duration: 1,
603
- ease: 'loader',
604
- });
605
-
606
- heroAnimation.fromTo('.wideletter',
607
- { y: '-150%', scale: 1 },
608
- { y: '0%', duration: 1, ease: 'loader2', stagger: 0.1 },
609
- '-=0.5')
610
- .call(() => {
611
- if (video) {
612
- video.removeAttribute('data-no-autoplay');
613
- video.play();
614
- }
615
- }, null, '<');
616
-
617
- heroAnimation.from('#heroBottomWrapper', {
618
- opacity: 0,
619
- duration: 1,
620
- ease: 'loader2',
621
- }, '>-0.4');
622
-
623
- console.log('Animation timeline setup completed');
624
647
  };
625
648
 
626
649
 
@@ -745,7 +768,6 @@ window.textScroll = function(e) {
745
768
  // Ensure .hero-line elements are created
746
769
  const heroLines = document.querySelectorAll('.hero-line');
747
770
  if (heroLines.length === 0) {
748
- console.error('GSAP target .hero-line not found.');
749
771
  return;
750
772
  }
751
773
 
@@ -1479,12 +1501,9 @@ window.animationTest4 = function(root) {
1479
1501
 
1480
1502
 
1481
1503
  window.pricingInteraction = function(e) {
1482
- console.log('[pricingInteraction] Function called');
1483
- console.log('[pricingInteraction] Window width:', window.innerWidth);
1484
1504
 
1485
1505
  // Check if the screen width is 992px or wider
1486
1506
  if (window.innerWidth >= 992) {
1487
- console.log('[pricingInteraction] Desktop mode - creating pin');
1488
1507
 
1489
1508
  const tabsContent = document.querySelector('.tabs-content');
1490
1509
  const tabsMenu = document.querySelector('.tabs-menu');
@@ -1493,23 +1512,12 @@ window.pricingInteraction = function(e) {
1493
1512
  console.log('[pricingInteraction] .tabs-menu found:', tabsMenu);
1494
1513
 
1495
1514
  if (!tabsContent || !tabsMenu) {
1496
- console.error('[pricingInteraction] Required elements not found!');
1497
1515
  return;
1498
1516
  }
1499
1517
 
1500
1518
  // Debug computed styles
1501
1519
  const tabsContentStyles = window.getComputedStyle(tabsContent);
1502
1520
  const tabsMenuStyles = window.getComputedStyle(tabsMenu);
1503
- console.log('[pricingInteraction] .tabs-content styles:', {
1504
- position: tabsContentStyles.position,
1505
- height: tabsContentStyles.height,
1506
- display: tabsContentStyles.display,
1507
- });
1508
- console.log('[pricingInteraction] .tabs-menu styles:', {
1509
- position: tabsMenuStyles.position,
1510
- height: tabsMenuStyles.height,
1511
- display: tabsMenuStyles.display,
1512
- });
1513
1521
 
1514
1522
  // Create the pinning effect
1515
1523
  const trigger = ScrollTrigger.create({
@@ -1520,9 +1528,6 @@ window.pricingInteraction = function(e) {
1520
1528
 
1521
1529
  });
1522
1530
 
1523
- console.log('[pricingInteraction] ScrollTrigger created:', trigger);
1524
- } else {
1525
- console.log('[pricingInteraction] Mobile mode - skipping pin');
1526
1531
  }
1527
1532
  };
1528
1533
 
@@ -1537,7 +1542,6 @@ window.caseStudyInteraction = function(e) {
1537
1542
  // Video mask animation
1538
1543
  const mask = e.querySelector('.portfolio_item_image-mask');
1539
1544
  if (!mask) {
1540
- console.error('Mask element not found in:', e);
1541
1545
  return;
1542
1546
  }
1543
1547
 
@@ -1560,7 +1564,6 @@ window.caseStudyInteraction = function(e) {
1560
1564
  if (window.innerWidth > 992) {
1561
1565
  videoElements.forEach(videoElement => {
1562
1566
  if (!videoElement) {
1563
- console.error('No video element found in:', e);
1564
1567
  return;
1565
1568
  }
1566
1569
 
@@ -2324,7 +2327,6 @@ window.heroSliders = function(e) {
2324
2327
  },
2325
2328
  };
2326
2329
  const slider = new Splide(e, config).mount();
2327
- console.log("Splide instance:", slider);
2328
2330
 
2329
2331
  if (window.innerWidth > 992) {
2330
2332
  slider.on('click', function () {
@@ -2634,64 +2636,32 @@ window.closeInfoBar = function() {
2634
2636
 
2635
2637
 
2636
2638
  // Hero 2026 animation - navbar letters on scroll
2637
- // EXPERIMENTAL: play/reverse version (to revert: replace this whole function with scrub version)
2638
2639
  window.heroAnimation2026 = function(e) {
2639
2640
  const wideletters = document.querySelectorAll('.wideletter');
2640
- const introSection = document.querySelector('[x-init*="introAnimation"]');
2641
-
2642
- if (!introSection) return;
2641
+ if (wideletters.length === 0) return;
2643
2642
 
2644
- // Wideletters animation timeline (paused)
2645
- const widelettersTimeline = gsap.timeline({ paused: true });
2646
- widelettersTimeline.fromTo(wideletters,
2647
- { y: '-150%' },
2643
+ // Timeline for letters OUT
2644
+ const lettersOutTimeline = gsap.timeline({ paused: true });
2645
+ lettersOutTimeline.fromTo(wideletters,
2646
+ { y: '0%', opacity: 1 },
2648
2647
  {
2649
- y: '0%',
2650
- duration: 0.8,
2651
- ease: 'power2.out',
2652
- stagger: 0.05,
2648
+ y: '-150%',
2649
+ opacity: 0,
2650
+ duration: 0.6,
2651
+ ease: 'power2.in',
2652
+ stagger: 0.03,
2653
2653
  }
2654
2654
  );
2655
2655
 
2656
- // Trigger for wideletters
2657
- ScrollTrigger.create({
2658
- trigger: introSection,
2659
- start: 'bottom bottom-=25%',
2660
- onEnter: () => widelettersTimeline.play(),
2661
- onLeaveBack: () => widelettersTimeline.reverse(),
2662
- });
2663
-
2664
- // Partner section animation
2665
- const partnerSection = document.querySelector('#partner');
2666
- const heroFlex = document.querySelector('.hero-flex');
2667
- const coverBg = document.querySelector('.cover-bg');
2668
-
2669
- if (!partnerSection || !heroFlex || !coverBg) return;
2670
-
2671
- // Partner timeline (cover-bg + wideletters reverse)
2672
- const partnerTimeline = gsap.timeline({ paused: true });
2673
-
2674
- // Cover-bg fade-in
2675
- partnerTimeline.fromTo(coverBg,
2676
- { opacity: 0 },
2677
- { opacity: 1, duration: 0.6, ease: 'power2.out' },
2678
- 0
2679
- );
2656
+ // Trigger: .update26 top reaches 80% viewport → letters OUT, scroll back → reverse
2657
+ const update26 = document.querySelector('.update26');
2658
+ if (!update26) return;
2680
2659
 
2681
- // Reverse wideletters
2682
- partnerTimeline.to(wideletters, {
2683
- y: '-150%',
2684
- duration: 0.6,
2685
- ease: 'power2.in',
2686
- stagger: 0.03,
2687
- }, 0);
2688
-
2689
- // Trigger for partner timeline
2690
2660
  ScrollTrigger.create({
2691
- trigger: partnerSection,
2661
+ trigger: update26,
2692
2662
  start: 'top 80%',
2693
- onEnter: () => partnerTimeline.play(),
2694
- onLeaveBack: () => partnerTimeline.reverse(),
2663
+ onEnter: () => lettersOutTimeline.play(),
2664
+ onLeaveBack: () => lettersOutTimeline.reverse(),
2695
2665
  });
2696
2666
  };
2697
2667
 
@@ -2836,12 +2806,13 @@ function gsapTitleAnimation() {
2836
2806
  ease: 'loader2',
2837
2807
  });
2838
2808
 
2839
- // Create ScrollTrigger with play/reverse
2809
+ // Create ScrollTrigger with play only
2840
2810
  ScrollTrigger.create({
2841
2811
  trigger: titleElement,
2842
2812
  start: 'top 80%',
2843
- onEnter: () => titleTimeline.play(),
2844
- onLeaveBack: () => titleTimeline.reverse(),
2813
+ animation: titleTimeline,
2814
+ toggleActions: 'play',
2815
+ invalidateOnRefresh: true,
2845
2816
  });
2846
2817
  });
2847
2818
  }
@@ -2871,12 +2842,13 @@ function gsapContainerAnimation() {
2871
2842
  ease: 'power3.out',
2872
2843
  });
2873
2844
 
2874
- // Create ScrollTrigger with play/reverse
2845
+ // Create ScrollTrigger with play only
2875
2846
  ScrollTrigger.create({
2876
2847
  trigger: container,
2877
2848
  start: 'top 80%',
2878
- onEnter: () => containerTimeline.play(),
2879
- onLeaveBack: () => containerTimeline.reverse(),
2849
+ animation: containerTimeline,
2850
+ toggleActions: 'play',
2851
+ invalidateOnRefresh: true,
2880
2852
  });
2881
2853
  });
2882
2854
  }
@@ -2900,12 +2872,13 @@ function gsapFadeAnimation() {
2900
2872
  ease: 'power3.out',
2901
2873
  });
2902
2874
 
2903
- // Create ScrollTrigger with play/reverse
2875
+ // Create ScrollTrigger with play only
2904
2876
  ScrollTrigger.create({
2905
2877
  trigger: element,
2906
2878
  start: 'top 65%',
2907
- onEnter: () => fadeTimeline.play(),
2908
- onLeaveBack: () => fadeTimeline.reverse(),
2879
+ animation: fadeTimeline,
2880
+ toggleActions: 'play',
2881
+ invalidateOnRefresh: true,
2909
2882
  });
2910
2883
  });
2911
2884
  }
@@ -2933,9 +2906,14 @@ window.Webflow.push(() => {
2933
2906
  contactFormOpenAnimation();
2934
2907
  openContactFormFromURL();
2935
2908
  disableScrollMenu();
2936
- gsapTitleAnimation();
2937
- gsapContainerAnimation();
2938
- gsapFadeAnimation();
2909
+ // Wait for DOM to be fully ready before creating ScrollTriggers
2910
+ setTimeout(() => {
2911
+ gsapTitleAnimation();
2912
+ gsapContainerAnimation();
2913
+ gsapFadeAnimation();
2914
+ // Refresh ScrollTrigger after creating all triggers to sync with Lenis
2915
+ ScrollTrigger.refresh();
2916
+ }, 200);
2939
2917
  refreshScrollTriggersAfterLoad();
2940
2918
 
2941
2919
  });