window.sketch = (runtime) => {
  const { c2, canvas, startFrame } = runtime;
  const renderer = new c2.Renderer(canvas);

  // reusable simple noise helper
  const hash = (x, y, t) => {
    const n = Math.sin(x * 127.1 + y * 311.7 + t * 0.7) * 43758.5453;
    return n - Math.floor(n);
  };

  // city building data
  const buildings = [];
  const numBuildings = 40;
  for (let i = 0; i < numBuildings; i++) {
    const w = 30 + Math.random() * 70;
    const h = 60 + Math.random() * 180;
    buildings.push({
      x: Math.random() * canvas.width,
      width: w,
      height: h,
      color: `hsl(${20 + Math.random() * 15}, 10%, ${15 + Math.random() * 15}%)`,
    });
  }

  // falling debris particles
  const debris = [];
  for (let i = 0; i < 180; i++) {
    debris.push({
      x: Math.random() * canvas.width,
      y: Math.random() * canvas.height * 0.6,
      vx: (Math.random() - 0.5) * 1.5,
      vy: 0.5 + Math.random() * 2.5,
      size: 2 + Math.random() * 6,
      life: 0.5 + Math.random() * 1.0,
      alive: true,
    });
  }

  // ember / spark particles for brimstone
  const embers = [];
  for (let i = 0; i < 120; i++) {
    embers.push({
      x: Math.random() * canvas.width,
      y: Math.random() * canvas.height,
      vx: (Math.random() - 0.5) * 1.0,
      vy: -0.5 - Math.random() * 2.0,
      size: 1.5 + Math.random() * 4,
      hue: 20 + Math.random() * 30,
      life: 1.0,
      alive: true,
    });
  }

  // flame flicker offsets
  const flameOffsets = [];
  for (let i = 0; i < 60; i++) {
    flameOffsets.push({
      x: (Math.random() - 0.5) * 16,
      y: Math.random() * 40 + 10,
      phase: Math.random() * 6.28,
    });
  }

  startFrame((frameCount) => {
    const w = canvas.width;
    const h = canvas.height;
    const t = frameCount * 0.02;

    // background: dark hellish sky
    renderer.clear('#0f0505');

    // --- distant glow (fire reflection) ---
    for (let i = 0; i < 50; i++) {
      const gx = (i / 50) * w;
      const gy = h * 0.3 + Math.sin(t + i * 0.2) * 20;
      const radius = 30 + Math.sin(t * 0.5 + i) * 15 + 20;
      renderer.fill(`rgba(200, 60, 0, ${0.02 + Math.sin(t + i) * 0.01})`);
      renderer.circle(gx, gy, radius);
    }

    // --- city buildings (silhouettes with burning windows) ---
    buildings.forEach((b, idx) => {
      const bx = b.x;
      const by = h - b.height - 20;
      const bw = b.width;
      const bh = b.height;

      // building body
      renderer.fill(b.color);
      renderer.stroke(false);
      renderer.rect(bx, by, bw, bh);

      // burning windows
      for (let row = 0; row < Math.floor(bh / 22); row++) {
        for (let col = 0; col < Math.floor(bw / 18); col++) {
          const wx = bx + 6 + col * 18;
          const wy = by + 8 + row * 22;
          const windowHash = hash(col * 7 + idx, row * 13, t * 0.5);
          if (windowHash > 0.4) {
            const flicker = Math.sin(t * 3 + col * 1.7 + row * 2.3 + idx) * 0.3 + 0.7;
            const intensity = Math.floor(140 + 115 * flicker);
            renderer.fill(`rgb(${intensity}, ${Math.floor(intensity * 0.5)}, 0)`);
            renderer.rect(wx, wy, 10, 14);
          }
        }
      }

      // roof flames
      const flameCount = 4 + Math.floor(Math.random() * 3);
      for (let f = 0; f < flameCount; f++) {
        const fx = bx + 4 + (f / flameCount) * (bw - 8);
        const fy = by - 6 - Math.sin(t * 4 + f * 1.2) * 8;
        const flameSize = 12 + Math.sin(t * 3 + f * 0.9) * 5;
        renderer.fill(`rgba(255, ${80 + Math.sin(t * 5 + f) * 30}, 0, 0.7)`);
        renderer.circle(fx, fy, flameSize);
        renderer.fill(`rgba(255, 200, 50, 0.4)`);
        renderer.circle(fx - 2, fy - 3, flameSize * 0.5);
      }
    });

    // --- fire / brimstone clouds near ground ---
    for (let i = 0; i < 40; i++) {
      const cx = (i / 40) * w + Math.sin(t + i * 0.3) * 30;
      const cy = h - 40 - Math.sin(t * 0.7 + i * 0.5) * 18;
      const cr = 40 + Math.sin(t * 0.4 + i) * 20;
      renderer.fill(`rgba(180, 60, 0, ${0.06 + Math.sin(t + i) * 0.02})`);
      renderer.circle(cx, cy, cr);
      renderer.fill(`rgba(255, 100, 0, 0.03)`);
      renderer.circle(cx - 10, cy - 5, cr * 0.6);
    }

    // --- molten brimstone streaks (falling fire lines) ---
    renderer.lineWidth(2 + Math.sin(t * 0.5) * 1);
    for (let i = 0; i < 25; i++) {
      const sx = ((i * 37 + t * 20) % w);
      const sy = ((t * 60 + i * 50) % (h * 0.7));
      const streakLen = 20 + Math.sin(t * 2 + i) * 12;
      const alpha = 0.3 + Math.sin(t + i) * 0.2;
      renderer.stroke(`rgba(255, 140, 0, ${alpha})`);
      renderer.line(sx, sy, sx + Math.sin(t + i) * 8, sy + streakLen);
    }
    renderer.lineWidth(1);
    renderer.stroke(false);

    // --- debris / falling chunks ---
    debris.forEach((d) => {
      if (!d.alive) return;
      d.x += d.vx + Math.sin(t + d.x * 0.01) * 0.2;
      d.y += d.vy;
      d.vy += 0.04; // gravity
      d.life -= 0.002;

      if (d.y > h || d.life <= 0) {
        d.x = Math.random() * w;
        d.y = -10 - Math.random() * 60;
        d.vy = 0.5 + Math.random() * 2.0;
        d.vx = (Math.random() - 0.5) * 1.5;
        d.life = 0.5 + Math.random() * 1.0;
        d.alive = true;
      }

      const glow = Math.max(0, d.life);
      renderer.fill(`rgba(180, 60, 0, ${glow * 0.7})`);
      renderer.circle(d.x, d.y, d.size * glow);

      // trailing ember
      renderer.fill(`rgba(255, 100, 0, ${glow * 0.3})`);
      renderer.circle(d.x - d.vx * 1.5, d.y - d.vy * 1.5, d.size * 0.5 * glow);
    });

    // --- ember sparks ---
    embers.forEach((e) => {
      if (!e.alive) return;
      e.x += e.vx + Math.sin(t * 2 + e.x * 0.01) * 0.3;
      e.y += e.vy;
      e.vy -= 0.02;
      e.life -= 0.003;

      if (e.y < -20 || e.life <= 0) {
        e.x = Math.random() * w;
        e.y = h * 0.6 + Math.random() * h * 0.3;
        e.vy = -0.5 - Math.random() * 2.0;
        e.vx = (Math.random() - 0.5) * 1.0;
        e.life = 1.0;
        e.alive = true;
      }

      const glow = Math.max(0, e.life);
      const hue = e.hue + Math.sin(t + e.x * 0.01) * 10;
      renderer.fill(`hsla(${hue}, 100%, 60%, ${glow * 0.8})`);
      renderer.circle(e.x, e.y, e.size * glow);

      // secondary glow
      renderer.fill(`hsla(${hue - 10}, 100%, 80%, ${glow * 0.2})`);
      renderer.circle(e.x - 2, e.y - 2, e.size * 0.7 * glow);
    });

    // --- foreground flame patches (brimstone pools) ---
    for (let i = 0; i < 14; i++) {
      const fx = ((i * 73 + t * 5) % w);
      const fy = h - 8 - Math.sin(t * 2 + i * 0.5) * 6;
      const fr = 20 + Math.sin(t * 1.5 + i) * 12;
      renderer.fill(`rgba(200, 80, 0, ${0.1 + Math.sin(t * 2 + i) * 0.05})`);
      renderer.circle(fx, fy, fr);
      renderer.fill(`rgba(255, 180, 20, ${0.08 + Math.sin(t * 3 + i) * 0.04})`);
      renderer.circle(fx - 3, fy - 4, fr * 0.5);
    }

    // --- floating smoke / ash ---
    for (let i = 0; i < 60; i++) {
      const sx = ((i * 29 + t * 8) % w);
      const sy = (h * 0.1 + Math.sin(t + i * 0.3) * (h * 0.2) + (i * 7) % (h * 0.4));
      const sr = 12 + Math.sin(t * 0.7 + i) * 6;
      renderer.fill(`rgba(80, 60, 40, ${0.03 + Math.sin(t + i * 0.5) * 0.01})`);
      renderer.circle(sx, sy, sr);
    }
  });
};
