Log in to post a comment.

// Rössler Attractor
// dx/dt = -y - z
// dy/dt = x + a*y
// dz/dt = b + z*(x - c)

const randomize_inputs = 1; // min=0, max=1, step=1 (Use Input, Randomize)
const steps = 40000; // min=5000, max=100000, step=1000

// --- ADJUSTABLE PARAMETERS ---
const a_param = 0.2;  // min=0.1, max=0.3, step=0.01 (Spiraling energy)
const b_param = 0.2;  // min=0.1, max=0.5, step=0.01 (The "Kick" strength)
const c_param = 5.7;  // min=2.0, max=15.0, step=0.1 (The "Folding" threshold)

// Set pen-related draw stuff
const scale = 5.5;    // min=1, max=20, step=0.1
const x_offset = 0;   // min=-100, max=100, step=1
const y_offset = 20;  // min=-100, max=100, step=1
const opacity = 0.4;  // min=0.0, max=1.0, step=0.01
const dt = 0.02;      // min=0.005, max=0.1, step=0.005

let a = a_param;
let b = b_param;
let c = c_param;

// Initial State (Standard Rössler start)
let x = 0.1;
let y = 0.0;
let z = 0.1;

if (randomize_inputs == 0) {
    a = 0.1 + Math.random() * 0.2;
    b = 0.1 + Math.random() * 0.3;
    c = 4 + Math.random() * 6;
}

Canvas.setpenopacity(opacity);
const turtle = new Turtle();
turtle.penup();

// 3D to 2D Projection (Side-tilt to see the "lift")
function project(currX, currY, currZ) {
    let screenX = (currX * scale) + x_offset;
    // We subtract currZ to show the vertical spikes
    let screenY = (currY * scale * 0.5) - (currZ * scale) + y_offset;
    return [screenX, screenY];
}

let startPos = project(x, y, z);
turtle.jump(startPos[0], startPos[1]);
turtle.pendown();

function walk(i) {
    // 1. Rössler Equations
    let dx = -y - z;
    let dy = x + (a * y);
    let dz = b + z * (x - c);

    // 2. Integration
    x += dx * dt;
    y += dy * dt;
    z += dz * dt;

    // 3. Draw
    let pos = project(x, y, z);
    
    // Safety check for divergence
    if (isNaN(x) || Math.abs(x) > 1000) return false;

    turtle.goto(pos[0], pos[1]);

    return i < steps;
}