window.sketch = (runtime) => {
  const { THREE, canvas, startFrame, width, height } = runtime;

  const scene = new THREE.Scene();
  scene.background = new THREE.Color(0x1a0a1e);

  const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
  camera.position.set(8, 5, 12);
  camera.lookAt(0, 0, 0);

  const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
  renderer.setSize(width, height, false);
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;

  // Lights
  const ambient = new THREE.AmbientLight(0x404060, 0.5);
  scene.add(ambient);

  const sunLight = new THREE.DirectionalLight(0xffdd99, 1.2);
  sunLight.position.set(10, 15, 5);
  sunLight.castShadow = true;
  sunLight.shadow.mapSize.width = 1024;
  sunLight.shadow.mapSize.height = 1024;
  const d = 20;
  sunLight.shadow.camera.left = -d;
  sunLight.shadow.camera.right = d;
  sunLight.shadow.camera.top = d;
  sunLight.shadow.camera.bottom = -d;
  sunLight.shadow.camera.near = 1;
  sunLight.shadow.camera.far = 30;
  scene.add(sunLight);

  const fillLight = new THREE.DirectionalLight(0xcc99ff, 0.6);
  fillLight.position.set(-5, 3, -8);
  scene.add(fillLight);

  const backLight = new THREE.DirectionalLight(0xffaa88, 0.4);
  backLight.position.set(-3, 1, -10);
  scene.add(backLight);

  // Ground plane with subtle color
  const groundGeo = new THREE.CircleGeometry(14, 64);
  const groundMat = new THREE.MeshStandardMaterial({
    color: 0x6b4e71,
    roughness: 0.7,
    metalness: 0.1,
    transparent: true,
    opacity: 0.85
  });
  const ground = new THREE.Mesh(groundGeo, groundMat);
  ground.rotation.x = -Math.PI / 2;
  ground.position.y = -0.5;
  ground.receiveShadow = true;
  scene.add(ground);

  // Decorative shimmer rings on ground
  for (let i = 0; i < 3; i++) {
    const ringGeo = new THREE.RingGeometry(2.5 + i * 1.5, 2.8 + i * 1.5, 48);
    const ringMat = new THREE.MeshBasicMaterial({
      color: 0xcc99ff,
      side: THREE.DoubleSide,
      transparent: true,
      opacity: 0.15 + i * 0.05
    });
    const ring = new THREE.Mesh(ringGeo, ringMat);
    ring.rotation.x = -Math.PI / 2;
    ring.position.y = -0.45;
    scene.add(ring);
  }

  // Central crystalline column
  const crystalMat = new THREE.MeshStandardMaterial({
    color: 0xca9eff,
    emissive: 0x552a7a,
    emissiveIntensity: 0.15,
    roughness: 0.25,
    metalness: 0.3,
    transparent: true,
    opacity: 0.9
  });
  const crystalGeo = new THREE.CylinderGeometry(1.2, 1.8, 3.5, 8);
  const crystal = new THREE.Mesh(crystalGeo, crystalMat);
  crystal.position.set(0, 1.2, 0);
  crystal.castShadow = true;
  crystal.receiveShadow = true;
  scene.add(crystal);

  // Floating orbs around crystal
  const orbGroup = new THREE.Group();
  const orbMat = new THREE.MeshStandardMaterial({
    color: 0xffbbdd,
    emissive: 0x8844aa,
    emissiveIntensity: 0.3,
    roughness: 0.2,
    metalness: 0.1
  });
  const orbGeo = new THREE.SphereGeometry(0.25, 16, 16);
  const orbCount = 12;
  for (let i = 0; i < orbCount; i++) {
    const orb = new THREE.Mesh(orbGeo, orbMat.clone());
    orb.material.color.setHSL(0.75 + i * 0.06, 0.7, 0.6);
    orb.castShadow = true;
    orb.receiveShadow = false;
    const angle = (i / orbCount) * Math.PI * 2;
    const radius = 2.8;
    orb.position.set(Math.cos(angle) * radius, 0.5 + Math.sin(i * 1.5) * 0.6, Math.sin(angle) * radius);
    orb.userData = { angle, radius, heightOffset: i * 0.4, speed: 0.6 + Math.random() * 0.4 };
    orbGroup.add(orb);
  }
  scene.add(orbGroup);

  // Floating petal / leaf shapes
  const petalGroup = new THREE.Group();
  const petalMat = new THREE.MeshStandardMaterial({
    color: 0xdd99ff,
    emissive: 0x664488,
    emissiveIntensity: 0.1,
    side: THREE.DoubleSide,
    transparent: true,
    opacity: 0.5,
    roughness: 0.4
  });
  const petalGeo = new THREE.CircleGeometry(0.4, 5);
  for (let i = 0; i < 30; i++) {
    const petal = new THREE.Mesh(petalGeo, petalMat.clone());
    petal.material.color.setHSL(0.7 + Math.random() * 0.25, 0.8, 0.6);
    const angle = Math.random() * Math.PI * 2;
    const radius = 2.0 + Math.random() * 5.0;
    petal.position.set(
      Math.cos(angle) * radius,
      -0.3 + Math.random() * 3.5,
      Math.sin(angle) * radius
    );
    petal.rotation.x = Math.random() * Math.PI;
    petal.rotation.y = Math.random() * Math.PI;
    petal.rotation.z = Math.random() * Math.PI;
    petal.userData = {
      angle: angle,
      radius: radius,
      ySpeed: 0.2 + Math.random() * 0.3,
      rotSpeed: 0.005 + Math.random() * 0.02,
      floatOffset: Math.random() * Math.PI * 2
    };
    petalGroup.add(petal);
  }
  scene.add(petalGroup);

  // Sky gradient spheres (distant dreamscape)
  const skyGroup = new THREE.Group();
  const glowMat = new THREE.MeshBasicMaterial({
    color: 0xcc88ff,
    transparent: true,
    opacity: 0.08
  });
  for (let i = 0; i < 8; i++) {
    const size = 1.0 + Math.random() * 3.0;
    const sphere = new THREE.Mesh(new THREE.SphereGeometry(size, 12, 12), glowMat.clone());
    sphere.material.color.setHSL(0.7 + Math.random() * 0.2, 0.7, 0.5 + Math.random() * 0.3);
    sphere.position.set(
      (Math.random() - 0.5) * 18,
      4 + Math.random() * 6,
      (Math.random() - 0.5) * 18 - 5
    );
    sphere.userData = {
      pulseSpeed: 0.2 + Math.random() * 0.4,
      pulseOffset: Math.random() * Math.PI * 2
    };
    skyGroup.add(sphere);
  }
  scene.add(skyGroup);

  // Small sparkle particles
  const particleCount = 400;
  const particleGeo = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);
  const colors = new Float32Array(particleCount * 3);
  const sizes = new Float32Array(particleCount);
  for (let i = 0; i < particleCount; i++) {
    const radius = 1.5 + Math.random() * 8;
    const angle = Math.random() * Math.PI * 2;
    positions[i * 3] = Math.cos(angle) * radius;
    positions[i * 3 + 1] = -0.3 + Math.random() * 5;
    positions[i * 3 + 2] = Math.sin(angle) * radius;
    const c = new THREE.Color().setHSL(0.7 + Math.random() * 0.3, 0.8, 0.5 + Math.random() * 0.4);
    colors[i * 3] = c.r;
    colors[i * 3 + 1] = c.g;
    colors[i * 3 + 2] = c.b;
    sizes[i] = 0.02 + Math.random() * 0.08;
  }
  particleGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  particleGeo.setAttribute('color', new THREE.BufferAttribute(colors, 3));
  particleGeo.setAttribute('size', new THREE.BufferAttribute(sizes, 1));

  const particleMat = new THREE.PointsMaterial({
    size: 0.06,
    vertexColors: true,
    transparent: true,
    opacity: 0.6,
    blending: THREE.AdditiveBlending,
    depthWrite: false
  });
  const particles = new THREE.Points(particleGeo, particleMat);
  scene.add(particles);

  // Cleanup
  const cleanup = () => {
    renderer.dispose();
    scene.traverse((obj) => {
      if (obj.isMesh) {
        obj.geometry?.dispose();
        if (Array.isArray(obj.material)) obj.material.forEach(m => m.dispose());
        else obj.material?.dispose();
      }
    });
  };

  let frameCount = 0;

  startFrame((delta) => {
    frameCount++;
    const time = performance.now() / 1000;

    // Animate orbs
    orbGroup.children.forEach((orb, idx) => {
      const data = orb.userData;
      const angle = data.angle + time * 0.3 * data.speed;
      const radius = data.radius + Math.sin(time * 0.5 + idx) * 0.15;
      orb.position.x = Math.cos(angle) * radius;
      orb.position.z = Math.sin(angle) * radius;
      orb.position.y = 0.8 + Math.sin(time * 0.8 + data.heightOffset) * 1.0;
      const scale = 0.8 + Math.sin(time * 1.2 + idx * 0.7) * 0.2;
      orb.scale.set(scale, scale, scale);
    });

    // Animate petals
    petalGroup.children.forEach((petal) => {
      const d = petal.userData;
      const floatY = Math.sin(time * d.ySpeed + d.floatOffset) * 0.4;
      petal.position.y += (floatY - petal.position.y * 0.005) * 0.01;
      petal.rotation.x += d.rotSpeed;
      petal.rotation.y += d.rotSpeed * 0.7;
      petal.rotation.z += d.rotSpeed * 0.3;
    });

    // Animate sky spheres
    skyGroup.children.forEach((sphere, i) => {
      const d = sphere.userData;
      const pulse = 0.7 + Math.sin(time * d.pulseSpeed + d.pulseOffset) * 0.3;
      sphere.material.opacity = 0.04 + pulse * 0.06;
      sphere.position.y += Math.sin(time * 0.1 + i) * 0.0005;
    });

    // Rotate particles
    particles.rotation.y += 0.0004;

    // Pulsate crystal
    const crystalGlow = 0.1 + Math.sin(time * 0.6) * 0.1;
    crystal.material.emissiveIntensity = crystalGlow;

    // Dreamy camera orbit
    const camRadius = 14;
    const camAngle = time * 0.03;
    camera.position.x = Math.sin(camAngle) * camRadius * 0.6;
    camera.position.z = Math.cos(camAngle) * camRadius * 0.8 + 4;
    camera.position.y = 4 + Math.sin(time * 0.05) * 0.6;
    camera.lookAt(0, 1.0, 0);

    renderer.render(scene, camera);
  });

  return cleanup;
};
