@@ -542,95 +542,50 @@ let cx=0,cy=0;
542542 const hits=getIntersects(e.clientX,e.clientY);
543543 if(!hits.length)return;
544544 const type=hits[0].object.parent.userData.type;
545- const clickedPill=type==='blue'?bPill:rPill;
546-
547- // Split-open animation: top half up, bottom half down, inner glow
548- const topHalf=clickedPill.children[1]; // sphere top
549- const botHalf=clickedPill.children[2]; // sphere bottom
550- const body=clickedPill.children[0]; // cylinder
551- const origTopY=topHalf.position.y, origBotY=botHalf.position.y;
552-
553- // Add inner glow light
554- // Inner glow — warm core light
555- const glowColor=type==='blue'?0x0044cc:0xcc0000;
556- const innerGlow=new THREE.PointLight(glowColor,0,8);
557- innerGlow.position.set(0,0,0);
558- clickedPill.add(innerGlow);
559-
560- // Scatter micro-particles from the seam
561- const sparkGeo=new THREE.BufferGeometry();
562- const sparkCount=60;
563- const sparkPos=new Float32Array(sparkCount*3);
564- const sparkVel=[];
565- for(let i=0;i<sparkCount;i++){
566- sparkPos[i*3]=0;sparkPos[i*3+1]=0;sparkPos[i*3+2]=0;
567- const a=Math.random()*Math.PI*2,sp=.02+Math.random()*.08;
568- sparkVel.push({vx:Math.cos(a)*sp,vy:(Math.random()-.3)*sp*1.5,vz:Math.sin(a)*sp});
569- }
570- sparkGeo.setAttribute('position',new THREE.BufferAttribute(sparkPos,3));
571- const sparkMat=new THREE.PointsMaterial({color:glowColor,size:.08,transparent:true,opacity:.9,blending:THREE.AdditiveBlending});
572- const sparks=new THREE.Points(sparkGeo,sparkMat);
573- clickedPill.add(sparks);
574-
575- let splitT=0;
576- const flashEl=document.getElementById('pill-flash');
577- function splitAnim(){
578- splitT+=0.025;
579- // Spring-like overshoot: ease with damped oscillation
580- const t=Math.min(splitT,1.2);
581- const spring=1-Math.exp(-6*t)*Math.cos(t*8);
582- const ease=Math.min(spring,1.3);
583-
584- // Split with slight outward rotation
585- topHalf.position.y=origTopY+ease*2.2;
586- topHalf.rotation.x=ease*.15;
587- topHalf.rotation.z=ease*.08;
588- botHalf.position.y=origBotY-ease*2.2;
589- botHalf.rotation.x=-ease*.12;
590- botHalf.rotation.z=-ease*.06;
591-
592- // Body dissolves
593- body.scale.y=Math.max(0,1-ease*.9);
594- body.material.opacity=Math.max(0,.94-ease*.94);
595-
596- // Inner glow ramps up with warmth
597- innerGlow.intensity=ease*40;
598- innerGlow.distance=3+ease*12;
599-
600- // Sparks fly outward
601- const sp=sparks.geometry.attributes.position.array;
602- for(let i=0;i<sparkCount;i++){
603- const v=sparkVel[i];
604- sp[i*3]+=v.vx;sp[i*3+1]+=v.vy;sp[i*3+2]+=v.vz;
605- }
606- sparks.geometry.attributes.position.needsUpdate=true;
607- sparkMat.opacity=Math.max(0,1-splitT*.6);
608-
609- // Screen flash: brief white burst then colored glow
610- if(splitT<.1){
611- const f=1-splitT/.1;
612- flashEl.style.background='radial-gradient(circle,rgba(255,255,255,'+f*.7+'),transparent 50%)';
545+ const chosenPill=type==='blue'?bPill:rPill;
546+ const otherPill=type==='blue'?rPill:bPill;
547+ const origZ=chosenPill.position.z;
548+
549+ // Chosen pill: glow → float toward camera → dissolve
550+ let dt=0;
551+ function dissolveAnim(){
552+ dt+=0.02;
553+ const t=Math.min(dt,1);
554+ const ease=1-Math.pow(1-t,3);
555+
556+ // Float toward camera + glow intensely
557+ chosenPill.position.z=origZ+ease*4;
558+ chosenPill.scale.setScalar(1+ease*.3);
559+ chosenPill.children.forEach(m=>{
560+ if(!m.material)return;
561+ m.material.emissiveIntensity=.15+ease*.8;
562+ if(dt>.5) m.material.opacity=Math.max(0,.94-(dt-.5)*1.88);
563+ });
564+
565+ // Unchosen pill: dim down
566+ otherPill.children.forEach(m=>{
567+ if(!m.material)return;
568+ m.material.emissiveIntensity=Math.max(.03,.15-ease*.12);
569+ m.material.opacity=Math.max(.3,.94-ease*.5);
570+ });
571+ otherPill.scale.setScalar(Math.max(.7,1-ease*.3));
572+
573+ // Screen color flash
574+ const flashEl=document.getElementById('pill-flash');
575+ if(dt<.15){
576+ flashEl.style.background='radial-gradient(circle,rgba(255,255,255,'+(1-dt/.15)*.5+'),transparent 50%)';
613577 flashEl.style.opacity='1';
614- }else if(splitT<.4){
615- const f=1-(splitT-.1)/.3;
578+ }else if(dt<.5){
616579 const rgb=type==='blue'?'0,68,204':'204,0,0';
617- flashEl.style.background='radial-gradient(circle,rgba('+rgb+','+f*.3+'),transparent 60%)';
618- flashEl.style.opacity='1';
580+ flashEl.style.background='radial-gradient(circle,rgba('+rgb+','+(1-(dt-.15)/.35)*.25+'),transparent 60%)';
619581 }else{
620582 flashEl.style.opacity='0';
621583 }
622584
623- // Fade out everything after split
624- if(splitT>1){
625- const fade=Math.max(0,1-(splitT-1)*1.5);
626- clickedPill.children.forEach(m=>{if(m.material)m.material.opacity=fade*.5});
627- sparkMat.opacity=fade*.3;
628- innerGlow.intensity=Math.max(0,innerGlow.intensity*fade);
629- if(fade<=0){clickedPill.visible=false;return}
630- }
631- requestAnimationFrame(splitAnim);
585+ if(dt<1.2) requestAnimationFrame(dissolveAnim);
586+ else chosenPill.visible=false;
632587 }
633- splitAnim ();
588+ dissolveAnim ();
634589
635590 // Red pill: shatter video as FIXED OVERLAY during scroll (no waiting)
636591 if(type==='red'){
@@ -666,6 +621,7 @@ let cx=0,cy=0;
666621 const vc=document.getElementById('vid-hero-calm');
667622 const vs=document.getElementById('vid-hero-shatter');
668623 if(vc&&vs){vc.style.opacity='1';vs.style.opacity='0'}
624+ document.getElementById('pill-canvas').style.opacity='0';
669625 resetObs.disconnect();
670626 }
671627 },{threshold:0});
@@ -916,10 +872,9 @@ document.querySelectorAll('.vid-bg').forEach(v=>{
916872 const vCalm=document.getElementById('vid-hero-calm');
917873 const vShatter=document.getElementById('vid-hero-shatter');
918874 if(vCalm&&vShatter){vCalm.style.opacity='1';vShatter.style.opacity='0'}
919- // Make pills visible again for re-choosing
875+ // Restore both pills to full state
920876 const bp=window._bPill,rp=window._rPill;
921- if(bp){bp.visible=true;bp.children.forEach(m=>{if(m.material)m.material.opacity=.94})}
922- if(rp){rp.visible=true;rp.children.forEach(m=>{if(m.material)m.material.opacity=.94})}
877+ [bp,rp].forEach(p=>{if(!p)return;p.visible=true;p.scale.setScalar(1);p.position.z=0;p.children.forEach(m=>{if(m.material){m.material.opacity=.94;m.material.emissiveIntensity=.15}})})
923878 // Scroll back
924879 document.getElementById('act-choice').scrollIntoView({behavior:'smooth'});
925880 // Pulse the red pill after arrival
0 commit comments