Fork: way wavy way

A fork with extra config options.

I lied in a sunbeam, feeling the Sun's hot kiss when, through my closed eyelids, I read its name.

Log in to post a comment.

// Forked from "way wavy way" by ge1doot
// https://turtletoy.net/turtle/65cb465053

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

const ySpacing = 1.6; //min=0 max=3 step=.1
const octaves = 3; //min=1 max=10 step=1
const seed = 257; //min=1 max=1000 step=1
const xScale = 1; //min=.1 max=5 step=0.1
const yScale = 0.5; //min=.1 max=5 step=0.1
const xOffset = 0; //min=-1000 max=1000 step=1
const yOffset = -54; //min=-1000 max=1000 step=1
const lineCount = 282; //min=1 max=1000 step=1

/*
Seedrandom function from 
https://github.com/davidbau/seedrandom/blob/released/seedrandom.js
Copyright 2019 David Bau.
See source for complete copyright information. 
The source has been modified slightly from the original to make it shorter. 
*/

(function (global, pool, math) {    
    var width = 256,        // each RC4 output is 0 <= x < 256
        chunks = 6,         // at least six RC4 outputs for each double
        digits = 52,        // there are 52 significant digits in a double
        rngname = 'random', // rngname: name for Math.random and Math.seedrandom
        startdenom = math.pow(width, chunks),
        significance = math.pow(2, digits),
        overflow = significance * 2,
        mask = width - 1
    
    function seedrandom(seed, options, callback) {
      var key = [];
      options = (options == true) ? { entropy: true } : (options || {});
    
      var shortseed = mixkey(flatten(
        options.entropy ? [seed, tostring(pool)] :
        (seed == null) ? autoseed() : seed, 3), key);
    
      var arc4 = new ARC4(key);
      var prng = function() {
        var n = arc4.g(chunks), d = startdenom, x = 0;                          
        while (n < significance) {          
          n = (n + x) * width;              
          d *= width;                       
          x = arc4.g(1);                    
        }
        while (n >= overflow) {             
          n /= 2;                           
          d /= 2;                           
          x >>>= 1;                         
        }
        return (n + x) / d;             
      };
    
      prng.int32 = function() { return arc4.g(4) | 0; }
      prng.quick = function() { return arc4.g(4) / 0x100000000; }
      prng.double = prng;
      mixkey(tostring(arc4.S), pool);
    
      return (options.pass || callback ||
          function(prng, seed, is_math_call, state) {
            if (state) {
              if (state.S) { copy(state, arc4); }
              prng.state = function() { return copy(arc4, {}); }
            }
            if (is_math_call) { math[rngname] = prng; return seed; }
            else return prng;
          })(
      prng,
      shortseed,
      'global' in options ? options.global : (this == math),
      options.state);
    }
    
    function ARC4(key) {
      var t, keylen = key.length,
          me = this, i = 0, j = me.i = me.j = 0, s = me.S = [];
    
      if (!keylen) { key = [keylen++]; }
      while (i < width) {
        s[i] = i++;
      }
      for (i = 0; i < width; i++) {
        s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))];
        s[j] = t;
      }
    
      (me.g = function(count) {
        var t, r = 0,
            i = me.i, j = me.j, s = me.S;
        while (count--) {
          t = s[i = mask & (i + 1)];
          r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))];
        }
        me.i = i; me.j = j;
        return r;
      })(width);
    }
    
    function copy(f, t) {
      t.i = f.i;
      t.j = f.j;
      t.S = f.S.slice();
      return t;
    };
    
    function flatten(obj, depth) {
      var result = [], typ = (typeof obj), prop;
      if (depth && typ == 'object') {
        for (prop in obj) {
          try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {}
        }
      }
      return (result.length ? result : typ == 'string' ? obj : obj + '\0');
    }
    
    function mixkey(seed, key) {
      var stringseed = seed + '', smear, j = 0;
      while (j < stringseed.length) {
        key[mask & j] =
          mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++));
      }
      return tostring(key);
    }
      
    function autoseed() {
      try {
        var out;
        out = new Uint8Array(width);
        (global.crypto || global.msCrypto).getRandomValues(out);
        return tostring(out);
      } catch (e) {
        var browser = global.navigator,
            plugins = browser && browser.plugins;
        return [+new Date, global, plugins, global.screen, tostring(pool)];
      }
    }

    function tostring(a) {return String.fromCharCode.apply(0, a);}

    mixkey(math.random(), pool);
    math['seed' + rngname] = seedrandom;
})((typeof self !== 'undefined') ? self : this,[],Math);
    
const turtle = new Turtle();
class Noise {
	// http://mrl.nyu.edu/~perlin/noise/
	constructor(octaves = 1) {
		this.p = new Uint8Array(512);
		this.octaves = octaves;
		var rng = new Math.seedrandom(seed)
		for (let i = 0; i < 512; ++i) {
			this.p[i] = rng() * 256;
		}
	}
	lerp(t, a, b) {
		return a + t * (b - a);
	}
	grad2d(i, x, y) {
		const v = (i & 1) === 0 ? x : y;
		return (i & 2) === 0 ? -v : v;
	}
	noise2d(x2d, y2d) {
		const X = Math.floor(x2d) & 255;
		const Y = Math.floor(y2d) & 255;
		const x = x2d - Math.floor(x2d);
		const y = y2d - Math.floor(y2d);
		const fx = (3 - 2 * x) * x * x;
		const fy = (3 - 2 * y) * y * y;
		const p0 = this.p[X] + Y;
		const p1 = this.p[X + 1] + Y;
		return this.lerp(
			fy,
			this.lerp(
				fx,
				this.grad2d(this.p[p0], x, y),
				this.grad2d(this.p[p1], x - 1, y)
			),
			this.lerp(
				fx,
				this.grad2d(this.p[p0 + 1], x, y - 1),
				this.grad2d(this.p[p1 + 1], x - 1, y - 1)
			)
		);
	}
	noise(x, y) {
		let e = 1,
			k = 1,
			s = 0;
		for (let i = 0; i < this.octaves; ++i) {
			e *= 0.5;
			s += e * (1 + this.noise2d(k * x, k * y)) / 2;
			k *= 2;
		}
		return s;
	}
}
const perlin = new Noise(octaves);
turtle.up();
function walk(i) {
    for (let j = -100; j < 101; j++) {
	    const h = perlin.noise(100 + j * 0.01, 100 + i * 0.01);
	    
	    turtle.goto(xOffset + j * xScale, yOffset + yScale * ySpacing * i + yScale * h * 200 - 100);
	    turtle.down();
	}
    turtle.up();
    return i < lineCount;
}