### Mushroom Gills 2

A circle of points connected by springs. They are constrained to a slowly growing circle. When they get too far from their neighbors, they split. Each point leaves a line behind as it moves.

```const RAD_INITIAL = 10;
const RAD_FINAL = 90;
const NUM_SEEDS = 23;  // min=3, max=100, step=1
const NUM_STEPS = 100;  // min=5, max=500, step=1
const SEED_JITTER = 0.95; // min=0, max=1, step=0.05
const LERP_FRACTION = 0.97;  // min=0, max=1.-, step=0.05
const SPLIT_DIST = 1.5; // min=2, max=40, step=1

Canvas.setpenopacity(1);
const turtle = new Turtle();
turtle.pendown();

let rand = (min, max) =>
Math.random() * (max - min) + min;

let randInt = (min, max) =>
Math.floor(rand(min, max));

let remap = (x, oldmin, oldmax, newmin, newmax) => {
let t = (x - oldmin) / (oldmax - oldmin);
return t * (newmax - newmin) + newmin;
}

let Point = (x, y) => {
let self = {x: x, y: y};
self.len = () =>
Math.sqrt((self.x * self.x) + (self.y * self.y));
self.mul = (f) => {
self.x *= f;
self.y *= f;
}
self.setlen = (newlen) => {
self.mul(newlen/self.len());
}
self.saveold = () => {
self.xold = self.x;
self.yold = self.y;
}
self.lerpto = (p2, t) => {
self.x = (self.x * (1-t)) + p2.x * t;
self.y = (self.y * (1-t)) + p2.y * t;
}
self.clone = () => {
let p2 = Point(self.x, self.y);
p2.xold = self.xold;
p2.yold = self.yold;
return p2;
}
self.jitter = (r) => {
self.x += rand(-r, r);
self.y += rand(-r, r);
}
return self;
};

let randPoint = () =>
Point(rand(-1, 1), rand(-1, 1));

let dist = (p1, p2) => {
let dx = p1.x - p2.x;
let dy = p1.y - p2.y;
return Math.sqrt(dx*dx + dy*dy);
}
let distold = (p1, p2) => {
let dx = p1.xold - p2.xold;
let dy = p1.yold - p2.yold;
return Math.sqrt(dx*dx + dy*dy);
}

let points = [];

// The walk function will be called until it returns false.
console.log('-------------------');
function walk(ii) {
if (ii === NUM_STEPS) { return false; }
// set out initial points
if (ii === 0) {
for (let pp = 0; pp < NUM_SEEDS; pp++) {
let theta = remap(pp + Math.random() * SEED_JITTER, 0, NUM_SEEDS, 0, Math.PI * 2);
let p = Point(Math.sin(theta), Math.cos(theta));
points.push(p);
}
}
// save existing positions
for (let p of points) {
p.saveold();
}
// smooth with neighbors and normalize to new radius
for (let pp = 0; pp < points.length; pp++) {
let p0 = points[(pp + 0) % points.length];
let p1 = points[(pp + 1) % points.length];
let p2 = points[(pp + 2) % points.length];
let midpoint = Point((p0.xold + p2.xold)/2, (p0.yold + p2.yold)/2);
p1.lerpto(midpoint, LERP_FRACTION);
}
// split when dist between neighbors is large enough
let points2 = [...points];
for (let pp = points2.length-1; pp >= 0; pp--) {
let p0 = points2[(pp + 0) % points2.length];
let p1 = points2[(pp + 1) % points2.length];
let p2 = points2[(pp + 2) % points2.length];
if (dist(p0, p2) > SPLIT_DIST) {
let p1b = p1.clone();
p1b.jitter(0.1);