<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Solar System Simulation</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="info">
Solar System Simulation<br>
Drag to rotate, Scroll to zoom, Right-drag to pan.
</div>
<div id="container"></div>
<!-- Include Three.js Library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<!-- Include OrbitControls Add-on -->
<script src="https://unpkg.com/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
<!-- Your simulation script -->
<script src="script.js"></script>
</body>
</html>
body {
margin: 0;
font-family: Arial, sans-serif;
background-color: #000000; /* Black space background */
color: #eee;
overflow: hidden; /* Prevent scrollbars from canvas */
}
#container {
width: 100vw;
height: 100vh;
display: block;
}
#info {
position: absolute;
top: 10px;
left: 10px;
padding: 10px;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 5px;
z-index: 100; /* Ensure it's on top */
color: #fff;
text-align: center;
width: auto;
}
// Basic check for Three.js and OrbitControls
if (typeof THREE === 'undefined' || typeof THREE.OrbitControls === 'undefined') {
alert('Error: Three.js or OrbitControls library not loaded!');
} else {
// --- Scene Setup ---
const scene = new THREE.Scene();
// --- Camera Setup ---
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 2000);
camera.position.z = 50; // Start further back
camera.position.y = 20; // Start slightly above the plane
// --- Renderer Setup ---
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio); // Adjust for device resolution
document.getElementById('container').appendChild(renderer.domElement);
// --- Orbit Controls ---
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // Smooths out the controls
controls.dampingFactor = 0.05;
controls.screenSpacePanning = false; // Keep panning relative to world origin
controls.minDistance = 5;
controls.maxDistance = 1000;
// --- Lighting ---
// Sun Light - Acts as the primary light source
const pointLight = new THREE.PointLight(0xffffff, 1.5, 2000); // Strong white light
scene.add(pointLight); // PointLight is automatically placed at (0,0,0)
// Ambient light for faint overall illumination
const ambientLight = new THREE.AmbientLight(0xffffff, 0.1); // Faint white light
scene.add(ambientLight);
// --- Sun Object ---
const sunGeometry = new THREE.SphereGeometry(5, 32, 32); // Larger sphere for Sun
// MeshBasicMaterial ignores lights, good for self-luminous objects
const sunMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00, wireframe: false });
const sunMesh = new THREE.Mesh(sunGeometry, sunMaterial);
scene.add(sunMesh);
// --- Planet Data (Artistic Scale & Simplified Speeds) ---
const planetsData = [
{ name: 'Mercury', radius: 0.5, color: 0xaaaaaa, orbitRadius: 10, speed: 0.040 },
{ name: 'Venus', radius: 0.9, color: 0xffe4b5, orbitRadius: 15, speed: 0.025 },
{ name: 'Earth', radius: 1.0, color: 0x4682b4, orbitRadius: 22, speed: 0.015 },
{ name: 'Mars', radius: 0.7, color: 0xff4500, orbitRadius: 30, speed: 0.010 },
{ name: 'Jupiter', radius: 3.5, color: 0xffa500, orbitRadius: 50, speed: 0.005 },
{ name: 'Saturn', radius: 3.0, color: 0xf4a460, orbitRadius: 75, speed: 0.003, hasRing: true },
{ name: 'Uranus', radius: 2.0, color: 0xadd8e6, orbitRadius: 100, speed: 0.002 },
{ name: 'Neptune', radius: 1.9, color: 0x0000ff, orbitRadius: 130, speed: 0.001 }
];
const planetMeshes = []; // To store planet meshes for potential interaction later
const planetPivots = []; // To store pivot points for easy rotation
// --- Create Planets and Orbits ---
planetsData.forEach(data => {
// Planet Mesh
const geometry = new THREE.SphereGeometry(data.radius, 16, 16);
// Use MeshStandardMaterial so planets react to light
const material = new THREE.MeshStandardMaterial({ color: data.color, roughness: 0.8, metalness: 0.1 });
const planetMesh = new THREE.Mesh(geometry, material);
planetMesh.position.x = data.orbitRadius; // Position planet along the x-axis initially
// Saturn's Ring
if (data.hasRing) {
const ringGeometry = new THREE.RingGeometry(data.radius * 1.3, data.radius * 2, 32);
// Make ring slightly transparent and double-sided
const ringMaterial = new THREE.MeshBasicMaterial({ color: 0xaaaaaa, side: THREE.DoubleSide, transparent: true, opacity: 0.6 });
const ringMesh = new THREE.Mesh(ringGeometry, ringMaterial);
ringMesh.rotation.x = Math.PI / 2; // Rotate ring to be horizontal
planetMesh.add(ringMesh); // Add ring as a child of Saturn mesh
}
// Orbit Path Visualization
const orbitPathGeometry = new THREE.BufferGeometry();
const points = [];
const segments = 128;
for (let i = 0; i <= segments; i++) {
const theta = (i / segments) * Math.PI * 2;
points.push(new THREE.Vector3(Math.cos(theta) * data.orbitRadius, 0, Math.sin(theta) * data.orbitRadius));
}
orbitPathGeometry.setFromPoints(points);
const orbitPathMaterial = new THREE.LineBasicMaterial({ color: 0x444444 }); // Dim grey orbits
const orbitLine = new THREE.Line(orbitPathGeometry, orbitPathMaterial);
// Pivot Point for Rotation
// Create an Object3D to act as the center of rotation for this planet
const pivot = new THREE.Object3D();
pivot.add(planetMesh); // Add the planet mesh to the pivot
scene.add(pivot); // Add the pivot to the main scene
scene.add(orbitLine); // Add the orbit line visualization to the scene
// Store for animation
planetMeshes.push(planetMesh);
planetPivots.push({ pivot: pivot, speed: data.speed });
});
// --- Window Resize Handling ---
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// --- Animation Loop ---
const clock = new THREE.Clock(); // For delta time (smoother animation)
function animate() {
requestAnimationFrame(animate); // Loop animation
const delta = clock.getDelta(); // Time since last frame
// Update planet rotations around the Sun
planetPivots.forEach(item => {
item.pivot.rotation.y += item.speed * delta * 10; // Multiply speed by delta and a factor
});
// Optional: Add self-rotation to planets (axial spin)
planetMeshes.forEach(mesh => {
mesh.rotation.y += 0.05 * delta * 10; // Example: simple same-speed spin
});
// Update controls (needed for damping)
controls.update();
// Render the scene
renderer.render(scene, camera);
}
// --- Start Animation ---
animate();
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.