import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0b0b14);
const camera = new THREE.PerspectiveCamera(42, 1, 0.1, 100);
camera.position.set(0, 0.5, 6.4);
const cv = document.createElement('canvas');
cv.width = cv.height = 128;
const cx = cv.getContext('2d');
cx.fillStyle = '#777'; cx.fillRect(0, 0, 128, 128);
for (let i = 0; i < 26; i++) {
const x = Math.random() * 128, y = Math.random() * 128, r = 6 + Math.random() * 10;
const g = cx.createRadialGradient(x, y, 0, x, y, r);
g.addColorStop(0, '#fff'); g.addColorStop(1, 'rgba(119,119,119,0)');
cx.fillStyle = g; cx.beginPath(); cx.arc(x, y, r, 0, Math.PI * 2); cx.fill();
}
const tex = new THREE.CanvasTexture(cv);
const bumpSphere = new THREE.Mesh(
new THREE.SphereGeometry(1.05, 64, 64),
new THREE.MeshStandardMaterial({ color: 0x8ecbff, bumpMap: tex, bumpScale: 0.06, roughness: 0.55 })
);
bumpSphere.position.x = -1.7;
const dispSphere = new THREE.Mesh(
new THREE.SphereGeometry(1.05, 128, 128),
new THREE.MeshStandardMaterial({ color: 0xffb648, displacementMap: tex, displacementScale: 0.34, roughness: 0.55 })
);
dispSphere.position.x = 1.7;
scene.add(bumpSphere, dispSphere);
const key = new THREE.DirectionalLight(0xffffff, 1.8); key.position.set(3, 4, 5); scene.add(key);
scene.add(new THREE.AmbientLight(0xffffff, 0.45));
function resize() { renderer.setSize(innerWidth, innerHeight); camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); }
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
const r = t * 0.00028;
bumpSphere.rotation.y = r; dispSphere.rotation.y = r;
camera.lookAt(0, 0, 0);
renderer.render(scene, camera);
});