+function screenY(y){return H-80-y}function floorAt(x,bottom,previous){for(const p of platforms){if(x+13>p.x&&x-13<p.x+p.w&&previous>=p.y&&bottom<=p.y)return p.y}return null}
+function hurt(){if(hero.inv>0)return;lives--;hero.inv=1000;dom.lives.textContent=Array(lives).fill("●").join(" ")||"—";if(lives<=0){run=false;dom.copy.innerHTML="The Skyworks shut Bolt down.<br>Restart the mission and try a new route.";dom.start.textContent="REBOOT";dom.overlay.style.display="grid";dom.boss.style.display="none"}}
+function screenY(y){return H-80-y}function floorAt(x,bottom,previous){for(const p of platforms){if(x+13>p.x&&x-13<p.x+p.w&&previous>=p.y&&bottom<=p.y)return p.y}return null}
+function hurt(){if(hero.inv>0)return;lives--;hero.inv=1000;dom.lives.textContent=Array(lives).fill("●").join(" ")||"—";if(lives<=0){run=false;dom.copy.innerHTML="The Skyworks shut Bolt down.<br>Restart the mission and try a new route.";dom.start.textContent="REBOOT";dom.overlay.style.display="grid";dom.boss.style.display="none"}}
</script></body></html>
-
-
function spawnBoss(){boss={x:3850,y:60,hp:42,max:42,vx:0,shot:0};el.boss.style.display="block";el.fill.style.width="100%"}
function spawnBoss(){boss={x:3850,y:60,hp:42,max:42,vx:0,shot:0};el.boss.style.display="block";el.fill.style.width="100%"}
-function end(){run=false;el.copy.innerHTML="<b>Skyworks cleared!</b><br>You defeated the Iron Warden and recovered the core.";el.start.textContent="PLAY AGAIN";el.overlay.style.display="grid";el.boss.style.display="none"}
-function end(){run=false;el.copy.innerHTML="<b>Skyworks cleared!</b><br>You defeated the Iron Warden and recovered the core.";el.start.textContent="PLAY AGAIN";el.overlay.style.display="grid";el.boss.style.display="none"}
-function loop(t){requestAnimationFrame(loop);let dt=Math.min(35,last?t-last:16);last=t;ctx.fillStyle="#80d3df";ctx.fillRect(0,0,W,H);let horizon=H*.55;ctx.fillStyle="#eff6ce";ctx.fillRect(0,horizon,W,H-horizon);for(let i=0;i<18;i++){let x=(i*310-cam*.22)% (W+310)-140;ctx.fillStyle=i%2?"#3d7e9a":"#2b6f8b";ctx.fillRect(x,horizon-60-(i%4)*35,80,60+(i%4)*35);ctx.fillStyle="#ffce5d";ctx.fillRect(x+12,horizon-40-(i%4)*35,14,6)}if(run){let dx=(keys.l?-1:0)+(keys.r?1:0);player.vx=dx*3.5;player.dir=dx||player.dir;let oldBottom=player.y;player.vy-=.00085*dt;player.y+=player.vy*dt;player.x+=player.vx*dt*.065;let landed=platformAt(player.x,player.y,oldBottom);if(landed&&player.vy<=0){player.y=landed.y;player.vy=0;player.ground=true}else player.ground=false;if(player.y<-120){player.y=70;player.x=Math.max(80,player.x-100);damage()}player.x=Math.max(30,Math.min(4200,player.x));cam+=((player.x-W*.35)-cam)*.08;cam=Math.max(0,Math.min(3800-W*.5,cam));player.inv=Math.max(0,player.inv-dt);if(keys.fire&&t>fireAt){shoot();fireAt=t+230}if(!boss&&player.x>3650&&chips.length===0)spawnBoss();for(const e of enemies){if(!e.dead&&Math.abs(player.x-e.x)<240&&t>(e.next||0)){shot(e.x,e.y+25,-3.8,true);e.next=t+1250}if(!e.dead&&Math.abs(player.x-e.x)<31&&Math.abs(player.y-e.y)<45)damage()}if(boss){boss.y=50+Math.sin(t*.002)*30;boss.x=3850+Math.sin(t*.001)*120;boss.shot-=dt;if(boss.shot<0){shot(boss.x,boss.y+20,-4.5,true);boss.shot=650}if(Math.abs(player.x-boss.x)<55&&Math.abs(player.y-boss.y)<70)damage()}for(let i=shots.length-1;i>=0;i--){let q=shots[i];q.x+=q.vx*dt*.06;let remove=q.x<cam-50||q.x>cam+W+50;if(!q.enemy){for(const e of enemies)if(!e.dead&&Math.abs(q.x-e.x)<28&&Math.abs(q.y-e.y-5)<32){e.hp--;remove=true;if(e.hp<=0)e.dead=true}if(boss&&Math.abs(q.x-boss.x)<55&&Math.abs(q.y-boss.y)<70){boss.hp--;remove=true;el.fill.style.width=boss.hp/boss.max*100+"%";if(boss.hp<=0)end()}}else if(Math.abs(q.x-player.x)<20&&Math.abs(q.y-player.y-23)<34){remove=true;damage()}if(remove)shots.splice(i,1)}for(let i=chips.length-1;i>=0;i--){let p=chips[i];if(Math.abs(player.x-p.x)<26&&Math.abs(player.y-p.y)<45){chips.splice(i,1);player.score++;el.chips.textContent=player.score+" / 8"}}}for(const p of plats){let x=p.x-cam;if(x+p.w<0||x>W)continue;ctx.fillStyle=p.y===0?"#276f79":"#7250a1";ctx.fillRect(x,H-(p.y+18),p.w,18);ctx.fillStyle="#ffd35f";ctx.fillRect(x,H-(p.y+18),p.w,4)}for(const chip of chips){ctx.fillStyle="#ffe35c";ctx.beginPath();ctx.arc(chip.x-cam,H-chip.y-20,9,0,7);ctx.fill()}for(const e of enemies)if(!e.dead)drawRobot(e.x,H-e.y-18,-1,true,.85);if(boss)drawRobot(boss.x,H-boss.y-18,-1,true,2.3);for(const q of shots){ctx.fillStyle=q.enemy?"#ff5a87":"#fff28a";ctx.fillRect(q.x-cam-5,H-q.y-23,10,4)}if(player&&(player.inv<=0||Math.floor(t/90)%2))drawRobot(player.x,H-player.y-18,player.dir);requestAnimationFrame(loop)}
-function loop(t){requestAnimationFrame(loop);let dt=Math.min(35,last?t-last:16);last=t;ctx.fillStyle="#80d3df";ctx.fillRect(0,0,W,H);let horizon=H*.55;ctx.fillStyle="#eff6ce";ctx.fillRect(0,horizon,W,H-horizon);for(let i=0;i<18;i++){let x=(i*310-cam*.22)% (W+310)-140;ctx.fillStyle=i%2?"#3d7e9a":"#2b6f8b";ctx.fillRect(x,horizon-60-(i%4)*35,80,60+(i%4)*35);ctx.fillStyle="#ffce5d";ctx.fillRect(x+12,horizon-40-(i%4)*35,14,6)}if(run){let dx=(keys.l?-1:0)+(keys.r?1:0);player.vx=dx*3.5;player.dir=dx||player.dir;let oldBottom=player.y;player.vy-=.00085*dt;player.y+=player.vy*dt;player.x+=player.vx*dt*.065;let landed=platformAt(player.x,player.y,oldBottom);if(landed&&player.vy<=0){player.y=landed.y;player.vy=0;player.ground=true}else player.ground=false;if(player.y<-120){player.y=70;player.x=Math.max(80,player.x-100);damage()}player.x=Math.max(30,Math.min(4200,player.x));cam+=((player.x-W*.35)-cam)*.08;cam=Math.max(0,Math.min(3800-W*.5,cam));player.inv=Math.max(0,player.inv-dt);if(keys.fire&&t>fireAt){shoot();fireAt=t+230}if(!boss&&player.x>3650&&chips.length===0)spawnBoss();for(const e of enemies){if(!e.dead&&Math.abs(player.x-e.x)<240&&t>(e.next||0)){shot(e.x,e.y+25,-3.8,true);e.next=t+1250}if(!e.dead&&Math.abs(player.x-e.x)<31&&Math.abs(player.y-e.y)<45)damage()}if(boss){boss.y=50+Math.sin(t*.002)*30;boss.x=3850+Math.sin(t*.001)*120;boss.shot-=dt;if(boss.shot<0){shot(boss.x,boss.y+20,-4.5,true);boss.shot=650}if(Math.abs(player.x-boss.x)<55&&Math.abs(player.y-boss.y)<70)damage()}for(let i=shots.length-1;i>=0;i--){let q=shots[i];q.x+=q.vx*dt*.06;let remove=q.x<cam-50||q.x>cam+W+50;if(!q.enemy){for(const e of enemies)if(!e.dead&&Math.abs(q.x-e.x)<28&&Math.abs(q.y-e.y-5)<32){e.hp--;remove=true;if(e.hp<=0)e.dead=true}if(boss&&Math.abs(q.x-boss.x)<55&&Math.abs(q.y-boss.y)<70){boss.hp--;remove=true;el.fill.style.width=boss.hp/boss.max*100+"%";if(boss.hp<=0)end()}}else if(Math.abs(q.x-player.x)<20&&Math.abs(q.y-player.y-23)<34){remove=true;damage()}if(remove)shots.splice(i,1)}for(let i=chips.length-1;i>=0;i--){let p=chips[i];if(Math.abs(player.x-p.x)<26&&Math.abs(player.y-p.y)<45){chips.splice(i,1);player.score++;el.chips.textContent=player.score+" / 8"}}}for(const p of plats){let x=p.x-cam;if(x+p.w<0||x>W)continue;ctx.fillStyle=p.y===0?"#276f79":"#7250a1";ctx.fillRect(x,H-(p.y+18),p.w,18);ctx.fillStyle="#ffd35f";ctx.fillRect(x,H-(p.y+18),p.w,4)}for(const chip of chips){ctx.fillStyle="#ffe35c";ctx.beginPath();ctx.arc(chip.x-cam,H-chip.y-20,9,0,7);ctx.fill()}for(const e of enemies)if(!e.dead)drawRobot(e.x,H-e.y-18,-1,true,.85);if(boss)drawRobot(boss.x,H-boss.y-18,-1,true,2.3);for(const q of shots){ctx.fillStyle=q.enemy?"#ff5a87":"#fff28a";ctx.fillRect(q.x-cam-5,H-q.y-23,10,4)}if(player&&(player.inv<=0||Math.floor(t/90)%2))drawRobot(player.x,H-player.y-18,player.dir);requestAnimationFrame(loop)}
+function win(){run=false;dom.copy.innerHTML="<b>Skyworks cleared!</b><br>You defeated the Iron Warden and recovered the core.";dom.start.textContent="PLAY AGAIN";dom.overlay.style.display="grid";dom.boss.style.display="none"}
+function win(){run=false;dom.copy.innerHTML="<b>Skyworks cleared!</b><br>You defeated the Iron Warden and recovered the core.";dom.start.textContent="PLAY AGAIN";dom.overlay.style.display="grid";dom.boss.style.display="none"}
+for(const d of drones){if(!d.dead&&Math.abs(hero.x-d.x)<35&&Math.abs(hero.y-d.y)<45)hurt();if(!d.dead&&Math.abs(hero.x-d.x)<300&&t>d.next){addBullet(d.x,d.y+24,-3.8,true);d.next=t+1250}}if(boss){boss.y=70+Math.sin(t*.002)*25;if(t>boss.next){addBullet(boss.x,boss.y+22,-4.8,true);boss.next=t+650}if(Math.abs(hero.x-boss.x)<65&&Math.abs(hero.y-boss.y)<65)hurt()}
+for(const d of drones){if(!d.dead&&Math.abs(hero.x-d.x)<35&&Math.abs(hero.y-d.y)<45)hurt();if(!d.dead&&Math.abs(hero.x-d.x)<300&&t>d.next){addBullet(d.x,d.y+24,-3.8,true);d.next=t+1250}}if(boss){boss.y=70+Math.sin(t*.002)*25;if(t>boss.next){addBullet(boss.x,boss.y+22,-4.8,true);boss.next=t+650}if(Math.abs(hero.x-boss.x)<65&&Math.abs(hero.y-boss.y)<65)hurt()}
+for(let i=bullets.length-1;i>=0;i--){const b=bullets[i];b.x+=b.vx*dt*.06;let remove=b.x<camera-60||b.x>camera+W+60;if(!b.enemy){for(const d of drones)if(!d.dead&&Math.abs(b.x-d.x)<26&&Math.abs(b.y-d.y)<30){d.hp--;remove=true;if(d.hp<=0)d.dead=true}if(boss&&Math.abs(b.x-boss.x)<56&&Math.abs(b.y-boss.y)<70){boss.hp--;remove=true;dom.fill.style.width=(boss.hp/boss.max*100)+"%";if(boss.hp<=0)win()}}else if(Math.abs(b.x-hero.x)<20&&Math.abs(b.y-(hero.y+25))<35){remove=true;hurt()}if(remove)bullets.splice(i,1)}
+for(let i=bullets.length-1;i>=0;i--){const b=bullets[i];b.x+=b.vx*dt*.06;let remove=b.x<camera-60||b.x>camera+W+60;if(!b.enemy){for(const d of drones)if(!d.dead&&Math.abs(b.x-d.x)<26&&Math.abs(b.y-d.y)<30){d.hp--;remove=true;if(d.hp<=0)d.dead=true}if(boss&&Math.abs(b.x-boss.x)<56&&Math.abs(b.y-boss.y)<70){boss.hp--;remove=true;dom.fill.style.width=(boss.hp/boss.max*100)+"%";if(boss.hp<=0)win()}}else if(Math.abs(b.x-hero.x)<20&&Math.abs(b.y-(hero.y+25))<35){remove=true;hurt()}if(remove)bullets.splice(i,1)}
+for(const p of platforms){const x=p.x-camera;if(x+p.w<0||x>W)continue;ctx.fillStyle=p.y===0?"#276f79":"#7050a2";ctx.fillRect(x,screenY(p.y)-18,p.w,18);ctx.fillStyle="#ffd35f";ctx.fillRect(x,screenY(p.y)-18,p.w,4)}for(const p of chips){ctx.fillStyle="#ffe35c";ctx.beginPath();ctx.arc(p.x-camera,screenY(p.y+25),9,0,Math.PI*2);ctx.fill()}for(const d of drones)if(!d.dead)drawBot(d.x,d.y,-1,true,.85);if(boss)drawBot(boss.x,boss.y,-1,true,2.25);for(const b of bullets){ctx.fillStyle=b.enemy?"#ff5a87":"#fff28a";ctx.fillRect(b.x-camera-5,screenY(b.y+25),10,4)}if(hero&&(hero.inv<=0||Math.floor(t/90)%2))drawBot(hero.x,hero.y,hero.dir,false);ctx.fillStyle="#fff";ctx.font="11px system-ui";if(run&&hero&&hero.collected<8)ctx.fillText("Collect all 8 energy chips",16,H-125)}
+for(const p of platforms){const x=p.x-camera;if(x+p.w<0||x>W)continue;ctx.fillStyle=p.y===0?"#276f79":"#7050a2";ctx.fillRect(x,screenY(p.y)-18,p.w,18);ctx.fillStyle="#ffd35f";ctx.fillRect(x,screenY(p.y)-18,p.w,4)}for(const p of chips){ctx.fillStyle="#ffe35c";ctx.beginPath();ctx.arc(p.x-camera,screenY(p.y+25),9,0,Math.PI*2);ctx.fill()}for(const d of drones)if(!d.dead)drawBot(d.x,d.y,-1,true,.85);if(boss)drawBot(boss.x,boss.y,-1,true,2.25);for(const b of bullets){ctx.fillStyle=b.enemy?"#ff5a87":"#fff28a";ctx.fillRect(b.x-camera-5,screenY(b.y+25),10,4)}if(hero&&(hero.inv<=0||Math.floor(t/90)%2))drawBot(hero.x,hero.y,hero.dir,false);ctx.fillStyle="#fff";ctx.font="11px system-ui";if(run&&hero&&hero.collected<8)ctx.fillText("Collect all 8 energy chips",16,H-125)}