Cyclops

"Root Burst" is a generative art script that creates an organic radial fractal. It features a textured spiral core and uses recursive branching logic to grow tendrils. Each tendril mimics biological growth through simulated line thickness, tapering off and splitting into smaller sub-branches based on distance and pseudo-random probability.
You can use the sliders to turn the whole thing from sharp, mechanical triangles into soft, organic bubbles.

Log in to post a comment.

// Root burst with solid core + tapering thickness + controllable recursion density

const core = 45;              // min=10 max=90 step=1
const outer = 190;            // min=80 max=230 step=1
const roots = 160;            // min=20 max=250 step=5
const levels = 5;             // min=1 max=8 step=1
const spread = 0.38;          // min=0.05 max=1 step=0.01
const curl = 0.22;            // min=-1 max=1 step=0.01
const density = 1.2;          // min=0 max=2 step=0.01
const baseWidth = 7;          // min=1 max=30 step=1
const taper = 1.4;            // min=0.3 max=3 step=0.01
const bw = 1                  // min=-1 max=1 step=0.01    

const recurseStart = 0.25;    // min=0 max=1 step=0.01
const branchBoost = 2.2;      // min=0.5 max=4 step=0.01
const maxChildren = 4;        // min=1 max=5 step=1

Canvas.setpenopacity(-0.55 * bw);

const t = new Turtle();

function rnd(n) {
    return Math.abs(Math.sin(n * 43758.5453) * 9999) % 1;
}

function jump(x, y) {
    t.penup();
    t.goto(x, y);
    t.pendown();
}

function circle(r) {
    jump(r, 0);
    for (let i = 0; i <= 180; i++) {
        let a = Math.PI * 2 * i / 180;
        t.goto(Math.cos(a) * r, Math.sin(a) * r);
    }
}

function solidCore(radius) {
    const passes = 3;     // increase for darker fill
    const step = 0.35;    // smaller = denser

    for (let p = 0; p < passes; p++) {

        // horizontal fill
        for (let y = -radius; y <= radius; y += step) {
            let x = Math.sqrt(radius * radius - y * y);

            jump(-x, y);
            t.goto(x, y);
        }

        // vertical fill (important — fills gaps)
        for (let x = -radius; x <= radius; x += step) {
            let y = Math.sqrt(radius * radius - x * x);

            jump(x, -y);
            t.goto(x, y);
        }
    }

    circle(radius);
}

function thickSegment(x1, y1, x2, y2, width) {
    let a = Math.atan2(y2 - y1, x2 - x1);
    let nx = Math.cos(a + Math.PI / 2);
    let ny = Math.sin(a + Math.PI / 2);

    for (let i = 0; i < width; i++) {
        let off = (i - width / 2) * 0.05;

        jump(x1 + nx * off, y1 + ny * off);
        t.goto(x2 + nx * off, y2 + ny * off);
    }
}

function branch(x, y, a, len, level, seed, startWidth) {
    if (level <= 0 || len < 4 || startWidth < 1) return;

    let px = x;
    let py = y;

    const steps = 9;

    for (let i = 1; i <= steps; i++) {
        let u = i / steps;

        a += Math.sin(u * Math.PI * 2 + seed) * curl;
        a += (rnd(seed + i) - 0.5) * 0.16;

        let nx = px + Math.cos(a) * len / steps;
        let ny = py + Math.sin(a) * len / steps;

        if (Math.sqrt(nx * nx + ny * ny) > outer) return;

        let w = Math.max(1, Math.floor(startWidth * Math.pow(1 - u, taper)));

        thickSegment(px, py, nx, ny, w);

        px = nx;
        py = ny;
    }

    let dist = Math.sqrt(px * px + py * py);
    let outward = (dist - core) / (outer - core);

    let childCount = 1;

    if (outward > recurseStart) {
        childCount = 1 + Math.floor(maxChildren * outward * branchBoost);
    }

    for (let c = 0; c < childCount; c++) {
        if (outward > recurseStart && rnd(seed * 17 + c) < density) {
            let side = c % 2 === 0 ? -1 : 1;

            branch(
                px,
                py,
                a + side * spread * (0.6 + rnd(seed + c)),
                len * (0.62 + rnd(seed + c * 2) * 0.12),
                level - 1,
                seed + c * 13.7 + level,
                startWidth * 0.65
            );
        }
    }
}

solidCore(core);

for (let i = 0; i < roots; i++) {
    let a = Math.PI * 2 * i / roots;
    let x = Math.cos(a) * core;
    let y = Math.sin(a) * core;

    branch(
        x,
        y,
        a,
        38 + rnd(i) * 18,
        levels,
        i + 1,
        baseWidth
    );
}

solidCore(core);