Code for Above

<div style="max-width:1500px;margin:0 auto;">
  <iframe
    title="FLAK POC — Shell Travel → Burst"
    scrolling="no"
    style="display:block;margin:0 auto;border:0;width:1500px;height:1500px;overflow:hidden;border-radius:14px;background:#000;"
    sandbox="allow-scripts allow-same-origin"
    srcdoc='<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>FLAK POC — Shell Travel → Burst</title>
<style>
  :root{color-scheme:dark;}
  html,body{margin:0;height:100%;background:#05070b;overflow:hidden;font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;}
  canvas{display:block;}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
(() => {
  const c = document.getElementById("c");
  const ctx = c.getContext("2d");
  const W = c.width = 1500;
  const H = c.height = 1500;

  const TAU = Math.PI*2;
  const clamp=(v,a,b)=>Math.max(a,Math.min(b,v));
  const rand=(a,b)=>a+Math.random()*(b-a);

  // ===== Player =====
  const ship = { x: W/2, y: H*0.72, a: -Math.PI/2 };

  // ===== FLAK params =====
  const rofs = [{name:"SLOW",sec:0.22},{name:"FAST",sec:0.12}];
  let rofIdx = 0;

  let fuseDist = 520;       // where shell should detonate (Z/C)
  let shellSpeed = 820;     // px/sec (G/H)
  let pelletN = 22;         // fragments per burst (X/V)
  let blastR  = 120;        // blast radius (B/N)
  let fragSpeed = 760;      // fragment velocity
  let fragLife  = 0.55;     // seconds
  let proxOn = false;       // proximity fuse (P)
  let proxR = 90;           // prox radius

  // ===== State =====
  const keys = Object.create(null);
  let triggerHeld = false;
  let cd = 0;

  const targets = [];
  const particles = []; // frags + visuals
  const shells = [];    // traveling shells

  let score=0, hits=0, kills=0;

  function spawnTarget() {
    const dist = rand(220, 820);
    const ang = ship.a + rand(-0.9, 0.9);
    const x = clamp(ship.x + Math.cos(ang)*dist, 80, W-80);
    const y = clamp(ship.y + Math.sin(ang)*dist, 120, H-80);
    targets.push({
      x,y, r: rand(12, 20),
      vx: rand(-42,42), vy: rand(-42,42),
      hp: 3
    });
  }
  function ensureTargets(){
    while(targets.length < 12) spawnTarget();
  }
  ensureTargets();

  // ===== Input =====
  addEventListener("keydown",(e)=>{
    const k=e.key.toLowerCase();
    keys[k]=true;

    if(e.key===" "){ e.preventDefault(); triggerHeld=true; }
    if(k==="r") reset();

    // fuse distance
    if(k==="z") fuseDist = Math.max(220, fuseDist-40);
    if(k==="c") fuseDist = Math.min(900, fuseDist+40);

    // pellet count
    if(k==="x") pelletN = Math.max(8, pelletN-2);
    if(k==="v") pelletN = Math.min(60, pelletN+2);

    // blast radius
    if(k==="b") blastR = Math.max(60, blastR-10);
    if(k==="n") blastR = Math.min(240, blastR+10);

    // fire rate
    if(k==="1") rofIdx = 0;
    if(k==="2") rofIdx = 1;

    // shell speed
    if(k==="g") shellSpeed = Math.max(420, shellSpeed-60);
    if(k==="h") shellSpeed = Math.min(1400, shellSpeed+60);

    // proximity fuse
    if(k==="p") proxOn = !proxOn;
  });
  addEventListener("keyup",(e)=>{
    const k=e.key.toLowerCase();
    keys[k]=false;
    if(e.key===" ") triggerHeld=false;
  });

  function reset(){
    targets.length=0;
    particles.length=0;
    shells.length=0;
    score=0; hits=0; kills=0;
    ensureTargets();
  }

  // ===== Effects =====
  function addExplosion(x,y){
    particles.push({type:"boom", x,y, t:0, dur:0.45});
    particles.push({type:"ring", x,y, t:0, dur:0.28, r0:10, r1:blastR});
    for(let j=0;j<18;j++){
      const a=rand(0,TAU), sp=rand(220,760);
      particles.push({type:"spark", x,y, vx:Math.cos(a)*sp, vy:Math.sin(a)*sp, t:0, dur:rand(0.18,0.35), s:rand(1.2,2.2)});
    }
  }

  function detonateShell(sx,sy, forwardAngle){
    // Burst visuals
    particles.push({type:"bloom", x:sx, y:sy, t:0, dur:0.18, r0:8, r1:60});
    particles.push({type:"ring", x:sx, y:sy, t:0, dur:0.25, r0:10, r1:blastR});

    // Immediate area damage
    let blastHits = 0;
    for(const t of targets){
      const d = Math.hypot(t.x-sx, t.y-sy);
      if(d <= blastR){
        const dmg = (d < blastR*0.5) ? 2 : 1;
        t.hp -= dmg;
        blastHits++;
      }
    }
    if(blastHits>0){ hits += blastHits; score += blastHits*2; }

    // Fragments (slightly forward-biased cone so it reads better)
    for(let i=0;i<pelletN;i++){
      const a = forwardAngle + rand(-1.05, 1.05);
      const sp = rand(fragSpeed*0.55, fragSpeed);
      particles.push({
        type:"frag",
        x:sx, y:sy,
        vx: Math.cos(a)*sp,
        vy: Math.sin(a)*sp,
        t:0, dur: rand(fragLife*0.7, fragLife),
        s: rand(1.6, 3.2)
      });
    }
  }

  // ===== Fire =====
  function fireShell(){
    cd = rofs[rofIdx].sec;

    const ax = Math.cos(ship.a);
    const ay = Math.sin(ship.a);

    const tx = ship.x + ax*fuseDist;
    const ty = ship.y + ay*fuseDist;

    const dist = Math.hypot(tx-ship.x, ty-ship.y);
    const ttl = dist / shellSpeed;

    shells.push({
      x: ship.x + ax*26,
      y: ship.y + ay*26,
      vx: ax*shellSpeed,
      vy: ay*shellSpeed,
      t: 0,
      ttl,
      tx, ty,
      a: ship.a
    });
  }

  // ===== Update =====
  function updateTargets(dt){
    for(const t of targets){
      t.x += t.vx*dt;
      t.y += t.vy*dt;
      if(t.x < 80 || t.x > W-80) t.vx *= -1;
      if(t.y < 120 || t.y > H-80) t.vy *= -1;
      t.x = clamp(t.x, 80, W-80);
      t.y = clamp(t.y, 120, H-80);
    }
    // remove dead
    for(let i=targets.length-1;i>=0;i--){
      if(targets[i].hp<=0){
        const tx=targets[i].x, ty=targets[i].y;
        addExplosion(tx,ty);
        targets.splice(i,1);
        kills++; score+=10;
      }
    }
  }

  function updateShells(dt){
    for(let i=shells.length-1;i>=0;i--){
      const s = shells[i];
      s.t += dt;
      s.x += s.vx*dt;
      s.y += s.vy*dt;

      // proximity fuse
      if(proxOn){
        for(const t of targets){
          const d = Math.hypot(t.x-s.x, t.y-s.y);
          if(d <= proxR){
            detonateShell(s.x,s.y,s.a);
            shells.splice(i,1);
            return;
          }
        }
      }

      // reached time-to-live or close to target point
      const dTo = Math.hypot(s.tx - s.x, s.ty - s.y);
      if(s.t >= s.ttl || dTo < 18){
        detonateShell(s.tx, s.ty, s.a);
        shells.splice(i,1);
      }
    }
  }

  function updateParticles(dt){
    for(let i=particles.length-1;i>=0;i--){
      const p=particles[i];
      p.t += dt;
      if(p.t >= p.dur){ particles.splice(i,1); continue; }

      if(p.type==="frag" || p.type==="spark"){
        p.x += p.vx*dt;
        p.y += p.vy*dt;
        p.vx *= Math.pow(0.08, dt);
        p.vy *= Math.pow(0.08, dt);

        if(p.type==="frag"){
          for(const t of targets){
            const d = Math.hypot(t.x-p.x, t.y-p.y);
            if(d <= t.r){
              t.hp -= 1;
              p.type="spark";
              p.dur = 0.14;
              p.t = Math.min(p.t, p.dur*0.4);
              hits++; score+=1;
              break;
            }
          }
        }
      }
    }
  }

  // ===== Render =====
  function roundRect(x,y,w,h,r){
    const rr=Math.min(r,w/2,h/2);
    ctx.beginPath();
    ctx.moveTo(x+rr,y);
    ctx.arcTo(x+w,y,x+w,y+h,rr);
    ctx.arcTo(x+w,y+h,x,y+h,rr);
    ctx.arcTo(x,y+h,x,y,rr);
    ctx.arcTo(x,y,x+w,y,rr);
    ctx.closePath();
  }

  function drawBackground(){
    ctx.fillStyle="#05070b";
    ctx.fillRect(0,0,W,H);
    ctx.globalAlpha=0.18;
    ctx.fillStyle="rgba(220,235,255,.9)";
    for(let i=0;i<240;i++){
      ctx.fillRect((i*173)%W,(i*97)%H,1,1);
    }
    ctx.globalAlpha=1;
  }

  function drawTargets(){
    for(const t of targets){
      ctx.globalAlpha=0.22;
      ctx.strokeStyle="rgba(240,245,255,.90)";
      ctx.lineWidth=2;
      ctx.beginPath(); ctx.arc(t.x,t.y,t.r+10,0,TAU); ctx.stroke();

      ctx.globalAlpha=0.95;
      ctx.fillStyle="rgba(255,200,120,.95)";
      ctx.beginPath(); ctx.arc(t.x,t.y,t.r,0,TAU); ctx.fill();

      ctx.globalAlpha=0.85;
      ctx.fillStyle="rgba(255,240,240,.9)";
      for(let i=0;i<t.hp;i++){
        ctx.beginPath();
        ctx.arc(t.x - (t.hp-1)*5 + i*10, t.y + t.r + 18, 2.2, 0, TAU);
        ctx.fill();
      }
      ctx.globalAlpha=1;
    }
  }

  function drawShells(){
    for(const s of shells){
      // trajectory line (faint) to detonation point
      ctx.globalAlpha=0.18;
      ctx.strokeStyle="rgba(120,255,210,.85)";
      ctx.lineWidth=2;
      ctx.beginPath();
      ctx.moveTo(s.x,s.y);
      ctx.lineTo(s.tx,s.ty);
      ctx.stroke();

      // shell glow
      ctx.globalAlpha=0.70;
      ctx.fillStyle="rgba(255,220,160,1)";
      ctx.beginPath(); ctx.arc(s.x,s.y,3.2,0,TAU); ctx.fill();

      ctx.globalAlpha=0.25;
      ctx.fillStyle="rgba(255,220,160,1)";
      ctx.beginPath(); ctx.arc(s.x,s.y,10,0,TAU); ctx.fill();
      ctx.globalAlpha=1;
    }
  }

  function drawParticles(){
    for(const p of particles){
      const u = p.t / p.dur;
      const a = 1-u;

      if(p.type==="frag"){
        ctx.globalAlpha=0.65*a;
        ctx.fillStyle="rgba(255,200,140,1)";
        ctx.beginPath(); ctx.arc(p.x,p.y,p.s*(0.7+a),0,TAU); ctx.fill();
      } else if(p.type==="spark"){
        ctx.globalAlpha=0.85*a;
        ctx.fillStyle="rgba(255,120,140,1)";
        ctx.beginPath(); ctx.arc(p.x,p.y,p.s*(0.6+a),0,TAU); ctx.fill();
      } else if(p.type==="ring"){
        const rr = p.r0 + (p.r1-p.r0)*(u*u);
        ctx.globalAlpha=0.40*a;
        ctx.strokeStyle="rgba(240,245,255,1)";
        ctx.lineWidth=2.0*a;
        ctx.beginPath(); ctx.arc(p.x,p.y,rr,0,TAU); ctx.stroke();
      } else if(p.type==="bloom"){
        const rr = p.r0 + (p.r1-p.r0)*(u*u);
        ctx.globalAlpha=0.22*a;
        ctx.fillStyle="rgba(255,220,160,1)";
        ctx.beginPath(); ctx.arc(p.x,p.y,rr,0,TAU); ctx.fill();
      } else if(p.type==="boom"){
        const rr = 18 + u*u*120;
        ctx.globalAlpha=0.24*a;
        ctx.fillStyle="rgba(255,160,120,1)";
        ctx.beginPath(); ctx.arc(p.x,p.y,rr,0,TAU); ctx.fill();
        ctx.globalAlpha=0.14*a;
        ctx.fillStyle="rgba(255,220,160,1)";
        ctx.beginPath(); ctx.arc(p.x,p.y,rr*0.55,0,TAU); ctx.fill();
      }
    }
    ctx.globalAlpha=1;
  }

  function drawShip(){
    ctx.globalAlpha=0.20;
    ctx.fillStyle="rgba(0,255,200,.50)";
    ctx.beginPath(); ctx.arc(ship.x,ship.y,42,0,TAU); ctx.fill();

    ctx.save();
    ctx.translate(ship.x,ship.y);
    ctx.rotate(ship.a);

    ctx.globalAlpha=1;
    ctx.strokeStyle="rgba(240,245,255,.95)";
    ctx.lineWidth=2;
    ctx.beginPath();
    ctx.moveTo(22,0);
    ctx.lineTo(-14,12);
    ctx.lineTo(-10,0);
    ctx.lineTo(-14,-12);
    ctx.closePath();
    ctx.stroke();

    // aim line to fuse point
    ctx.globalAlpha=0.22;
    ctx.beginPath();
    ctx.moveTo(22,0);
    ctx.lineTo(fuseDist,0);
    ctx.stroke();

    ctx.restore();
    ctx.globalAlpha=1;

    // fuse point marker
    const ax=Math.cos(ship.a), ay=Math.sin(ship.a);
    const bx=ship.x + ax*fuseDist;
    const by=ship.y + ay*fuseDist;
    ctx.globalAlpha=0.55;
    ctx.strokeStyle="rgba(120,255,210,.85)";
    ctx.lineWidth=2;
    ctx.beginPath(); ctx.arc(bx,by,10,0,TAU); ctx.stroke();
    ctx.globalAlpha=1;
  }

  function drawHUD(){
    ctx.globalAlpha=0.85;
    ctx.fillStyle="rgba(8,10,16,.65)";
    ctx.strokeStyle="rgba(255,255,255,.10)";
    ctx.lineWidth=1;
    roundRect(18,18,720,120,14);
    ctx.fill(); ctx.stroke();

    ctx.globalAlpha=0.95;
    ctx.fillStyle="rgba(240,245,255,.92)";
    ctx.font="800 14px system-ui";
    ctx.fillText("FLAK POC — Shell travels to fuse point then bursts. Space fires (hold). A/D rotates. R reset.", 32, 42);

    ctx.font="700 12px system-ui";
    ctx.globalAlpha=0.85;
    ctx.fillText(`Score ${score} • Hits ${hits} • Kills ${kills} • Targets ${targets.length} • Shells ${shells.length}`, 32, 64);

    ctx.fillText(`FuseDist ${fuseDist} (Z/C) • ShellSpeed ${shellSpeed} (G/H) • Pellets ${pelletN} (X/V) • Radius ${blastR} (B/N) • ROF ${rofs[rofIdx].name} (1/2)`, 32, 86);

    ctx.fillText(`Proximity Fuse ${proxOn?"ON":"OFF"} (P) • ProxRadius ${proxR}`, 32, 108);

    ctx.globalAlpha=1;
  }

  // ===== Loop =====
  let last = performance.now();
  function tick(now){
    const dt = Math.min(0.033,(now-last)/1000);
    last = now;

    // rotate
    const turn=2.4;
    if(keys["a"]||keys["arrowleft"]) ship.a -= turn*dt;
    if(keys["d"]||keys["arrowright"]) ship.a += turn*dt;

    if(cd>0) cd -= dt;

    if(triggerHeld && cd<=0){
      fireShell();
    }

    updateTargets(dt);
    updateShells(dt);
    updateParticles(dt);
    ensureTargets();

    drawBackground();
    drawTargets();
    drawShells();
    drawParticles();
    drawShip();
    drawHUD();

    requestAnimationFrame(tick);
  }
  requestAnimationFrame(tick);
})();
</script>
</body>
</html>'
  ></iframe>
</div>