const canvas = document.querySelector('#webgl')
// Debug
// const gui = new dat.GUI()
const parameters = {
color: 0x66af67,
lightColor: 0xd7f3fa,
rotationX: Math.PI / 8,
rotationY: Math.PI / 4,
spin: () => {
gsap.to(body.rotation, {
y: body.rotation.y + Math.PI * 2,
duration: 1,
});
}
}
// Scene
const scene = new THREE.Scene()
/* Geometry */
// Material
const material = new THREE.MeshLambertMaterial({
color: parameters.color
})
// Body
const body = new THREE.Group()
scene.add(body)
body.rotation.y = parameters.rotationY
body.rotation.x = parameters.rotationX
// Head
const head = new THREE.Group()
const createHead = () => {
const geometry = new THREE.SphereGeometry(0.52, 30, 30)
const main = new THREE.Mesh(geometry, material)
head.add(main)
}
createHead()
body.add(head)
head.position.y = 0.27
head.position.x = -1.5
gsap.to(head.rotation, {
z: 0.35,
delay: 0.24,
duration: 0.8,
repeat: -1,
yoyo: true,
ease: 'power2.inOut'
})
// Lil spheres (body segements)
let lastPos = -1.5
for (i = 0; i <= 8; i++) {
const s = i > 2 ? (8 - i) * 0.1 : 0.5
const geometry = new THREE.SphereGeometry(s, 15, 15)
const material = new THREE.MeshLambertMaterial({
color: `rgb(${i * 30}, 175, 103)`
})
const mesh = new THREE.Mesh(geometry, material)
mesh.position.x = i <= 2 ? i * 0.6 - 1.5 : lastPos + (s * 1.5)
lastPos = mesh.position.x
if (i > 0) {
body.add(mesh)
}
gsap.to(mesh.position, {
y: 0.16,
delay: i * 0.24,
duration: 0.8,
repeat: -1,
yoyo: true,
ease: 'sine.inOut'
})
}
for (i = 0; i <= 2; i++) {
// Antenna
const cylinderGeometry = new THREE.CylinderGeometry(0.025, 0.05, 0.7, 8)
const antennaMaterial = new THREE.MeshLambertMaterial({
color: 0x176654
})
const cylinder = new THREE.Mesh(cylinderGeometry, antennaMaterial)
const topGeometry = new THREE.SphereGeometry(0.07, 8, 8)
const topMesh = new THREE.Mesh(topGeometry, antennaMaterial)
cylinder.position.x = -0.14
cylinder.position.y = 0.36
cylinder.position.z = i === 0 ? -0.2 : 0.2
topMesh.position.x = -0.14
topMesh.position.y = 0.7
topMesh.position.z = i === 0 ? -0.2 : 0.2
head.add(cylinder)
head.add(topMesh)
// Eyes
const geometry = new THREE.SphereGeometry(0.12, 10, 10)
const eyeMaterial = new THREE.MeshPhongMaterial({
color: 0x2b3542
})
const eyeMesh = new THREE.Mesh(geometry, eyeMaterial)
eyeMesh.position.x = -0.25
eyeMesh.position.y = 0.18
eyeMesh.position.z = i === 0 ? -0.36 : 0.36
head.add(eyeMesh)
}
// Mouth
const mouthGeometry = new THREE.TorusGeometry(0.08, 0.07, 6, 15)
const mouthMaterial = new THREE.MeshPhongMaterial({
color: 0x2b3542
})
const mouth = new THREE.Mesh(mouthGeometry, material)
head.add(mouth)
mouth.position.x = -0.48
mouth.rotation.y = Math.PI / 2
const sizes = {
width: window.innerWidth,
height: window.innerHeight,
}
window.addEventListener("resize", () => {
// Update sizes
sizes.width = window.innerWidth;
sizes.height = window.innerHeight;
camera.aspect = sizes.width / sizes.height;
camera.updateProjectionMatrix();
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
})
// Debug
// gui.add(body.position, 'x').min(-3).max(3).step(0.01)
// gui.add(body.position, 'y').min(-3).max(3).step(0.01)
// gui.add(body, 'visible')
// gui.add(material, 'wireframe')
// gui.addColor(parameters, 'color').onChange(() => {
// material.color.set(parameters.color)
// })
// gui.add(parameters, 'spin')
// Camera
const camera = new THREE.PerspectiveCamera(
65,
sizes.width / sizes.height,
0.1,
75
);
camera.position.z = 5
scene.add(camera)
// Lighting
const lightAmbient = new THREE.AmbientLight(0xffea63)
const lightDirectional = new THREE.DirectionalLight(0xffffff, 0.5)
scene.add(lightAmbient)
scene.add(lightDirectional)
lightDirectional.position.x = 1.5
lightDirectional.position.y = 1.5
lightDirectional.position.z = 3
// Controls
const controls = new THREE.OrbitControls(camera, canvas);
controls.enableDamping = true;
// Renderer
const renderer = new THREE.WebGLRenderer({
canvas,
alpha: true
});
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setClearColor(0xc4ddff, 1)
renderer.render(scene, camera)
// Animate
const clock = new THREE.Clock()
const tick = () => {
const elapsedTime = clock.getElapsedTime()
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()