';
hero.appendChild(layer);
const canvas=layer.querySelector('#plChipCanvas');
const labelLayer=layer.querySelector('#plChipLabels');
const ctx=canvas.getContext('2d',{alpha:true,desynchronized:true});
if(!ctx) return;
const labels=[];
CFG.labels.forEach((item)=>{
const a=document.createElement('a');
a.className='pl-chip-card';
a.href=item.href||'#';
a.textContent=item.text;
a.setAttribute('aria-label',item.text);
labelLayer.appendChild(a);
labels.push(a);
});
const labelPos=[
[-205,-154],[0,-184],[205,-154],[238,-65],[242,48],[190,142],
[58,174],[-62,174],[-190,140],[-242,48],[-238,-62]
];
let W=1,H=1,DPR=1,cx=0,cy=0;
const FRAME_MS=1000/60;
let lastPaint=0;
function resize(){
const r=hero.getBoundingClientRect();
W=Math.max(1,r.width);
H=Math.max(1,r.height);
DPR=Math.min(window.devicePixelRatio||1,1.5);
canvas.width=Math.floor(W*DPR);
canvas.height=Math.floor(H*DPR);
canvas.style.width=W+'px';
canvas.style.height=H+'px';
ctx.setTransform(DPR,0,0,DPR,0,0);
cx=W*.52;
cy=H*.50;
}
resize();
window.addEventListener('resize',resize,{passive:true});
function dark(){
return document.body.classList.contains('pl-dark');
}
function C(){
return dark()
? {c1:[123,217,255],c2:[155,140,255],c3:[233,109,183],line:[123,217,255]}
: {c1:[85,215,242],c2:[88,220,199],c3:[140,120,232],c4:[233,109,183],line:[15,55,105]};
}
function rgba(c,a){return 'rgba('+c[0]+','+c[1]+','+c[2]+','+a+')'}
function clamp(v,a,b){return Math.max(a,Math.min(b,v))}
function easeInOut(t){return t*t*(3-2*t)}
function easeOut(t){return 1-Math.pow(1-t,3)}
function lerp(a,b,t){return a+(b-a)*t}
function rotate(p,rx,ry,rz){
let x=p.x,y=p.y,z=p.z;
let c=Math.cos(rx),s=Math.sin(rx);
let y1=y*c-z*s,z1=y*s+z*c;
y=y1;z=z1;
c=Math.cos(ry);s=Math.sin(ry);
let x1=x*c+z*s,z2=-x*s+z*c;
x=x1;z=z2;
c=Math.cos(rz);s=Math.sin(rz);
return {x:x*c-y*s,y:x*s+y*c,z:z};
}
function project(p,scale){
const cam=900;
const k=cam/(cam-p.z);
return {x:cx+p.x*k*scale,y:cy-p.y*k*scale,z:p.z,k};
}
/* Punto optimizado: evita save/restore y shadowBlur por partícula.
El brillo se conserva mediante un halo global económico. */
function dot(x,y,r,col,a,glow){
ctx.beginPath();
ctx.fillStyle=rgba(col,a);
ctx.arc(x,y,r,0,Math.PI*2);
ctx.fill();
}
function seg(a,b,col,w,a0){
ctx.beginPath();
ctx.moveTo(a.x,a.y);
ctx.lineTo(b.x,b.y);
ctx.strokeStyle=rgba(col,a0);
ctx.lineWidth=w;
ctx.lineCap='round';
ctx.stroke();
}
/* ---------- Snapshot / partículas de transición ---------- */
let snapshot=null;
const snapParticles=[];
function makeSnapshot(){
const snap=document.createElement('canvas');
snap.width=Math.max(1,Math.floor(W));
snap.height=Math.max(1,Math.floor(H));
const sctx=snap.getContext('2d',{willReadFrequently:true});
if(brainCanvas) sctx.drawImage(brainCanvas,0,0,W,H);
if(anatomyCanvas) sctx.drawImage(anatomyCanvas,0,0,W,H);
snapshot=snap;
snapParticles.length=0;
const step=Math.max(7,Math.round(Math.min(W,H)/145));
const iw=snap.width;
const ih=snap.height;
const data=sctx.getImageData(0,0,iw,ih).data;
for(let y=step>>1;y
>1;x36 && Math.random()<.42){
const dx=x-cx,dy=y-cy;
const d=Math.hypot(dx,dy)+1;
snapParticles.push({
x,y,
dx:(dx/d)*(80+Math.random()*Math.max(W,H)*.38),
dy:(dy/d)*(60+Math.random()*Math.max(W,H)*.30),
r:.45+Math.random()*1.5,
hue:Math.random(),
z:(Math.random()-.5)*460
});
}
}
}
}
function drawExplosion(q){
if(!snapParticles.length) return;
const cc=C();
ctx.save();
ctx.globalCompositeOperation='lighter';
const n=snapParticles.length;
const e=easeOut(clamp(q,0,1));
for(let i=0;iproject(rotate(p,a.rx,a.ry,a.rz),s));
const sp=back.map(p=>project(rotate(p,a.rx,a.ry,a.rz),s));
ctx.save();
ctx.globalAlpha=alpha;
ctx.beginPath();
bp.forEach((p,i)=>i?ctx.lineTo(p.x,p.y):ctx.moveTo(p.x,p.y));
ctx.closePath();
ctx.fillStyle=dark()?'rgba(7,18,28,.52)':'rgba(247,250,252,.30)';
ctx.fill();
for(let i=0;i<4;i++){
const j=(i+1)%4;
seg(bp[i],bp[j],cc.c1,1.15,.65*alpha*build);
seg(sp[i],sp[j],cc.line,.55,.24*alpha*build);
seg(bp[i],sp[i],cc.line,.60,.20*alpha*build);
}
const ih=69;
const frame=[
{x:-ih,y:-ih,z:20},{x:ih,y:-ih,z:20},
{x:ih,y:ih,z:20},{x:-ih,y:ih,z:20}
].map(p=>project(rotate(p,a.rx,a.ry,a.rz),s));
for(let i=0;i<4;i++){
seg(frame[i],frame[(i+1)%4],cc.c2||cc.c1,.82,.50*alpha*build);
}
for(let i=0;i<4;i++){
const p1=frame[i],p2=frame[(i+1)%4];
for(let k=1;k<5;k++){
dot(lerp(p1.x,p2.x,k/5),lerp(p1.y,p2.y,k/5),.75,cc.c1,.56*alpha*build,5);
}
}
const center=project(rotate({x:0,y:0,z:23},a.rx,a.ry,a.rz),s);
ctx.textAlign='center';
ctx.textBaseline='middle';
ctx.font='700 '+Math.max(27,Math.round(42*Math.max(.78,Math.min(1.12,s*2.8))))+'px Rajdhani,sans-serif';
const grd=ctx.createLinearGradient(center.x-60,center.y,center.x+60,center.y);
grd.addColorStop(0,dark()?'#FFFFFF':'#2E2A27');
grd.addColorStop(.5,dark()?'#BCEFFF':'#55D7F2');
grd.addColorStop(1,dark()?'#9B8CFF':'#8C78E8');
ctx.fillStyle=grd;
ctx.globalAlpha=.95*alpha*build;
ctx.shadowBlur=16;
ctx.shadowColor=rgba(cc.c1,.32*alpha*build);
ctx.fillText('AI',center.x,center.y+1);
ctx.restore();
return s;
}
function cardCenter(el){
const r=el.getBoundingClientRect();
const hr=hero.getBoundingClientRect();
return {x:r.left+r.width/2-hr.left,y:r.top+r.height/2-hr.top};
}
function drawDirectConnections(time,alpha){
const cc=C();
const s=Math.min(W,H)/520*CFG.chipScale;
const a=chipParams(time);
const chipRadius=94*s*1.03;
ctx.save();
ctx.globalCompositeOperation='lighter';
labels.forEach((el,i)=>{
if(!el.classList.contains('is-visible')) return;
const to=cardCenter(el);
const dx=to.x-cx,dy=to.y-cy;
const d=Math.hypot(dx,dy)||1;
const sx=cx+(dx/d)*chipRadius;
const sy=cy+(dy/d)*chipRadius*.84;
/* vena principal */
const bend=20*Math.sin(i*1.7+time*.00035);
const mx=(sx+to.x)/2-(dy/d)*bend;
const my=(sy+to.y)/2+(dx/d)*bend*.35;
const hue=i%3===0?cc.c1:(i%3===1?cc.c2:cc.c3);
/* núcleo + halo */
ctx.beginPath();
ctx.moveTo(sx,sy);
ctx.lineTo(mx,my);
ctx.lineTo(to.x,to.y);
ctx.strokeStyle=rgba(hue,.20*alpha);
ctx.lineWidth=1.35;
ctx.stroke();
ctx.beginPath();
ctx.moveTo(sx,sy);
ctx.lineTo(mx,my);
ctx.lineTo(to.x,to.y);
ctx.strokeStyle=rgba(hue,.58*alpha);
ctx.lineWidth=.46;
ctx.stroke();
/* pequeñas ramificaciones */
for(let b=0;b<2;b++){
const t=.25+b*.22;
const bx=lerp(sx,mx,t);
const by=lerp(sy,my,t);
const side=b%2?1:-1;
const px=bx-(dy/d)*side*8;
const py=by+(dx/d)*side*8;
ctx.beginPath();
ctx.moveTo(bx,by);
ctx.lineTo(px,py);
ctx.strokeStyle=rgba(hue,.24*alpha);
ctx.lineWidth=.34;
ctx.stroke();
}
const pulse=(time*.00068+i*.11)%1;
let px,py;
if(pulse<.5){
const q=pulse*2;
px=lerp(sx,mx,q);
py=lerp(sy,my,q);
}else{
const q=(pulse-.5)*2;
px=lerp(mx,to.x,q);
py=lerp(my,to.y,q);
}
dot(px,py,1.8,hue,.96*alpha,0);
dot(to.x,to.y,1.1,hue,.68*alpha,0);
});
ctx.restore();
}
function drawChip(time,alpha=1,build=1){
const cc=C();
const s=Math.min(W,H)/520*CFG.chipScale;
const a=chipParams(time);
drawChipBody(time,alpha,build);
for(let i=0;i=chipStart &&
elapsed=(i+1)*CFG.labelEvery;
if(visible){
const [bx,by]=labelPos[i];
const t=elapsed-chipStart;
el.style.setProperty('--sx',(bx+Math.sin(t*.0006+i*.9)*3)+'px');
el.style.setProperty('--sy',(by+Math.cos(t*.00052+i*.7)*3)+'px');
el.classList.add('is-visible');
}else{
el.classList.remove('is-visible');
}
}
labelLayer.style.pointerEvents='none';
}
/* ---------- snapshot de implosión final ---------- */
const implosionParticles=Array.from({length:240},(_,i)=>({
ang:i*2.399963,
rad:80+Math.random()*Math.max(W,H)*.30,
yScale:.62+.24*Math.random(),
r:.45+Math.random()*1.15
}));
function drawImplosion(q){
const cc=C();
ctx.save();
ctx.globalCompositeOperation='lighter';
for(let i=0;i=loopMs){
cycleStart+=Math.floor(e/loopMs)*loopMs;
/* reinicio duro para evitar acumulación temporal */
enterState(T.BRAIN,0);
state=T.BRAIN;
return 0;
}
return e;
}
function render(now){
if(!running) return;
if(now-lastPaint < FRAME_MS){
raf=requestAnimationFrame(render);
return;
}
lastPaint=now;
const elapsed=resetCycleIfNeeded(now);
const next=resolveState(elapsed);
if(next!==lastState){
enterState(next,elapsed);
lastState=next;
}
updateLabels(elapsed);
ctx.clearRect(0,0,W,H);
if(next===T.BRAIN){
/* cerebro dibujado exclusivamente por el motor original */
layer.classList.remove('is-active');
hero.classList.remove('pl-orchestrator-hide-brain');
}
else if(next===T.TRANSITION_IN){
/* Cerebro ya está oculto: solo transición propia. */
hero.classList.add('pl-orchestrator-hide-brain');
layer.classList.add('is-active');
const q=(elapsed-CFG.brainHold)/CFG.transitionIn;
if(q<.52){
drawExplosion(q/.52);
}
const iq=clamp((q-.42)/.58,0,1);
if(iq>0){
drawChip(now,easeInOut(iq),easeOut(iq));
}
}
else if(next===T.CHIP){
hero.classList.add('pl-orchestrator-hide-brain');
layer.classList.add('is-active');
drawChip(now,1,1);
}
else{
/* TRANSITION_OUT:
El chip se destruye. El cerebro sigue OCULTO.
Solo al finalizar los 5s se cambia al estado BRAIN. */
hero.classList.add('pl-orchestrator-hide-brain');
layer.classList.add('is-active');
const q=(elapsed-(CFG.brainHold+CFG.transitionIn+CFG.chipHold))/CFG.transitionOut;
if(q<.58){
const e=q/.58;
drawChip(now,1-easeInOut(e),1-easeInOut(e));
}
const iq=clamp((q-.38)/.62,0,1);
if(iq>0) drawImplosion(iq);
}
raf=requestAnimationFrame(render);
}
function resume(){
if(!raf){
running=true;
const now=performance.now();
/* no reiniciar el ciclo al volver al viewport */
raf=requestAnimationFrame(render);
}
}
function pause(){
running=false;
if(raf){
cancelAnimationFrame(raf);
raf=0;
}
}
/* Inicialización determinista:
al comenzar la página el cerebro es el único estado visible. */
enterState(T.BRAIN,0);
lastState=T.BRAIN;
cycleStart=performance.now();
if('IntersectionObserver' in window){
const obs=new IntersectionObserver(entries=>{
const visible=entries.some(e=>e.isIntersecting);
if(visible&&!document.hidden) resume();
else pause();
},{threshold:.01});
obs.observe(hero);
}
document.addEventListener('visibilitychange',()=>{
if(document.hidden){
pause();
}else{
const r=hero.getBoundingClientRect();
if(r.bottom>0&&r.top