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(0x070812);
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(0, 0, 4.8);
camera.lookAt(0, 0, 0);
const vertexShader = [
'uniform float uTime;',
'varying vec3 vNormal;',
'varying float vN;',
'float hash(vec3 p) { return fract(sin(dot(p, vec3(127.1, 311.7, 74.7))) * 43758.5453); }',
'float noise(vec3 p) {',
' vec3 i = floor(p); vec3 f = fract(p); f = f * f * (3.0 - 2.0 * f);',
' float n000 = hash(i), n100 = hash(i + vec3(1.0,0.0,0.0)), n010 = hash(i + vec3(0.0,1.0,0.0)), n110 = hash(i + vec3(1.0,1.0,0.0));',
' float n001 = hash(i + vec3(0.0,0.0,1.0)), n101 = hash(i + vec3(1.0,0.0,1.0)), n011 = hash(i + vec3(0.0,1.0,1.0)), n111 = hash(i + vec3(1.0,1.0,1.0));',
' float nx00 = mix(n000, n100, f.x), nx10 = mix(n010, n110, f.x), nx01 = mix(n001, n101, f.x), nx11 = mix(n011, n111, f.x);',
' float nxy0 = mix(nx00, nx10, f.y), nxy1 = mix(nx01, nx11, f.y);',
' return mix(nxy0, nxy1, f.z);',
'}',
'void main() {',
' float n = noise(position * 1.8 + uTime * 0.3);',
' vec3 p = position + normal * n * 0.35;',
' vN = n;',
' vNormal = normalize(normalMatrix * normal);',
' gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0);',
'}',
].join('\n');
const fragmentShader = [
'varying vec3 vNormal;',
'varying float vN;',
'void main() {',
' vec3 light = normalize(vec3(0.5, 0.8, 0.6));',
' float diff = max(dot(normalize(vNormal), light), 0.0);',
' vec3 low = vec3(0.15, 0.2, 0.55);',
' vec3 high = vec3(0.5, 0.85, 0.95);',
' vec3 base = mix(low, high, clamp(vN, 0.0, 1.0));',
' gl_FragColor = vec4(base * (0.35 + diff * 0.85), 1.0);',
'}',
].join('\n');
const geo = new THREE.SphereGeometry(1.3, 128, 128);
const mat = new THREE.ShaderMaterial({ uniforms: { uTime: { value: 0 } }, vertexShader, fragmentShader });
const mesh = new THREE.Mesh(geo, mat);
scene.add(mesh);
function resize() { renderer.setSize(innerWidth, innerHeight); camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); }
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
mat.uniforms.uTime.value = t * 0.0006;
mesh.rotation.y = t * 0.0003;
renderer.render(scene, camera);
});