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(0x030308);
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(0, 0, 4.4);
const vertexShader = [
'varying vec3 vNormal;',
'varying vec3 vViewDir;',
'void main() {',
' vNormal = normalize(normalMatrix * normal);',
' vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);',
' vViewDir = normalize(-mvPosition.xyz);',
' gl_Position = projectionMatrix * mvPosition;',
'}',
].join('\n');
const fragmentShader = [
'varying vec3 vNormal;',
'varying vec3 vViewDir;',
'uniform vec3 uCore;',
'uniform vec3 uRim;',
'uniform float uPower;',
'void main() {',
' float fresnel = pow(1.0 - clamp(dot(normalize(vNormal), normalize(vViewDir)), 0.0, 1.0), uPower);',
' vec3 color = mix(uCore, uRim, fresnel);',
' gl_FragColor = vec4(color, fresnel * 0.5 + 0.5);',
'}',
].join('\n');
const mat = new THREE.ShaderMaterial({
uniforms: {
uCore: { value: new THREE.Color(0x0c1a3a) },
uRim: { value: new THREE.Color(0x5fd0ff) },
uPower: { value: 2.2 },
},
vertexShader,
fragmentShader,
transparent: true,
});
const mesh = new THREE.Mesh(new THREE.IcosahedronGeometry(1.4, 5), mat);
scene.add(mesh);
function resize() { renderer.setSize(innerWidth, innerHeight); camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); }
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
mesh.rotation.y = t * 0.0003;
mesh.rotation.x = Math.sin(t * 0.0002) * 0.4;
renderer.render(scene, camera);
});