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(0x07050c);
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(0, 0.6, 5);
camera.lookAt(0, 0, 0);
const vertexShader = [
'varying vec3 vPos;',
'varying vec3 vNormal;',
'void main() {',
' vPos = position;',
' vNormal = normalize(normalMatrix * normal);',
' gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);',
'}',
].join('\n');
const fragmentShader = [
'uniform float uProgress;',
'varying vec3 vPos;',
'varying vec3 vNormal;',
'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(vPos * 2.2);',
' if (n < uProgress) discard;',
' float edge = smoothstep(uProgress, uProgress + 0.08, n);',
' vec3 base = vec3(0.25, 0.5, 0.95);',
' vec3 glow = vec3(1.0, 0.65, 0.25);',
' vec3 color = mix(glow, base, edge);',
' float rim = pow(1.0 - abs(dot(normalize(vNormal), vec3(0.0, 0.0, 1.0))), 2.0);',
' gl_FragColor = vec4(color + rim * 0.15, 1.0);',
'}',
].join('\n');
const mat = new THREE.ShaderMaterial({ uniforms: { uProgress: { value: 0 } }, vertexShader, fragmentShader });
const mesh = new THREE.Mesh(new THREE.IcosahedronGeometry(1.3, 3), mat);
scene.add(mesh);
function resize() { renderer.setSize(innerWidth, innerHeight); camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); }
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
const time = t * 0.001;
mat.uniforms.uProgress.value = 0.25 + 0.2 * Math.sin(time * 0.4);
mesh.rotation.y = time * 0.25;
mesh.rotation.x = Math.sin(time * 0.15) * 0.3;
renderer.render(scene, camera);
});