<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reverse Big Bang Simulation - 2025</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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.2.3/howler.min.js"></script>
<style>
body {
margin: 0;
background: linear-gradient(180deg, #0d1b2a, #1b263b); /* Cosmic gradient */
font-family: 'Arial', sans-serif;
overflow: hidden;
}
canvas { display: block; }
/* Control Panel Styling */
.control-panel {
position: fixed;
top: 15px;
left: 15px;
z-index: 10;
background: rgba(27, 38, 59, 0.9); /* Dark blue semi-transparent */
padding: 15px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 255, 255, 0.3);
}
.control-panel label {
color: #e0e1dd; /* Light gray */
font-size: 14px;
display: block;
margin-bottom: 5px;
}
.control-panel input[type="range"] {
width: 200px;
accent-color: #00d4ff; /* Cyan accent */
}
.control-panel input[type="color"] {
width: 50px;
height: 30px;
border: none;
cursor: pointer;
}
.control-panel button {
width: 100px;
padding: 8px;
margin: 5px 0;
background: #415a77; /* Muted blue */
color: #e0e1dd;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background 0.3s;
}
.control-panel button:hover {
background: #778da9; /* Lighter blue on hover */
}
.control-panel span {
color: #00d4ff; /* Cyan text */
margin-left: 10px;
}
/* Timeline Styling */
#timeline {
position: fixed;
bottom: 15px;
left: 15px;
color: #e0e1dd;
font-size: 16px;
z-index: 10;
background: rgba(27, 38, 59, 0.7);
padding: 5px 10px;
border-radius: 5px;
}
/* Data Tooltip */
.tooltip {
position: absolute;
background: rgba(0, 212, 255, 0.9);
color: #0d1b2a;
padding: 5px 10px;
border-radius: 5px;
font-size: 12px;
pointer-events: none;
z-index: 20;
display: none;
}
</style>
</head>
<body>
<div class="control-panel">
<label for="timeSlider">Time Reversal Speed:</label>
<input type="range" id="timeSlider" min="1" max="10" value="5" step="1">
<span id="speedLabel">Speed: 5</span>
<label for="particleColor">Particle Color:</label>
<input type="color" id="particleColor" value="#00d4ff"> <!-- Cyan default -->
<label for="particleSize">Particle Size:</label>
<input type="range" id="particleSize" min="0.1" max="1" value="0.2" step="0.1">
<span id="sizeLabel">Size: 0.2</span>
<button id="pauseBtn">Pause</button>
<button id="resetBtn">Reset</button>
<button id="toggleSound">Mute Sound</button>
</div>
<div id="timeline">Epoch: Big Bang</div>
<div class="tooltip" id="dataTooltip"></div>
<script>
// Scene Setup
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, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Lighting
const ambientLight = new THREE.AmbientLight(0xe0e1dd, 0.4); // Soft white
scene.add(ambientLight);
const pointLight = new THREE.PointLight(0xffffff, 1.5, 100);
pointLight.position.set(10, 10, 10);
scene.add(pointLight);
// Singularity (Big Bang Origin)
const sphereGeometry = new THREE.SphereGeometry(1, 64, 64);
const sphereMaterial = new THREE.MeshPhysicalMaterial({
color: 0xff1a1a, // Bright red
emissive: 0xff1a1a,
emissiveIntensity: 1.5,
metalness: 0.2,
roughness: 0.5
});
const bigBangSphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(bigBangSphere);
// Particle System
const particleCount = 15000; // Increased for more detail
const particleGeometry = new THREE.BufferGeometry();
const particles = new Float32Array(particleCount * 3);
const velocities = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount * 3; i += 3) {
const radius = Math.random() * 100;
const theta = Math.random() * Math.PI * 2;
const phi = Math.acos(2 * Math.random() - 1);
particles[i] = radius * Math.sin(phi) * Math.cos(theta);
particles[i + 1] = radius * Math.sin(phi) * Math.sin(theta);
particles[i + 2] = radius * Math.cos(phi);
velocities[i] = -particles[i] * 0.001; // Initial inward velocity
velocities[i + 1] = -particles[i + 1] * 0.001;
velocities[i + 2] = -particles[i + 2] * 0.001;
}
particleGeometry.setAttribute('position', new THREE.BufferAttribute(particles, 3));
const particleMaterial = new THREE.PointsMaterial({
color: 0x00d4ff, // Cyan
size: 0.2,
transparent: true,
opacity: 0.8
});
const particleSystem = new THREE.Points(particleGeometry, particleMaterial);
scene.add(particleSystem);
camera.position.z = 50;
// Control Variables
let scale = 1;
let contractionRate = 0.05;
let simulationRunning = true;
let soundOn = true;
// DOM Elements
const timeSlider = document.getElementById("timeSlider");
const speedLabel = document.getElementById("speedLabel");
const particleColorPicker = document.getElementById("particleColor");
const particleSizeSlider = document.getElementById("particleSize");
const sizeLabel = document.getElementById("sizeLabel");
const pauseBtn = document.getElementById("pauseBtn");
const resetBtn = document.getElementById("resetBtn");
const toggleSoundBtn = document.getElementById("toggleSound");
const timelineDiv = document.getElementById("timeline");
const tooltip = document.getElementById("dataTooltip");
// Controls
timeSlider.addEventListener("input", () => {
contractionRate = timeSlider.value * 0.01;
speedLabel.innerText = `Speed: ${timeSlider.value}`;
});
particleColorPicker.addEventListener("input", () => {
particleMaterial.color.set(particleColorPicker.value);
});
particleSizeSlider.addEventListener("input", () => {
particleMaterial.size = parseFloat(particleSizeSlider.value);
sizeLabel.innerText = `Size: ${particleSizeSlider.value}`;
});
pauseBtn.addEventListener("click", () => {
simulationRunning = !simulationRunning;
pauseBtn.innerText = simulationRunning ? "Pause" : "Resume";
});
resetBtn.addEventListener("click", () => {
scale = 1;
contractionRate = 0.05;
for (let i = 0; i < particleCount * 3; i += 3) {
const radius = Math.random() * 100;
const theta = Math.random() * Math.PI * 2;
const phi = Math.acos(2 * Math.random() - 1);
particles[i] = radius * Math.sin(phi) * Math.cos(theta);
particles[i + 1] = radius * Math.sin(phi) * Math.sin(theta);
particles[i + 2] = radius * Math.cos(phi);
velocities[i] = -particles[i] * 0.001;
velocities[i + 1] = -particles[i + 1] * 0.001;
velocities[i + 2] = -particles[i + 2] * 0.001;
}
particleGeometry.attributes.position.needsUpdate = true;
simulationRunning = true;
pauseBtn.innerText = "Pause";
});
toggleSoundBtn.addEventListener("click", () => {
soundOn = !soundOn;
toggleSoundBtn.innerText = soundOn ? "Mute Sound" : "Unmute Sound";
soundOn ? sound.play() : sound.pause();
});
// Sound
const sound = new Howl({
src: ['https://www.soundjay.com/buttons/beep-01a.mp3'], // Placeholder sound
volume: 0.3,
loop: true,
});
sound.play();
// Timeline Events
const events = [
{ time: 0, label: "Big Bang", desc: "The universe begins." },
{ time: 0.1, label: "Cosmic Inflation", desc: "Rapid expansion occurs." },
{ time: 0.5, label: "First Stars", desc: "Stars begin to form." },
{ time: 1, label: "Galaxies Form", desc: "Galaxies take shape." },
{ time: 2, label: "CMB Radiation", desc: "Cosmic background radiation emerges." },
{ time: 3, label: "Mature Universe", desc: "Universe stabilizes." },
];
function updateTimeline(time) {
let eventLabel = "Epoch: ";
events.forEach(event => {
if (time >= event.time) eventLabel = `Epoch: ${event.label}`;
});
timelineDiv.innerText = eventLabel;
}
// Clickable Data Points
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
window.addEventListener('mousemove', (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(bigBangSphere);
if (intersects.length > 0) {
tooltip.style.display = 'block';
tooltip.style.left = `${event.clientX + 10}px`;
tooltip.style.top = `${event.clientY + 10}px`;
tooltip.innerText = `Singularity\nScale: ${scale.toFixed(2)}`;
} else {
tooltip.style.display = 'none';
}
});
window.addEventListener('click', (event) => {
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(bigBangSphere);
if (intersects.length > 0) {
alert(`Singularity Data:\nScale: ${scale.toFixed(2)}\nTime: ${(3 - scale).toFixed(2)} units`);
}
});
// Animation Loop
function animate() {
requestAnimationFrame(animate);
if (simulationRunning) {
scale -= contractionRate;
if (scale < 0.1) scale = 0.1;
bigBangSphere.scale.set(scale, scale, scale);
const positions = particleGeometry.attributes.position.array;
for (let i = 0; i < particleCount * 3; i += 3) {
positions[i] += velocities[i];
positions[i + 1] += velocities[i + 1];
positions[i + 2] += velocities[i + 2];
const dist = Math.sqrt(positions[i] ** 2 + positions[i + 1] ** 2 + positions[i + 2] ** 2);
if (dist < 1) {
velocities[i] = velocities[i + 1] = velocities[i + 2] = 0; // Stop at singularity
}
}
particleGeometry.attributes.position.needsUpdate = true;
updateTimeline(3 - scale); // Reverse timeline
controls.update();
renderer.render(scene, camera);
}
}
animate();
// Resize Handling
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
</script>
</body>
</html>