Spaces:
Sleeping
Sleeping
| /* ========================================================= | |
| 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<starPos.length;i++) starPos[i]=(Math.random()-.5)*140; | |
| starGeo.setAttribute('position',new THREE.BufferAttribute(starPos,3)); | |
| scene.add(new THREE.Points(starGeo,new THREE.PointsMaterial({color:0xffffff,size:.15,transparent:true,opacity:.7}))); | |
| /* Torus Knot */ | |
| const knot=new THREE.Mesh( | |
| new THREE.TorusKnotGeometry(1,.3,200,24), | |
| new THREE.MeshStandardMaterial({color:0x38bdf8,emissive:0x818cf8,emissiveIntensity:.5,metalness:.85,roughness:.1}) | |
| ); | |
| knot.position.set(4,.2,-1); | |
| scene.add(knot); | |
| /* Particle ring around knot */ | |
| const rCount=700,rPos=new Float32Array(rCount*3); | |
| for(let i=0;i<rCount;i++){ | |
| const a=(i/rCount)*Math.PI*2,r=2.5+(Math.random()-.5)*.6; | |
| rPos[i*3]=Math.cos(a)*r; rPos[i*3+1]=(Math.random()-.5)*.3; rPos[i*3+2]=Math.sin(a)*r; | |
| } | |
| const rGeo=new THREE.BufferGeometry(); | |
| rGeo.setAttribute('position',new THREE.BufferAttribute(rPos,3)); | |
| const ringMesh=new THREE.Points(rGeo,new THREE.PointsMaterial({color:0x38bdf8,size:.055,transparent:true,opacity:.6})); | |
| ringMesh.position.copy(knot.position); scene.add(ringMesh); | |
| /* Floaters */ | |
| const floaters=[],cols=[0x38bdf8,0x818cf8,0xf472b6,0xfbbf24]; | |
| for(let i=0;i<14;i++){ | |
| const m=new THREE.Mesh( | |
| new THREE.IcosahedronGeometry(Math.random()*.22+.07,0), | |
| new THREE.MeshStandardMaterial({color:cols[i%4],emissive:cols[i%4],emissiveIntensity:.6,wireframe:Math.random()>.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); | |
| }); |