Grid011
With Console Logging of the arrays
Which can be manually added to a Fork of Architecture 004
Architecture 004
Log in to post a comment.
// Architecture 002 — Nested Rectangles + connecting lines
// 10 November 2025
// Code from ChatGPT with 2 hours of frustrating prompting
// it's both amazing and also infuriating to work with.
// Because it's not intelegent in any sense of the word
// Large Language Models have ZERO intelegence they are just
// statistical models. It's like calling Excel intelegent.
// Hope you enjoy it :-)
const opacity = -1; // min=-1, max=1, step=0.1
Canvas.setpenopacity(opacity);
const turtle = new Turtle();
// ===== PARAMETERS =====
const parentMinX = -90;
const parentMaxX = 90;
const parentMinY = -90;
const parentMaxY = 90;
const canvasW = parentMaxX - parentMinX;
const canvasH = parentMaxY - parentMinY;
const baseCols = 7; // min=1 max=7 step=1
const baseRows = 7; // min=1 max=7 step=1
const mergeChance = 0.45; // min=0.1 max= 1 step=0.1
const parentCellMinWidth = 20;
const parentCellMaxWidth = 80;
const parentCellMinHeight = 15;
const parentCellMaxHeight = 60;
const minInset = 0.1;
const maxInset = 0.3;
const innerMinWidth = 5;
const innerMaxWidth = 60;
const innerMinHeight = 5;
const innerMaxHeight = 60;
const innerPaddingX = 10;
const innerPaddingY = 10;
const connectorLines = 15; // Number of connecting lines along each edge
// ===== DRAW MODE =====
const drawmode = 2; // 0 = Black only, 1 = White only, 2 = Both
// ===== STORAGE ARRAY =====
const corners = []; // combined array for parent + child
// ===== GRID SETUP =====
function randomProportions(n) {
let vals = Array.from({ length: n }, () => 0.5 + Math.random());
const sum = vals.reduce((a, b) => a + b, 0);
return vals.map(v => v / sum);
}
const colWeights = randomProportions(baseCols);
const rowWeights = randomProportions(baseRows);
const colWidths = colWeights.map(w => w * canvasW);
const rowHeights = rowWeights.map(h => h * canvasH);
let colX = [parentMinX];
for (let i = 0; i < baseCols; i++) colX.push(colX[i] + colWidths[i]);
let rowY = [parentMinY];
for (let j = 0; j < baseRows; j++) rowY.push(rowY[j] + rowHeights[j]);
let filled = Array.from({ length: baseRows }, () => Array(baseCols).fill(false));
// ===== DRAW CELLS =====
for (let r = 0; r < baseRows; r++) {
for (let c = 0; c < baseCols; c++) {
if (filled[r][c]) continue;
// Merge cells
let mergeW = 1;
let mergeH = 1;
if (Math.random() < mergeChance && c < baseCols - 1 && !filled[r][c + 1]) mergeW = 2;
if (Math.random() < mergeChance && r < baseRows - 1 && !filled[r + 1][c]) mergeH = 2;
if (c + mergeW > baseCols) mergeW = 1;
if (r + mergeH > baseRows) mergeH = 1;
// Constrain size
const tempX2 = colX[c + mergeW];
const tempY2 = rowY[r + mergeH];
const tempWidth = tempX2 - colX[c];
const tempHeight = tempY2 - rowY[r];
if (tempWidth < parentCellMinWidth || tempWidth > parentCellMaxWidth) mergeW = 1;
if (tempHeight < parentCellMinHeight || tempHeight > parentCellMaxHeight) mergeH = 1;
// Mark cells filled
for (let rr = r; rr < r + mergeH; rr++) {
for (let cc = c; cc < c + mergeW; cc++) {
filled[rr][cc] = true;
}
}
// Parent rectangle
const px1 = colX[c];
const px2 = colX[c + mergeW];
const py1 = rowY[r];
const py2 = rowY[r + mergeH];
rectangle(px1, py1, px2, py2);
// ===== CHILD RECTANGLE =====
const w = px2 - px1;
const h = py2 - py1;
const insetFrac = minInset + Math.random() * (maxInset - minInset);
const maxInnerWByInset = w * (1 - insetFrac);
const maxInnerHByInset = h * (1 - insetFrac);
const maxInnerW = Math.min(innerMaxWidth, maxInnerWByInset, w - 2 * innerPaddingX);
const maxInnerH = Math.min(innerMaxHeight, maxInnerHByInset, h - 2 * innerPaddingY);
const randInnerW = innerMinWidth + Math.random() * Math.max(0, maxInnerW - innerMinWidth);
const randInnerH = innerMinHeight + Math.random() * Math.max(0, maxInnerH - innerMinHeight);
const cx1 = px1 + innerPaddingX + Math.random() * (w - randInnerW - 2 * innerPaddingX);
const cy1 = py1 + innerPaddingY + Math.random() * (h - randInnerH - 2 * innerPaddingY);
const cx2 = cx1 + randInnerW;
const cy2 = cy1 + randInnerH;
rectangle(cx1, cy1, cx2, cy2);
// Save combined parent+child corners, rounded to 2 decimals
// Open the Console and copy the array.
// You will have to edit this to match the format used in Architecture 004
// https://turtletoy.net/turtle/9c1aa52ddb
// 0: {1: -90, 2: -90, 3: -31, 4: -41, 5: -56, 6: -72, 7: -46, 8: -64}
// 1: {1: -31, 2: -90, 3: -5, 4: -75, 5: -21, 6: -89, 7: -16, 8: -84}
// The Log from the consode needs to be manually edited to match the following format:
// {x1: -90, y1: -90, x2: -31, y2: -41, x3: -56, y3: -72, x4: -46, y4: -64, hNum: 1, vNum: 1},
// {x1: -31, y1: -90, x2: -5, y2: -75, x3: -21, y3: -89, x4: -16, y4: -84, hNum: 1, vNum: 1},
// hNum and vNum let you multiply the default number of horozontal and vertical black and whitle lines
// for any specific cells.
corners.push({
1: parseFloat(px1.toFixed(0)),
2: parseFloat(py1.toFixed(0)),
3: parseFloat(px2.toFixed(0)),
4: parseFloat(py2.toFixed(0)),
5: parseFloat(cx1.toFixed(0)),
6: parseFloat(cy1.toFixed(0)),
7: parseFloat(cx2.toFixed(0)),
8: parseFloat(cy2.toFixed(0))
});
// ===== CONNECT CHILD TO PARENT =====
connectChildToParent(px1, py1, px2, py2, cx1, cy1, cx2, cy2, connectorLines, drawmode);
}
}
// ===== FUNCTIONS =====
function rectangle(xA, yA, xB, yB) {
turtle.penup();
turtle.goto(xA, yA);
turtle.pendown();
turtle.goto(xB, yA);
turtle.goto(xB, yB);
turtle.goto(xA, yB);
turtle.goto(xA, yA);
}
function connectChildToParent(px1, py1, px2, py2, cx1, cy1, cx2, cy2, lines, drawmode) {
// TOP EDGE → White
if (drawmode === 1 || drawmode === 2) {
for (let i = 0; i <= lines; i++) {
const t = i / lines;
const childX = cx1 + t * (cx2 - cx1);
turtle.penup();
turtle.goto(childX, cy1);
turtle.pendown();
const parentX = px1 + t * (px2 - px1);
turtle.goto(parentX, py1);
}
}
// RIGHT EDGE → White
if (drawmode === 1 || drawmode === 2) {
for (let i = 0; i <= lines; i++) {
const t = i / lines;
const childY = cy1 + t * (cy2 - cy1);
turtle.penup();
turtle.goto(cx2, childY);
turtle.pendown();
const parentY = py1 + t * (py2 - py1);
turtle.goto(px2, parentY);
}
}
// BOTTOM EDGE → Black
if (drawmode === 0 || drawmode === 2) {
for (let i = 0; i <= lines; i++) {
const t = i / lines;
const childX = cx1 + t * (cx2 - cx1);
turtle.penup();
turtle.goto(childX, cy2);
turtle.pendown();
const parentX = px1 + t * (px2 - px1);
turtle.goto(parentX, py2);
}
}
// LEFT EDGE → Black
if (drawmode === 0 || drawmode === 2) {
for (let i = 0; i <= lines; i++) {
const t = i / lines;
const childY = cy1 + t * (cy2 - cy1);
turtle.penup();
turtle.goto(cx1, childY);
turtle.pendown();
const parentY = py1 + t * (py2 - py1);
turtle.goto(px1, parentY);
}
}
}
// ===== OUTPUT =====
console.log("Combined parent+child corners:", corners);