### Osmos ⭕

Yo dawg! I heard you like circle packers so I put a circle packer in your circle packer!!!

Osmos ⭕ (variation)

```// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(1);

const plottable = 0; //min=0 max=1 step=1 (No, Yes)
const black = .2; //min=.2 max=1 step=.1
const bigCircleRadius = 200; //min=50 max=300 step=5
const padding = .2; //min=0 max=.9 step=.05
const margin1000 = 1; //min=0 max=200 step=1
const maxRadius = .5; //min=.1 max=.9 step=.1
const border = 0; //min=0 max=90 step=1
const drawBorder = 0; //min=0 max=1 step=1 (No, Yes)

// Global code will be evaluated once.
const turtle = new Turtle();
const polygons = new Polygons();

const add2 = (a,b) => [a[0]+b[0],a[1]+b[1]];
const scale2 = (a, s) => [a[0]*s, a[1]*s];
const pi2 = Math.PI * 2;

const iterator = cp.getPolygonIterator();

if(border != 0) {
let pts = [[border-100,border-100],[100-border,border-100],[100-border,100-border],[border-100,100-border],[border-100,border-100],[-200, -200],[-200,200],[200, 200], [200, -200], [-200, -200]];
const p = polygons.create();
polygons.draw(turtle, p);
turtle.jump(pts[0]);
if(drawBorder)pts.filter((i, k) => k < 5).map((i, k) => k == 0? turtle.jump(i):turtle.goto(i));
}

// The walk function will be called until it returns false.
function walk(i) {
let p = iterator.next();
if(!p.done) {
polygons.draw(turtle, p.value);
}
return !p.done;
}

const colors = [[1, black], [1, 900]];

function InceptionCircle(pos, radius, fillRatio = .8, margin = .02, maxRadius = .5) {
class InceptionCircle {
constructor(pos, radius, fillRatio = .8, margin = .02, maxRadius = .5, generation = 0) {
this.position = pos;
this.fillRatio = fillRatio;
this.generation = generation;
this.margin = margin;

this.cp = new CirclePacker(fillRatio <= 1? radius * fillRatio: radius - fillRatio);
}
*getPolygonIterator() {
for(let i = 0; i < this.r * 25; i++) {
let c = this.cp.get(100, this.maxRadius, this.margin);
const origin = add2(this.position, [c[2], c[3]]);
if(this.generation < 20) {
if(-100 < origin[0] + c[4] && origin[0] - c[4] < 100 && -100 < origin[1] + c[4] && origin[1] - c[4] < 100 ) {
if(Math.max(.5, this.r/40) < c[4]) {
const cp = new InceptionCircle(origin, c[4], this.fillRatio, this.margin, this.maxRadius, this.generation + 1);
for(let p of cp.getPolygonIterator()) {
yield p;
}
}
}
}
}

if(-100 < this.position[0] + this.r && this.position[0] - this.r < 100 && -100 < this.position[1] + this.r && this.position[1] - this.r < 100 ) {
const p = polygons.create();
for(let i = 0, max = Math.max(40, Math.ceil(2*Math.PI*this.r)); i < max; i++) {
}
if(plottable == 0) {
} else {
}
yield p;
}
}
}
}

class CirclePacker {
pts = [] //a, r, x, y, radius
}
get(candidates = 10, radiusRatio = .5, marginRatio = .02) {
let cs = Array.apply(null,{length: candidates}).map(b => [
Math.PI * 2 * Math.random(),
Math.sqrt(Math.random()) * this.r
]);
cs = cs.map(i => [...i, Math.cos(i[0]) * i[1], Math.sin(i[0]) * i[1], 0] );
//i: cA, cR, x, y, r
for(let csi = 0; csi < cs.length; csi++) {
cs[csi][4] = Math.min(this.r * radiusRatio, this.r - (cs[csi][2]**2+cs[csi][3]**2)**.5);
for(let ptsi = 0; ptsi < this.pts.length; ptsi++) {
cs[csi][4] = Math.min(cs[csi][4], (((this.pts[ptsi][2] - cs[csi][2])**2 + (this.pts[ptsi][3] - cs[csi][3])**2)**.5 - this.pts[ptsi][4]));
}
cs[csi][4] -= this.r * marginRatio;
}

cs.sort((a,b) => a[4] < b[4]? 1: -1);
this.pts.push(cs[0]);

return cs[0];
}
}