Trace: start

This is an old revision of the document!


Why This Page?

Welcome to my project journal, my place for tracking, organizing, and sharing projects.

It is not a landing page for my personal brand. It is maintained as a digital garden - pruned, reshaped, parts wild, parts neat - for ongoing work, research, and ideas.

The site is meant to serve as both a personal archive and a way to share my work with collaborators and visitors like you.

It’s built with simplicity and functionality in mind.

For your own safety, use the Ramble Meter as an indicator of the state of the information in a post.

<html lang=“en”> <head>

  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Interactive Double Slit Experiment</title>
  <style>
      body {
          font-family: Arial, sans-serif;
          max-width: 900px;
          margin: 0 auto;
          padding: 20px;
          background-color: #f7f7f7;
      }
      .container {
          background-color: white;
          border-radius: 8px;
          padding: 20px;
          box-shadow: 0 2px 10px rgba(0,0,0,0.1);
      }
      h1 {
          color: #333;
          text-align: center;
      }
      .controls {
          display: grid;
          grid-template-columns: 1fr 1fr;
          gap: 20px;
          margin-bottom: 20px;
      }
      .control-group {
          background-color: #f9f9f9;
          padding: 15px;
          border-radius: 6px;
      }
      .control-title {
          font-weight: bold;
          margin-bottom: 10px;
      }
      .slider-container {
          margin-bottom: 10px;
      }
      .slider-container label {
          display: block;
          margin-bottom: 5px;
      }
      .slider-container input[type="range"] {
          width: 100%;
      }
      .slider-value {
          font-weight: bold;
          margin-left: 5px;
      }
      canvas {
          display: block;
          margin: 0 auto;
          border: 1px solid #ddd;
          background-color: #000;
      }
      .explanation {
          margin-top: 20px;
          background-color: #f0f7ff;
          padding: 15px;
          border-radius: 6px;
          border-left: 4px solid #3498db;
      }
      .checkbox-container {
          margin-top: 10px;
      }
      button {
          background-color: #4CAF50;
          color: white;
          border: none;
          padding: 8px 16px;
          border-radius: 4px;
          cursor: pointer;
          font-size: 14px;
          margin-right: 10px;
      }
      button:hover {
          background-color: #45a049;
      }
      .button-container {
          text-align: center;
          margin: 15px 0;
      }
  </style>

</head> <body>

  <div class="container">
      <h1>Interactive Double Slit Experiment</h1>
      
      <div class="controls">
          <div class="control-group">
              <div class="control-title">Slit Configuration</div>
              <div class="slider-container">
                  <label for="slitCount">Number of Slits: <span id="slitCountValue" class="slider-value">2</span></label>
                  <input type="range" id="slitCount" min="1" max="10" value="2" step="1">
              </div>
              <div class="slider-container">
                  <label for="slitWidth">Slit Width: <span id="slitWidthValue" class="slider-value">10</span> nm</label>
                  <input type="range" id="slitWidth" min="5" max="50" value="10" step="1">
              </div>
              <div class="slider-container">
                  <label for="slitSeparation">Slit Separation: <span id="slitSeparationValue" class="slider-value">100</span> nm</label>
                  <input type="range" id="slitSeparation" min="30" max="300" value="100" step="10">
              </div>
          </div>
          
          <div class="control-group">
              <div class="control-title">Wave Properties</div>
              <div class="slider-container">
                  <label for="wavelength">Wavelength: <span id="wavelengthValue" class="slider-value">500</span> nm</label>
                  <input type="range" id="wavelength" min="400" max="700" value="500" step="5">
              </div>
              <div class="slider-container">
                  <label for="intensity">Intensity: <span id="intensityValue" class="slider-value">100</span>%</label>
                  <input type="range" id="intensity" min="10" max="100" value="100" step="5">
              </div>
              <div class="checkbox-container">
                  <input type="checkbox" id="showIndividual">
                  <label for="showIndividual">Show Individual Slit Patterns</label>
              </div>
          </div>
      </div>
      
      <div class="button-container">
          <button id="animateBtn">Start Animation</button>
          <button id="resetBtn">Reset</button>
      </div>
      
      <canvas id="slitCanvas" width="800" height="400"></canvas>
      
      <div class="explanation">
          <h3>About the Double Slit Experiment</h3>
          <p>The double slit experiment demonstrates the wave-particle duality of light and matter. When light passes through two narrow slits, an interference pattern appears on the screen behind - alternating bright and dark bands called fringes.</p>
          <p>This interference pattern occurs because light behaves as a wave, with waves from each slit interfering with each other. Where waves are in phase (crests align), they create bright fringes through constructive interference. Where they are out of phase (crests meet troughs), they create dark fringes through destructive interference.</p>
          <p>Try changing the parameters to see how the interference pattern changes:</p>
          <ul>
              <li><strong>Number of Slits:</strong> More slits create sharper, more complex patterns</li>
              <li><strong>Slit Width:</strong> Wider slits produce less pronounced diffraction effects</li>
              <li><strong>Slit Separation:</strong> Greater separation creates narrower fringes</li>
              <li><strong>Wavelength:</strong> Longer wavelengths create wider fringes</li>
          </ul>
      </div>
  </div>
  <script>
      // Canvas and context
      const canvas = document.getElementById('slitCanvas');
      const ctx = canvas.getContext('2d');
      
      // Controls
      const slitCountSlider = document.getElementById('slitCount');
      const slitWidthSlider = document.getElementById('slitWidth');
      const slitSeparationSlider = document.getElementById('slitSeparation');
      const wavelengthSlider = document.getElementById('wavelength');
      const intensitySlider = document.getElementById('intensity');
      const showIndividualCheckbox = document.getElementById('showIndividual');
      const animateBtn = document.getElementById('animateBtn');
      const resetBtn = document.getElementById('resetBtn');
      
      // Value displays
      const slitCountValue = document.getElementById('slitCountValue');
      const slitWidthValue = document.getElementById('slitWidthValue');
      const slitSeparationValue = document.getElementById('slitSeparationValue');
      const wavelengthValue = document.getElementById('wavelengthValue');
      const intensityValue = document.getElementById('intensityValue');
      
      // Animation variables
      let animationId = null;
      let isAnimating = false;
      let time = 0;
      
      // Constants
      const SCREEN_DISTANCE = 1000; // Distance from slits to screen in nm
      
      // Initialize the canvas
      function initCanvas() {
          ctx.fillStyle = 'black';
          ctx.fillRect(0, 0, canvas.width, canvas.height);
          
          // Draw slits
          drawSlits();
          
          // Draw initial pattern
          drawInterferencePattern();
      }
      
      // Draw the slits on the left side of the canvas
      function drawSlits() {
          const slitCount = parseInt(slitCountSlider.value);
          const slitWidth = parseInt(slitWidthSlider.value);
          const slitSeparation = parseInt(slitSeparationSlider.value);
          
          // Clear the slit area
          ctx.fillStyle = 'black';
          ctx.fillRect(0, 0, 30, canvas.height);
          
          // Draw barrier
          ctx.fillStyle = '#555';
          ctx.fillRect(20, 0, 10, canvas.height);
          
          // Calculate total height of all slits and spaces
          const totalHeight = (slitCount * slitWidth) + ((slitCount - 1) * slitSeparation);
          const startY = (canvas.height - totalHeight) / 2;
          
          // Draw slits
          ctx.fillStyle = 'white';
          for (let i = 0; i < slitCount; i++) {
              const slitY = startY + i * (slitWidth + slitSeparation);
              ctx.fillRect(20, slitY, 10, slitWidth);
          }
      }
      
      // Calculate the intensity at a given point on the screen
      function calculateIntensity(y) {
          const slitCount = parseInt(slitCountSlider.value);
          const slitWidth = parseInt(slitWidthSlider.value) / 10; // Convert to suitable units
          const slitSeparation = parseInt(slitSeparationSlider.value) / 10; // Convert to suitable units
          const wavelength = parseInt(wavelengthSlider.value) / 100; // Convert to suitable units
          const intensity = parseInt(intensitySlider.value) / 100;
          
          // Calculate center position of the slits
          const centerPosition = canvas.height / 2;
          
          // Calculate the total intensity from all slits
          let totalIntensity = 0;
          let individualIntensities = [];
          
          // Calculate the center position of the first slit
          const firstSlitCenter = centerPosition - (slitCount - 1) * (slitWidth + slitSeparation) / 2;
          
          for (let i = 0; i < slitCount; i++) {
              // Calculate the position of the current slit
              const slitCenter = firstSlitCenter + i * (slitWidth + slitSeparation);
              
              // Calculate the path difference
              const pathDifference = Math.abs(y - slitCenter) * wavelength / SCREEN_DISTANCE;
              
              // Calculate the phase difference
              const phaseDifference = 2 * Math.PI * pathDifference / wavelength;
              
              // Calculate the amplitude contribution from this slit
              const amplitude = Math.cos(phaseDifference + time);
              
              // Add to total intensity
              totalIntensity += amplitude;
              
              // Store individual slit intensity
              individualIntensities.push(amplitude);
          }
          
          // Square the amplitude to get intensity
          const resultIntensity = Math.pow(totalIntensity, 2) * intensity;
          
          // Return the intensity and individual intensities
          return {
              total: resultIntensity,
              individual: individualIntensities.map(amp => Math.pow(amp, 2) * intensity)
          };
      }
      
      // Draw the interference pattern
      function drawInterferencePattern() {
          const showIndividual = showIndividualCheckbox.checked;
          
          // Clear the pattern area
          ctx.fillStyle = 'black';
          ctx.fillRect(40, 0, canvas.width - 40, canvas.height);
          
          // Draw the intensity pattern
          const imageData = ctx.createImageData(canvas.width - 50, canvas.height);
          
          for (let x = 0; x < canvas.width - 50; x++) {
              for (let y = 0; y < canvas.height; y++) {
                  const screenY = y;
                  const { total, individual } = calculateIntensity(screenY);
                  
                  // Convert intensity to color (0-255)
                  let intensity = Math.min(255, Math.max(0, total * 255));
                  
                  // Set pixel color based on position and intensity
                  const pixelIndex = (y * (canvas.width - 50) + x) * 4;
                  
                  // Gradient color based on position and wavelength
                  const wavelength = parseInt(wavelengthSlider.value);
                  let r, g, b;
                  
                  // Simple wavelength to RGB approximation
                  if (wavelength < 480) {
                      // Blue to violet
                      r = intensity * (wavelength - 400) / 80;
                      g = 0;
                      b = intensity;
                  } else if (wavelength < 510) {
                      // Blue to green
                      r = 0;
                      g = intensity * (wavelength - 480) / 30;
                      b = intensity * (510 - wavelength) / 30;
                  } else if (wavelength < 580) {
                      // Green to yellow
                      r = intensity * (wavelength - 510) / 70;
                      g = intensity;
                      b = 0;
                  } else if (wavelength < 645) {
                      // Yellow to red
                      r = intensity;
                      g = intensity * (645 - wavelength) / 65;
                      b = 0;
                  } else {
                      // Red
                      r = intensity;
                      g = 0;
                      b = 0;
                  }
                  
                  // Add visual effect to illustrate interference pattern
                  const distance = Math.abs(x - (canvas.width - 50) / 2);
                  const falloff = 1 - Math.min(1, distance / 300);
                  
                  r *= falloff;
                  g *= falloff;
                  b *= falloff;
                  
                  imageData.data[pixelIndex] = r;
                  imageData.data[pixelIndex + 1] = g;
                  imageData.data[pixelIndex + 2] = b;
                  imageData.data[pixelIndex + 3] = 255;
              }
          }
          
          ctx.putImageData(imageData, 50, 0);
          
          // Draw intensity graph on the right side
          ctx.strokeStyle = 'white';
          ctx.lineWidth = 2;
          ctx.beginPath();
          
          const graphWidth = 150;
          const graphX = canvas.width - graphWidth;
          
          for (let y = 0; y < canvas.height; y++) {
              const { total, individual } = calculateIntensity(y);
              const intensity = total * graphWidth * 0.8;
              
              if (y === 0) {
                  ctx.moveTo(graphX + intensity, y);
              } else {
                  ctx.lineTo(graphX + intensity, y);
              }
          }
          
          ctx.stroke();
          
          // Draw individual slit patterns if requested
          if (showIndividual) {
              const slitCount = parseInt(slitCountSlider.value);
              const colors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40', '#C9CBCF', '#7FFF00', '#FF00FF', '#00FFFF'];
              
              for (let i = 0; i < slitCount; i++) {
                  ctx.strokeStyle = colors[i % colors.length];
                  ctx.beginPath();
                  
                  for (let y = 0; y < canvas.height; y++) {
                      const { individual } = calculateIntensity(y);
                      const intensity = individual[i] * graphWidth * 0.8;
                      
                      if (y === 0) {
                          ctx.moveTo(graphX + intensity, y);
                      } else {
                          ctx.lineTo(graphX + intensity, y);
                      }
                  }
                  
                  ctx.stroke();
              }
          }
      }
      
      // Animation function
      function animate() {
          time += 0.05;
          drawInterferencePattern();
          animationId = requestAnimationFrame(animate);
      }
      
      // Update value displays
      function updateValueDisplays() {
          slitCountValue.textContent = slitCountSlider.value;
          slitWidthValue.textContent = slitWidthSlider.value;
          slitSeparationValue.textContent = slitSeparationSlider.value;
          wavelengthValue.textContent = wavelengthSlider.value;
          intensityValue.textContent = intensitySlider.value;
      }
      
      // Event listeners
      slitCountSlider.addEventListener('input', () => {
          updateValueDisplays();
          drawSlits();
          drawInterferencePattern();
      });
      
      slitWidthSlider.addEventListener('input', () => {
          updateValueDisplays();
          drawSlits();
          drawInterferencePattern();
      });
      
      slitSeparationSlider.addEventListener('input', () => {
          updateValueDisplays();
          drawSlits();
          drawInterferencePattern();
      });
      
      wavelengthSlider.addEventListener('input', () => {
          updateValueDisplays();
          drawInterferencePattern();
      });
      
      intensitySlider.addEventListener('input', () => {
          updateValueDisplays();
          drawInterferencePattern();
      });
      
      showIndividualCheckbox.addEventListener('change', drawInterferencePattern);
      
      animateBtn.addEventListener('click', () => {
          if (isAnimating) {
              cancelAnimationFrame(animationId);
              animateBtn.textContent = 'Start Animation';
              isAnimating = false;
          } else {
              animate();
              animateBtn.textContent = 'Stop Animation';
              isAnimating = true;
          }
      });
      
      resetBtn.addEventListener('click', () => {
          // Reset sliders to default values
          slitCountSlider.value = 2;
          slitWidthSlider.value = 10;
          slitSeparationSlider.value = 100;
          wavelengthSlider.value = 500;
          intensitySlider.value = 100;
          showIndividualCheckbox.checked = false;
          
          // Stop animation if running
          if (isAnimating) {
              cancelAnimationFrame(animationId);
              animateBtn.textContent = 'Start Animation';
              isAnimating = false;
          }
          
          // Reset time
          time = 0;
          
          // Update displays
          updateValueDisplays();
          
          // Redraw
          drawSlits();
          drawInterferencePattern();
      });
      
      // Initialize the visualization
      updateValueDisplays();
      initCanvas();
  </script>

</body> </html>

start.1744705205.txt.gz · Last modified: 2025/04/15 10:20