<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Chaos-Controlled Light Interference</title>

  <style>

    body, html { margin: 0; padding: 0; overflow: hidden; }

    canvas { display: block; }

  </style>

</head>

<body>

  <canvas id="shaderCanvas"></canvas>

  <script>

    // Vertex Shader (Simple Pass-Through)

    const vertexShaderSource = `

      attribute vec4 position;

      void main() {

        gl_Position = position;

      }

    `;

    // Pixel Shader (Chaos-Controlled Light Interference)

    const fragmentShaderSource = `

      precision highp float;

      uniform float time;

      uniform vec2 resolution;

      // Chaotic Attractor (Lorenz System)

      vec3 lorenzAttractor(vec3 pos, float t) {

        float sigma = 10.0;

        float rho = 28.0;

        float beta = 8.0 / 3.0;

        float dx = sigma * (pos.y - pos.x);

        float dy = pos.x * (rho - pos.z) - pos.y;

        float dz = pos.x * pos.y - beta * pos.z;

        return vec3(dx, dy, dz) * 0.01;

      }

      void main() {

        vec2 uv = gl_FragCoord.xy / resolution.xy; // Normalize coordinates

        uv = uv * 2.0 - 1.0; // Center coordinates

        // Initialize Lorenz attractor

        vec3 lorenzPos = vec3(uv.x, uv.y, 0.0);

        for (int i = 0; i < 5; i++) { // Reduced iterations for mobile

          lorenzPos += lorenzAttractor(lorenzPos, time);

        }

        // Use chaotic system to control light wave parameters

        float phase1 = lorenzPos.x * 10.0; // Phase for wave 1

        float phase2 = lorenzPos.y * 10.0; // Phase for wave 2

        float amplitude1 = 0.5 + 0.5 * sin(lorenzPos.z * 5.0 + time); // Amplitude for wave 1

        float amplitude2 = 0.5 + 0.5 * cos(lorenzPos.z * 5.0 + time); // Amplitude for wave 2

        // Simulate two interfering light waves

        float wave1 = amplitude1 * sin(uv.x * 20.0 + phase1 + time);

        float wave2 = amplitude2 * sin(uv.y * 20.0 + phase2 + time);

        // Combine waves to create interference pattern

        float interference = wave1 + wave2;

        // Map interference intensity to a vibrant color gradient

        vec3 color = vec3(

          0.5 + 0.5 * sin(interference * 10.0 + time), // Red

          0.5 + 0.5 * cos(interference * 5.0 + time),  // Green

          0.5 + 0.5 * sin(interference * 3.0 + time)   // Blue

        );

        gl_FragColor = vec4(color, 1.0);

      }

    `;

    // WebGL Setup

    const canvas = document.getElementById('shaderCanvas');

    const gl = canvas.getContext('webgl');

    if (!gl) {

      console.error('WebGL not supported');

      throw new Error('WebGL not supported');

    }

    // Compile Shader

    function compileShader(gl, source, type) {

      const shader = gl.createShader(type);

      gl.shaderSource(shader, source);

      gl.compileShader(shader);

      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

        console.error('Shader compile error:', gl.getShaderInfoLog(shader));

        return null;

      }

      return shader;

    }

    // Create Program

    const vertexShader = compileShader(gl, vertexShaderSource, gl.VERTEX_SHADER);

    const fragmentShader = compileShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);

    const program = gl.createProgram();

    gl.attachShader(program, vertexShader);

    gl.attachShader(program, fragmentShader);

    gl.linkProgram(program);

    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {

      console.error('Program link error:', gl.getProgramInfoLog(program));

      throw new Error('Program link error');

    }

    gl.useProgram(program);

    // Set Up Buffers

    const positionBuffer = gl.createBuffer();

    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

    const positions = [-1, -1, 1, -1, -1, 1, 1, 1]; // Full-screen quad

    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

    const positionLocation = gl.getAttribLocation(program, 'position');

    gl.enableVertexAttribArray(positionLocation);

    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

    // Set Up Uniforms

    const timeLocation = gl.getUniformLocation(program, 'time');

    const resolutionLocation = gl.getUniformLocation(program, 'resolution');

    // Render Loop

    function render(time) {

      time *= 0.001; // Convert to seconds

      gl.uniform1f(timeLocation, time);

      gl.uniform2f(resolutionLocation, canvas.width, canvas.height);

      gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

      requestAnimationFrame(render);

    }

    // Resize Handler

    function resize() {

      canvas.width = window.innerWidth;

      canvas.height = window.innerHeight;

      gl.viewport(0, 0, canvas.width, canvas.height);

    }

    window.addEventListener('resize', resize);

    resize();

    // Start Rendering

    requestAnimationFrame(render);

  </script>

</body>

</html>

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.