mirror of
https://github.com/System-End/3d-website.git
synced 2026-04-19 16:38:20 +00:00
259 lines
6.6 KiB
JavaScript
259 lines
6.6 KiB
JavaScript
import * as THREE from "three";
|
|
|
|
const scene = new THREE.Scene();
|
|
scene.background = new THREE.Color(0x1a1a2e);
|
|
|
|
const camera = new THREE.PerspectiveCamera(
|
|
75,
|
|
window.innerWidth / window.innerHeight,
|
|
0.1,
|
|
1000,
|
|
);
|
|
|
|
// Connect to the canvas element instead of appending to body
|
|
const renderer = new THREE.WebGLRenderer({
|
|
canvas: document.querySelector("#bg"),
|
|
antialias: true,
|
|
});
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
renderer.setPixelRatio(window.devicePixelRatio);
|
|
|
|
// Lights
|
|
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
|
|
scene.add(ambientLight);
|
|
|
|
const mainLight = new THREE.DirectionalLight(0xffffff, 1);
|
|
mainLight.position.set(5, 5, 5);
|
|
scene.add(mainLight);
|
|
|
|
const fillLight = new THREE.DirectionalLight(0x4fc3f7, 0.3);
|
|
fillLight.position.set(-5, 0, -5);
|
|
scene.add(fillLight);
|
|
|
|
const protogen = new THREE.Group();
|
|
|
|
// Materials
|
|
const bodyMaterial = new THREE.MeshStandardMaterial({
|
|
color: 0x2d2d2d,
|
|
metalness: 0.7,
|
|
roughness: 0.3,
|
|
});
|
|
|
|
const accentMaterial = new THREE.MeshStandardMaterial({
|
|
color: 0x1a1a1a,
|
|
metalness: 0.8,
|
|
roughness: 0.2,
|
|
});
|
|
|
|
const glowMaterial = new THREE.MeshStandardMaterial({
|
|
color: 0x00ffff,
|
|
emissive: 0x00ffff,
|
|
emissiveIntensity: 0.8,
|
|
metalness: 0.3,
|
|
roughness: 0.4,
|
|
});
|
|
|
|
const visorMaterial = new THREE.MeshStandardMaterial({
|
|
color: 0x001a1a,
|
|
emissive: 0x003333,
|
|
emissiveIntensity: 0.3,
|
|
metalness: 0.9,
|
|
roughness: 0.1,
|
|
transparent: true,
|
|
opacity: 0.9,
|
|
});
|
|
|
|
// HEAD
|
|
const headGeometry = new THREE.BoxGeometry(2, 1.8, 2);
|
|
const head = new THREE.Mesh(headGeometry, bodyMaterial);
|
|
head.position.y = 0;
|
|
protogen.add(head);
|
|
|
|
const snoutGeometry = new THREE.BoxGeometry(1.4, 0.8, 1.2);
|
|
const snout = new THREE.Mesh(snoutGeometry, bodyMaterial);
|
|
snout.position.set(0, -0.3, 1.2);
|
|
protogen.add(snout);
|
|
|
|
// Snout tip
|
|
const snoutTipGeometry = new THREE.BoxGeometry(1.0, 0.5, 0.4);
|
|
const snoutTip = new THREE.Mesh(snoutTipGeometry, bodyMaterial);
|
|
snoutTip.position.set(0, -0.35, 1.9);
|
|
protogen.add(snoutTip);
|
|
|
|
// VISOR
|
|
const visorGeometry = new THREE.BoxGeometry(1.8, 1.2, 0.1);
|
|
const visor = new THREE.Mesh(visorGeometry, visorMaterial);
|
|
visor.position.set(0, 0.1, 1.05);
|
|
protogen.add(visor);
|
|
|
|
// Visor frame
|
|
const visorFrameShape = new THREE.Shape();
|
|
visorFrameShape.moveTo(-1, -0.7);
|
|
visorFrameShape.lineTo(1, -0.7);
|
|
visorFrameShape.lineTo(1, 0.7);
|
|
visorFrameShape.lineTo(-1, 0.7);
|
|
visorFrameShape.lineTo(-1, -0.7);
|
|
|
|
const visorHole = new THREE.Path();
|
|
visorHole.moveTo(-0.85, -0.55);
|
|
visorHole.lineTo(0.85, -0.55);
|
|
visorHole.lineTo(0.85, 0.55);
|
|
visorHole.lineTo(-0.85, 0.55);
|
|
visorHole.lineTo(-0.85, -0.55);
|
|
visorFrameShape.holes.push(visorHole);
|
|
|
|
const visorFrameGeometry = new THREE.ExtrudeGeometry(visorFrameShape, {
|
|
depth: 0.15,
|
|
bevelEnabled: false,
|
|
});
|
|
const visorFrame = new THREE.Mesh(visorFrameGeometry, accentMaterial);
|
|
visorFrame.position.set(0, 0.1, 1.0);
|
|
protogen.add(visorFrame);
|
|
|
|
// VISOR DISPLAY
|
|
const eyeGroup = new THREE.Group();
|
|
|
|
// Left eye
|
|
const leftEyeShape = new THREE.Shape();
|
|
leftEyeShape.moveTo(-0.5, 0);
|
|
leftEyeShape.lineTo(-0.2, 0.25);
|
|
leftEyeShape.lineTo(-0.2, 0.15);
|
|
leftEyeShape.lineTo(-0.35, 0);
|
|
leftEyeShape.lineTo(-0.2, -0.15);
|
|
leftEyeShape.lineTo(-0.2, -0.25);
|
|
leftEyeShape.lineTo(-0.5, 0);
|
|
|
|
const leftEyeGeometry = new THREE.ShapeGeometry(leftEyeShape);
|
|
const leftEye = new THREE.Mesh(leftEyeGeometry, glowMaterial);
|
|
leftEye.position.set(-0.25, 0.15, 1.12);
|
|
eyeGroup.add(leftEye);
|
|
|
|
// Right eye
|
|
const rightEyeShape = new THREE.Shape();
|
|
rightEyeShape.moveTo(0.5, 0);
|
|
rightEyeShape.lineTo(0.2, 0.25);
|
|
rightEyeShape.lineTo(0.2, 0.15);
|
|
rightEyeShape.lineTo(0.35, 0);
|
|
rightEyeShape.lineTo(0.2, -0.15);
|
|
rightEyeShape.lineTo(0.2, -0.25);
|
|
rightEyeShape.lineTo(0.5, 0);
|
|
|
|
const rightEyeGeometry = new THREE.ShapeGeometry(rightEyeShape);
|
|
const rightEye = new THREE.Mesh(rightEyeGeometry, glowMaterial);
|
|
rightEye.position.set(0.25, 0.15, 1.12);
|
|
eyeGroup.add(rightEye);
|
|
|
|
protogen.add(eyeGroup);
|
|
|
|
// EARS
|
|
function createEar(isLeft) {
|
|
const earGroup = new THREE.Group();
|
|
|
|
// Main ear
|
|
const earShape = new THREE.Shape();
|
|
earShape.moveTo(0, 0);
|
|
earShape.lineTo(0.4, 0);
|
|
earShape.lineTo(0.2, 1.0);
|
|
earShape.lineTo(0, 0);
|
|
|
|
const earGeometry = new THREE.ExtrudeGeometry(earShape, {
|
|
depth: 0.3,
|
|
bevelEnabled: true,
|
|
bevelThickness: 0.05,
|
|
bevelSize: 0.05,
|
|
});
|
|
|
|
const ear = new THREE.Mesh(earGeometry, bodyMaterial);
|
|
earGroup.add(ear);
|
|
|
|
// Inner ear glow
|
|
const innerEarShape = new THREE.Shape();
|
|
innerEarShape.moveTo(0.1, 0.15);
|
|
innerEarShape.lineTo(0.3, 0.15);
|
|
innerEarShape.lineTo(0.2, 0.7);
|
|
innerEarShape.lineTo(0.1, 0.15);
|
|
|
|
const innerEarGeometry = new THREE.ShapeGeometry(innerEarShape);
|
|
const innerEar = new THREE.Mesh(innerEarGeometry, glowMaterial);
|
|
innerEar.position.z = 0.31;
|
|
earGroup.add(innerEar);
|
|
|
|
const xPos = isLeft ? -0.9 : 0.5;
|
|
earGroup.position.set(xPos, 0.7, -0.3);
|
|
earGroup.rotation.x = -0.3;
|
|
earGroup.rotation.z = isLeft ? 0.2 : -0.2;
|
|
|
|
return earGroup;
|
|
}
|
|
|
|
protogen.add(createEar(true));
|
|
protogen.add(createEar(false));
|
|
|
|
// NECK
|
|
const neckGeometry = new THREE.CylinderGeometry(0.6, 0.7, 0.8, 8);
|
|
const neck = new THREE.Mesh(neckGeometry, bodyMaterial);
|
|
neck.position.set(0, -1.2, 0);
|
|
protogen.add(neck);
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
const ringGeometry = new THREE.TorusGeometry(0.65, 0.03, 8, 32);
|
|
const ring = new THREE.Mesh(ringGeometry, glowMaterial);
|
|
ring.position.set(0, -0.95 - i * 0.2, 0);
|
|
ring.rotation.x = Math.PI / 2;
|
|
protogen.add(ring);
|
|
}
|
|
|
|
// CHEEK ACCENTS
|
|
const cheekGeometry = new THREE.BoxGeometry(0.1, 0.4, 0.6);
|
|
const leftCheek = new THREE.Mesh(cheekGeometry, glowMaterial);
|
|
leftCheek.position.set(-1.05, 0, 0.5);
|
|
protogen.add(leftCheek);
|
|
|
|
const rightCheek = new THREE.Mesh(cheekGeometry, glowMaterial);
|
|
rightCheek.position.set(1.05, 0, 0.5);
|
|
protogen.add(rightCheek);
|
|
|
|
scene.add(protogen);
|
|
|
|
// Set initial camera position
|
|
camera.position.set(0, 0, 5);
|
|
|
|
// Handle window resize
|
|
window.addEventListener("resize", () => {
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
|
camera.updateProjectionMatrix();
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
});
|
|
|
|
// Scroll animation function
|
|
function moveCamera() {
|
|
const t = document.body.getBoundingClientRect().top;
|
|
|
|
// Rotate protogen slightly on scroll
|
|
protogen.rotation.y = t * -0.002;
|
|
protogen.rotation.x = t * -0.0005;
|
|
|
|
// Move camera on scroll
|
|
camera.position.z = 5 + t * -0.005;
|
|
}
|
|
|
|
document.body.onscroll = moveCamera;
|
|
moveCamera();
|
|
|
|
let time = 0;
|
|
|
|
function animate() {
|
|
requestAnimationFrame(animate);
|
|
time += 0.016;
|
|
|
|
// Gentle floating animation
|
|
protogen.position.y = Math.sin(time * 0.5) * 0.1;
|
|
|
|
// Pulsing glow effect
|
|
const pulse = 0.6 + Math.sin(time * 2) * 0.3;
|
|
glowMaterial.emissiveIntensity = pulse;
|
|
|
|
renderer.render(scene, camera);
|
|
}
|
|
|
|
animate();
|