Edited main.js
This commit is contained in:
parent
0bb49cb169
commit
17f271574f
1 changed files with 101 additions and 163 deletions
244
js/main.js
244
js/main.js
|
|
@ -1,15 +1,13 @@
|
|||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// 1. Initialize Lenis Smooth Scroll
|
||||
|
||||
// ── 1. LENIS SMOOTH SCROLL ────────────────────────────────────────
|
||||
const lenis = new Lenis({
|
||||
duration: 1.2,
|
||||
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
|
||||
direction: 'vertical',
|
||||
gestureDirection: 'vertical',
|
||||
smooth: true,
|
||||
mouseMultiplier: 1,
|
||||
smoothTouch: false,
|
||||
touchMultiplier: 2,
|
||||
infinite: false,
|
||||
});
|
||||
|
||||
function raf(time) {
|
||||
|
|
@ -18,69 +16,40 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
}
|
||||
requestAnimationFrame(raf);
|
||||
|
||||
// 2. Preloader Animation
|
||||
const tl = gsap.timeline();
|
||||
tl.to('#loader-text', {
|
||||
y: 0,
|
||||
duration: 1,
|
||||
ease: 'power4.out',
|
||||
delay: 0.2
|
||||
})
|
||||
.to('#loader-text', {
|
||||
y: '-100%',
|
||||
duration: 1,
|
||||
ease: 'power4.in',
|
||||
delay: 0.5
|
||||
})
|
||||
.to('#preloader', {
|
||||
y: '-100%',
|
||||
duration: 1,
|
||||
ease: 'power4.inOut'
|
||||
}, '-=0.5')
|
||||
.from('.hero-title', {
|
||||
y: 100,
|
||||
opacity: 0,
|
||||
duration: 1.5,
|
||||
stagger: 0.2,
|
||||
ease: 'power4.out'
|
||||
}, '-=0.5')
|
||||
.to('.hero-subtitle', {
|
||||
opacity: 1,
|
||||
duration: 1,
|
||||
ease: 'power2.out'
|
||||
}, '-=1');
|
||||
// ── 2. GSAP PLUGINS ───────────────────────────────────────────────
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
// 3. Custom Cursor
|
||||
// ── 3. PRELOADER ──────────────────────────────────────────────────
|
||||
gsap.set('.hero-title, .hero-subtitle', { opacity: 0 });
|
||||
|
||||
gsap.timeline()
|
||||
.to('#loader-text', { y: 0, duration: 1, ease: 'power4.out', delay: 0.2 })
|
||||
.to('#loader-text', { y: '-100%', duration: 1, ease: 'power4.in', delay: 0.5 })
|
||||
.to('#preloader', { y: '-100%', duration: 1, ease: 'power4.inOut' }, '-=0.5')
|
||||
.to('.hero-title', { y: 0, opacity: 1, duration: 1.5, stagger: 0.15, ease: 'power4.out' }, '-=0.4')
|
||||
.to('.hero-subtitle', { y: 0, opacity: 1, duration: 1.2, stagger: 0.12, ease: 'power3.out' }, '-=1.2');
|
||||
|
||||
|
||||
|
||||
// ── 4. CUSTOM CURSOR ──────────────────────────────────────────────
|
||||
if (window.innerWidth >= 768) {
|
||||
const cursor = document.getElementById('cursor');
|
||||
const cursorDot = document.getElementById('cursor-dot');
|
||||
const hoverTargets = document.querySelectorAll('.hover-target');
|
||||
|
||||
if (window.innerWidth >= 768) {
|
||||
let mouseX = 0;
|
||||
let mouseY = 0;
|
||||
let cursorX = 0;
|
||||
let cursorY = 0;
|
||||
let mouseX = 0, mouseY = 0, cursorX = 0, cursorY = 0;
|
||||
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
mouseX = e.clientX;
|
||||
mouseY = e.clientY;
|
||||
|
||||
// Instant dot
|
||||
gsap.to(cursorDot, {
|
||||
x: mouseX,
|
||||
y: mouseY,
|
||||
duration: 0
|
||||
});
|
||||
gsap.to(cursorDot, { x: mouseX, y: mouseY, duration: 0 });
|
||||
});
|
||||
|
||||
// Smooth outer circle
|
||||
gsap.ticker.add(() => {
|
||||
cursorX += (mouseX - cursorX) * 0.2;
|
||||
cursorY += (mouseY - cursorY) * 0.2;
|
||||
gsap.set(cursor, { x: cursorX, y: cursorY });
|
||||
});
|
||||
|
||||
hoverTargets.forEach(target => {
|
||||
document.querySelectorAll('.hover-target').forEach(target => {
|
||||
target.addEventListener('mouseenter', () => {
|
||||
gsap.to(cursor, { scale: 2.5, backgroundColor: 'rgba(255,255,255,1)', duration: 0.3 });
|
||||
gsap.to(cursorDot, { opacity: 0, duration: 0.3 });
|
||||
|
|
@ -92,137 +61,106 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
});
|
||||
}
|
||||
|
||||
// 4. Interactive Canvas Background (Particles)
|
||||
const canvas = document.getElementById('hero-canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
let width, height;
|
||||
let particles = [];
|
||||
|
||||
function resize() {
|
||||
width = window.innerWidth;
|
||||
height = window.innerHeight;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
window.addEventListener('resize', resize);
|
||||
resize();
|
||||
|
||||
class Particle {
|
||||
constructor() {
|
||||
this.x = Math.random() * width;
|
||||
this.y = Math.random() * height;
|
||||
this.vx = (Math.random() - 0.5) * 0.5;
|
||||
this.vy = (Math.random() - 0.5) * 0.5;
|
||||
this.radius = Math.random() * 1.5 + 0.5;
|
||||
}
|
||||
update() {
|
||||
this.x += this.vx;
|
||||
this.y += this.vy;
|
||||
if (this.x < 0 || this.x > width) this.vx *= -1;
|
||||
if (this.y < 0 || this.y > height) this.vy *= -1;
|
||||
}
|
||||
draw() {
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
particles.push(new Particle());
|
||||
}
|
||||
|
||||
let mouse = { x: null, y: null };
|
||||
window.addEventListener('mousemove', (e) => {
|
||||
mouse.x = e.clientX;
|
||||
mouse.y = e.clientY;
|
||||
// ── 5. SCROLL PROGRESS BAR ────────────────────────────────────────
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
lenis.on('scroll', ({ progress }) => {
|
||||
if (progressBar) progressBar.style.width = `${progress * 100}%`;
|
||||
});
|
||||
|
||||
function animateParticles() {
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
// ── 6. ACTIVE NAV LINK ────────────────────────────────────────────
|
||||
const navLinks = document.querySelectorAll('.nav-link');
|
||||
const sections = document.querySelectorAll('section[id]');
|
||||
|
||||
particles.forEach(p => {
|
||||
p.update();
|
||||
p.draw();
|
||||
|
||||
// Connect to mouse
|
||||
if (mouse.x != null) {
|
||||
const dx = mouse.x - p.x;
|
||||
const dy = mouse.y - p.y;
|
||||
const dist = Math.sqrt(dx * dx + dy * dy);
|
||||
if (dist < 150) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(p.x, p.y);
|
||||
ctx.lineTo(mouse.x, mouse.y);
|
||||
ctx.strokeStyle = `rgba(255, 255, 255, ${1 - dist/150})`;
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.stroke();
|
||||
}
|
||||
const sectionObserver = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
const id = entry.target.getAttribute('id');
|
||||
navLinks.forEach(link => {
|
||||
link.classList.toggle('active', link.dataset.section === id);
|
||||
});
|
||||
}
|
||||
});
|
||||
requestAnimationFrame(animateParticles);
|
||||
}, { rootMargin: '-40% 0px -40% 0px', threshold: 0 });
|
||||
|
||||
sections.forEach(s => sectionObserver.observe(s));
|
||||
|
||||
// ── 7. MOBILE MENU ────────────────────────────────────────────────
|
||||
const hamburger = document.getElementById('hamburger');
|
||||
const mobileOverlay = document.getElementById('mobile-overlay');
|
||||
|
||||
if (hamburger && mobileOverlay) {
|
||||
hamburger.addEventListener('click', () => {
|
||||
const isOpen = hamburger.classList.contains('open');
|
||||
hamburger.classList.toggle('open');
|
||||
mobileOverlay.classList.toggle('open');
|
||||
isOpen ? lenis.start() : lenis.stop();
|
||||
});
|
||||
|
||||
document.querySelectorAll('.mobile-nav-link').forEach(link => {
|
||||
link.addEventListener('click', () => {
|
||||
hamburger.classList.remove('open');
|
||||
mobileOverlay.classList.remove('open');
|
||||
lenis.start();
|
||||
});
|
||||
});
|
||||
}
|
||||
animateParticles();
|
||||
|
||||
// 5. GSAP Scroll Animations
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
// Reveal Text
|
||||
const revealTexts = document.querySelectorAll('.reveal-text');
|
||||
revealTexts.forEach(text => {
|
||||
gsap.from(text, {
|
||||
scrollTrigger: {
|
||||
trigger: text,
|
||||
start: 'top 80%',
|
||||
},
|
||||
y: 50,
|
||||
// ── 8. REVEAL TEXT ANIMATIONS ─────────────────────────────────────
|
||||
gsap.utils.toArray('.reveal-text').forEach(el => {
|
||||
gsap.from(el, {
|
||||
scrollTrigger: { trigger: el, start: 'top 85%' },
|
||||
y: 60,
|
||||
opacity: 0,
|
||||
duration: 1,
|
||||
ease: 'power3.out'
|
||||
duration: 1.2,
|
||||
ease: 'power3.out',
|
||||
});
|
||||
});
|
||||
|
||||
// Parallax Images
|
||||
const parallaxImgs = document.querySelectorAll('.parallax-img');
|
||||
parallaxImgs.forEach(img => {
|
||||
// ── 9. CV STAGGERED ANIMATIONS ────────────────────────────────────
|
||||
gsap.utils.toArray('.cv-column').forEach(col => {
|
||||
const items = col.querySelectorAll('.group');
|
||||
if (!items.length) return;
|
||||
gsap.from(items, {
|
||||
scrollTrigger: { trigger: col, start: 'top 82%' },
|
||||
y: 40,
|
||||
opacity: 0,
|
||||
duration: 0.85,
|
||||
stagger: 0.18,
|
||||
ease: 'power3.out',
|
||||
});
|
||||
});
|
||||
|
||||
// ── 10. PARALLAX IMAGES ───────────────────────────────────────────
|
||||
gsap.utils.toArray('.parallax-img').forEach(img => {
|
||||
gsap.to(img, {
|
||||
scrollTrigger: {
|
||||
trigger: img.parentElement,
|
||||
start: 'top bottom',
|
||||
end: 'bottom top',
|
||||
scrub: true
|
||||
scrub: true,
|
||||
},
|
||||
y: 50,
|
||||
ease: 'none'
|
||||
ease: 'none',
|
||||
});
|
||||
});
|
||||
|
||||
// Horizontal Scroll for Gallery
|
||||
// ── 11. DRAGGABLE GALLERY ─────────────────────────────────────────
|
||||
const gallery = document.getElementById('gallery');
|
||||
let isDown = false;
|
||||
let startX;
|
||||
let scrollLeft;
|
||||
if (gallery) {
|
||||
let isDown = false, startX, scrollLeft;
|
||||
|
||||
gallery.addEventListener('mousedown', (e) => {
|
||||
isDown = true;
|
||||
gallery.classList.add('active');
|
||||
startX = e.pageX - gallery.offsetLeft;
|
||||
scrollLeft = gallery.scrollLeft;
|
||||
});
|
||||
gallery.addEventListener('mouseleave', () => {
|
||||
isDown = false;
|
||||
gallery.classList.remove('active');
|
||||
});
|
||||
gallery.addEventListener('mouseup', () => {
|
||||
isDown = false;
|
||||
gallery.classList.remove('active');
|
||||
});
|
||||
gallery.addEventListener('mouseleave', () => { isDown = false; });
|
||||
gallery.addEventListener('mouseup', () => { isDown = false; });
|
||||
gallery.addEventListener('mousemove', (e) => {
|
||||
if (!isDown) return;
|
||||
e.preventDefault();
|
||||
const x = e.pageX - gallery.offsetLeft;
|
||||
const walk = (x - startX) * 2; // Scroll-fast
|
||||
gallery.scrollLeft = scrollLeft - walk;
|
||||
gallery.scrollLeft = scrollLeft - (e.pageX - gallery.offsetLeft - startX) * 2;
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue