<template>
  <div class="color-page">
    <div class="color-header">
      <h1>三维空间色彩粒子</h1>
      <p>这是从旧项目抽离出来的第一个实验场景，后续可以继续补充更多交互与玩法。</p>
    </div>
    <div class="color-canvas" ref="canvasRoot"></div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, onBeforeUnmount, ref } from 'vue'
import * as THREE from 'three'

const canvasRoot = ref<HTMLDivElement | null>(null)

let renderer: THREE.WebGLRenderer | null = null
let scene: THREE.Scene | null = null
let camera: THREE.PerspectiveCamera | null = null
let animationId = 0

onMounted(() => {
  if (!canvasRoot.value) return

  const container = canvasRoot.value
  const width = container.clientWidth
  const height = container.clientHeight

  renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(width, height)
  container.appendChild(renderer.domElement)

  scene = new THREE.Scene()
  camera = new THREE.PerspectiveCamera(55, width / height, 0.1, 2000)
  camera.position.set(0, 0, 380)

  const geometry = new THREE.IcosahedronGeometry(1, 3)
  const group = new THREE.Group()

  const gridSize = 64
  const spacing = 8
  for (let x = -gridSize; x <= gridSize; x += spacing) {
    for (let y = -gridSize; y <= gridSize; y += spacing) {
      const zLayerCount = 3
      for (let zIndex = 0; zIndex < zLayerCount; zIndex++) {
        if (Math.random() > 0.55) continue
        const color = new THREE.Color()
        color.setHSL(Math.random(), 0.7, Math.random() * 0.2 + 0.2)
        const material = new THREE.MeshBasicMaterial({ color })
        const mesh = new THREE.Mesh(geometry, material)
        mesh.position.set(
          x,
          y + (Math.random() - 0.5) * 10,
          zIndex * 18 + (Math.random() - 0.5) * 20,
        )
        const s = Math.random() * 3 + 1.2
        mesh.scale.setScalar(s)
        group.add(mesh)
      }
    }
  }

  scene.add(group)

  const clock = new THREE.Clock()

  const animate = () => {
    animationId = requestAnimationFrame(animate)
    const t = clock.getElapsedTime()

    group.rotation.y = t * 0.16
    group.rotation.x = Math.sin(t * 0.3) * 0.35

    if (camera) {
      camera.position.z = 360 + Math.sin(t * 0.5) * 40
      camera.lookAt(0, 0, 0)
    }

    renderer?.render(scene as THREE.Scene, camera as THREE.PerspectiveCamera)
  }

  animate()

  const onResize = () => {
    if (!renderer || !camera) return
    const w = container.clientWidth
    const h = container.clientHeight
    renderer.setSize(w, h)
    camera.aspect = w / h
    camera.updateProjectionMatrix()
  }

  window.addEventListener('resize', onResize)

  onBeforeUnmount(() => {
    cancelAnimationFrame(animationId)
    window.removeEventListener('resize', onResize)
    if (renderer) {
      renderer.dispose()
    }
    if (scene) {
      scene.traverse((obj) => {
        if ((obj as THREE.Mesh).geometry) {
          ;(obj as THREE.Mesh).geometry.dispose()
        }
        if ((obj as THREE.Mesh).material) {
          const mat = (obj as THREE.Mesh).material
          if (Array.isArray(mat)) {
            mat.forEach((m) => m.dispose())
          } else {
            mat.dispose()
          }
        }
      })
    }
    if (canvasRoot.value && renderer) {
      canvasRoot.value.removeChild(renderer.domElement)
    }
  })
})
</script>


