test

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Differential Equations: Gravity Simulator</title>
    <style>
        body { margin: 0; overflow: hidden; font-family: Arial, sans-serif; }
        canvas { display: block; }
        #ui {
            position: absolute;
            top: 10px;
            left: 10px;
            color: white;
            background: rgba(0,0,0,0.7);
            padding: 10px;
            border-radius: 5px;
            max-width: 300px;
        }
        #controls {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(0,0,0,0.7);
            padding: 10px;
            border-radius: 10px;
            color: white;
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 10px;
        }
        button {
            padding: 8px 15px;
            background: #4CAF50;
            border: none;
            border-radius: 4px;
            color: white;
            cursor: pointer;
        }
        button:hover { background: #45a049; }
        .slider-container {
            margin: 5px 0;
        }
        .slider-container label {
            display: inline-block;
            width: 120px;
        }
        #planet-info {
            margin-top: 10px;
        }
        #graph-container {
            position: absolute;
            top: 10px;
            right: 10px;
            width: 300px;
            height: 200px;
            background: rgba(0,0,0,0.5);
        }
    </style>
</head>
<body>
    <div id="ui">
        <h2>Gravity Simulator: Solving d²r/dt² = GM/r²</h2>
        <p>Click to add planets. Adjust mass/velocity to change orbits.</p>
        <div id="planet-info"></div>
    </div>

    <div id="controls">
        <button id="add-planet">🪐 Add Planet</button>
        <button id="pause-btn">⏸️ Pause</button>
        <button id="step-btn">⏯️ Step Frame</button>
        <button id="reset-btn">🔄 Reset</button>
        
        <div class="slider-container">
            <label for="mass-slider">Mass:</label>
            <input type="range" id="mass-slider" min="1" max="100" value="10">
            <span id="mass-value">10</span>
        </div>
        
        <div class="slider-container">
            <label for="speed-slider">Initial Speed:</label>
            <input type="range" id="speed-slider" min="0" max="5" step="0.1" value="1">
            <span id="speed-value">1</span>
        </div>
    </div>

    <div id="graph-container"></div>

    <!-- Three.js & Plotly for graphs -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/controls/OrbitControls.js"></script>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>

    <script>
        // Scene setup
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x000033);
        
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 20, 30);
        camera.lookAt(0, 0, 0);
        
        const renderer = new THREE.WebGLRenderer({ antialias: 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(0x404040);
        scene.add(ambientLight);
        
        const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.set(1, 1, 1);
        scene.add(directionalLight);
        
        // Central star (fixed gravity source)
        const starGeometry = new THREE.SphereGeometry(2, 32, 32);
        const starMaterial = new THREE.MeshPhongMaterial({ 
            color: 0xFFFF00,
            emissive: 0xFFFF00,
            emissiveIntensity: 0.5
        });
        const star = new THREE.Mesh(starGeometry, starMaterial);
        scene.add(star);
        
        // Physics variables
        const G = 6.67430e-11; // Gravitational constant
        const planets = [];
        let isPaused = false;
        let currentMass = 10;
        let currentSpeed = 1;
        
        // Planet class (solves differential equations)
        class Planet {
            constructor(mass, position, velocity) {
                this.mass = mass;
                this.position = position.clone();
                this.velocity = velocity.clone();
                this.radius = Math.cbrt(mass) * 0.3;
                
                // Create 3D mesh
                this.geometry = new THREE.SphereGeometry(this.radius, 16, 16);
                this.material = new THREE.MeshPhongMaterial({ 
                    color: new THREE.Color(Math.random() * 0xFFFFFF) 
                });
                this.mesh = new THREE.Mesh(this.geometry, this.material);
                this.mesh.position.copy(position);
                scene.add(this.mesh);
                
                // Store trajectory points
                this.trajectory = [];
                this.trajectoryLine = null;
            }
            
            // Solve F = ma (d²r/dt² = -GM/r²)
            update(dt) {
                const r = this.position.length();
                const acceleration = this.position.clone()
                    .normalize()
                    .multiplyScalar(-G * 1000 / (r * r)); // Scaled for visualization
                
                this.velocity.add(acceleration.multiplyScalar(dt));
                this.position.add(this.velocity.clone().multiplyScalar(dt));
                this.mesh.position.copy(this.position);
                
                // Update trajectory
                this.trajectory.push(this.position.clone());
                if (this.trajectory.length > 1000) this.trajectory.shift();
                
                if (this.trajectory.length > 1) {
                    if (this.trajectoryLine) scene.remove(this.trajectoryLine);
                    const lineGeometry = new THREE.BufferGeometry().setFromPoints(this.trajectory);
                    const lineMaterial = new THREE.LineBasicMaterial({ color: 0xFFFFFF, transparent: true, opacity: 0.5 });
                    this.trajectoryLine = new THREE.Line(lineGeometry, lineMaterial);
                    scene.add(this.trajectoryLine);
                }
            }
        }
        
        // Add a new planet
        function addPlanet() {
            const position = new THREE.Vector3(
                (Math.random() - 0.5) * 20,
                0,
                (Math.random() - 0.5) * 20
            );
            
            // Set initial velocity (tangential to star)
            const direction = new THREE.Vector3(-position.z, 0, position.x).normalize();
            const velocity = direction.multiplyScalar(currentSpeed);
            
            const planet = new Planet(currentMass, position, velocity);
            planets.push(planet);
            
            document.getElementById("planet-info").innerHTML = 
                `Planets: ${planets.length}<br>Mass: ${currentMass}<br>Speed: ${currentSpeed.toFixed(1)}`;
        }
        
        // Update physics
        function updatePhysics(dt) {
            planets.forEach(planet => planet.update(dt));
            updateGraph();
        }
        
        // Energy graph (Plotly)
        function updateGraph() {
            if (planets.length === 0) return;
            
            const planet = planets[0];
            const r = planet.position.length();
            const v = planet.velocity.length();
            
            // Kinetic energy: KE = ½mv²
            const KE = 0.5 * planet.mass * v * v;
            
            // Potential energy: PE = -GMm/r
            const PE = -G * 1000 * planet.mass / r;
            
            const data = [{
                y: [KE, PE, KE + PE],
                type: 'bar',
                name: 'Energy',
                marker: { color: ['#FF5733', '#33FF57', '#3357FF'] }
            }];
            
            Plotly.newPlot('graph-container', data, {
                title: 'Energy Conservation (KE + PE = Constant)',
                barmode: 'stack'
            });
        }
        
        // Event listeners
        document.getElementById("add-planet").addEventListener("click", addPlanet);
        document.getElementById("pause-btn").addEventListener("click", () => {
            isPaused = !isPaused;
            document.getElementById("pause-btn").textContent = isPaused ? "▶️ Play" : "⏸️ Pause";
        });
        document.getElementById("step-btn").addEventListener("click", () => {
            if (isPaused) updatePhysics(0.1);
        });
        document.getElementById("reset-btn").addEventListener("click", () => {
            planets.forEach(planet => scene.remove(planet.mesh));
            planets.length = 0;
            document.getElementById("planet-info").textContent = "";
        });
        
        document.getElementById("mass-slider").addEventListener("input", (e) => {
            currentMass = parseFloat(e.target.value);
            document.getElementById("mass-value").textContent = currentMass;
        });
        
        document.getElementById("speed-slider").addEventListener("input", (e) => {
            currentSpeed = parseFloat(e.target.value);
            document.getElementById("speed-value").textContent = currentSpeed;
        });
        
        // Animation loop
        let lastTime = 0;
        function animate(currentTime) {
            requestAnimationFrame(animate);
            
            const deltaTime = (currentTime - lastTime) / 1000; // Convert to seconds
            lastTime = currentTime;
            
            if (!isPaused && deltaTime < 0.1) {
                updatePhysics(deltaTime);
            }
            
            controls.update();
            renderer.render(scene, camera);
        }
        
        animate(0);
        
        // Handle window resize
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });
    </script>
</body>
</html>
Scroll to Top