Lots of turtles stepping through Perlin Noise fields. Each step the turtle moves forward an amount based on its position in one Perlin Noise field and rotates it's heading based on its position in another Perlin Noise field. This creates a whimsical effect in the flow of each turtle.
Log in to post a comment.
// You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(1); // Global code will be evaluated once. const turtles = []; let seed = 1000; // min=1, max=1000000, step=1 const bits = 20; const samples = 150000; const mod = 1<<bits; const turtles_count = 351; // min = 1 max = 1000 step = 1 const steps = 2000 // min = 1 max = 3000 step = 1 const angle_perlin = 3; // min = 1 max = 10 step = 1 const angle_perlin_mag = 3.4; // min = .1 max = 5 step = .1 const length_perlin = 3; // min = 1 max = 10 step = 1 const length_perlin_mag = 1; // min = .1 max = 5 step = .1 const spawn_range = 9; // min = 0 max = 100 step = 1 function random() { // returns a number [0, 1[ let r = 1103515245 * (((seed+=12345) >> 1) ^ seed); r = 1103515245 * (r ^ (r >> 3)); r = r ^ (r >> 16); return (r % mod) / mod; } for(let i = turtles_count; i > 0; i--) { let turtle = new Turtle; turtle.penup(); turtle.setheading(random() * 360); turtle.setx(random() * spawn_range * 2 - spawn_range); turtle.sety(random() * spawn_range * 2 - spawn_range); turtle.pendown(); turtles.push(turtle); } class Perlin { constructor(size, gridSize) { this.size = size; this.gridSize = gridSize; this.grid = []; for (let i = 0; i <= gridSize; i++) { let table = []; for (let j = 0; j <= gridSize; j++) { let angle = random() * 2 * Math.PI; let x = Math.cos(angle); let y = Math.sin(angle); table.push([x, y]); } this.grid.push(table); } } get(x, y) { x = x / 2 + this.size / 2; y = y / 2 + this.size / 2; if (x < 0) x = 0; if (x >= this.size) x = this.size - 0.01; if (y < 0) y = 0; if (y >= this.size) y = this.size - 0.01; let posx = x * this.gridSize / this.size; let posy = y * this.gridSize / this.size; let x1 = Math.floor(posx); let x2 = x1 + 1; let y1 = Math.floor(posy); let y2 = y1 + 1; let scal = []; scal.push(this.scalar(posx, posy, x1, y1)); scal.push(this.scalar(posx, posy, x2, y1)); scal.push(this.scalar(posx, posy, x1, y2)); scal.push(this.scalar(posx, posy, x2, y2)); let int1 = this.interpolate(posx - x1, scal[0], scal[1]); let int2 = this.interpolate(posx - x1, scal[2], scal[3]); return this.interpolate(posy - y1, int1, int2); } scalar(x, y, vx, vy) { x -= vx; y -= vy; return x * this.grid[vx][vy][0] + y * this.grid[vx][vy][1]; } smooth(v) { if (v < 0) v = 0; if (v > 1) v = 1; return v ** 2 * (3 - 2 * v); } interpolate(x, a, b) { return a + (b - a) * this.smooth(x); } } //////////////////////////////////////////////////////////////// // Pseudorandom number generator. Created by Reinder Nijhoff 2024 // https://turtletoy.net/turtle/a2274fd1fe //////////////////////////////////////////////////////////////// let perlin_angle = new Perlin(100, angle_perlin); let perlin_length = new Perlin(100, length_perlin); // The walk function will be called until it returns false. function walk(i) { for(let j = turtles_count-1; j > 0; j--) { let x = turtles[j].x(); let y = turtles[j].y(); turtles[j].forward(perlin_length.get(x,y) * length_perlin_mag); turtles[j].right(perlin_angle.get(x,y) * angle_perlin_mag); } return i < steps; }