228

Lorenz Strange Attractor

Interactive study of Edward Lorenz's foundational non-linear ordinary differential equations. Demonstrates the butterfly effect, dual orbital manifolds, Runge-Kutta numerical integration, and real-time Lyapunov divergence of two starting trajectories perturbed by Δx₀ = 10⁻⁵.

Playground
60 FPS Canvas 2D
Click + Drag to interact with field
</>

Full Executable Algorithm Code

// 057 - Lorenz Strange Attractor (physics)
// 1:1 Original algorithm engine source
function createLorenzAttractor() {
  const TRAIL_LENGTH = 1200;
  let trailA = [];
  let trailB = [];
  let stateA = { x: 0.1, y: 0, z: 0 };
  let stateB = { x: 0.10001, y: 0, z: 0 };
  return {
    setup() {
      trailA = [];
      trailB = [];
      stateA = { x: 0.1, y: 0, z: 0 };
      stateB = { x: 0.10001, y: 0, z: 0 };
    },
    render(context, timeState, params) {
      const { ctx, width, height } = context;
      const sigma = Number(params.sigma || 10);
      const rho = Number(params.rho || 28);
      const beta = Number(params.beta || 8 / 3);
      const t = timeState.time;
      ctx.fillStyle = "rgba(2, 3, 7, 0.25)";
      ctx.fillRect(0, 0, width, height);
      const cx = width * 0.5;
      const cy = height * 0.52;
      const scale = Math.min(width, height) * 0.016;
      const dt = 8e-3;
      const subSteps = 6;
      function lorenzDerivs(s) {
        return {
          dx: sigma * (s.y - s.x),
          dy: s.x * (rho - s.z) - s.y,
          dz: s.x * s.y - beta * s.z
        };
      }
      for (let step = 0; step < subSteps; step++) {
        const dA1 = lorenzDerivs(stateA);
        const kA2 = {
          x: stateA.x + dA1.dx * dt * 0.5,
          y: stateA.y + dA1.dy * dt * 0.5,
          z: stateA.z + dA1.dz * dt * 0.5
        };
        const dA2 = lorenzDerivs(kA2);
        const kA3 = {
          x: stateA.x + dA2.dx * dt * 0.5,
          y: stateA.y + dA2.dy * dt * 0.5,
          z: stateA.z + dA2.dz * dt * 0.5
        };
        const dA3 = lorenzDerivs(kA3);
        const kA4 = {
          x: stateA.x + dA3.dx * dt,
          y: stateA.y + dA3.dy * dt,
          z: stateA.z + dA3.dz * dt
        };
        const dA4 = lorenzDerivs(kA4);
        stateA.x += (dA1.dx + 2 * dA2.dx + 2 * dA3.dx + dA4.dx) * (dt / 6);
        stateA.y += (dA1.dy + 2 * dA2.dy + 2 * dA3.dy + dA4.dy) * (dt / 6);
        stateA.z += (dA1.dz + 2 * dA2.dz + 2 * dA3.dz + dA4.dz) * (dt / 6);
        const dB1 = lorenzDerivs(stateB);
        stateB.x += dB1.dx * dt;
        stateB.y += dB1.dy * dt;
        stateB.z += dB1.dz * dt;
        trailA.push({ ...stateA });
        trailB.push({ ...stateB });
        if (trailA.length > TRAIL_LENGTH) trailA.shift();
        if (trailB.length > TRAIL_LENGTH) trailB.shift();
      }
      const rotY = t * 0.4;
      const rotX = 0.45;
      const rotZ = 0;
      ctx.save();
      ctx.globalCompositeOperation = "screen";
      if (trailA.length > 2) {
        ctx.beginPath();
        for (let i = 0; i < trailA.length; i++) {
          const pt = trailA[i];
          const rawX = pt.x * scale * 25;
          const rawY = -(pt.z - 25) * scale * 25;
          const rawZ = pt.y * scale * 25;
          const p = project3D(rawX, rawY, rawZ, rotX, rotY, rotZ, cx, cy, 450, 520);
          if (i === 0) ctx.moveTo(p.x, p.y);
          else ctx.lineTo(p.x, p.y);
        }
        ctx.strokeStyle = "#38bdf8";
        ctx.lineWidth = 1.6;
        ctx.stroke();
      }
      if (trailB.length > 2) {
        ctx.beginPath();
        for (let i = 0; i < trailB.length; i++) {
          const pt = trailB[i];
          const rawX = pt.x * scale * 25;
          const rawY = -(pt.z - 25) * scale * 25;
          const rawZ = pt.y * scale * 25;
          const p = project3D(rawX, rawY, rawZ, rotX, rotY, rotZ, cx, cy, 450, 520);
          if (i === 0) ctx.moveTo(p.x, p.y);
          else ctx.lineTo(p.x, p.y);
        }
        ctx.strokeStyle = "#f43f5e";
        ctx.lineWidth = 1.4;
        ctx.stroke();
      }
      const pA = project3D(stateA.x * scale * 25, -(stateA.z - 25) * scale * 25, stateA.y * scale * 25, rotX, rotY, rotZ, cx, cy, 450, 520);
      ctx.fillStyle = "#ffffff";
      ctx.beginPath();
      ctx.arc(pA.x, pA.y, 4.5, 0, Math.PI * 2);
      ctx.fill();
      const pB = project3D(stateB.x * scale * 25, -(stateB.z - 25) * scale * 25, stateB.y * scale * 25, rotX, rotY, rotZ, cx, cy, 450, 520);
      ctx.fillStyle = "#f43f5e";
      ctx.beginPath();
      ctx.arc(pB.x, pB.y, 4.5, 0, Math.PI * 2);
      ctx.fill();
      const divergenceDist = Math.hypot(stateA.x - stateB.x, stateA.y - stateB.y, stateA.z - stateB.z);
      ctx.restore();
      ctx.save();
      ctx.font = "11px monospace";
      ctx.fillStyle = "rgba(56, 189, 248, 0.9)";
      ctx.fillText(`Lorenz Strange Attractor \u2014 Chaos Theory`, 20, 28);
      ctx.fillStyle = "#94a3b8";
      ctx.fillText(`dx/dt = \u03C3(y - x) | dy/dt = x(\u03C1 - z) - y | dz/dt = xy - \u03B2z`, 20, 44);
      ctx.fillText(`Parameters: \u03C3=${sigma.toFixed(1)}, \u03C1=${rho.toFixed(1)}, \u03B2=${beta.toFixed(2)}`, 20, 60);
      ctx.fillStyle = divergenceDist > 1 ? "#f43f5e" : "#34d399";
      ctx.fillText(`Lyapunov Divergence \u0394(t): ${divergenceDist.toFixed(4)} (Initial \u0394\u2080 = 10\u207B\u2075)`, 20, 76);
      ctx.restore();
    }
  };
}

// Default parameters from content metadata
const defaultParams = [
  {
    "key": "sigma",
    "label": "Prandtl (σ)",
    "type": "range",
    "min": 5,
    "max": 20,
    "step": 0.5,
    "defaultValue": 10,
    "description": "Prandtl number representing fluid viscosity"
  },
  {
    "key": "rho",
    "label": "Rayleigh (ρ)",
    "type": "range",
    "min": 10,
    "max": 50,
    "step": 1,
    "defaultValue": 28,
    "description": "Rayleigh number representing convective driving force"
  }
];

if (!window.__art_instances) window.__art_instances = {};
if (!window.__art_instances['lorenz-attractor-chaos']) {
  const inst = typeof createLorenzAttractor === 'function' ? createLorenzAttractor() : null;
  if (inst && inst.setup) {
    inst.setup({ ctx, width, height, dpr: 1, aspectRatio: width / height }, defaultParams);
  }
  window.__art_instances['lorenz-attractor-chaos'] = inst;
}

const instance = window.__art_instances['lorenz-attractor-chaos'];
if (instance && instance.render) {
  instance.render(
    { ctx, width, height, dpr: 1, aspectRatio: width / height },
    { time, deltaTime: dt, frameCount: Math.floor(time * 60), fps: 60 },
    defaultParams
  );
}
Edit in Interactive Playground Zero Dependencies • Standalone Canvas 2D
ƒ

Mathematical Formulation

high
Analytical Equation
dxdt=σ(yx),dydt=x(ρz)y,dzdt=xyβz\frac{dx}{dt} = \sigma(y - x), \quad \frac{dy}{dt} = x(\rho - z) - y, \quad \frac{dz}{dt} = xy - \beta z
Click to expand
Compact Formula
dx=s*(y-x)*dt; dy=(x*(r-z)-y)*dt; dz=(x*y-b*z)*dt;

Mathematical Tags

#chaos-theory #dynamical-systems #lorenz-attractor #butterfly-effect #differential-equations #math-study
Author: Chaos Dynamics Core Target: 60 FPS

Export & Embed: Lorenz Strange Attractor

4K PNG Snapshot

High-resolution single frame render

WebM Video (5s Loop)

60 FPS browser-captured stream

Standalone JS Script

Complete executable Canvas 2D algorithm

HTML Iframe Embed

<iframe src="https://art.fazleyrabbi.xyz/embed/lorenz-attractor-chaos" width="500" height="500" frameborder="0" loading="lazy"></iframe>
ESC
↑↓ Navigate Select
110 Mathematical Artworks
Made by Fazley Rabbi

Support the Project

Keep mathematical creative coding alive & open source

Or via Direct Payoneer ($0 Fee)
Payoneer Customer ID: $0 Fee Direct
24076084

💡 Payoneer app: Go to Pay → Pay to recipient → Enter ID 24076084.

Thank you for supporting generative mathematical animations! ✨