From 17f271574f8dd31648f23211e3fb44b51ac58b10 Mon Sep 17 00:00:00 2001 From: Plexi09 Date: Mon, 23 Feb 2026 00:01:42 +0100 Subject: [PATCH] Edited main.js --- js/main.js | 264 ++++++++++++++++++++--------------------------------- 1 file changed, 101 insertions(+), 163 deletions(-) diff --git a/js/main.js b/js/main.js index 26629c1..ce8ecc7 100644 --- a/js/main.js +++ b/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 - const cursor = document.getElementById('cursor'); - const cursorDot = document.getElementById('cursor-dot'); - const hoverTargets = document.querySelectorAll('.hover-target'); + // ── 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) { - let mouseX = 0; - let mouseY = 0; - let cursorX = 0; - let cursorY = 0; + const cursor = document.getElementById('cursor'); + const cursorDot = document.getElementById('cursor-dot'); + 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); - - 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(); - } + // ── 6. ACTIVE NAV LINK ──────────────────────────────────────────── + const navLinks = document.querySelectorAll('.nav-link'); + const sections = document.querySelectorAll('section[id]'); + + 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; + startX = e.pageX - gallery.offsetLeft; + scrollLeft = gallery.scrollLeft; + }); + gallery.addEventListener('mouseleave', () => { isDown = false; }); + gallery.addEventListener('mouseup', () => { isDown = false; }); + gallery.addEventListener('mousemove', (e) => { + if (!isDown) return; + e.preventDefault(); + gallery.scrollLeft = scrollLeft - (e.pageX - gallery.offsetLeft - startX) * 2; + }); + } - 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('mousemove', (e) => { - if (!isDown) return; - e.preventDefault(); - const x = e.pageX - gallery.offsetLeft; - const walk = (x - startX) * 2; // Scroll-fast - gallery.scrollLeft = scrollLeft - walk; - }); });