About this technique →
lorenz/sketch.js
// Lorenz Attractor — projected 2D trace
//
// dx/dt = sigma * (y - x)
// dy/dt = x * (rho - z) - y
// dz/dt = x * y - beta * z

export const WARMUP = { framesBeforeReady: 240 };

export const PARAMS = {
  sigma: { value: 10.0, min: 1, max: 30, step: 0.1, label: "Sigma", folder: "Dynamics" },
  rho:   { value: 28.0, min: 1, max: 100, step: 0.1, label: "Rho", folder: "Dynamics" },
  beta:  { value: 8 / 3, min: 0.1, max: 5, step: 0.01, label: "Beta", folder: "Dynamics" },
  dt:    { value: 0.005, min: 0.001, max: 0.02, step: 0.001, label: "Step Size", folder: "Dynamics" },
  trail: { value: 4000, min: 100, max: 20000, step: 100, label: "Trail Length", folder: "Appearance" },
  hue:   { value: 30, min: 0, max: 360, step: 1, label: "Base Hue", folder: "Appearance" },
  bgFade:{ value: 0.04, min: 0, max: 0.5, step: 0.01, label: "Background Fade", folder: "Appearance" },
  scale: { value: 12, min: 1, max: 40, step: 0.5, label: "Scale", folder: "Appearance" },
};

export const SHARE = {
  bookmarked: ["sigma", "rho", "beta", "dt", "trail", "hue", "scale"],
};

let state;

export function sketchSetup(p, w, h) {
  p.colorMode(p.HSB, 360, 100, 100, 1);
  p.background(20);
  state = {
    x: 0.1,
    y: 0,
    z: 0,
    history: [],
  };
  return state;
}

export function sketchDraw(p, w, h, params) {
  // Background fade for trails
  p.noStroke();
  p.fill(0, 0, 5, params.bgFade);
  p.rect(0, 0, w, h);

  // Step the system several times per frame for smooth motion
  for (let i = 0; i < 4; i++) {
    const { x, y, z } = state;
    const dx = params.sigma * (y - x);
    const dy = x * (params.rho - z) - y;
    const dz = x * y - params.beta * z;
    state.x += dx * params.dt;
    state.y += dy * params.dt;
    state.z += dz * params.dt;
    state.history.push({ x: state.x, y: state.z });
  }

  while (state.history.length > params.trail) state.history.shift();

  // Draw the trail — XZ projection
  p.strokeWeight(1);
  const cx = w / 2;
  const cy = h / 2;
  const len = state.history.length;
  for (let i = 1; i < len; i++) {
    const a = state.history[i - 1];
    const b = state.history[i];
    const t = i / len;
    p.stroke((params.hue + t * 60) % 360, 80, 95, 0.7);
    p.line(
      cx + a.x * params.scale,
      cy + (a.y - 25) * params.scale,
      cx + b.x * params.scale,
      cy + (b.y - 25) * params.scale
    );
  }
}