<script setup lang="ts">
import {
  AmbientLight,
  Mesh,
  MeshBasicMaterial,
  PerspectiveCamera,
  PlaneGeometry,
  Scene,
  SphereGeometry,
  WebGLRenderer,
} from 'three'
import { Ref } from 'vue'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

const experience: Ref<WebGLRenderer | null> = ref(null)
let renderer: WebGLRenderer
let controls: OrbitControls

const { width, height } = useWindowSize()
const aspectRatio = computed(() => width.value / height.value)

watch(aspectRatio, updateRenderer)
watch(aspectRatio, updateCamera)

const scene = new Scene()
const camera = new PerspectiveCamera(45, aspectRatio.value, 0.1, 1000)

camera.position.set(15, 15, 15)
scene.add(camera)

const light = new AmbientLight(0xffaaff)
light.position.set(10, 10, 10)
scene.add(light)

// Objects
const sphere = new Mesh(new SphereGeometry(2, 32, 32), new MeshBasicMaterial({ color: 'teal' }))

sphere.position.set(0, 4, 0)
scene.add(sphere)

const plane = new Mesh(new PlaneGeometry(10, 10, 10, 10), new MeshBasicMaterial({ color: '#444' }))

plane.rotation.set(-Math.PI / 2, 0, 0)

scene.add(plane)

const loop = () => {
  // Update renderer

  controls.update()
  renderer.render(scene, camera)
  requestAnimationFrame(loop)
}

function updateRenderer() {
  renderer.setSize(width.value, height.value)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
}

function updateCamera() {
  camera.aspect = aspectRatio.value
  camera.updateProjectionMatrix()
}

onMounted(() => {
  renderer = new WebGLRenderer({
    canvas: experience.value as unknown as HTMLCanvasElement,
    antialias: true,
    alpha: true,
  })

  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  loop()
  updateRenderer()
})
</script>

<template>
  <canvas ref="experience"></canvas>
</template>

<route lang="yaml">
meta:
  layout: experiment
  title: Basic Scene
  status: published
  media: '/basic/basic-scene.png'
  description: 'Basic ThreeJS Scene with a Geometry, a Plane, Orbit Controls'
  tags: ['basic']
</route>
