/* ========================================================= Kartik Kumar Portfolio v2 — script.js ========================================================= */ /* ── CURSOR ─────────────────────────────────────────── */ const cursor = document.getElementById('cursor'); const ring = document.getElementById('cursorRing'); let mx=0,my=0,rx=0,ry=0; document.addEventListener('mousemove',e=>{ mx=e.clientX; my=e.clientY; cursor.style.left=mx+'px'; cursor.style.top=my+'px'; }); (function loopRing(){ rx+=(mx-rx)*.13; ry+=(my-ry)*.13; ring.style.left=rx+'px'; ring.style.top=ry+'px'; requestAnimationFrame(loopRing); })(); document.querySelectorAll('a,button,.skill-card,.project-card,.exp-card-inner,.contact-item').forEach(el=>{ el.addEventListener('mouseenter',()=>{ ring.style.width='54px'; ring.style.height='54px'; ring.style.borderColor='var(--accent2)'; }); el.addEventListener('mouseleave',()=>{ ring.style.width='34px'; ring.style.height='34px'; ring.style.borderColor='var(--accent)'; }); }); /* ── NAVBAR SCROLL ──────────────────────────────────── */ const navbar=document.getElementById('navbar'); window.addEventListener('scroll',()=>{ navbar.classList.toggle('scrolled',window.scrollY>60); }); /* ── HAMBURGER ──────────────────────────────────────── */ const ham=document.getElementById('hamburger'); const navLinks=document.getElementById('navLinks'); ham.addEventListener('click',()=>{ const open=navLinks.classList.toggle('open'); const s=ham.querySelectorAll('span'); s[0].style.transform=open?'rotate(45deg) translate(5px,5px)':''; s[1].style.opacity=open?'0':''; s[2].style.transform=open?'rotate(-45deg) translate(5px,-5px)':''; }); navLinks.querySelectorAll('a').forEach(a=>a.addEventListener('click',()=>{ navLinks.classList.remove('open'); ham.querySelectorAll('span').forEach(s=>{s.style.transform='';s.style.opacity='';}); })); /* ── TYPING ANIMATION ───────────────────────────────── */ const phrases=['AI/ML Developer','Full Stack Developer','App Developer','Prompt Engineer','Computer Vision Engineer']; let pi=0,ci=0,del=false; const typingEl=document.getElementById('typingText'); function type(){ const cur=phrases[pi]; typingEl.textContent=del?cur.slice(0,--ci):cur.slice(0,++ci); let d=del?55:105; if(!del&&ci===cur.length){d=2000;del=true;} else if(del&&ci===0){del=false;pi=(pi+1)%phrases.length;d=350;} setTimeout(type,d); } type(); /* ── THREE.JS HERO ──────────────────────────────────── */ (function initThree(){ const canvas=document.getElementById('heroCanvas'); if(!canvas||!window.THREE)return; const renderer=new THREE.WebGLRenderer({canvas,alpha:true,antialias:true}); renderer.setPixelRatio(Math.min(devicePixelRatio,2)); renderer.setSize(innerWidth,innerHeight); const scene=new THREE.Scene(); const camera=new THREE.PerspectiveCamera(60,innerWidth/innerHeight,.1,1000); camera.position.z=6; /* Stars */ const starGeo=new THREE.BufferGeometry(); const starPos=new Float32Array(5000*3); for(let i=0;i.5}) ); m.position.set((Math.random()-.5)*12,(Math.random()-.5)*7,(Math.random()-.5)*5-1); m.userData={rx:(Math.random()-.5)*.022,ry:(Math.random()-.5)*.022,baseY:m.position.y}; scene.add(m); floaters.push(m); } /* Lights */ scene.add(new THREE.AmbientLight(0xffffff,.4)); const pl1=new THREE.PointLight(0x38bdf8,2.5,22); pl1.position.set(3,3,3); scene.add(pl1); const pl2=new THREE.PointLight(0x818cf8,2.5,22); pl2.position.set(-3,-2,2); scene.add(pl2); const pl3=new THREE.PointLight(0xf472b6,1.5,15); pl3.position.set(0,4,-2); scene.add(pl3); let mmx=0,mmy=0; window.addEventListener('mousemove',e=>{ mmx=(e.clientX/innerWidth-.5)*2; mmy=(e.clientY/innerHeight-.5)*2; }); window.addEventListener('resize',()=>{ camera.aspect=innerWidth/innerHeight; camera.updateProjectionMatrix(); renderer.setSize(innerWidth,innerHeight); }); let t=0; (function animate(){ requestAnimationFrame(animate); t+=.008; knot.rotation.x+=.007; knot.rotation.y+=.011; knot.rotation.z+=.004; ringMesh.rotation.y+=.005; ringMesh.rotation.x=.4; floaters.forEach(f=>{ f.rotation.x+=f.userData.rx; f.rotation.y+=f.userData.ry; f.position.y=f.userData.baseY+Math.sin(t+f.userData.baseY)*.35; }); camera.position.x+=(mmx*.6-camera.position.x)*.04; camera.position.y+=(-mmy*.35-camera.position.y)*.04; camera.lookAt(scene.position); renderer.render(scene,camera); })(); })(); /* ── SCROLL AOS ──────────────────────────────────────── */ const obs=new IntersectionObserver(entries=>{ entries.forEach(e=>{ if(e.isIntersecting){ e.target.classList.add('in-view'); obs.unobserve(e.target); } }); },{threshold:.1}); document.querySelectorAll('[data-aos]').forEach(el=>obs.observe(el)); /* skill bars */ const skillObs=new IntersectionObserver(entries=>{ if(entries[0].isIntersecting){ document.querySelectorAll('.skill-fill').forEach(b=>{ b.style.width=b.dataset.width+'%'; }); skillObs.unobserve(entries[0].target); } },{threshold:.2}); const sk=document.getElementById('skills'); if(sk) skillObs.observe(sk); /* ── NAV ACTIVE HIGHLIGHT ────────────────────────────── */ const sections=document.querySelectorAll('section[id]'); const anchors=document.querySelectorAll('.nav-links a'); function hlNav(){ let cur=''; sections.forEach(s=>{ if(window.scrollY>=s.offsetTop-130) cur=s.id; }); anchors.forEach(a=>{ a.classList.toggle('active',a.getAttribute('href')==='#'+cur); }); } window.addEventListener('scroll',hlNav); hlNav(); /* ── HERO PARALLAX ───────────────────────────────────── */ window.addEventListener('scroll',()=>{ const y=window.scrollY; const hc=document.querySelector('.hero-content'); if(hc) hc.style.transform=`translateY(${y*.22}px)`; }); /* ── CONTACT FORM ────────────────────────────────────── */ const form=document.getElementById('contactForm'); form&&form.addEventListener('submit',async e=>{ e.preventDefault(); const btn=form.querySelector('button[type=submit]'); const orig=btn.innerHTML; btn.innerHTML='Sending…'; btn.disabled=true; await new Promise(r=>setTimeout(r,1300)); btn.innerHTML='✓ Sent!'; document.getElementById('formSuccess').style.display='block'; form.reset(); setTimeout(()=>{ btn.innerHTML=orig; btn.disabled=false; document.getElementById('formSuccess').style.display='none'; },4000); });