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

  // Easing helper
  const easeInOut = (t) => t * t * (3 - 2 * t);

  // Utility: random float
  const rand = (min, max) => Math.random() * (max - min) + min;

  // Gravity-defying river points (spiral upward)
  class River {
    constructor() {
      this.reset();
    }
    reset() {
      this.x = rand(canvas.width * 0.2, canvas.width * 0.8);
      this.y = canvas.height + rand(50, 150);
      this.speedY = rand(-1.2, -0.6);
      this.speedX = rand(-0.3, 0.3);
      this.spiralRadius = rand(10, 30);
      this.spiralSpeed = rand(0.02, 0.05);
      this.phase = rand(0, Math.PI * 2);
      this.points = [];
      this.length = rand(30, 60);
    }
    update() {
      this.x += this.speedX + Math.sin(this.phase) * 0.2;
      this.y += this.speedY;
      this.phase += this.spiralSpeed;
      // add current point
      this.points.push({ x: this.x + Math.sin(this.phase) * this.spiralRadius, y: this.y + Math.cos(this.phase) * this.spiralRadius * 0.3 });
      if (this.points.length > this.length) this.points.shift();
      if (this.y < -50) this.reset();
    }
    draw() {
      if (this.points.length < 2) return;
      renderer.stroke('#b8ccee');
      renderer.lineWidth(1.2);
      renderer.alpha(0.5 + 0.2 * Math.sin(this.phase));
      for (let i = 1; i < this.points.length; i++) {
        const p1 = this.points[i - 1];
        const p2 = this.points[i];
        renderer.line(p1.x, p1.y, p2.x, p2.y);
      }
    }
  }

  // Floating island with upward waterfall
  class FloatingIsland {
    constructor() {
      this.x = rand(0, canvas.width);
      this.y = rand(-canvas.height * 0.2, canvas.height * 0.4);
      this.radius = rand(20, 50);
      this.driftX = rand(-0.3, 0.3);
      this.driftPhase = rand(0, Math.PI * 2);
      this.waterfallHeight = rand(40, 90);
      this.waterfallWidth = rand(3, 8);
    }
    update() {
      this.driftPhase += 0.01;
      this.x += this.driftX + Math.sin(this.driftPhase) * 0.3;
      if (this.x > canvas.width + 60) this.x = -60;
      if (this.x < -60) this.x = canvas.width + 60;
    }
    draw(frameCount) {
      const pulse = Math.sin(frameCount * 0.02 + this.driftPhase) * 0.1 + 0.9;
      // island body
      renderer.fill('#6b5b7b');
      renderer.stroke(false);
      renderer.alpha(0.7);
      renderer.circle(this.x, this.y, this.radius * pulse);
      // upward waterfall (ribbons)
      renderer.stroke('#a0d0e8');
      renderer.lineWidth(1.5);
      renderer.alpha(0.5);
      const wX = this.x + rand(-4, 4);
      for (let i = 0; i < 5; i++) {
        const offset = i * 2;
        const tipX = wX + offset + Math.sin(frameCount * 0.05 + i) * 3;
        const tipY = this.y - this.waterfallHeight * 0.5 - Math.sin(frameCount * 0.03 + i) * 6;
        renderer.line(wX + offset, this.y - this.radius * pulse, tipX, tipY);
      }
    }
  }

  // Tree with translucent bark and galaxy trunk
  class DreamTree {
    constructor() {
      this.x = rand(0, canvas.width);
      this.y = canvas.height - rand(40, 120);
      this.trunkHeight = rand(50, 90);
      this.trunkWidth = rand(8, 18);
      this.canopyRadius = rand(30, 60);
      this.colorShift = rand(0, Math.PI * 2);
    }
    draw(frameCount) {
      const t = frameCount * 0.01 + this.colorShift;
      // translucent trunk with galaxy swirl
      renderer.fill('#2a1e3a');
      renderer.stroke(false);
      renderer.alpha(0.3);
      renderer.rect(this.x - this.trunkWidth / 2, this.y - this.trunkHeight, this.trunkWidth, this.trunkHeight);
      // galaxy swirl inside trunk
      for (let i = 0; i < 6; i++) {
        const angle = t + i * 1.2;
        const radius = this.trunkWidth * 0.3 * (0.5 + 0.5 * Math.sin(angle * 0.5));
        const gx = this.x + Math.cos(angle) * radius;
        const gy = (this.y - this.trunkHeight / 2) + Math.sin(angle * 0.7) * radius * 0.8;
        renderer.fill('#d4a0e0');
        renderer.alpha(0.2 + 0.1 * Math.sin(angle));
        renderer.circle(gx, gy, 2 + Math.sin(i + t) * 1);
      }
      // leaves shifting colors
      const leafColors = ['#b8a9d4', '#c7b3e6', '#e0c8f0', '#a7d8c8', '#d4b8c8'];
      for (let i = 0; i < 14; i++) {
        const angle = (i / 14) * Math.PI * 2 + Math.sin(t + i) * 0.3;
        const dist = this.canopyRadius * (0.4 + 0.4 * Math.sin(t * 0.6 + i));
        const lx = this.x + Math.cos(angle) * dist;
        const ly = (this.y - this.trunkHeight) + Math.sin(angle) * dist * 0.5 - 5;
        const col = leafColors[Math.floor((i + Math.floor(t * 2)) % leafColors.length)];
        renderer.fill(col);
        renderer.alpha(0.6);
        renderer.circle(lx, ly, 5 + 3 * Math.sin(t + i * 0.7));
      }
    }
  }

  // Geometric stained-glass butterfly
  class GlassButterfly {
    constructor() {
      this.x = rand(0, canvas.width);
      this.y = rand(0, canvas.height);
      this.vx = rand(-0.5, 0.5);
      this.vy = rand(-0.4, 0.4);
      this.size = rand(8, 18);
      this.phase = rand(0, Math.PI * 2);
      this.colorSet = ['#e04060', '#60b0e0', '#f0c060', '#a060d0'];
    }
    update() {
      this.phase += 0.04;
      this.x += this.vx + Math.sin(this.phase) * 0.3;
      this.y += this.vy + Math.cos(this.phase * 0.7) * 0.2;
      if (this.x < -20) this.x = canvas.width + 20;
      if (this.x > canvas.width + 20) this.x = -20;
      if (this.y < -20) this.y = canvas.height + 20;
      if (this.y > canvas.height + 20) this.y = -20;
    }
    draw() {
      const flap = Math.sin(this.phase) * 0.4 + 0.6;
      renderer.stroke(false);
      // left wing
      renderer.fill(this.colorSet[Math.floor(this.phase * 0.5) % this.colorSet.length]);
      renderer.alpha(0.7);
      renderer.triangle(
        this.x, this.y,
        this.x - this.size * 1.5 * flap, this.y - this.size * 0.6,
        this.x - this.size * 1.2 * flap, this.y + this.size * 0.5
      );
      // right wing
      renderer.fill(this.colorSet[(Math.floor(this.phase * 0.5) + 1) % this.colorSet.length]);
      renderer.alpha(0.7);
      renderer.triangle(
        this.x, this.y,
        this.x + this.size * 1.5 * flap, this.y - this.size * 0.6,
        this.x + this.size * 1.2 * flap, this.y + this.size * 0.5
      );
      // body
      renderer.fill('#3a2a4a');
      renderer.alpha(0.9);
      renderer.circle(this.x, this.y, 2);
    }
  }

  // Fox with tail of living flames
  class FlameFox {
    constructor() {
      this.x = rand(50, canvas.width - 50);
      this.y = canvas.height - rand(60, 120);
      this.vx = rand(-0.4, 0.4);
      this.phase = rand(0, Math.PI * 2);
    }
    update() {
      this.phase += 0.03;
      this.x += this.vx + Math.sin(this.phase * 0.5) * 0.2;
      if (this.x < 20 || this.x > canvas.width - 20) this.vx *= -1;
    }
    draw(frameCount) {
      // body (simple)
      renderer.fill('#d47a40');
      renderer.stroke(false);
      renderer.alpha(0.85);
      renderer.circle(this.x, this.y, 6);
      // head
      renderer.circle(this.x + 6, this.y - 2, 4);
      // tail of living flames
      const tailLen = 18;
      const segments = 8;
      for (let i = 0; i < segments; i++) {
        const t = (i / segments) * tailLen;
        const flicker = Math.sin(frameCount * 0.08 + i * 0.9 + this.phase) * 2;
        const tx = this.x - t * 0.5 + flicker * 0.5;
        const ty = this.y - 2 + Math.sin(frameCount * 0.1 + i * 0.7) * 3 - i * 0.8;
        const size = 5 - i * 0.4;
        const hue = 20 + i * 6 + Math.sin(frameCount * 0.05 + i) * 10;
        const color = `hsl(${hue}, 90%, ${50 + i * 4}%)`;
        renderer.fill(color);
        renderer.alpha(0.5 + 0.3 * Math.sin(frameCount * 0.06 + i));
        renderer.circle(tx, ty, size);
      }
    }
  }

  // Fish swimming in air
  class AirFish {
    constructor() {
      this.x = rand(0, canvas.width);
      this.y = rand(canvas.height * 0.1, canvas.height * 0.6);
      this.vx = rand(0.3, 1.0);
      this.vy = rand(-0.2, 0.2);
      this.size = rand(5, 12);
      this.phase = rand(0, Math.PI * 2);
    }
    update() {
      this.phase += 0.05;
      this.x += this.vx;
      this.y += this.vy + Math.sin(this.phase) * 0.2;
      if (this.x > canvas.width + 20) this.x = -20;
    }
    draw() {
      renderer.fill('#7ac0d0');
      renderer.stroke(false);
      renderer.alpha(0.6);
      // body
      renderer.ellipse(this.x, this.y, this.size * 1.5, this.size * 0.6);
      // tail
      renderer.triangle(
        this.x - this.size * 1.2, this.y,
        this.x - this.size * 1.8, this.y - this.size * 0.3,
        this.x - this.size * 1.8, this.y + this.size * 0.3
      );
    }
  }

  // Flowers with eye petals
  class EyeFlower {
    constructor() {
      this.x = rand(20, canvas.width - 20);
      this.y = canvas.height - rand(20, 80);
      this.size = rand(8, 16);
      this.blinkPhase = rand(0, Math.PI * 2);
    }
    draw(frameCount) {
      const blink = Math.sin(frameCount * 0.03 + this.blinkPhase);
      const eyeOpen = Math.abs(blink) > 0.7 ? 1 : 0.2;
      // petals (eyes)
      const numPetals = 6;
      for (let i = 0; i < numPetals; i++) {
        const angle = (i / numPetals) * Math.PI * 2 + Math.sin(frameCount * 0.01 + i) * 0.1;
        const px = this.x + Math.cos(angle) * this.size * 0.9;
        const py = this.y + Math.sin(angle) * this.size * 0.9;
        renderer.fill('#d8c0e8');
        renderer.stroke(false);
        renderer.alpha(0.7);
        renderer.ellipse(px, py, this.size * 0.5, this.size * 0.3 * eyeOpen);
        // pupil
        if (eyeOpen > 0.5) {
          renderer.fill('#2a1e3a');
          renderer.alpha(0.8);
          renderer.circle(px, py, 1.5);
        }
      }
      // center
      renderer.fill('#4a3a5a');
      renderer.alpha(0.9);
      renderer.circle(this.x, this.y, 3);
    }
  }

  // Path of broken mirrors
  class MirrorPath {
    constructor() {
      this.segments = [];
      for (let i = 0; i < 18; i++) {
        this.segments.push({
          x: rand(0, canvas.width),
          y: canvas.height - rand(20, 160),
          angle: rand(0, Math.PI * 2),
          size: rand(10, 25),
          colorOffset: rand(0, 1)
        });
      }
    }
    draw(frameCount) {
      for (const seg of this.segments) {
        const flicker = Math.sin(frameCount * 0.02 + seg.colorOffset * 10) * 0.2 + 0.8;
        const h = (seg.colorOffset * 60 + frameCount * 0.1) % 360;
        renderer.fill(`hsl(${h}, 40%, ${50 + 20 * flicker}%)`);
        renderer.alpha(0.4 + 0.2 * flicker);
        renderer.stroke(false);
        // draw a tilted rectangle as mirror shard
        const s = seg.size * 0.5;
        const cosA = Math.cos(seg.angle);
        const sinA = Math.sin(seg.angle);
        const x1 = seg.x + (-s * cosA - s * sinA);
        const y1 = seg.y + (-s * sinA + s * cosA);
        const x2 = seg.x + (s * cosA - s * sinA);
        const y2 = seg.y + (s * sinA + s * cosA);
        const x3 = seg.x + (s * cosA + s * sinA);
        const y3 = seg.y + (s * sinA - s * cosA);
        const x4 = seg.x + (-s * cosA + s * sinA);
        const y4 = seg.y + (-s * sinA - s * cosA);
        renderer.polygon([{x:x1,y:y1},{x:x2,y:y2},{x:x3,y:y3},{x:x4,y:y4}]);
      }
    }
  }

  // ------ Scene Init ------
  const rivers = [];
  for (let i = 0; i < 6; i++) rivers.push(new River());
  const islands = [];
  for (let i = 0; i < 4; i++) islands.push(new FloatingIsland());
  const trees = [];
  for (let i = 0; i < 5; i++) trees.push(new DreamTree());
  const butterflies = [];
  for (let i = 0; i < 8; i++) butterflies.push(new GlassButterfly());
  const fox = new FlameFox();
  const airFish = [];
  for (let i = 0; i < 5; i++) airFish.push(new AirFish());
  const flowers = [];
  for (let i = 0; i < 7; i++) flowers.push(new EyeFlower());
  const mirrorPath = new MirrorPath();

  // ------ Animation Loop ------
  startFrame((frameCount) => {
    // gradient sky (lavender to amber)
    renderer.clear('#0c0a1a');
    // soft sky gradient (drawn manually with many rects)
    for (let i = 0; i < canvas.height; i++) {
      const t = i / canvas.height;
      const r = Math.floor(20 + 60 * t);
      const g = Math.floor(10 + 40 * t);
      const b = Math.floor(60 + 30 * (1 - t));
      renderer.fill(`rgb(${r},${g},${b})`);
      renderer.alpha(0.15);
      renderer.rect(0, i, canvas.width, 1);
    }

    // distant floating mountains (simple silhouettes)
    renderer.fill('#4a3a5a');
    renderer.stroke(false);
    renderer.alpha(0.3);
    for (let i = 0; i < 4; i++) {
      const mx = canvas.width * 0.2 + i * canvas.width * 0.25 + Math.sin(frameCount * 0.005 + i) * 15;
      const my = canvas.height * 0.35 + Math.sin(frameCount * 0.01 + i * 1.5) * 8;
      renderer.triangle(mx - 40, my + 30, mx + 40, my + 30, mx + Math.sin(i) * 10, my - 35);
    }

    // rivers
    for (const r of rivers) { r.update(); r.draw(); }

    // islands
    for (const is of islands) { is.update(); is.draw(frameCount); }

    // trees
    for (const tr of trees) tr.draw(frameCount);

    // butterflies
    for (const b of butterflies) { b.update(); b.draw(); }

    // fox
    fox.update();
    fox.draw(frameCount);

    // air fish
    for (const f of airFish) { f.update(); f.draw(); }

    // flowers
    for (const fl of flowers) fl.draw(frameCount);

    // mirror path
    mirrorPath.draw(frameCount);

    // subtle breath pulse overlay
    renderer.fill('#d0b0e0');
    renderer.alpha(0.03 + 0.02 * Math.sin(frameCount * 0.02));
    renderer.circle(canvas.width/2, canvas.height/2, canvas.width * 0.7);
  });
};
