RTS
GPT 5.6 Luna · full

Reviews & generation details
Reviews
No human review yet. Unreviewed does not mean unsuccessful.
Generation context
Imported historical artifact. Its exact original instructions and lineage are not known.
Generation prompt · exact text unavailable
See the current prompt for reference. It may differ from the instructions used to generate this artifact.
Inspect original source 24,768 bytes · SHA-256 bd98d1c7a703
<!doctype html>
<html><head><meta charset="utf-8"><title>FRONTIER WAR // Helix-9</title><style>
:root{--cyan:#54e6ff;--lime:#b9ff78;--red:#ff5874;--amber:#ffc857;--panel:#07131ddd;--line:#245168}*{box-sizing:border-box}html,body{margin:0;height:100%;overflow:hidden;background:#02060d;color:#d8f5ff;font:13px system-ui,Segoe UI,sans-serif}canvas{display:block;position:fixed;inset:0;cursor:crosshair}#hud{position:fixed;inset:0;pointer-events:none}.top{height:70px;background:linear-gradient(180deg,#020711ed,#06101bce);border-bottom:1px solid #1c4d62;display:flex;align-items:center;padding:0 18px;gap:24px;pointer-events:auto}.brand{font-weight:900;letter-spacing:4px;color:var(--cyan);font-size:18px}.brand small{display:block;color:#5a8ca0;letter-spacing:2px;font-size:9px}.stat{min-width:105px}.stat b{font-size:18px;color:#fff}.stat label{display:block;color:#6a9bad;font-size:10px;letter-spacing:1px}.bar{height:5px;background:#173040;border-radius:4px;margin-top:4px;overflow:hidden}.bar i{display:block;height:100%;background:var(--cyan);width:70%}.bar.red i{background:var(--red)}#pause{margin-left:auto;background:#112a3b;color:#cff7ff;border:1px solid #2c7389;padding:8px 14px;border-radius:3px;pointer-events:auto}.right{position:absolute;right:16px;top:84px;width:260px;pointer-events:auto}.card{background:var(--panel);border:1px solid #245168;box-shadow:0 8px 30px #0009;padding:12px;margin-bottom:10px;backdrop-filter:blur(5px)}.card h3{margin:0 0 8px;color:var(--cyan);letter-spacing:2px;font-size:11px}.help{line-height:1.65;color:#9dc0cc}.help kbd{color:#fff;background:#173142;border:1px solid #386074;padding:1px 4px;border-radius:2px}.mini{height:150px;background:#06121a;border:1px solid #28586a;position:relative;overflow:hidden}.mini canvas{position:absolute;width:100%;height:100%;inset:0}.selection{min-height:75px}.selname{font-size:16px;color:#fff;font-weight:700}.tag{color:#7ba7b4;font-size:11px}.actions{display:flex;flex-wrap:wrap;gap:5px;margin-top:9px}.actions button,.buildbtn{background:#102a39;color:#b8edf7;border:1px solid #2b667a;padding:6px 8px;font-size:11px;border-radius:2px;cursor:pointer}.actions button:hover,.buildbtn:hover{border-color:var(--cyan);color:white;background:#174155}.queue{display:flex;gap:4px;min-height:28px}.q{width:28px;height:28px;border:1px solid #396273;text-align:center;padding-top:5px;color:var(--amber);background:#132330}.notice{position:absolute;bottom:18px;left:18px;background:#06121de8;border-left:3px solid var(--cyan);padding:10px 15px;max-width:450px;opacity:0;transition:.25s}.notice.on{opacity:1}.build{display:grid;grid-template-columns:1fr 1fr;gap:5px}.overlay{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:radial-gradient(circle at 50% 35%,#10344acc,#02050cee 65%);z-index:5}.modal{width:630px;border:1px solid #34758a;background:#06131eeF;padding:38px 44px;box-shadow:0 0 80px #00a6ce25}.modal h1{font-size:48px;letter-spacing:9px;margin:0;color:#bcefff;text-shadow:0 0 25px #3bd4ff}.modal h2{color:var(--cyan);font-size:13px;letter-spacing:4px;margin:3px 0 25px}.modal p{color:#9bbbc6;line-height:1.7}.start{margin-top:22px;background:#16738e;border:1px solid #75e9ff;color:white;padding:13px 26px;letter-spacing:3px;font-weight:800;cursor:pointer}.legend{display:flex;gap:16px;margin-top:18px;color:#8fb4c0;font-size:11px}.dot{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:5px}.hidden{display:none!important}
</style></head><body><canvas id="view"></canvas><div id="hud" class="hidden"><div class="top"><div class="brand">FRONTIER WAR<small>HELIX-9 // EXPEDITION COMMAND</small></div><div class="stat"><b id="ore">420</b><label>CRYSTAL ORE</label></div><div class="stat"><b id="supply">5 / 24</b><label>SUPPLY NETWORK</label><div class="bar"><i id="supbar"></i></div></div><div class="stat"><b id="clock">00:00</b><label>OPERATION TIME</label></div><button id="pause">Ⅱ PAUSE</button></div><div class="right"><div class="card"><h3>TACTICAL MAP // <span id="vis">SCANNING</span></h3><div class="mini"><canvas id="map"></canvas></div></div><div class="card selection"><h3>SELECTION</h3><div id="sel"><span class="tag">Select a unit or structure</span></div><div class="actions" id="actions"></div></div><div class="card"><h3>BUILD QUEUE</h3><div class="queue" id="queue"></div><div id="build" class="build"></div></div><div class="card help"><b style="color:#fff">FIELD MANUAL</b><br><kbd>WASD</kbd> pan · <kbd>Wheel</kbd> zoom · <kbd>Q/E</kbd> rotate<br><kbd>Drag</kbd> box select · <kbd>RMB</kbd> move / gather<br><kbd>A</kbd> attack-move · <kbd>H</kbd> hold · <kbd>1-4</kbd> control groups<br><span style="color:#ffc857">Amber = visible enemy · Cyan = expedition</span></div></div><div class="notice" id="notice"></div></div><div id="intro" class="overlay"><div class="modal"><h1>FRONTIER WAR</h1><h2>THE HELIX-9 CAMPAIGN</h2><p>Command the Asterion Expedition across an uncharted crystal frontier. Establish a supply chain, scout through the fog, and out-produce the rival Vanta Syndicate. Destroy every enemy headquarters to secure the planet.</p><p><b style="color:#b9ff78">OPENING DIRECTIVE:</b> Your three Prospector drones can harvest the nearby seam. Build a Relay, then raise a Foundry. The rival is quiet for 90 seconds.</p><div class="legend"><span><i class="dot" style="background:#54e6ff"></i>ASTERION</span><span><i class="dot" style="background:#ff5874"></i>VANTA SYNDICATE</span><span><i class="dot" style="background:#ffc857"></i>ORE DEPOSIT</span></div><button class="start" id="start">DEPLOY EXPEDITION →</button></div></div><div id="end" class="overlay hidden"><div class="modal"><h1 id="endtitle">MISSION COMPLETE</h1><h2 id="endsub">THE FRONTIER IS OURS</h2><p id="endcopy"></p><button class="start" id="restart">RESTART OPERATION</button></div></div>
<script>
const C=document.getElementById('view'),X=C.getContext('2d'),M=document.getElementById('map'),mx=M.getContext('2d');let W,H,game=false,paused=false,last=0,elapsed=0,ore=420,supplyMax=24,group={},selected=[],drag=null,buildMode=null,noticeTimer=0;
const world={w:1800,h:1300,cam:{x:480,y:350,z:1,rot:0}};const units=[],buildings=[],deposits=[],shots=[],particles=[],tiles=[];let aiOre=420;
const types={worker:{name:'Prospector',hp:45,max:45,spd:72,range:20,damage:4,cost:50,supply:1,build:5,ground:true,role:'harvester'},blade:{name:'Razorclaw',hp:105,max:105,spd:57,range:22,damage:18,cost:90,supply:1,build:7,ground:true,armor:'light',role:'melee'},rifle:{name:'Lancer',hp:72,max:72,spd:52,range:150,damage:13,cost:110,supply:1,build:9,ground:true,armor:'light',role:'ranged'},tank:{name:'Bastion',hp:270,max:270,spd:30,range:125,damage:34,cost:240,supply:3,build:16,ground:true,armor:'heavy',role:'armor'},drone:{name:'Skyrazor',hp:125,max:125,spd:92,range:170,damage:22,cost:180,supply:2,build:14,ground:false,role:'air'}};
const btypes={hq:{name:'Command Spire',hp:1100,max:1100,size:34,cost:0},relay:{name:'Supply Relay',hp:320,max:320,size:22,cost:100,supply:12},foundry:{name:'War Foundry',hp:520,max:520,size:28,cost:180,prod:['blade','rifle','tank']},hangar:{name:'Aero Hangar',hp:440,max:440,size:27,cost:240,prod:['drone']},turret:{name:'Sentinel Turret',hp:260,max:260,size:20,cost:150,range:210,damage:22}};
function rnd(a,b){return a+Math.random()*(b-a)} function dist(a,b){return Math.hypot(a.x-b.x,a.y-b.y)} function clamp(v,a,b){return Math.max(a,Math.min(b,v))} function say(s){let n=document.getElementById('notice');n.textContent=s;n.classList.add('on');clearTimeout(noticeTimer);noticeTimer=setTimeout(()=>n.classList.remove('on'),2600)}
function init(){for(let i=0;i<70;i++)tiles.push({x:rnd(30,1770),y:rnd(30,1270),r:rnd(10,45),c:Math.random()<.5?'#0b2630':'#102d32'});[[390,370,260],[610,500,190],[1300,900,280],[1000,260,240],[1460,390,220],[850,1080,200],[1260,600,180]].forEach((p,i)=>deposits.push({x:p[0],y:p[1],amount:p[2],max:p[2]}));
addB('player','hq',250,350);addB('ai','hq',1510,950);for(let i=0;i<3;i++){let u=addU('player','worker',300+i*24,410);let d=deposits[0];u.deposit=d;u.tx=d.x;u.ty=d.y;u.order='gather'}for(let i=0;i<3;i++){let u=addU('ai','worker',1450+i*24,1010);let d=deposits[2];u.deposit=d;u.tx=d.x;u.ty=d.y;u.order='gather'}world.cam.x=500;world.cam.y=480;}
function addU(side,type,x,y){let t=types[type],u={id:Math.random(),side,type,x,y,hp:t.hp,max:t.hp,order:'idle',tx:x,ty:y,target:null,carry:0,hold:false,group:0,flash:0};units.push(u);return u}
function addB(side,type,x,y){let t=btypes[type],b={id:Math.random(),side,type,x,y,hp:t.hp,max:t.hp,queue:[],progress:0,construct:type!=='hq',rally:{x:x+60,y},seen:true};buildings.push(b);return b}
function visible(o,side='player'){if(o.side===side)return true;return units.some(u=>u.side===side&&dist(u,o)<180)||buildings.some(b=>b.side===side&&dist(b,o)<210)}
function project(x,y,z=0){let q=world.cam.rot,dx=x-world.cam.x,dy=y-world.cam.y;let rx=dx*Math.cos(q)-dy*Math.sin(q),ry=dx*Math.sin(q)+dy*Math.cos(q);return {x:W/2+rx*world.cam.z,y:H/2+ry*world.cam.z-z*world.cam.z*.65}}
function unproject(sx,sy){let q=world.cam.rot,z=world.cam.z,rx=(sx-W/2)/z,ry=(sy-H/2)/z;return {x:world.cam.x+rx*Math.cos(q)+ry*Math.sin(q),y:world.cam.y-rx*Math.sin(q)+ry*Math.cos(q)}}
function draw(){X.fillStyle='#06141d';X.fillRect(0,0,W,H);let corners=[project(0,0),project(world.w,0),project(world.w,world.h),project(0,world.h)];X.beginPath();corners.forEach((p,i)=>i?X.lineTo(p.x,p.y):X.moveTo(p.x,p.y));X.closePath();X.fillStyle='#102b31';X.fill();for(let t of tiles){let p=project(t.x,t.y);if(p.x<-80||p.x>W+80||p.y<-80||p.y>H+80)continue;X.fillStyle=t.c;X.beginPath();X.arc(p.x,p.y,t.r*world.cam.z,0,7);X.fill()}fog();for(let d of deposits){if(!inSight(d))continue;let p=project(d.x,d.y);X.fillStyle='#ffc857';X.globalAlpha=.18;X.beginPath();X.arc(p.x,p.y,25*world.cam.z,0,7);X.fill();X.globalAlpha=1;X.fillStyle='#ffe187';X.beginPath();X.moveTo(p.x,p.y-10);X.lineTo(p.x+8,p.y+3);X.lineTo(p.x,p.y+12);X.lineTo(p.x-8,p.y+3);X.fill();}
buildings.filter(b=>b.side==='player'||visible(b)).sort((a,b)=>a.y-b.y).forEach(drawB);units.filter(u=>u.side==='player'||visible(u)).sort((a,b)=>a.y-b.y).forEach(drawU);shots.forEach(s=>{let a=project(s.x,s.y,s.z),b=project(s.tx,s.ty,s.z);X.strokeStyle=s.side==='player'?'#7af4ff':'#ff6c79';X.lineWidth=2;X.beginPath();X.moveTo(a.x,a.y);X.lineTo(b.x,b.y);X.stroke()});if(drag){X.strokeStyle='#70efff';X.setLineDash([5,4]);X.strokeRect(Math.min(drag.x,drag.ex),Math.min(drag.y,drag.ey),Math.abs(drag.ex-drag.x),Math.abs(drag.ey-drag.y));X.setLineDash([])}drawMini()}
function inSight(o){return o.side==='player'||units.some(u=>u.side==='player'&&dist(u,o)<190)||buildings.some(b=>b.side==='player'&&dist(b,o)<220)}function fog(){X.save();X.fillStyle='rgba(1,7,13,.76)';X.fillRect(0,70,W,H);X.globalCompositeOperation='destination-out';units.filter(u=>u.side==='player').forEach(u=>{let p=project(u.x,u.y),r=175*world.cam.z,g=X.createRadialGradient(p.x,p.y,r*.45,p.x,p.y,r);g.addColorStop(0,'rgba(0,0,0,1)');g.addColorStop(.72,'rgba(0,0,0,.85)');g.addColorStop(1,'rgba(0,0,0,0)');X.fillStyle=g;X.beginPath();X.arc(p.x,p.y,r,0,7);X.fill()});buildings.filter(b=>b.side==='player').forEach(b=>{let p=project(b.x,b.y),r=210*world.cam.z,g=X.createRadialGradient(p.x,p.y,r*.35,p.x,p.y,r);g.addColorStop(0,'rgba(0,0,0,1)');g.addColorStop(.8,'rgba(0,0,0,.8)');g.addColorStop(1,'rgba(0,0,0,0)');X.fillStyle=g;X.beginPath();X.arc(p.x,p.y,r,0,7);X.fill()});X.restore()}
function drawB(b){let p=project(b.x,b.y,0),t=btypes[b.type],enemy=b.side==='ai';X.save();X.translate(p.x,p.y);let col=enemy?'#9d2f55':'#2186a0';X.globalAlpha=b.construct?.55:1;X.shadowBlur=16;X.shadowColor=col;X.fillStyle=col;X.strokeStyle=enemy?'#ff5874':'#54e6ff';X.lineWidth=2;X.beginPath();X.moveTo(-t.size,8);X.lineTo(-t.size*.7,-t.size*.8);X.lineTo(0,-t.size*1.15);X.lineTo(t.size*.7,-t.size*.8);X.lineTo(t.size,8);X.lineTo(0,t.size*.65);X.closePath();X.fill();X.stroke();X.shadowBlur=0;if(b.type==='hq'){X.fillStyle='#d5fbff';X.fillRect(-3,-30,6,26)}if(b.type==='turret'){X.fillStyle='#ffcf62';X.fillRect(-4,-26,8,26)}X.restore();hpbar(p.x,p.y-t.size*1.3,b.hp/b.max,t.size*2,enemy);if(b.construct){X.fillStyle='#ffc857';X.fillRect(p.x-t.size,p.y+t.size,p.x? t.size*2*(b.progress/10):0,3)}}
function drawU(u){let p=project(u.x,u.y,u.type==='drone'?30:0),t=types[u.type],enemy=u.side==='ai';X.save();X.translate(p.x,p.y);if(selected.includes(u)){X.strokeStyle='#dffbff';X.beginPath();X.ellipse(0,8,15,6,0,0,7);X.stroke()}X.fillStyle=enemy?'#e83f62':u.type==='worker'?'#8df6c0':u.type==='tank'?'#d7983d':u.type==='drone'?'#b77bff':'#52d8ed';X.strokeStyle=enemy?'#ff9aa9':'#b9ffff';X.lineWidth=1.5;if(u.type==='drone'){X.beginPath();X.ellipse(0,0,15,6,0,0,7);X.fill();X.stroke();X.fillRect(-2,-12,4,24)}else if(u.type==='tank'){X.fillRect(-13,-8,26,16);X.fillStyle='#f4c45a';X.fillRect(-4,-15,8,13)}else{X.beginPath();X.moveTo(0,-12);X.lineTo(10,9);X.lineTo(-10,9);X.closePath();X.fill();X.stroke()}X.restore();hpbar(p.x,p.y-17,t.hp/t.max,25,enemy);if(u.carry){X.fillStyle='#ffc857';X.beginPath();X.arc(p.x+10,p.y-10,3,0,7);X.fill()}}
function hpbar(x,y,v,w,enemy){X.fillStyle='#12232b';X.fillRect(x-w/2,y,w,3);X.fillStyle=enemy?'#ff526e':'#63efac';X.fillRect(x-w/2,y,w*clamp(v,0,1),3)}
function drawMini(){mx.clearRect(0,0,260,150);mx.fillStyle='#0b282e';mx.fillRect(0,0,260,150);let sx=260/world.w,sy=150/world.h;deposits.forEach(d=>{if(inSight(d)){mx.fillStyle='#d7ad48';mx.fillRect(d.x*sx-2,d.y*sy-2,4,4)}});buildings.forEach(b=>{if(b.side==='player'||visible(b)){mx.fillStyle=b.side==='player'?'#54e6ff':'#ff5874';mx.fillRect(b.x*sx-3,b.y*sy-3,6,6)}});units.forEach(u=>{if(u.side==='player'||visible(u)){mx.fillStyle=u.side==='player'?'#96f7da':'#ff7887';mx.fillRect(u.x*sx,u.y*sy,2,2)}});mx.strokeStyle='#ffffff88';let c=world.cam;mx.strokeRect((c.x-W/(2*c.z))*sx,(c.y-H/(2*c.z))*sy,(W/c.z)*sx,(H/c.z)*sy)}
function update(dt){if(paused)return;elapsed+=dt;let ps=units.filter(u=>u.side==='player'&&u.type!=='worker').length;for(let u of units){u.flash=Math.max(0,u.flash-dt);if(u.order==='move'||u.order==='attackmove'||u.order==='gather'||u.order==='return')moveUnit(u,dt);if(u.order==='gather')harvest(u,dt);if(u.target&&dist(u,u.target)<types[u.type].range+10)fight(u,dt);else if(!u.target)acquire(u);}
for(let b of buildings){if(b.construct){b.progress+=dt;if(b.progress>=10)b.construct=false}if(b.queue.length&&!b.construct){let q=b.queue[0];if(q.type==='research'){q.t-=dt;if(q.t<=0){b.queue.shift();say('RESEARCH COMPLETE: weapon matrices improved')}}else if(b.progress+=dt,b.progress>=types[q.type].build){let p=addU(b.side,q.type,b.rally.x,b.rally.y);b.queue.shift();b.progress=0;if(b.side==='player')say(types[q.type].name+' deployed')} }}
for(let s of shots){s.t+=dt;s.x+=(s.tx-s.x)*dt*8;s.y+=(s.ty-s.y)*dt*8;if(s.t>.22){let target=s.target;if(target&&target.hp>0){let mod=target.type==='tank'&&s.kind==='ranged'?.8:1;target.hp-=s.dmg*mod;target.flash=.1}shots.splice(shots.indexOf(s),1)}}for(let p of particles){p.t-=dt;p.y-=dt*12}particles.splice(0,particles.length,...particles.filter(p=>p.t>0));aiThink(dt);cleanup();hud();draw()}
function moveUnit(u,dt){let dx=u.tx-u.x,dy=u.ty-u.y,d=Math.hypot(dx,dy);if(d<6){if(u.order==='move'||u.order==='attackmove')u.order='idle';return}let sp=types[u.type].spd;u.x+=dx/d*sp*dt;u.y+=dy/d*sp*dt;if(u.target&&dist(u,u.target)>types[u.type].range+20)u.target=null}
function harvest(u,dt){let h=buildings.find(b=>b.side===u.side&&(b.type==='hq'||b.type==='relay')&&!b.construct&&dist(b,u)<30);if(h&&u.carry>0){if(u.side==='player')ore+=u.carry;else aiOre+=u.carry;u.carry=0;if(u.deposit){u.tx=u.deposit.x;u.ty=u.deposit.y;u.order='gather'}}if(!u.deposit||u.deposit.amount<=0){let d=deposits.filter(x=>x.amount>0).sort((a,b)=>dist(a,u)-dist(b,u))[0];if(d){u.deposit=d;u.tx=d.x;u.ty=d.y;u.order='gather'}}if(u.deposit&&u.order==='gather'&&dist(u,u.deposit)<30){if(u.carry<20){u.deposit.amount=Math.max(0,u.deposit.amount-dt*3);u.carry+=dt*3}else{let drop=buildings.find(b=>b.side===u.side&&(b.type==='hq'||b.type==='relay')&&!b.construct);if(drop){u.tx=drop.x;u.ty=drop.y;u.order='return'}}}}
function acquire(u){if(u.hold)return;let foes=units.filter(v=>v.side!==u.side&&visible(v,u.side)&&((types[u.type].ground)||v.type==='drone')).sort((a,b)=>dist(u,a)-dist(u,b));if(foes[0]&&dist(u,foes[0])<types[u.type].range+100){u.target=foes[0];u.order='attackmove'}}
function fight(u,dt){let t=u.target;if(!t||t.hp<=0){u.target=null;return}let d=types[u.type].damage;if(Math.random()<dt*2){shots.push({x:u.x,y:u.y,tx:t.x,ty:t.y,z:u.type==='drone'?25:0,t:0,target:t,dmg:d,kind:u.type==='tank'?'ranged':'normal',side:u.side})}}
function cleanup(){for(let i=units.length-1;i>=0;i--)if(units[i].hp<=0){if(selected.includes(units[i]))selected.splice(selected.indexOf(units[i]),1);units.splice(i,1);say('UNIT LOST')}for(let i=buildings.length-1;i>=0;i--)if(buildings[i].hp<=0){let b=buildings[i];buildings.splice(i,1);say(b.side==='player'?'STRUCTURE DESTROYED':'ENEMY STRUCTURE DESTROYED')}let ph=buildings.some(b=>b.side==='player'&&b.type==='hq'),ah=buildings.some(b=>b.side==='ai'&&b.type==='hq');if(!ph||!ah)finish(ph)}
function aiThink(dt){if(Math.floor(elapsed)%8===0&&Math.random()<dt){let h=buildings.find(b=>b.side==='ai'&&b.type==='hq');if(h){let f=buildings.find(b=>b.side==='ai'&&b.type==='foundry');if(!f&&elapsed>15)addB('ai','foundry',h.x-70,h.y);else if(f&&f.queue.length<3&&Math.random()<.8){let it=['blade','rifle','tank'][Math.floor(Math.random()*3)],cost=types[it].cost;if(aiOre>=cost){aiOre-=cost;f.queue.push({type:it,t:0})}}let ws=units.filter(u=>u.side==='ai'&&u.type==='worker');ws.forEach((u,i)=>{if(!u.deposit||u.deposit.amount<=0){let d=deposits.filter(d=>d.amount>0).sort((a,b)=>dist(a,u)-dist(b,u))[0];if(d){u.deposit=d;u.tx=d.x;u.ty=d.y;u.order='gather'}}});if(elapsed>90){let army=units.filter(u=>u.side==='ai'&&u.type!=='worker');let ph=buildings.find(b=>b.side==='player'&&visible(b,'ai'));if(ph)army.forEach(u=>{u.tx=ph.x+Math.random()*80-40;u.ty=ph.y+Math.random()*80-40;u.order='attackmove'})}}}}
function finish(win){game=false;document.getElementById('end').classList.remove('hidden');document.getElementById('endtitle').textContent=win?'MISSION COMPLETE':'EXPEDITION LOST';document.getElementById('endsub').textContent=win?'THE FRONTIER IS OURS':'THE VANTA SYNDICATE PREVAILS';document.getElementById('endcopy').textContent=win?'All hostile command spires have been neutralized. Helix-9 is secured.':'Your command network has collapsed. The frontier waits for another expedition.'}
function hud(){supplyMax=24+buildings.filter(b=>b.side==='player'&&b.type==='relay'&&!b.construct).length*12;document.getElementById('ore').textContent=Math.floor(ore);let used=units.filter(u=>u.side==='player').reduce((a,u)=>a+types[u.type].supply,0);document.getElementById('supply').textContent=used+' / '+supplyMax;document.getElementById('supbar').style.width=Math.min(100,used/supplyMax*100)+'%';let m=Math.floor(elapsed/60),s=Math.floor(elapsed%60);document.getElementById('clock').textContent=String(m).padStart(2,'0')+':'+String(s).padStart(2,'0');let el=document.getElementById('sel');let ac=document.getElementById('actions');if(selected.length){el.innerHTML='<div class="selname">'+(selected.length>1?selected.length+' units':selected[0].type==='worker'?'Prospector':types[selected[0].type]?.name||btypes[selected[0].type].name)+'</div><span class="tag">'+(selected[0].side==='player'?'ASTERION COMMAND':'')+'</span>';ac.innerHTML='<button onclick="cmdStop()">STOP [S]</button><button onclick="cmdHold()">HOLD [H]</button><button onclick="cmdAttack()">ATTACK-MOVE [A]</button>'}else{el.innerHTML='<span class="tag">Select a unit or structure</span>';ac.innerHTML=''}let q=document.getElementById('queue');q.innerHTML='';if(selected.length===1&&selected[0].queue)selected[0].queue.forEach(x=>{let d=document.createElement('div');d.className='q';d.textContent=x.type==='research'?'R':x.type[0].toUpperCase();q.appendChild(d)});let b=document.getElementById('build');b.innerHTML='';if(selected.length===1&&selected[0].side==='player'){let o=selected[0];if(o.type==='worker')['relay','foundry','hangar','turret','hq'].forEach(t=>{let d=document.createElement('button');d.className='buildbtn';d.textContent='+'+btypes[t].name+' '+btypes[t].cost;d.onclick=()=>{buildMode=t;say('Placement mode: click a clear location');};b.appendChild(d)});if(btypes[o.type]?.prod)btypes[o.type].prod.forEach(t=>{let d=document.createElement('button');d.className='buildbtn';d.textContent='TRAIN '+types[t].name+' · '+types[t].cost;d.onclick=()=>train(o,t);b.appendChild(d)})}}
function train(b,t){let cost=types[t].cost;if(ore<cost){say('INSUFFICIENT ORE');return}let used=units.filter(u=>u.side==='player').reduce((a,u)=>a+types[u.type].supply,0),reserved=btypesFoundSupply();if(used+reserved+types[t].supply>supplyMax){say('SUPPLY SHORTAGE — build a Relay');return}ore-=cost;b.queue.push({type:t,t:0});say('Queue confirmed: '+types[t].name)}function btypesFoundSupply(){return buildings.reduce((a,b)=>a+b.queue.filter(q=>q.type!=='research'&&b.side==='player').reduce((x,q)=>x+types[q.type].supply,0),0)}
function cmdStop(){selected.forEach(u=>{if(u.type)u.order='idle';u.target=null})}function cmdHold(){selected.forEach(u=>u.hold=!u.hold)}function cmdAttack(){selected.forEach(u=>u.order='attackmove');say('Attack-move: select destination')}
function click(e){let p=unproject(e.clientX,e.clientY);if(buildMode){let t=btypes[buildMode],ok=ore>=t.cost&&!buildings.some(b=>dist(b,p)<t.size+30);if(ok){ore-=t.cost;addB('player',buildMode,p.x,p.y);buildMode=null;say('Construction started')}else say('INVALID PLACEMENT / INSUFFICIENT ORE');return}let hit=[...units,...buildings].filter(o=>(o.side==='player'||visible(o))&&dist(o,p)<(o.queue!==undefined?btypes[o.type].size:18)).sort((a,b)=>dist(a,p)-dist(b,p))[0];if(hit){if(!e.shiftKey)selected=[];if(!selected.includes(hit))selected.push(hit);if(hit.type==='hq'||hit.type==='foundry'||hit.type==='hangar'||hit.type==='relay')selected=[hit]}else if(!e.shiftKey)selected=[];}
C.onmousedown=e=>{if(!game||e.clientX>W-285)return;if(e.button===0)drag={x:e.clientX,y:e.clientY,ex:e.clientX,ey:e.clientY};};C.onmousemove=e=>{if(drag){drag.ex=e.clientX;drag.ey=e.clientY}};C.onmouseup=e=>{if(!drag)return;if(Math.abs(drag.ex-drag.x)>8){let a=unproject(drag.x,drag.y),b=unproject(drag.ex,drag.ey);if(!e.shiftKey)selected=[];units.filter(u=>u.side==='player'&&u.x>Math.min(a.x,b.x)&&u.x<Math.max(a.x,b.x)&&u.y>Math.min(a.y,b.y)&&u.y<Math.max(a.y,b.y)).forEach(u=>{if(!selected.includes(u))selected.push(u)})}else if(e.button===0)click(e);else if(e.button===2){let p=unproject(e.clientX,e.clientY);selected.filter(u=>u.type).forEach((u,i)=>{u.tx=p.x+(i%5)*22-44;u.ty=p.y+Math.floor(i/5)*22;u.order='move';u.target=null;let d=deposits.find(d=>dist(d,p)<35);if(u.type==='worker'&&d){u.deposit=d;u.order='gather'}})}drag=null};C.oncontextmenu=e=>e.preventDefault();
window.onkeydown=e=>{if(!game)return;if(e.key===' ')togglePause();if(e.key==='h'||e.key==='H')cmdHold();if(e.key==='s'||e.key==='S')cmdStop();if(e.key==='a'||e.key==='A')cmdAttack();if(e.key==='Escape'){buildMode=null}if(e.key==='w'||e.key==='W')world.cam.y-=100;if(e.key==='ArrowDown')world.cam.y+=100;if(e.key==='ArrowLeft')world.cam.x-=100;if(e.key==='d'||e.key==='D')world.cam.x+=100;if(e.key==='q'||e.key==='Q')world.cam.rot-=.15;if(e.key==='e'||e.key==='E')world.cam.rot+=.15;if(e.key>='1'&&e.key<='4'){let n=+e.key;if(e.ctrlKey)group[n]=[...selected];else selected=group[n]||[]}};C.onwheel=e=>{world.cam.z=clamp(world.cam.z-e.deltaY*.0008,.45,1.8)};M.onclick=e=>{let r=M.getBoundingClientRect();world.cam.x=(e.clientX-r.left)/r.width*world.w;world.cam.y=(e.clientY-r.top)/r.height*world.h};
function togglePause(){paused=!paused;document.getElementById('pause').textContent=paused?'▶ RESUME':'Ⅱ PAUSE'}document.getElementById('pause').onclick=togglePause;document.getElementById('start').onclick=()=>{document.getElementById('intro').classList.add('hidden');document.getElementById('hud').classList.remove('hidden');game=true;init();say('DIRECTIVE: establish your economy');};document.getElementById('restart').onclick=()=>location.reload();function resize(){W=C.width=innerWidth;H=C.height=innerHeight;M.width=260;M.height=150}addEventListener('resize',resize);resize();function loop(t){let dt=Math.min(.05,(t-last)/1000||0);last=t;if(game)update(dt);else draw();requestAnimationFrame(loop)}requestAnimationFrame(loop);
</script></body></html>
<!-- agent-meta {"model":"openai/gpt-5.6-luna","provider":"openrouter","persona":"full","sessionId":"760da924-bceb-4275-a184-929d908c6cbd","tokensIn":236424,"tokensOut":12415,"tokensTotal":248839,"cost":0.02509163,"turns":13,"toolCalls":18,"failedToolCalls":0,"timestamp":"2026-09-30T21:34:11.571Z"} -->