Fake hyperbolic plane ✈️

Just search for the nice values / curves.

Log in to post a comment.

console.clear();

const turtle = new Turtle();
const PI2 = Math.PI*2;

const depth = 5; // min=2, max=100, step=1
const useOddEven = 1; // min=0, max=1, step=1

const innerRadius = 3; // min=0, max=100, step=0.01
const outerRadius = 80; // min=0, max=100, step=0.01

const radiusEasing = 2; // min=0, max=40, step=1
const radiusEase = getEasing(radiusEasing);
console.log("radiusEase: " + radiusEase.name);

const innerAmount = 1; // min=0, max=100, step=0.1
const outerAmount = 16.7; // min=0, max=100, step=0.1
const amountEasing = 0; // min=0, max=40, step=1
const amountEase = getEasing(amountEasing);
console.log("amountEase: " + amountEase.name);

const innerCircleRadius = 1; // min=0, max=50, step=0.01
const outerCircleRadius = 15.4; // min=0, max=50, step=0.01
const circleRadiusEasing = 0; // min=0, max=40, step=1
const circleRadiusEase = getEasing(circleRadiusEasing);
console.log("circleRadiusEase: " + circleRadiusEase.name);

function walk(i) {
    let r = i/depth;
    circles(
        i, 
        lerp(innerRadius, outerRadius, radiusEase.fn(r)), 
        lerp(innerAmount, outerAmount, amountEase.fn(r))|0, 
        lerp(innerCircleRadius, outerCircleRadius, circleRadiusEase.fn(r)));
    
    return i < depth;
}

function lerp(a, b, r) {
     return a + (b - a) * r;
}

function circles(idx, radius, amount, circleRadius) {
    let f = 1 / amount;
    for (let i = 0; i<amount; i++) {
        let t = f * i;
        let a = PI2 * t;
        if (useOddEven && idx & 1) a += PI2 * f * 0.5;
        let pos = [Math.sin(a) * radius, Math.cos(a) * radius - circleRadius];
        turtle.jump(pos);
        turtle.circle(circleRadius);
    }
}


function getEasing(idx) {
    return [
        {name: "linear", fn: t => t},
        {name: "smoothstep", fn: t => t * t * (3.0 - 2.0 * t)},
        {name: "quad in", fn: t => t * t},
        {name: "quad out", fn: t => t * (2.0 - t)},
        {name: "quad in/out", fn: t => t <= 0.5 ? t * t * 2.0 : 1.0 - (--t) * t * 2.0},
        {name: "quad out/in", fn: t => (t < 0.5) ? -0.5 * (t = (t * 2.0)) * (t - 2.0) : 0.5 * (t = (t * 2.0 - 1.0)) * t + 0.5},
        {name: "pow in", fn: t => Math.pow(t, 5)},
        {name: "pow out", fn: t => 1 - Math.pow(1 - t, 5)},
        {name: "sine in", fn: t => 1 - Math.cos((Math.PI * 0.5) * t)},
        {name: "sine out", fn: t => Math.sin(Math.PI * 0.5 * t)},
        {name: "sine in/out", fn: t => .5 - Math.cos(Math.PI * t) / 2.0},
        {name: "sine out/in", fn: t => { if (t == 0.0) return 0.0
         else if (t == 1.0) return 1.0
         else return (t < 0.5) ? 0.5 * Math.sin((t * 2.0) * Math.PI*0.5) : -0.5 * Math.cos((t * 2.0 - 1.0) * Math.PI*0.5) + 1.0
         }},
        {name: "circ in", fn: t => 1.0 - Math.sqrt(1.0 - t * t)},
        {name: "circ out", fn: t => { --t; return Math.sqrt(1.0 - t * t) }},
        {name: "circ in/out", fn: t => t <= 0.5 ? (Math.sqrt(1.0 - t * t * 4.0) - 1.0) / -2.0 : (Math.sqrt(1.0 - (t * 2.0 - 2.0) * (t * 2.0 - 2.0)) + 1.0) / 2.0},
        {name: "circ out/in", fn: t => (t < 0.5) ? 0.5 * Math.sqrt(1.0 - (t = t * 2.0 - 1.0) * t) : -0.5 * ((Math.sqrt(1.0 - (t = t * 2.0 - 1.0) * t) - 1.0) - 1.0)},
        
        {name: "cube in", fn: t => t * t * t},
        {name: "cube out", fn: t => 1.0 + (--t) * t * t},
        {name: "cube in/out", fn: t => t <= 0.5 ? t * t * t * 4.0 : 1.0 + (--t) * t * t * 4.0},
        {name: "cube out/in", fn: t =>  0.5 * ((t = t * 2.0 - 1.0) * t * t + 1.0)},
        
        {name: "quart in", fn: t => t * t * t * t},
        {name: "quart out", fn: t => 1.0 - (--t) * t * t * t},
        {name: "quart in/out", fn: t => t <= 0.5 ? t * t * t * t * 8.0 : (1.0 - (t = t * 2.0 - 2.0) * t * t * t) * 0.5 + 0.5},
        {name: "quart out/in", fn: t => (t < 0.5) ? -0.5 * (t = t * 2.0 - 1.0) * t * t * t + 0.5 : 0.5 * (t = t * 2.0 - 1.0) * t * t * t + 0.5},
        
        {name: "quint in", fn: t => t * t * t * t * t},
        {name: "quint out", fn: t => (t = t - 1) * t * t * t * t + 1.0},
        {name: "quint in/out", fn: t => ((t *= 2.0) < 1.0) ? (t * t * t * t * t) / 2.0 : ((t -= 2.0) * t * t * t * t + 2.0) / 2.0},
        {name: "quint out/in", fn: t => 0.5 * ((t = t * 2.0 - 1.0) * t * t * t * t + 1.0)},
        
        {name: "expo in", fn: t => Math.pow(2, 10.0 * (t - 1.0))},
        {name: "expo out", fn: t => -Math.pow(2, -10.0 * t) + 1.0},
        {name: "expo in/out", fn: t => t < .5 ? Math.pow(2, 10.0 * (t * 2.0 - 1.0)) / 2.0 : (-Math.pow(2, -10.0 * (t * 2.0 - 1.0)) + 2.0) / 2.0},
        {name: "expo out/in", fn: t => (t < 0.5) ? 0.5 * (1.0 - Math.pow(2, -20.0 * t)) : (t == 0.5) ?  0.5 :  0.5 * (Math.pow(2, 20.0 * (t - 1.0)) + 1.0)},
        
        {name: "back in", fn: t => t * t * (5.0 * t - 4.0)},
        {name: "back out", fn: t => 1 - --t * t * (-5.0 * t - 4.0)},
        {name: "back in/out", fn: t => { t *= 2.0
         if (t < 1.0) return t * t * (5.0 * t - 4.0) / 2.0
         t -= 2.0
         return (1 - t * t * (-5.0 * t - 4.0)) / 2.0 + 0.5
        }},
        
        {name: "elastic in", fn: t => {const ELASTIC_AMPLITUDE=1, ELASTIC_PERIOD=0.4; return -(ELASTIC_AMPLITUDE * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - (ELASTIC_PERIOD / (Math.PI / 2) * Math.asin(1 / ELASTIC_AMPLITUDE))) * (Math.PI * 2) / ELASTIC_PERIOD))}},
        {name: "elastic out", fn: t => {const ELASTIC_AMPLITUDE=1, ELASTIC_PERIOD=0.4; return  (ELASTIC_AMPLITUDE * Math.pow(2, -10 * t) * Math.sin((t - (ELASTIC_PERIOD / (Math.PI * 2) * Math.asin(1 / ELASTIC_AMPLITUDE))) * (Math.PI * 2) / ELASTIC_PERIOD) +1)}},
        {name: "elastic in/out", fn: t => {const ELASTIC_AMPLITUDE=1, ELASTIC_PERIOD=0.4; if (t < 0.5) return -0.5 * (Math.pow(2, 10.0 * (t -= 0.5)) * Math.sin((t - (ELASTIC_PERIOD / 4.0)) * (Math.PI * 2) / ELASTIC_PERIOD));
         return Math.pow(2, -10 * (t -= 0.5)) * Math.sin((t - (ELASTIC_PERIOD / 4)) * (Math.PI * 2.0) / ELASTIC_PERIOD) * 0.5 + 1.0;}},
        
        {name: "steps", fn: t => Math.floor(t * 10.0) / 10.0},
        {name: "array", fn: t => [0.0, 0.4, 0.7, 0.2, 1.0][Math.floor(t * 5.0)]},
        {name: "randomish", fn: t => t + -0.03 + Math.random() * 0.06}
    ][idx];
}