Forked from: Onions have layers 🐸 Onions have layers 🐸
Converted to a Tortoise, added a additional transform (effect) to make it look bit like fractal-ish flower. other than that it is still same thing as the fork.
Log in to post a comment.
// Forked from "Onions have layers 🐸" by markknol // https://turtletoy.net/turtle/3b2af756c2 Canvas.setpenopacity(.85); const grid = 10; // min=3, max=20, step=1 const linePrecision = 7; // min=2, max=40, step=1 const totalPerOnion = 11; // min=3, max=60, step=1 const thickness = 23; // min=3, max=60, step=1 const shakyness = 3.1; // min=0, max=25, step=0.1 const posOffset = 10; // min=0, max=25, step=0.1 const size = 200 / grid; function EFFECT(s) { return p => [ Math.sin(p[1]/s)*p[0], Math.cos(p[0]/s)*p[1] ] } const turtle = new Tortoise(); const shakeRandom = new Random(777); const effect = 65; turtle.addTransform(EFFECT(effect)); const getPos = (val, rnd) => Math.max(-100,Math.min(100, (-100 + val * size + (rnd-.5) * posOffset))); // The walk function will be called until it returns false. function walk(i) { const gridX = i % grid; const gridY = (i / grid)|0; const x1 = getPos(gridX, hash2([gridX, gridY])); const y1 = getPos(gridY, hash2([gridX, gridY])); const nextGridX = gridX + 1; const nextGridY = gridY + 1; const x2 = getPos(gridX, hash2([gridX, nextGridY])); const y2 = getPos(nextGridY, hash2([gridX, nextGridY])); const x3 = getPos(nextGridX, hash2([nextGridX, gridY])); const y3 = getPos(gridY, hash2([nextGridX, gridY])); const t = (gridX / grid); if (gridX > 0 && gridY < grid) onion(x1,y1, x2,y2, shake(thickness, thickness/2), shake(totalPerOnion, 4)|0); if (gridY > 0 && gridX < grid) onion(x1,y1, x3,y3, shake(thickness, thickness/2), shake(totalPerOnion, 4)|0); return i + 1 < grid * grid; } function onion(x1,y1, x2,y2, thickness, total) { const angle = Math.atan2(y2-y1, x2-x1) + Math.PI/2; for(let i=0; i<=total; i++) { const t = (-0.5 + i / total) * 2; const cx = lerp(x1, x2, 0.5) + Math.cos(angle) * (t * thickness); const cy = lerp(y1, y2, 0.5) + Math.sin(angle) * (t * thickness); curve(x1,y1, cx,cy, x2,y2); } } const lerp = (from,to, t) => from + (to - from) * t; const smooth = (from,to, t) => { t = (-2.0 * t * t * t + 3.0 * t * t); return (to * t + from * (1.0 - t)); } const quad = (from,control,to, t) => { const q = 1 - t; return (q * q) * from + 2 * q * t * control + (t * t) * to; } function shake(v,amount) { return v + -(amount * .5) + shakeRandom.get() * amount; } function curve(x1,y1, cx,cy, x2,y2) { turtle.penup(); for(let i=0; i<=linePrecision; i++) { const t = i / linePrecision; const x = quad(x1, shake(cx, shakyness), x2, t); const y = quad(y1, shake(cy, shakyness), y2, t); if (i != 0) turtle.pendown(); turtle.goto(x,y); } } // seeded random function Random(seed) { this.state = (seed * 777) % 2147483647 } Random.prototype.nextInt = function() { return this.state = (1103515245.0 * this.state + 12543) % 2147483647; } Random.prototype.get = function() { return this.nextInt() / 2147483647; } function fract(a) {return a-Math.floor(a);} function hash(n) { return fract(Math.sin(n) * 1.0e4); } function hash2(p) { return fract(1.0e4 * Math.sin(17.0 * p[0] + p[1] * 0.1) * (0.1 + Math.abs(Math.sin(p[1] * 13.0 + p[0])))); } //////////////////////////////////////////////////////////////// // Tortoise utility code (Minimal Turtle and Transforms) // https://turtletoy.net/turtle/102cbd7c4d //////////////////////////////////////////////////////////////// function Tortoise(x, y) { class Tortoise extends Turtle { constructor(x, y) { super(x, y); this.ps = Array.isArray(x) ? [...x] : [x || 0, y || 0]; this.transforms = []; } addTransform(t) { this.transforms.push(t); this.jump(this.ps); return this; } applyTransforms(p) { if (!this.transforms) return p; let pt = [...p]; this.transforms.map(t => { pt = t(pt); }); return pt; } goto(x, y) { const p = Array.isArray(x) ? [...x] : [x, y]; const pt = this.applyTransforms(p); if (this.isdown() && (this.pt[0]-pt[0])**2 + (this.pt[1]-pt[1])**2 > 4) { this.goto((this.ps[0]+p[0])/2, (this.ps[1]+p[1])/2); this.goto(p); } else { super.goto(pt); this.ps = p; this.pt = pt; } } position() { return this.ps; } } return new Tortoise(x,y); }