______________
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Air Particle Simulation</title>
    <style>
        body {
            display: flex;
            flex-direction: column;
            align-items: center;
            font-family: sans-serif;
            background-color: #f0f0f0;
            padding: 20px;
        }
        #canvas-container {
            border: 1px solid #ccc;
            background-color: #fff;
            margin-bottom: 20px;
        }
        #particleCanvas {
            display: block; /* Remove extra space below canvas */
        }
        .controls {
            display: flex;
            gap: 20px;
            width: 80%;
            max-width: 600px;
            justify-content: center;
        }
        .slider-group {
            display: flex;
            flex-direction: column;
            flex: 1;
        }
        .slider-group label {
            margin-bottom: 5px;
            font-weight: bold;
        }
        .slider-group input[type="range"] {
            width: 100%;
        }
    </style>
</head>
<body>

    <h1>Air Particle Simulation</h1>

    <div id="canvas-container">
        <canvas id="particleCanvas" width="600" height="400"></canvas>
    </div>

    <div class="controls">
        <div class="slider-group">
            <label for="temperatureSlider">Temperature: <span id="tempValue">10</span></label>
            <input type="range" id="temperatureSlider" min="1" max="20" value="10" step="1">
        </div>
        <div class="slider-group">
            <label for="pressureSlider">Pressure: <span id="pressureValue">5</span></label>
            <input type="range" id="pressureSlider" min="1" max="10" value="5" step="1">
        </div>
    </div>

    <script>
        const canvas = document.getElementById('particleCanvas');
        const ctx = canvas.getContext('2d');
        const temperatureSlider = document.getElementById('temperatureSlider');
        const pressureSlider = document.getElementById('pressureSlider');
        const tempValueSpan = document.getElementById('tempValue');
        const pressureValueSpan = document.getElementById('pressureValue');

        const canvasWidth = canvas.width;
        const canvasHeight = canvas.height;
        const numParticles = 50; // Number of particles
        const particleRadius = 3;

        let particles = [];
        let temperature = parseFloat(temperatureSlider.value);
        let pressure = parseFloat(pressureSlider.value);

        // --- Particle Class ---
        class Particle {
            constructor() {
                this.x = Math.random() * (canvasWidth - particleRadius * 2) + particleRadius;
                this.y = Math.random() * (canvasHeight - particleRadius * 2) + particleRadius;
                this.vx = (Math.random() * 2 - 1) * 1; // Initial velocity X
                this.vy = (Math.random() * 2 - 1) * 1; // Initial velocity Y
                this.color = 'blue';
            }

            move() {
                this.x += this.vx;
                this.y += this.vy;

                // Collision detection with walls
                if (this.x + particleRadius > canvasWidth || this.x - particleRadius < 0) {
                    this.vx = -this.vx;
                    // Prevent particle from getting stuck in wall
                    if (this.x + particleRadius > canvasWidth) this.x = canvasWidth - particleRadius;
                    else this.x = particleRadius;
                }
                if (this.y + particleRadius > canvasHeight || this.y - particleRadius < 0) {
                    this.vy = -this.vy;
                    // Prevent particle from getting stuck in wall
                    if (this.y + particleRadius > canvasHeight) this.y = canvasHeight - particleRadius;
                    else this.y = particleRadius;
                }
            }

            draw() {
                ctx.beginPath();
                ctx.arc(this.x, this.y, particleRadius, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.fill();
                ctx.closePath();
            }
        }

        // --- Initialization ---
        function initParticles() {
            particles = [];
            for (let i = 0; i < numParticles; i++) {
                particles.push(new Particle());
            }
            updateParticleVelocity(); // Initial velocity based on sliders
        }

        // --- Update Particle Velocity based on Temperature and Pressure ---
        function updateParticleVelocity() {
            // Temperature affects average kinetic energy (speed)
            // Pressure affects collision frequency and force (can also influence speed in a simplified model)
            
            // Base velocity
            let baseVelocity = 1;

            // Add a factor based on temperature (higher temp = higher speed)
            let tempFactor = temperature * 0.5; // Adjust multiplier as needed

            // Add a factor based on pressure (higher pressure = more collisions, potentially higher speed)
            // In a simplified model, pressure can directly increase speed slightly.
            // A more ideal gas model relates pressure and temperature to kinetic energy (which is proportional to temperature).
            // Here, we use pressure as a factor influencing speed directly, combining both concepts.
            let pressureFactor = pressure * 0.2; // Adjust multiplier as needed

            // Combine factors to determine velocity magnitude
            let velocityMagnitude = baseVelocity + tempFactor + pressureFactor;

            // Apply velocity magnitude to all particles
            particles.forEach(p => {
                // Randomize direction as well
                const angle = Math.random() * Math.PI * 2;
                p.vx = Math.cos(angle) * velocityMagnitude;
                p.vy = Math.sin(angle) * velocityMagnitude;
            });
        }

        // --- Animation Loop ---
        function animate() {
            // Clear the canvas
            ctx.clearRect(0, 0, canvasWidth, canvasHeight);

            // Update and draw particles
            particles.forEach(p => {
                p.move();
                p.draw();
            });

            // Request the next frame
            requestAnimationFrame(animate);
        }

        // --- Event Listeners ---
        temperatureSlider.addEventListener('input', (event) => {
            temperature = parseFloat(event.target.value);
            tempValueSpan.textContent = temperature;
            updateParticleVelocity();
        });

        pressureSlider.addEventListener('input', (event) => {
            pressure = parseFloat(event.target.value);
            pressureValueSpan.textContent = pressure;
            updateParticleVelocity();
        });

        // --- Initialize Simulation ---
        initParticles();
        tempValueSpan.textContent = temperature;
        pressureValueSpan.textContent = pressure;
        animate();

    </script>

</body>
</html>
________________
Implement the following in the above html file:
______________
Below is the smallest possible change set that turns the “fake” collision logic into a physically-sound, perfectly elastic 2-D collision between equal-mass disks.  
Only two blocks are added / modified:

1. A new `handleParticleCollisions()` routine (added just under `updateParticleVelocity()`).
2. A tiny rewrite of the animation loop so we first move everything, then resolve collisions, and finally draw.

Everything else stays exactly the same.

```html
<!-- ‑---------------  unchanged code above  ‑--------------- -->
<script>
    /* … all the code that is already in the page … */

    // --- Update Particle Velocity based on Temperature and Pressure ---
    function updateParticleVelocity() {
        …
    }

    // -----------------------------------------------------------------
    //  NEW :  perfectly-elastic, equal-mass particle–particle collisions
    // -----------------------------------------------------------------
    function handleParticleCollisions() {
        const minDist = particleRadius * 2;

        for (let i = 0; i < particles.length; i++) {
            for (let j = i + 1; j < particles.length; j++) {
                const p1 = particles[i];
                const p2 = particles[j];

                const dx = p2.x - p1.x;
                const dy = p2.y - p1.y;
                const dist = Math.hypot(dx, dy) || 0.0001;   // avoid 0-division

                if (dist < minDist) {          // --- they overlap → collide ---
                    /* 1. push the two disks so they are just touching */
                    const overlap = (minDist - dist) / 2;
                    const nx = dx / dist;      // normalised collision normal
                    const ny = dy / dist;

                    p1.x -= nx * overlap;
                    p1.y -= ny * overlap;
                    p2.x += nx * overlap;
                    p2.y += ny * overlap;

                    /* 2. elastic response (equal mass, restitution = 1) */
                    const dvx = p1.vx - p2.vx;
                    const dvy = p1.vy - p2.vy;
                    const vn  = dvx * nx + dvy * ny; // velocity along normal

                    if (vn > 0) continue;  // already separating

                    // impulse scalar for equal masses (m1 = m2 = 1)
                    const impulse = -2 * vn / 2;

                    const ix = impulse * nx;
                    const iy = impulse * ny;

                    p1.vx += ix;
                    p1.vy += iy;
                    p2.vx -= ix;
                    p2.vy -= iy;
                }
            }
        }
    }

    // ---------------------------- Animation Loop ----------------------------
    function animate() {
        ctx.clearRect(0, 0, canvasWidth, canvasHeight);

        // 1. move all particles
        particles.forEach(p => p.move());

        // 2. resolve particle–particle collisions
        handleParticleCollisions();

        // 3. draw the updated state
        particles.forEach(p => p.draw());

        requestAnimationFrame(animate);
    }

    /* … rest of the file (event listeners, init, etc.) … */
</script>
```

What changed and why:

• The double-loop inside `handleParticleCollisions()` checks every unique pair once (`i + 1 …`) so work is O(n²) but no pair is handled twice.

• When two centres are closer than `2 × radius`, the particles overlap – we
  1. Separate them along the line connecting their centres (to avoid sticking),
  2. Compute the normal component of their relative velocity and apply a
     perfectly elastic impulse (`restitution = 1`).  
   Because all particles have identical mass (=1), the impulse simplifies to
   `-2 vn / (m1 + m2) = ‑2 vn / 2`.

• The animation order was switched to “move ➜ collide ➜ draw”, ensuring that the frame shown on screen already contains the corrected post-collision positions and velocities.

Open the page and the blue dots now bounce realistically off each other and the walls, at speeds dictated by the Temperature and Pressure sliders.