html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Galaxy Exploration - 3D WebGL</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128/examples/js/controls/OrbitControls.js"></script>
<style>
body { margin: 0; background: black; }
canvas { display: block; }
#info { position: absolute; top: 10px; left: 10px; color: white; font-size: 16px; }
#controls { position: absolute; top: 50px; left: 10px; color: white; font-size: 16px; }
</style>
</head>
<body>
<div id="info"></div>
<div id="controls">
<button onclick="changeSpeed(0.0001)">Slow</button>
<button onclick="changeSpeed(0.001)">Normal</button>
<button onclick="changeSpeed(0.01)">Fast</button>
<button onclick="focusOnBlackHole()">Focus on Black Hole</button>
</div>
<script>
// Initialize scene, camera, renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Add orbit controls for interaction
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// Galaxy Parameters
const galaxyRadius = 50;
const galaxyThickness = 2;
const starCount = 10000;
const spiralArmsCount = 2; // Number of spiral arms
const spiralGeometry = new THREE.BufferGeometry();
const spiralPositions = new Float32Array(starCount * 3);
const starInfo = [];
// Create stars in spiral arms
for (let i = 0; i < starCount; i++) {
const angle = Math.random() * Math.PI * 2;
const arm = Math.floor(Math.random() * spiralArmsCount);
const radius = Math.random() * galaxyRadius;
const armAngle = arm * Math.PI / spiralArmsCount + angle * 2;
// Generate spiral arm positions
spiralPositions[i * 3] = radius * Math.cos(armAngle);
spiralPositions[i * 3 + 1] = (Math.random() - 0.5) * galaxyThickness;
spiralPositions[i * 3 + 2] = radius * Math.sin(armAngle);
// Store star info
starInfo.push({
name: `Star ${i}`,
distance: radius,
size: Math.random() * 0.5 + 0.5, // Random star size
position: new THREE.Vector3(spiralPositions[i * 3], spiralPositions[i * 3 + 1], spiralPositions[i * 3 + 2])
});
}
spiralGeometry.setAttribute('position', new THREE.BufferAttribute(spiralPositions, 3));
const material = new THREE.PointsMaterial({ color: 0xffffff, size: 0.05 });
const galaxy = new THREE.Points(spiralGeometry, material);
scene.add(galaxy);
// Add black hole
const blackHoleGeometry = new THREE.SphereGeometry(2, 32, 32);
const blackHoleMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });
const blackHole = new THREE.Mesh(blackHoleGeometry, blackHoleMaterial);
blackHole.position.set(0, 0, 0);
scene.add(blackHole);
// Set camera position
camera.position.z = 100;
// Create raycaster for star selection
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
// Add event listener for mouse click
window.addEventListener('click', onMouseClick, false);
window.addEventListener('mousemove', onMouseMove, false);
let rotationSpeed = 0.001; // Default speed
function onMouseClick(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// Update raycaster based on mouse position
raycaster.update(camera, renderer.domElement);
// Check for intersection with stars
const intersects = raycaster.intersectObject(galaxy);
if (intersects.length > 0) {
const star = intersects[0].object;
const starIndex = intersects[0].index;
const selectedStar = starInfo[starIndex];
document.getElementById('info').innerHTML = `
<strong>${selectedStar.name}</strong><br>
Distance: ${selectedStar.distance.toFixed(2)} light years<br>
Size: ${selectedStar.size.toFixed(2)} Solar radii
`;
}
}
function onMouseMove(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
function changeSpeed(speed) {
rotationSpeed = speed;
}
function focusOnBlackHole() {
new TWEEN.Tween(camera.position)
.to({ x: 0, y: 0, z: 20 }, 2000)
.easing(TWEEN.Easing.Quadratic.Out)
.start();
}
// Animation loop
function animate() {
requestAnimationFrame(animate);
galaxy.rotation.x += rotationSpeed;
galaxy.rotation.y += rotationSpeed;
controls.update(); // Update the controls
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>