Spell checker not included.
Log in to post a comment.
// LL 2021
Canvas.setpenopacity(1);
const tt = new ClippingTurtle();
const text_size = 2; // min=1 max=5 step=0.25
const columns = 3; // min=1 max=4 step=1
const seed=0; // min=0 max=100 step=1
var rng;
const fake_text = new FakeText();
function walk(i) {
if (i==0) {
rng = new RNG(seed);
const paper_width = 130;
const paper_height = paper_width / 8.5 * 11;
const margin = paper_width * 0.05 / columns;
const title_size = text_size * 5;
const subtitle_size = text_size * 2.5;
const margin_top = margin * 2 + title_size + subtitle_size;
// Draw pages
tt.jump(-paper_width/2, -paper_height/2);
drawPaper(tt, paper_width, paper_height, 5);
// Draw title
for (var t=0; t<3; t++)
{
const title_length = ((paper_width - margin * 2) / title_size / 1.5) | 0;
const title_text = generateRandomText(1, title_length);
const title_width = title_length * title_size;
tt.jump(-title_width/2, -paper_height/2 + margin);
fake_text.print(tt, title_text, title_size);
}
// Draw subtitle
{
const subtitle_length = ((paper_width - margin * 2) / subtitle_size / 2) | 0;
const subtitle_text = generateRandomText(1, subtitle_length);
const subtitle_width = subtitle_length * subtitle_size;
tt.jump(-subtitle_width/2, -paper_height/2 + margin + title_size);
fake_text.print(tt, subtitle_text, subtitle_size);
}
// Draw columns
for (var c=0; c<columns; c++) {
const left = -paper_width/2 + margin + c * (paper_width/columns - margin/columns);
const top = -paper_height/2 + margin_top;
const width = paper_width/columns - margin - margin / columns;
const height = paper_height - margin - margin_top;
drawColumn(tt, left, top, width, height, text_size);
}
}
return false;
}
function drawColumn(turtle, x, y, w, h, text_size) {
{
const line_count = (w / text_size) | 0;
const top_line = (random() * (h / text_size - line_count)) | 0;
drawFigure(turtle, x, y + top_line * text_size, w, line_count * text_size);
turtle.setWindow(x, y + top_line * text_size, x + w * 1.01, y + (top_line + line_count) * text_size);
turtle.drawInsideWindow = false;
}
{
const line_count = (h / text_size) | 0;
const line_width = (w / text_size) | 0;
const col_text = generateRandomText(line_count, line_width);
turtle.jump(x, y);
fake_text.print(turtle, col_text, text_size);
}
turtle.setWindow([]);
}
var available_figures = [];
function drawFigure(turtle, x, y, w, h) {
const figure_count = 5;
if (available_figures.length == 0)
available_figures = [drawDNA, drawLissajous, drawChart, drawFlower, drawMoire, drawDefault];
turtle.setWindow(x + w * 0.05, y + h * 0.05, x + w * 0.95, y + h * 0.95);
turtle.drawInsideWindow = true;
const figure_index = (random() * available_figures.length) | 0;
available_figures[figure_index](turtle, x, y, w, h);
available_figures.splice(figure_index, 1);
}
function drawDefault(turtle, x, y, w, h) {
const cx = x + w/2;
const cy = y + h/2;
const r = 0.45 * Math.min(w, h);
const step = Math.PI * 2 / (10 + random() * 10);
const add = step + 10 * random();
for (var a = 0; a < Math.PI * 2; a += step) {
turtle.jump(cx + r * Math.cos(a), cy + r * Math.sin(a));
turtle.goto(cx + r * Math.cos(a+add), cy + r * Math.sin(a+add));
}
}
function drawMoire(turtle, x, y, w, h) {
for (var t=0; t<=1; t++) {
const cx = x + w * random();
const cy = y + h * random();
const interval = 1.5;
turtle.down();
for (var r = interval; r < Math.max(w, h) * 2; r += interval) {
turtle.jump(cx, cy - r);
turtle.circle(r);
}
}
}
function drawLissajous(turtle, x, y, w, h) {
const cx = x + w/2;
const cy = y + h/2;
const r = 0.45 * Math.min(w, h);
const step = Math.PI * 2 / ((10 + random() * 10)|0);
const mul = random() * 30.1 + 1;
turtle.jump(cx + r, cy);
for (var a = 0; a < Math.PI * 2 * 10; a += step) {
turtle.goto(cx + r * Math.cos(a), cy + r * Math.sin(a*mul));
}
}
function drawFlower(turtle, x, y, w, h) {
const cx = x + w/2;
const cy = y + h/2;
const r = 0.25 * Math.min(w, h);
const r2 = r * 0.8;
const step = Math.PI * 2 / 100;
const mul = random() * 10 + 1;
turtle.up();
for (var a = 0; a < Math.PI * 2 * 2.1; a += step) {
turtle.goto(cx + r * Math.cos(a) + r2 * Math.cos(a * mul), cy + r * Math.sin(a) + r2 * Math.sin(a * mul));
turtle.down();
}
}
function rotX(x, y, a) { return Math.cos(a) * x - Math.sin(a) * y; }
function rotY(x, y, a) { return Math.sin(a) * x + Math.cos(a) * y; }
function getY(oy, cr, dir, offset, a) {
return oy + dir * Math.sin(offset + a * Math.PI*2) * cr;
}
function drawDNA(turtle, x, y, w, h) {
turtle.down();
const offset = random() * Math.PI * 2;
const ox = x + w/2;
const oy = y + h/2;
const cr = w / (5 + 10 * random());
const r = 0.0025 * w;
const aa = random() * Math.PI * 2;
const step = 1/(50 + 30 * random());
const freq = 3;
const w2 = w * 1.3;
const factor = 1 + random() * 2;
[-1, 1].forEach(dir => {
var previous = false;
var index = -2;
for (var a=0; a<1+step/2; a+=step) {
const x2 = ox - w2 / 2 + w2 * a;
const y2 = getY(oy, cr, dir, offset, a * factor);
const rx = rotX(x2 - ox, y2 - oy, aa) + ox;
const ry = rotY(x2 - ox, y2 - oy, aa) + oy;
const current = [rx, ry];
if (previous) {
turtle.jump(previous);
turtle.goto(current);
}
previous = current;
if ((index%freq)==0) {
turtle.jump(rx, ry-r*5);
turtle.circle(r*5);
if (dir == 1) {
const y3 = getY(oy, cr, -dir, offset, a * factor);
const rx2 = rotX(x2 - ox, y3 - oy, aa) + ox;
const ry2 = rotY(x2 - ox, y3 - oy, aa) + oy;
turtle.jump(rx2, ry2);
turtle.goto(rx, ry);
}
} else {
turtle.jump(rx, ry-r*2);
turtle.circle(r*2);
}
index++;
}
});
}
function drawChart(turtle, x, y, w, h) {
const cx = x + w * 0.1;
const cw = w * 0.8;
const cy = y + h * 0.9;
const ch = -h * 0.8;
turtle.down();
turtle.jump(cx, cy+ch);
turtle.goto(cx, cy-ch * 0.1);
turtle.jump(cx-cw * 0.1, cy);
turtle.goto(cx+cw, cy);
for (var fy=.3; fy<.91; fy+=.3) {
const step = 1/40;
turtle.up();
for (var fx=0, d=true; fx<1.01; fx+=step, d=!d) {
turtle.goto(cx + fx * cw, cy + fy * ch);
d ? turtle.down() : turtle.up();
}
}
{
const step = 1/10;
const tw = cw * 0.025;
turtle.down();
for (var t=step; t<1; t+=step) {
turtle.jump(cx + t * cw, cy + tw);
turtle.goto(cx + t * cw, cy - tw);
turtle.jump(cx - tw, cy + t * ch);
turtle.goto(cx + tw, cy + t * ch);
}
}
turtle.up();
const phase = random();
const step = 1/100;
for (var fx=0; fx<1.01; fx+=step) {
const fy = .5 + (Math.cos((fx + phase) * Math.PI * 2) / 2 + Math.cos((fx + phase) * Math.PI * 2 * 2 + phase) / 4 + Math.cos(fx * Math.PI * 2 * 4 + phase) / 8) /2;
turtle.goto(cx + fx * cw, cy + fy * ch);
turtle.down();
}
}
function drawPaper(turtle, width, height, pages) {
const x = turtle.position()[0], y = turtle.position()[1];
const step = height / 200;
turtle.down();
[[1,0],[1,1],[0,1],[0,0]].forEach(p => turtle.goto(x + width * p[0], y + height * p[1]));
for (var p=1; p<pages; p++) {
turtle.up();
[[1,1,0,0],[1,0,0,0],[1,0,1,0],[0,0,1,0],[0,0,1,1]].forEach(q => {
turtle.goto(x + width * q[0] + step * (p - q[1]), y + height * q[2] + step * (p - q[3]));
turtle.down();
});
}
}
//function random() { return Math.random(); }
function random() { return rng.nextFloat(); }
function generateRandomText(line_count, line_width) {
var str = "";
for (var line=0; line<line_count; line++) {
if (line > 0) str += '\n';
var need_space = 0;
for (var c=0; c<line_width; c++) {
if (c == line_width-1) need_space = 0;
if (need_space > 1 && random()<0.2) {
str += " ";
need_space = 0;
} else {
str += String.fromCharCode(33 + (random()*94)|0);
need_space++;
}
}
}
return str;
}
function FakeText() {
var font = null;
function generate_font() {
if (font != null) return;
font = {};
for (var c=33; c<127; c++) {
font[c] = [];
const count = 2 + random() * 8;
const h = count / 20 + random() * 0.5;
for (var i=0; i<count; i++) {
const line = [ [ random(), 1 - random() * h], [ random(), 1 - random() * h] ];
font[c].push(line);
}
}
}
function print_chr(turtle, x, y, chr, char_width, char_height) {
turtle.down();
const list = font[chr.charCodeAt(0)];
if (list !== undefined) {
list.forEach(line => {
turtle.jump(x + line[0][0] * char_width * 1.1, y + line[0][1] * char_height);
turtle.goto(x + line[1][0] * char_width * 1.1, y + line[1][1] * char_height);
});
}
}
function print_str(turtle, str, size=10) {
generate_font();
str = str.toLowerCase();
const char_height = size;
const char_width = size;
var x = turtle.position()[0];
const left_x = x;
var y = turtle.position()[1];
for (var i=0; i<str.length; i++) {
if (str[i] == '\n') {
x = left_x;
y += char_height;
} else {
print_chr(turtle, x, y, str[i], char_width*1.2, char_height);
x += char_width;
}
}
turtle.jump(x, y);
}
return {
print: (turtle, str, size) => print_str(turtle, str, size),
};
}
///////////////////////////////////////////////////////////////////////////
// Clipping Turtle utility code (minified). Created by Lionel Lemarie 2021
// https://turtletoy.net/turtle/2b46e93a22
///////////////////////////////////////////////////////////////////////////
function ClippingTurtle(){function i(i,s,t){return i-1e-4<=s&&s<=t+1e-4||t-1e-4<=s&&s<=i+1e-4}return new class extends Turtle{constructor(){super(),this.window=[],this.drawInsideWindow=!0}setWindow(i,s,t,n){this.window=[i,s,t,n]}drawWindow(){if(4!=this.window.length)return;const i=this.position(),s=!this.isdown();this.down(),super.jump(this.window[0],this.window[1]),super.goto(this.window[2],this.window[1]),super.goto(this.window[2],this.window[3]),super.goto(this.window[0],this.window[3]),super.goto(this.window[0],this.window[1]),super.jump(i),s&&this.up()}pointInside(i){return i[0]>=this.window[0]&&i[1]>=this.window[1]&&i[0]<=this.window[2]&&i[1]<=this.window[3]}lineInside(i){return this.pointInside(i[0])&&this.pointInside(i[1])}lineOutside(i){return i[0][0]<this.window[0]&&i[1][0]<this.window[0]||i[0][1]<this.window[1]&&i[1][1]<this.window[1]||i[0][0]>this.window[2]&&i[1][0]>this.window[2]||i[0][1]>this.window[3]&&i[1][1]>this.window[3]}clipLine(s,t,n,o,w){const e=(h=this.window[t],d=this.window[n],r=this.window[o],p=this.window[w],u=s[0][0],a=s[0][1],c=s[1][0],l=s[1][1],g=((h*p-d*r)*(u-c)-(h-r)*(u*l-a*c))/((h-r)*(a-l)-(d-p)*(u-c)),I=((h*p-d*r)*(a-l)-(d-p)*(u*l-a*c))/((h-r)*(a-l)-(d-p)*(u-c)),!(isNaN(g)||isNaN(I)||!i(h,g,r)||!i(d,I,p)||!i(u,g,c)||!i(a,I,l))&&[g,I]);var h,d,r,p,u,a,c,l,g,I;return e&&(s[this.pointInside(s[0])^this.drawInsideWindow?0:1]=[...e]),s}goto(i,s){const t=Array.isArray(i)?[...i]:[i,s];if(this.isdown()&&4==this.window.length){var n=[this.position(),[...t]];this.lineInside(n)?this.drawInsideWindow?super.goto(t):super.jump(t):this.lineOutside(n)?this.drawInsideWindow?super.jump(t):super.goto(t):(n=this.clipLine(n,0,1,2,1),n=this.clipLine(n,2,1,2,3),n=this.clipLine(n,0,3,2,3),n=this.clipLine(n,0,1,0,3),super.jump(n[0]),super.goto(n[1]),super.jump(t))}else super.goto(t)}circle(i){const s=this.position(),t=2*Math.PI/100;for(var n=-Math.PI/2;n<=1.501*Math.PI;n+=t)this.goto(s[0]+i*Math.cos(n),s[1]+i+i*Math.sin(n))}}}
// Minified Random Number Generator from https://turtletoy.net/turtle/ab7a7e539e
function RNG(t){return new class{constructor(t){this.m=2147483648,this.a=1103515245,this.c=12345,this.state=t||Math.floor(Math.random()*(this.m-1))}nextFloat(){return this.state=(this.a*this.state+this.c)%this.m,this.state/(this.m-1)}}(t)}