Half-Square Hilbert
cArraycolorPicker1colorPicker2patternSelectrerollButtonblockFunctioncreateControlscontrolsDivbuttonsDivsaveImageButtoncreateNewPatternvalidhasC1hasC2useC1updateColorspickedColor1pickedColor2oldC1oldC2currentArraytruchetblock1block2
let w;
let cnv;
let c1 = [50, 50, 205];
let c2 = [250, 250, 220];
let cArray = [];
let colorPicker1;
let colorPicker2;
let patternSelect;
let rerollButton;
function setup() {
w = 0.9 * min(windowWidth - 40, windowHeight - 200);
cnv = createCanvas(w, w);
cnv.parent("sketch-container");
noStroke();
createControls();
createNewPattern();
describe(
"a quilt following a hilbert-like pattern made with half-square triangles."
);
loop();
}
function draw() {
translate(w / 2, w / 2);
background(c1);
strokeWeight(w / 200);
noStroke();
const blockFunction = window["block" + patternSelect.value()];
if (typeof blockFunction === "function") {
blockFunction(w);
}
}
function windowResized() {
w = min(windowWidth - 40, windowHeight - 200);
resizeCanvas(w, w);
loop();
redraw();
}
function createControls() {
const controlsDiv = createDiv();
controlsDiv.id("controls");
controlsDiv.style("margin-top", "20px");
controlsDiv.style("display", "flex");
controlsDiv.style("flex-wrap", "wrap");
controlsDiv.style("gap", "20px");
createP("Background Color:").parent(controlsDiv);
colorPicker1 = createColorPicker(color(c1[0], c1[1], c1[2]));
colorPicker1.parent(controlsDiv);
colorPicker1.input(() => {
updateColors();
loop();
});
createP("Accent Color:").parent(controlsDiv);
colorPicker2 = createColorPicker(color(c2[0], c2[1], c2[2]));
colorPicker2.parent(controlsDiv);
colorPicker2.input(() => {
updateColors();
loop();
});
colorPicker1.style("width", "60px");
colorPicker1.style("height", "30px");
colorPicker2.style("width", "60px");
colorPicker2.style("height", "30px");
createP("Pattern Size:").parent(controlsDiv);
patternSelect = createSelect();
patternSelect.parent(controlsDiv);
for (let i = 1; i <= 7; i++) {
patternSelect.option(i);
}
patternSelect.selected("5");
patternSelect.changed(() => {
loop();
redraw();
});
const buttonsDiv = createDiv();
buttonsDiv.parent(controlsDiv);
rerollButton = createButton("Reroll Pattern");
rerollButton.parent(buttonsDiv);
rerollButton.mousePressed(() => {
createNewPattern();
loop();
});
const saveImageButton = createButton("Save as Image");
saveImageButton.parent(buttonsDiv);
saveImageButton.mousePressed(() => {
saveCanvas(cnv, "truchet_pattern", "png");
});
}
function createNewPattern() {
let valid = false;
while (!valid) {
cArray = [];
let hasC1 = false;
let hasC2 = false;
for (let i = 0; i < 8; i++) {
const useC1 = random() > 0.5;
cArray[i] = useC1 ? [...c1] : [...c2];
if (useC1) hasC1 = true;
else hasC2 = true;
}
valid = hasC1 && hasC2;
}
loop();
redraw();
}
function updateColors() {
const pickedColor1 = colorPicker1.color();
const pickedColor2 = colorPicker2.color();
const oldC1 = [...c1];
const oldC2 = [...c2];
c1 = [red(pickedColor1), green(pickedColor1), blue(pickedColor1)];
c2 = [red(pickedColor2), green(pickedColor2), blue(pickedColor2)];
for (let i = 0; i < cArray.length; i++) {
const currentArray = cArray[i];
if (
Array.isArray(currentArray) &&
currentArray.length === 3 &&
currentArray[0] === oldC1[0] &&
currentArray[1] === oldC1[1] &&
currentArray[2] === oldC1[2]
) {
cArray[i] = [...c1];
} else {
cArray[i] = [...c2];
}
}
loop();
redraw();
}
function truchet(d1, a, b) {
push();
fill(a);
triangle(-d1, -d1, -d1, d1, d1, d1);
fill(b);
triangle(-d1, -d1, d1, -d1, d1, d1);
pop();
}
function block1(d) {
push();
translate(-d / 4, -d / 4);
truchet(d / 4, cArray[0], cArray[1]);
translate(0, d / 2);
truchet(d / 4, cArray[2], cArray[3]);
pop();
push();
translate(d / 4, d / 4);
truchet(d / 4, cArray[4], cArray[5]);
translate(0, -d / 2);
truchet(d / 4, cArray[6], cArray[7]);
pop();
}
function block2(d) {
push();
scale(1 / 2, 1 / 2);
push();
translate(-w / 2, -w / 2);
block1(d);
translate(w, 0);
scale(-1, 1);
block1(d);
pop();
push();
translate(-w / 2, w / 2);
rotate(PI / 2);
block1(d);
pop();
push();
translate(w / 2, w / 2);
rotate(-PI / 2);
scale(-1, 1);
block1(d);
pop();
pop();
}
function block3(d) {
push();
scale(1 / 2, 1 / 2);
push();
translate(-w / 2, -w / 2);
block2(d);
translate(w, 0);
scale(-1, 1);
block2(d);
pop();
push();
translate(-w / 2, w / 2);
rotate(PI / 2);
block2(d);
pop();
push();
translate(w / 2, w / 2);
rotate(-PI / 2);
scale(-1, 1);
block2(d);
pop();
pop();
}
function block4(d) {
push();
scale(1 / 2, 1 / 2);
push();
translate(-w / 2, -w / 2);
block3(d);
translate(w, 0);
scale(-1, 1);
block3(d);
pop();
push();
translate(-w / 2, w / 2);
rotate(PI / 2);
block3(d);
pop();
push();
translate(w / 2, w / 2);
rotate(-PI / 2);
scale(-1, 1);
block3(d);
pop();
pop();
}
function block5(d) {
push();
scale(1 / 2, 1 / 2);
push();
translate(-w / 2, -w / 2);
block4(d);
translate(w, 0);
scale(-1, 1);
block4(d);
pop();
push();
translate(-w / 2, w / 2);
rotate(PI / 2);
block4(d);
pop();
push();
translate(w / 2, w / 2);
rotate(-PI / 2);
scale(-1, 1);
block4(d);
pop();
pop();
}
function block6(d) {
push();
scale(1 / 2, 1 / 2);
push();
translate(-w / 2, -w / 2);
block5(d);
translate(w, 0);
scale(-1, 1);
block5(d);
pop();
push();
translate(-w / 2, w / 2);
rotate(PI / 2);
block5(d);
pop();
push();
translate(w / 2, w / 2);
rotate(-PI / 2);
scale(-1, 1);
block5(d);
pop();
pop();
}
function block7(d) {
push();
scale(1 / 2, 1 / 2);
push();
translate(-w / 2, -w / 2);
block6(d);
translate(w, 0);
scale(-1, 1);
block6(d);
pop();
push();
translate(-w / 2, w / 2);
rotate(PI / 2);
block6(d);
pop();
push();
translate(w / 2, w / 2);
rotate(-PI / 2);
scale(-1, 1);
block6(d);
pop();
pop();
}