Update CSS and JavaScript to enhance mobile responsiveness, fix image alignment issues, and refine animations for a better user experience on smaller screens. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 8e995c99-f0dc-4535-89de-ddffaca13380 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 9c30b65d-1fff-4139-8042-cad809186f1b Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e2c5cd18-6007-4bb1-a111-e14cc125923d/8e995c99-f0dc-4535-89de-ddffaca13380/imQgZBK Replit-Helium-Checkpoint-Created: true
399 lines
15 KiB
JavaScript
399 lines
15 KiB
JavaScript
/* =====================================================
|
|
TSCB — Homepage GSAP Masterpiece
|
|
Linked ONLY in index.html | v2.0 (mobile-aware)
|
|
===================================================== */
|
|
|
|
(function () {
|
|
'use strict';
|
|
|
|
/* Guard: only run when there is a hero section */
|
|
if (!document.querySelector('.hero')) return;
|
|
|
|
/* Register GSAP plugins */
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
|
|
/* ── Mobile detection ── */
|
|
var isMobile = window.matchMedia('(max-width: 767px)').matches ||
|
|
('ontouchstart' in window && window.innerWidth < 900);
|
|
|
|
/* ====================================================
|
|
1. HERO — ORBS ENTRANCE
|
|
==================================================== */
|
|
|
|
gsap.from('.hero-orb-1', {
|
|
scale: 0.2, opacity: 0, duration: 2.8,
|
|
ease: 'power3.out', delay: 0.85
|
|
});
|
|
gsap.from('.hero-orb-2', {
|
|
scale: 0.2, opacity: 0, duration: 3.2,
|
|
ease: 'power3.out', delay: 1.0
|
|
});
|
|
gsap.from('.hero-orb-3', {
|
|
scale: 0.2, opacity: 0, duration: 2.2,
|
|
ease: 'power3.out', delay: 1.3
|
|
});
|
|
|
|
/* Orb subtle glow pulse */
|
|
gsap.to('.hero-orb-1', {
|
|
opacity: 0.85, scale: 1.08,
|
|
duration: 3, ease: 'sine.inOut',
|
|
yoyo: true, repeat: -1, delay: 1.8
|
|
});
|
|
|
|
/* Orb scroll parallax — desktop + mobile */
|
|
ScrollTrigger.create({
|
|
trigger: '.hero',
|
|
start: 'top top',
|
|
end: 'bottom top',
|
|
scrub: 1.8,
|
|
onUpdate: function (self) {
|
|
var p = self.progress;
|
|
gsap.set('.hero-orb-1', { y: p * -130, x: p * 45 });
|
|
gsap.set('.hero-orb-2', { y: p * -90, x: p * -35 });
|
|
gsap.set('.hero-orb-3', { y: p * -60, rotate: p * 50 });
|
|
}
|
|
});
|
|
|
|
/* Hero parallax:
|
|
Desktop → mouse-follow
|
|
Mobile → gentle continuous drift (no cursor needed) */
|
|
var heroEl = document.querySelector('.hero');
|
|
|
|
if (!isMobile) {
|
|
heroEl.addEventListener('mousemove', function (e) {
|
|
var rect = heroEl.getBoundingClientRect();
|
|
var xR = (e.clientX - rect.left) / rect.width - 0.5;
|
|
var yR = (e.clientY - rect.top) / rect.height - 0.5;
|
|
gsap.to('.hero-orb-1', { x: xR * 55, y: yR * 35, duration: 1.8, ease: 'power2.out', overwrite: 'auto' });
|
|
gsap.to('.hero-orb-2', { x: xR * -40, y: yR * -25, duration: 2.0, ease: 'power2.out', overwrite: 'auto' });
|
|
gsap.to('.hero-orb-3', { x: xR * 25, y: yR * 18, duration: 1.4, ease: 'power2.out', overwrite: 'auto' });
|
|
});
|
|
} else {
|
|
/* Mobile: slow ambient drift on orbs */
|
|
gsap.to('.hero-orb-2', {
|
|
x: 30, y: -20,
|
|
duration: 4, ease: 'sine.inOut',
|
|
yoyo: true, repeat: -1, delay: 0.5
|
|
});
|
|
gsap.to('.hero-orb-3', {
|
|
x: -20, y: 15, rotate: 20,
|
|
duration: 5, ease: 'sine.inOut',
|
|
yoyo: true, repeat: -1, delay: 1
|
|
});
|
|
}
|
|
|
|
/* ====================================================
|
|
2. COUNTER SECTION — single clean entrance
|
|
(replaces the previous 3-stage cascade that caused
|
|
the "spasm" effect; waypoints/counterUp still runs)
|
|
==================================================== */
|
|
|
|
var counterSection = document.querySelector('.our-counter');
|
|
if (counterSection) {
|
|
|
|
/* One unified entrance: box scales in, items slide up together */
|
|
var counterTl = gsap.timeline({
|
|
scrollTrigger: {
|
|
trigger: '.our-counter',
|
|
start: 'top 82%',
|
|
once: true
|
|
}
|
|
});
|
|
|
|
counterTl
|
|
.from('.counter-box', {
|
|
scale: 0.9, opacity: 0,
|
|
duration: 0.9, ease: 'power3.out',
|
|
immediateRender: false
|
|
})
|
|
.from('.counter-item', {
|
|
y: 40, opacity: 0,
|
|
duration: 0.65, stagger: 0.12,
|
|
ease: 'power3.out',
|
|
immediateRender: false
|
|
}, '-=0.5');
|
|
|
|
/* Counter hover — desktop only */
|
|
if (!isMobile) {
|
|
document.querySelectorAll('.counter-item').forEach(function (item) {
|
|
item.addEventListener('mouseenter', function () {
|
|
gsap.to(item.querySelector('.counter-title h2'), {
|
|
scale: 1.12, color: '#d92800',
|
|
duration: 0.35, ease: 'back.out(2)'
|
|
});
|
|
});
|
|
item.addEventListener('mouseleave', function () {
|
|
gsap.to(item.querySelector('.counter-title h2'), {
|
|
scale: 1, color: '',
|
|
duration: 0.5, ease: 'power2.out'
|
|
});
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
/* ====================================================
|
|
3. MISSION IMAGE — SCROLL PARALLAX (desktop only)
|
|
On mobile the parallax y-shift breaks the stacked
|
|
layout and makes the image float out of place.
|
|
==================================================== */
|
|
|
|
if (!isMobile) {
|
|
gsap.to('.mission-img', {
|
|
scrollTrigger: {
|
|
trigger: '.our-mission',
|
|
start: 'top bottom',
|
|
end: 'bottom top',
|
|
scrub: 1.8
|
|
},
|
|
y: -60, ease: 'none'
|
|
});
|
|
|
|
gsap.to('.mission-life-circle', {
|
|
scrollTrigger: {
|
|
trigger: '.our-mission',
|
|
start: 'top bottom',
|
|
end: 'bottom top',
|
|
scrub: 2.5
|
|
},
|
|
y: -95, rotate: 35, ease: 'none'
|
|
});
|
|
}
|
|
|
|
/* ====================================================
|
|
4. SERVICE TICKER — FADE IN
|
|
==================================================== */
|
|
|
|
gsap.from('.service-ticker', {
|
|
scrollTrigger: { trigger: '.service-ticker', start: 'top 92%', once: true },
|
|
opacity: 0, scaleY: 0.6,
|
|
transformOrigin: 'center center',
|
|
duration: 0.7, ease: 'back.out(2)',
|
|
immediateRender: false
|
|
});
|
|
|
|
/* ====================================================
|
|
5. SERVICE CARDS
|
|
Desktop → 3D tilt on hover
|
|
Mobile → slide-up stagger on scroll
|
|
==================================================== */
|
|
|
|
if (!isMobile) {
|
|
document.querySelectorAll('.service-item').forEach(function (card) {
|
|
card.style.transformStyle = 'preserve-3d';
|
|
card.addEventListener('mousemove', function (e) {
|
|
var rect = card.getBoundingClientRect();
|
|
var rotX = ((e.clientY - rect.top - rect.height / 2) / (rect.height / 2)) * -10;
|
|
var rotY = ((e.clientX - rect.left - rect.width / 2) / (rect.width / 2)) * 10;
|
|
gsap.to(card, {
|
|
rotationX: rotX, rotationY: rotY,
|
|
transformPerspective: 700,
|
|
duration: 0.35, ease: 'power2.out', overwrite: 'auto'
|
|
});
|
|
});
|
|
card.addEventListener('mouseleave', function () {
|
|
gsap.to(card, {
|
|
rotationX: 0, rotationY: 0,
|
|
duration: 0.75, ease: 'elastic.out(1, 0.45)', overwrite: 'auto'
|
|
});
|
|
});
|
|
});
|
|
} else {
|
|
/* Mobile: tap-scale feedback */
|
|
document.querySelectorAll('.service-item').forEach(function (card) {
|
|
card.addEventListener('touchstart', function () {
|
|
gsap.to(card, { scale: 0.97, duration: 0.15, ease: 'power2.out' });
|
|
}, { passive: true });
|
|
card.addEventListener('touchend', function () {
|
|
gsap.to(card, { scale: 1, duration: 0.35, ease: 'elastic.out(1.2, 0.5)' });
|
|
}, { passive: true });
|
|
});
|
|
}
|
|
|
|
/* ====================================================
|
|
6. SPONSORS — GUARANTEED VISIBILITY
|
|
==================================================== */
|
|
|
|
var sponsorItems = document.querySelectorAll('.sponsor-logo-item');
|
|
if (sponsorItems.length) {
|
|
|
|
gsap.set(sponsorItems, { opacity: 0, y: 50, scale: 0.82 });
|
|
|
|
var sponsorsPlayed = false;
|
|
function playSponsors() {
|
|
if (sponsorsPlayed) return;
|
|
sponsorsPlayed = true;
|
|
gsap.to(sponsorItems, {
|
|
opacity: 1, y: 0, scale: 1,
|
|
duration: 0.8, stagger: 0.15,
|
|
ease: 'back.out(1.6)'
|
|
});
|
|
}
|
|
|
|
ScrollTrigger.create({
|
|
trigger: '.our-sponsors-section',
|
|
start: 'top 88%',
|
|
once: true,
|
|
onEnter: playSponsors
|
|
});
|
|
|
|
window.addEventListener('load', function () {
|
|
setTimeout(function () {
|
|
var sec = document.querySelector('.our-sponsors-section');
|
|
if (!sec) return;
|
|
var rect = sec.getBoundingClientRect();
|
|
if (rect.top < window.innerHeight * 0.92) {
|
|
playSponsors();
|
|
}
|
|
}, 980);
|
|
});
|
|
|
|
/* 3D tilt — desktop only */
|
|
if (!isMobile) {
|
|
sponsorItems.forEach(function (card) {
|
|
card.style.transformStyle = 'preserve-3d';
|
|
card.addEventListener('mousemove', function (e) {
|
|
var rect = card.getBoundingClientRect();
|
|
var rotX = ((e.clientY - rect.top - rect.height / 2) / (rect.height / 2)) * -8;
|
|
var rotY = ((e.clientX - rect.left - rect.width / 2) / (rect.width / 2)) * 8;
|
|
gsap.to(card, {
|
|
rotationX: rotX, rotationY: rotY,
|
|
transformPerspective: 500,
|
|
duration: 0.3, ease: 'power2.out', overwrite: 'auto'
|
|
});
|
|
});
|
|
card.addEventListener('mouseleave', function () {
|
|
gsap.to(card, {
|
|
rotationX: 0, rotationY: 0,
|
|
duration: 0.65, ease: 'elastic.out(1, 0.45)', overwrite: 'auto'
|
|
});
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
/* ====================================================
|
|
7. CTA BOX — SPLIT ENTRANCE
|
|
==================================================== */
|
|
|
|
gsap.from('.cta-box-content', {
|
|
scrollTrigger: { trigger: '.cta-box', start: 'top 82%', once: true },
|
|
x: isMobile ? 0 : -70,
|
|
y: isMobile ? 30 : 0,
|
|
opacity: 0,
|
|
duration: 1.1, ease: 'power4.out',
|
|
immediateRender: false
|
|
});
|
|
|
|
/* ====================================================
|
|
8. GLOBAL SCROLL PROGRESS FLASH
|
|
==================================================== */
|
|
|
|
var sectionFlashSections = document.querySelectorAll('.our-counter, .our-services, .our-sponsors-section, .cta-box');
|
|
sectionFlashSections.forEach(function (sec) {
|
|
ScrollTrigger.create({
|
|
trigger: sec,
|
|
start: 'top 60%',
|
|
once: true,
|
|
onEnter: function () {
|
|
var bar = document.getElementById('tscb-progress');
|
|
if (!bar) return;
|
|
gsap.fromTo(bar, { boxShadow: '0 0 0 0 rgba(217,40,0,0)' },
|
|
{ boxShadow: '0 0 18px 4px rgba(217,40,0,0.7)', duration: 0.3, yoyo: true, repeat: 1, ease: 'power2.inOut' });
|
|
}
|
|
});
|
|
});
|
|
|
|
/* ====================================================
|
|
9. ABOUT-LIST ICON BOXES — STAGGER SPIN-IN
|
|
==================================================== */
|
|
|
|
gsap.from('#home-about .about-list-item .icon-box', {
|
|
scrollTrigger: { trigger: '#home-about .about-content-body', start: 'top 82%', once: true },
|
|
scale: 0, rotate: -180, opacity: 0,
|
|
duration: 0.75, stagger: 0.2, delay: 0.15,
|
|
ease: 'back.out(2)',
|
|
immediateRender: false
|
|
});
|
|
|
|
/* ====================================================
|
|
10. MOBILE-SPECIFIC SCROLL ANIMATIONS
|
|
Beautiful slide-in effects activated by scroll
|
|
(replaces cursor-dependent hover animations)
|
|
==================================================== */
|
|
|
|
if (isMobile) {
|
|
|
|
/* About section list items: stagger slide from left */
|
|
gsap.from('#home-about .about-list-item', {
|
|
scrollTrigger: { trigger: '#home-about .about-content-body', start: 'top 88%', once: true },
|
|
x: -30, opacity: 0,
|
|
duration: 0.6, stagger: 0.15,
|
|
ease: 'power3.out',
|
|
immediateRender: false
|
|
});
|
|
|
|
/* Mission section: text slides in from left, image from bottom */
|
|
gsap.from('.mission-content .section-title', {
|
|
scrollTrigger: { trigger: '.our-mission', start: 'top 85%', once: true },
|
|
x: -40, opacity: 0,
|
|
duration: 0.75, ease: 'power3.out',
|
|
immediateRender: false
|
|
});
|
|
|
|
gsap.from('.mission-image', {
|
|
scrollTrigger: { trigger: '.mission-image', start: 'top 90%', once: true },
|
|
y: 50, opacity: 0,
|
|
duration: 0.8, ease: 'power3.out',
|
|
immediateRender: false
|
|
});
|
|
|
|
/* Service items: alternate slide from left/right */
|
|
document.querySelectorAll('.service-item').forEach(function (card, i) {
|
|
gsap.from(card, {
|
|
scrollTrigger: { trigger: card, start: 'top 90%', once: true },
|
|
x: i % 2 === 0 ? -40 : 40,
|
|
opacity: 0,
|
|
duration: 0.65,
|
|
ease: 'power3.out',
|
|
immediateRender: false
|
|
});
|
|
});
|
|
|
|
/* CTA box: gentle scale pop */
|
|
gsap.from('.cta-box', {
|
|
scrollTrigger: { trigger: '.cta-box', start: 'top 90%', once: true },
|
|
scale: 0.95, opacity: 0,
|
|
duration: 0.75, ease: 'back.out(1.8)',
|
|
immediateRender: false
|
|
});
|
|
}
|
|
|
|
/* ====================================================
|
|
11. HERO BRIGHTNESS SHIFT ON SCROLL (desktop only)
|
|
==================================================== */
|
|
|
|
if (!isMobile) {
|
|
ScrollTrigger.create({
|
|
trigger: '.hero',
|
|
start: 'top top',
|
|
end: 'bottom top',
|
|
scrub: 1,
|
|
onUpdate: function (self) {
|
|
heroEl.style.filter = 'brightness(' + (1 - self.progress * 0.18) + ')';
|
|
}
|
|
});
|
|
}
|
|
|
|
/* ====================================================
|
|
FINALIZE: refresh ScrollTrigger after full load
|
|
==================================================== */
|
|
|
|
window.addEventListener('load', function () {
|
|
setTimeout(function () {
|
|
ScrollTrigger.refresh();
|
|
}, 400);
|
|
});
|
|
|
|
})();
|