1(function () { 2 // ââ Mars Globe ââ 3 const canvas = document.getElementById('mars-canvas'); 4 const renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true }); 5 renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); 6 7 const scene = new THREE.Scene(); 8 const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100); 9 camera.position.z = 2.8; 10 11 // Sphere 12 const geo = new THREE.SphereGeometry(1, 64, 64); 13 14 // Procedural Mars texture using canvas 15 const texCanvas = document.createElement('canvas'); 16 texCanvas.width = 512; texCanvas.height = 256; 17 const ctx = texCanvas.getContext('2d'); 18 19 // Base color 20 const grad = ctx.createLinearGradient(0, 0, 512, 256); 21 grad.addColorStop(0, '#7a2a10'); 22 grad.addColorStop(0.3, '#a33a18'); 23 grad.addColorStop(0.6, '#8b3012'); 24 grad.addColorStop(1, '#6a2208'); 25 ctx.fillStyle = grad; 26 ctx.fillRect(0, 0, 512, 256); 27 28 // Add noise-like craters / terrain 29 for (let i = 0; i < 800; i++) { 30 const x = Math.random() * 512; 31 const y = Math.random() * 256; 32 const r = Math.random() * 18 + 1; 33 const brightness = Math.random() > 0.5 ? 1.15 : 0.82; 34 const cg = ctx.createRadialGradient(x, y, 0, x, y, r); 35 const base = 'rgba(' + Math.floor(140*brightness) + ',' + Math.floor(50*brightness) + ',' + Math.floor(20*brightness); 36 cg.addColorStop(0, base + ',0.45)'); 37 cg.addColorStop(1, base + ',0)'); 38 ctx.fillStyle = cg; 39 ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2); ctx.fill(); 40 } 41 42 const texture = new THREE.CanvasTexture(texCanvas); 43 const mat = new THREE.MeshStandardMaterial({ 44 map: texture, 45 roughness: 0.85, 46 metalness: 0.05, 47 }); 48 const sphere = new THREE.Mesh(geo, mat); 49 sphere.position.set(3.2, -0.3, -1); 50 scene.add(sphere); 51 52 // Atmosphere glow 53 const atmGeo = new THREE.SphereGeometry(1.06, 32, 32); 54 const atmMat = new THREE.MeshBasicMaterial({ 55 color: new THREE.Color('#c8451a'), 56 transparent: true, 57 opacity: 0.08, 58 side: THREE.BackSide, 59 }); 60 const atm = new THREE.Mesh(atmGeo, atmMat); 61 atm.position.copy(sphere.position); 62 scene.add(atm); 63 64 // Stars 65 const starGeo = new THREE.BufferGeometry(); 66 const starCount = 1200; 67 const positions = new Float32Array(starCount * 3); 68 for (let i = 0; i < starCount * 3; i++) { 69 positions[i] = (Math.random() - 0.5) * 80; 70 } 71 starGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3)); 72 const starMat = new THREE.PointsMaterial({ color: 0xffffff, size: 0.04 }); 73 scene.add(new THREE.Points(starGeo, starMat)); 74 75 // Lights 76 scene.add(new THREE.AmbientLight(0xffffff, 0.18)); 77 const sun = new THREE.DirectionalLight(0xffddbb, 1.4); 78 sun.position.set(5, 2, 4); 79 scene.add(sun); 80 81 // Resize 82 function resize() { 83 const w = canvas.clientWidth, h = canvas.clientHeight; 84 renderer.setSize(w, h, false); 85 camera.aspect = w / h; 86 camera.updateProjectionMatrix(); 87 } 88 window.addEventListener('resize', resize); 89 resize(); 90 91 // Mouse parallax 92 let mx = 0, my = 0; 93 window.addEventListener('mousemove', function (e) { 94 mx = (e.clientX / window.innerWidth - 0.5) * 0.04; 95 my = (e.clientY / window.innerHeight - 0.5) * 0.02; 96 }); 97 98 let t = 0; 99 (function animate() { 100 requestAnimationFrame(animate); 101 t += 0.004; 102 sphere.rotation.y = t; 103 sphere.position.x = 3.2 + mx; 104 sphere.position.y = -0.3 + my; 105 atm.position.copy(sphere.position); 106 renderer.render(scene, camera); 107 })(); 108 109 // ââ Scroll reveal ââ 110 var observer = new IntersectionObserver(function (entries) { 111 entries.forEach(function (e) { if (e.isIntersecting) { e.target.classList.add('visible'); } }); 112 }, { threshold: 0.1 }); 113 document.querySelectorAll('.reveal').forEach(function (el) { observer.observe(el); }); 114})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.