About this technique →
aizawa-3d/sketch.js
import * as THREE from 'three';

export const WARMUP = { framesBeforeReady: 480 };

export const PARAMS = {
  a:     { value: 0.95, min: 0.1, max: 2, step: 0.01, label: "a", folder: "Dynamics" },
  b:     { value: 0.7,  min: 0.1, max: 2, step: 0.01, label: "b", folder: "Dynamics" },
  c:     { value: 0.6,  min: 0.1, max: 2, step: 0.01, label: "c", folder: "Dynamics" },
  d:     { value: 3.5,  min: 0.1, max: 5, step: 0.01, label: "d", folder: "Dynamics" },
  e:     { value: 0.25, min: 0.0, max: 2, step: 0.01, label: "e", folder: "Dynamics" },
  f:     { value: 0.1,  min: 0.0, max: 2, step: 0.01, label: "f", folder: "Dynamics" },
  dt:    { value: 0.01, min: 0.001, max: 0.05, step: 0.001, label: "Step", folder: "Dynamics" },
  trail: { value: 12000, min: 1000, max: 60000, step: 500, label: "Trail Length", folder: "Appearance" },
  hue:   { value: 200, min: 0, max: 360, step: 1, label: "Hue", folder: "Appearance" },
};

export const SHARE = { bookmarked: ["a","b","c","d","e","f","dt","trail","hue"] };

export function sceneSetup(THREE, scene, camera, renderer, params, seed) {
  scene.background = new THREE.Color(0x07080a);
  camera.position.set(0, 0, 5);

  const positions = new Float32Array(params.trail * 3);
  const geo = new THREE.BufferGeometry();
  geo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geo.setDrawRange(0, 0);
  const mat = new THREE.LineBasicMaterial({ color: new THREE.Color().setHSL(params.hue / 360, 0.7, 0.55) });
  const line = new THREE.Line(geo, mat);
  scene.add(line);

  return {
    p: { x: 0.1, y: 0, z: 0 },
    positions, geo, mat, line, count: 0,
  };
}

export function sceneAnimate(THREE, scene, camera, state, params, time, delta) {
  state.mat.color.setHSL(params.hue / 360, 0.7, 0.55);

  const { a, b, c, d, e, f, dt } = params;
  const trail = params.trail | 0;

  for (let i = 0; i < 8; i++) {
    const { x, y, z } = state.p;
    const dx = (z - b) * x - d * y;
    const dy = d * x + (z - b) * y;
    const dz = c + a * z - (z * z * z) / 3 - (x * x + y * y) * (1 + e * z) + f * z * x * x * x;
    state.p.x += dx * dt;
    state.p.y += dy * dt;
    state.p.z += dz * dt;

    const idx = (state.count % trail) * 3;
    state.positions[idx] = state.p.x;
    state.positions[idx + 1] = state.p.y;
    state.positions[idx + 2] = state.p.z;
    state.count++;
  }

  state.geo.attributes.position.needsUpdate = true;
  state.geo.setDrawRange(0, Math.min(state.count, trail));
}