A pendant fit for a Titan.
Log in to post a comment.
// Forked from "Multiball Exhibition" by maraz
// https://turtletoy.net/turtle/51730d3ea5
const quality = 2.25; // min=0.15, max=9, step=0.15
const letterbox = 0; // min=0.0, max=1.0, step=0.01
const canvasSize = 1024;
const coordSize = 200;
const step = coordSize/canvasSize/quality;
const halfCanvas = canvasSize/2;
const halfCoord = coordSize/2;
const topCoord = -halfCoord+letterbox*halfCoord;
const bottomCoord = halfCoord - letterbox*halfCoord;
const nBalls = 23;
const ballMinSize = 1;
const ballMaxSize = 40;
const ballYGap = 5;
const ballsY = -80.5;
const ballsX = 61;
const ballsMinDX = -60;
const ballsMaxDX = 15;
const ballDarkest = 0.6;
const ballLightest = 1;
const ballSeries = (n, xFn, yFn, sizeFn, darknessFn) => {
let balls = []
for (let i = 0; i <= n; i++) {
balls.push({
i,
size: sizeFn(i),
xPos: xFn(i),
yPos: yFn(i),
darkness: darknessFn(i),
})
}
return balls.reverse();
}
const balls = ballSeries(nBalls,
(i) => ballsX
+((i+1)%2) * i**2.7/nBalls/64*ballsMinDX
+(i%2) * i**2.7/nBalls/64*ballsMaxDX,
(i) => ballsY
+((i+1)%2) * (Math.sin(Math.PI*0.76+Math.PI*i**2/nBalls*0.0102)*i**2/nBalls*2)*ballYGap
+(i%2) * (Math.sin(Math.PI*0.29+Math.PI*i**2/nBalls*0.0102)*i**2/nBalls*2)*ballYGap,
(i) => ballMinSize+((1+i)/nBalls)**2*(ballMaxSize-ballMinSize),
(i) => ballLightest+(i)/nBalls*(ballDarkest-ballLightest),
)
Turtle.prototype.step = function(draw = false) {
draw && this.pendown();
this.forward(step);
draw && this.penup();
}
// This gives us antialiasing for quality > 1.
Canvas.setpenopacity(-1+0.0875*(quality-1));
const turtle = new Turtle();
turtle.penup();
turtle.goto(-halfCoord, topCoord);
turtle.seth(0);
const getCirclePos = (x, y) => Math.sqrt(x*x+y*y);
const checkCircle = (circle, x, y) => {
const ax = Math.abs(x);
const ay = Math.abs(y);
if (ay < circle.size && ax < circle.size) {
const circlePos = getCirclePos(x, y);
if (circlePos < circle.size) {
return circlePos;
}
}
return false;
}
const checkBalls = (x, y) => {
for (const ball of balls) {
const _x = x - ball.xPos;
const _y = y - ball.yPos;
const ballPos = checkCircle(ball, _x, _y);
if (ballPos != false) {
return { ...ball, x: _x, y: _y, ballPos };
}
}
return false;
}
const ballStep = (_ball) => {
return (
(Math.round(7*Math.random()) == 0)
||
Math.round(1.25-(Math.random()*(-_ball.x/(_ball.size))))>1
||
Math.round(0.875-(Math.random()*(_ball.x/(_ball.size))))>1
||
Math.round(1.25-(Math.random()*(_ball.ballPos/(_ball.size))))<1
)
&& Math.round(_ball.darkness * Math.random())==0
}
const backgroundStep = (_x, _y, xoff, yoff, xt, yt, dt) => {
const x = _x + xoff;
const y = _y + yoff;
return (
(Math.round(7*Math.random()) == 0)
||
Math.round(
Math.abs(-0.25 + (halfCoord/2+y)/halfCoord*8
*Math.sin(xt*(100+y) + Math.cos(dt*(100+y)) + Math.cos(dt*(100+x)))
*Math.cos(yt*(100+x) + Math.sin(dt*(100+x)) + Math.sin(dt*(100+y) + Math.cos(1.92*dt*(100+y))))
)
* Math.random()/0.25*Math.abs(y)/halfCoord
)==3
);
}
function drawBackground(x, y) {
turtle.step(backgroundStep(x, y, 4836, -174, 0.045, 0.0063, 0.029));
}
function drawBall(_ball) {
turtle.step(ballStep(_ball));
}
const lineMultiplier = 1/quality;
let stillMultiplying = 0;
let yStep = step/lineMultiplier;
function walk(i) {
const x = turtle.x();
const y = turtle.y();
if (x > halfCoord) {
if (quality < 1) {
if (stillMultiplying >= lineMultiplier) {
stillMultiplying = 0;
}
stillMultiplying = stillMultiplying + 1;
turtle.goto(-halfCoord, y+yStep);
}
else {
turtle.goto(-halfCoord, y+step);
}
return true;
}
const maybeBall = checkBalls(x, y-yStep*stillMultiplying);
if (maybeBall) {
drawBall(maybeBall);
}
else {
drawBackground(x, y);
}
return y < bottomCoord;
}